Logo Search packages:      
Sourcecode: kazehakase version File versions

kz-thumbnails-view.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2003-2004 Takuro Ashie
 *  Copyright (C) 2004 Hiroyuki Ikezoe
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#include "kz-thumbnails-view.h"

#include <glib/gi18n.h>
#include "kazehakase.h"
#include "gobject-utils.h"
#include "kz-thumbnail.h"
#include "egg-pixbuf-thumbnail.h"
#include "kz-marshalers.h"

struct _KzThumbnailsViewPriv
{
      KzThumbnailsViewMode mode;
};

enum {
      ACTIVATE,
      LAST_SIGNAL
};

#define KZ_THUMBNAIL_BOOKMARK_KEY "KzThumbnail::Bookmark"

static void     kz_thumbnails_view_class_init (KzThumbnailsViewClass *klass);
static void     kz_thumbnails_view_init       (KzThumbnailsView      *view);
static void     kz_thumbnails_view_dispose    (GObject              *object);
static void     kz_thumbnails_view_finalize   (GObject              *object);

static void       kz_thumbnails_view_size_allocate (GtkWidget        *widget,
                                            GtkAllocation    *allocation);

static void       kz_thumbnails_view_redraw      (KzThumbnailsView *view);

static void     connect_bookmark_signals     (KzThumbnailsView *view,
                                    KzBookmark *bookmark);
static void     disconnect_bookmark_signals  (KzThumbnailsView *view,
                                    KzBookmark *bookmark);

static void     insert_bookmark              (KzThumbnailsView *view,
                                    KzBookmark *bookmark,
                                      KzBookmark *child,
                                    KzBookmark *sibling);

static gboolean cb_thumbnail_release         (GtkWidget *thumbnail,
                                    GdkEventButton *event,
                                    KzThumbnailsView *view); 
static gboolean cb_thumbnail_enter_notify    (GtkWidget        *widget,
                                    GdkEventCrossing *event);
static gboolean cb_thumbnail_leave_notify    (GtkWidget        *widget,
                                    GdkEventCrossing *event);

static GtkLayoutClass *parent_class = NULL;

static gint kz_thumbnails_view_signals[LAST_SIGNAL] = {0};

KZ_OBJECT_GET_TYPE(kz_thumbnails_view, "KzThumbnailsView", KzThumbnailsView,
               kz_thumbnails_view_class_init, kz_thumbnails_view_init,
               GTK_TYPE_TABLE)

static void
kz_thumbnails_view_class_init (KzThumbnailsViewClass *klass)
{
      GObjectClass *object_class;
      GtkWidgetClass *widget_class;

      parent_class = g_type_class_peek_parent (klass);

      object_class  = (GObjectClass *) klass;
      widget_class  = (GtkWidgetClass *) klass;

      object_class->dispose  = kz_thumbnails_view_dispose;
      object_class->finalize = kz_thumbnails_view_finalize;

      widget_class->size_allocate       = kz_thumbnails_view_size_allocate;

      klass->activate = NULL;

      kz_thumbnails_view_signals[ACTIVATE]
            = g_signal_new ("activate",
                        G_TYPE_FROM_CLASS (klass),
                        G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                        G_STRUCT_OFFSET (KzThumbnailsViewClass, activate),
                        NULL, NULL,
                        _kz_marshal_VOID__OBJECT_INT,
                        G_TYPE_NONE, 2,
                        KZ_TYPE_BOOKMARK, G_TYPE_INT);
}


static void
kz_thumbnails_view_init (KzThumbnailsView *view)
{
      view->folder = NULL;
      
      view->priv = g_new0(KzThumbnailsViewPriv, 1);
      view->priv->mode = KZ_THUMBNAILS_VIEW_VERTICAL;
      gtk_table_set_homogeneous(GTK_TABLE(view), FALSE);
      gtk_table_set_col_spacings(GTK_TABLE(view), 4);
      gtk_table_set_row_spacings(GTK_TABLE(view), 4);
}


static void
kz_thumbnails_view_dispose (GObject *object)
{
      KzThumbnailsView *view = KZ_THUMBNAILS_VIEW(object);

      if (view->folder)
      {
            disconnect_bookmark_signals(view, view->folder);
            g_object_unref(view->folder);
            view->folder = NULL;
      }

      if (G_OBJECT_CLASS(parent_class)->dispose)
            G_OBJECT_CLASS (parent_class)->dispose(object);
}


KZ_OBJECT_FINALIZE (kz_thumbnails_view, KzThumbnailsView)


static void       
kz_thumbnails_view_size_allocate (GtkWidget *widget,
                                  GtkAllocation *allocation)
{
      GtkAllocation old_allocation;
      gint old_width;
      KzThumbnailsView *view;
      
      view = KZ_THUMBNAILS_VIEW(widget);

      old_allocation = widget->allocation;
      old_width = old_allocation.width;

      GTK_WIDGET_CLASS(parent_class)->size_allocate (widget, allocation);

      if (view->priv->mode == KZ_THUMBNAILS_VIEW_PLANE &&
          old_width != allocation->width)
      {
            kz_thumbnails_view_redraw(view);
      }
}

GtkWidget *
kz_thumbnails_view_new (void)
{
      KzThumbnailsView *view;
      view = g_object_new(KZ_TYPE_THUMBNAILS_VIEW,
                        NULL);

      return GTK_WIDGET(view);
}


static void
kz_thumbnails_view_set_thumbnail_at_pos (KzThumbnailsView *view,
                               GtkWidget *thumbnail,
                               gint pos)
{
      switch (view->priv->mode)
      {
      case KZ_THUMBNAILS_VIEW_PLANE:
      {
            gint xnum, xpos, ypos;
            gint width;
            width = GTK_WIDGET(view)->allocation.width;

            if (width < EGG_PIXBUF_THUMB_NORMAL)
                  xnum = 1;
            else
                  xnum = (width / EGG_PIXBUF_THUMB_NORMAL);
            ypos = pos / xnum;
            xpos = pos % xnum;      
            gtk_table_attach(GTK_TABLE(view),
                         thumbnail,
                         xpos, xpos + 1,
                         ypos, ypos + 1,
                         GTK_SHRINK, GTK_SHRINK,
                         4, 4);
            break;
      }
      case KZ_THUMBNAILS_VIEW_HORIZONTAL:
            gtk_table_attach(GTK_TABLE(view),
                         thumbnail,
                         pos, pos + 1,
                         0, 1,
                         GTK_SHRINK, GTK_SHRINK,
                         4, 4);
            break;
      case KZ_THUMBNAILS_VIEW_VERTICAL:
      default:
            gtk_table_attach(GTK_TABLE(view),
                         thumbnail,
                         0, 1,
                         pos, pos + 1,
                         GTK_SHRINK, GTK_SHRINK,
                         4, 4);
            break;
      }
}


static void 
kz_thumbnails_view_redraw (KzThumbnailsView *view)
{
      GList *node;
      gint i = 0;

      for (node = view->children; node; node = g_list_next(node))
      {
            GtkWidget *thumb = node->data;

            g_object_ref(thumb);
            gtk_container_remove(GTK_CONTAINER(view), thumb);
            kz_thumbnails_view_set_thumbnail_at_pos(view, thumb, i);          
            g_object_unref(thumb);
            i++;
      }
}


static void
destroy_child_widget (gpointer data, gpointer user_data)
{
      if (GTK_IS_WIDGET(data))
            gtk_widget_destroy(data);
}

void
kz_thumbnails_view_set_folder (KzThumbnailsView *view,
                         KzBookmark *folder)
{
      GList *children, *node;
      
      g_return_if_fail(KZ_IS_THUMBNAILS_VIEW(view));
      g_return_if_fail(!folder || kz_bookmark_is_folder(folder));

      if (view->folder)
      {
            disconnect_bookmark_signals(view, view->folder);
            g_object_unref(view->folder);
            view->folder = NULL;

            /* remove old widgets */
            g_list_foreach(view->children,
                         destroy_child_widget, NULL);
            g_list_free(view->children);
      }

      if (!folder) return;

      view->folder = g_object_ref(folder);
      connect_bookmark_signals(view, view->folder);

      children = kz_bookmark_get_children(folder);
      for (node = children; node; node = g_list_next(node))
      {
            insert_bookmark(view, view->folder,
                        node->data, NULL);
      }
      g_list_free(children);
}


void       
kz_thumbnails_view_set_mode (KzThumbnailsView *view,
                         KzThumbnailsViewMode mode)
{
      if (view->priv->mode == mode)
            return;

      view->priv->mode = mode;

      /* redraw */
      kz_thumbnails_view_redraw(view);
}


static GtkWidget *
find_thumbnail_widget (KzThumbnailsView *view, KzBookmark *bookmark)
{
      GtkWidget *widget;
      GList *children;
      gint index;
      
      children = kz_bookmark_get_children(view->folder);
      index = g_list_index(children, bookmark); 
      g_list_free(children);

      widget = g_list_nth_data(view->children, index);

      return widget;
}

static void
thumbnail_set_bookmark_property (GtkWidget *thumbnail, KzBookmark *bookmark)
{
      const gchar *uri, *desc;
      
      uri = kz_bookmark_get_link(bookmark);
      if (!uri)
            uri = "about:blank";

      kz_thumbnail_set_thumbnail_from_uri(KZ_THUMBNAIL(thumbnail), uri);
      
      desc = kz_bookmark_get_description(bookmark);
      if (desc)
      {
            GtkTooltips *tooltip;
            tooltip = gtk_tooltips_new();
            gtk_tooltips_set_tip(tooltip, thumbnail, desc, NULL);
      }
}


static void
cb_bookmark_notify (GObject *object, GParamSpec *pspec,
                KzThumbnailsView *view)
{
      KzBookmark *bookmark;
      const gchar *prop;
        GValue value = { 0 };

      g_return_if_fail(KZ_IS_BOOKMARK(object));

      bookmark = KZ_BOOKMARK(object);

      prop = g_param_spec_get_name(pspec);
      g_return_if_fail(prop);

        g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
        g_object_get_property(object, prop, &value);

      if (!strcmp(prop, "link"))
      {
            GtkWidget *thumbnail;

            thumbnail = find_thumbnail_widget(view, bookmark);
            if (!thumbnail) return;

            thumbnail_set_bookmark_property(thumbnail, bookmark);
      }
      g_value_unset(&value);
}


static void
insert_bookmark (KzThumbnailsView *view,
             KzBookmark *bookmark,
             KzBookmark *child,
             KzBookmark *sibling)
{
      GtkWidget *thumbnail;
      gint pos = -1;

      thumbnail = kz_thumbnail_new();
      thumbnail_set_bookmark_property(thumbnail, child);

      g_object_set_data(G_OBJECT(thumbnail),
                    KZ_THUMBNAIL_BOOKMARK_KEY,
                    child);
      g_signal_connect(thumbnail, "button_release_event",
                   G_CALLBACK(cb_thumbnail_release), view);
      g_signal_connect(thumbnail, "enter-notify-event",
                   G_CALLBACK(cb_thumbnail_enter_notify), NULL);
      g_signal_connect(thumbnail, "leave-notify-event",
                   G_CALLBACK(cb_thumbnail_leave_notify), NULL);

      if (sibling)
      {
            GList *children;
            
            children = kz_bookmark_get_children(bookmark);
            pos = g_list_index(children, sibling); 
            g_list_free(children);
      }

      if (pos >= 0)
      {
            GList *node, *pos_node;
            gint i = pos + 1;
            pos_node = g_list_nth(view->children, pos);

            for (node = pos_node; node; node = g_list_next(node))
            {
                  GtkWidget *thumb = node->data;

                  g_object_ref(thumb);
                  gtk_container_remove(GTK_CONTAINER(view), thumb);

                  kz_thumbnails_view_set_thumbnail_at_pos(view, thumb, i);          
                  g_object_unref(thumb);
                  i++;
            }
      }
      else
      {
            pos = g_list_length(view->children);
      }
      view->children = g_list_insert(view->children,
                               thumbnail,
                               pos);

      gtk_widget_show(thumbnail);

      kz_thumbnails_view_set_thumbnail_at_pos(view, thumbnail, pos);          
      g_signal_connect(child, "notify",
                   G_CALLBACK(cb_bookmark_notify), view);
}


static void
cb_bookmark_insert_child (KzBookmark *bookmark,
                    KzBookmark *child,
                    KzBookmark *sibling,
                    KzThumbnailsView *view)
{
      insert_bookmark(view, bookmark, child, sibling);
}


static void
cb_bookmark_remove_child (KzBookmark *bookmark,
                    KzBookmark *child,
                    KzThumbnailsView *view)
{
      GtkWidget *thumbnail;

      g_signal_handlers_disconnect_by_func
            (child,
             G_CALLBACK(cb_bookmark_notify), view);

      thumbnail = find_thumbnail_widget(view, child);

      if (thumbnail)
      {
            gtk_widget_destroy(thumbnail);
            view->children = g_list_remove(view->children, thumbnail);
      }
}


static void
connect_bookmark_signals (KzThumbnailsView *view,
                    KzBookmark *bookmark)
{
      g_return_if_fail(KZ_IS_BOOKMARK(bookmark));

      g_signal_connect(bookmark, "insert-child",
                   G_CALLBACK(cb_bookmark_insert_child), view);
      g_signal_connect(bookmark, "remove-child",
                   G_CALLBACK(cb_bookmark_remove_child), view);
}


static void
disconnect_bookmark_signals (KzThumbnailsView *view,
                       KzBookmark *bookmark)
{
      g_return_if_fail(KZ_IS_BOOKMARK(bookmark));

      g_signal_handlers_disconnect_by_func
            (bookmark,
             G_CALLBACK(cb_bookmark_insert_child), view);
      g_signal_handlers_disconnect_by_func
            (bookmark,
             G_CALLBACK(cb_bookmark_remove_child), view);
}


static gboolean
cb_thumbnail_release (GtkWidget *thumbnail, GdkEventButton *event,
                  KzThumbnailsView *view)
{
      KzBookmark *bookmark;
      GList *children;
      gint index;
      
      if (event->button == 3)
            return TRUE;

      bookmark = g_object_get_data(G_OBJECT(thumbnail),
                             KZ_THUMBNAIL_BOOKMARK_KEY);
      children = kz_bookmark_get_children(view->folder);
      index = g_list_index(children, bookmark);
      g_list_free(children);

      g_signal_emit(view,
                  kz_thumbnails_view_signals[ACTIVATE],
                  0,
                  bookmark, index);

      return FALSE;
}

static gboolean
cb_thumbnail_enter_notify (GtkWidget *widget,
                     GdkEventCrossing *event)
{
      gtk_widget_set_state(widget, GTK_STATE_PRELIGHT);
      return FALSE;
}


static gboolean
cb_thumbnail_leave_notify (GtkWidget *widget,
                     GdkEventCrossing *event)
{
      return FALSE;     
}



Generated by  Doxygen 1.6.0   Back to index