Logo Search packages:      
Sourcecode: kazehakase version File versions

kz-bookmark-item.c

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

/*
 *  Copyright (C) 2003-2004 Hiroyuki Ikezoe
 *  Copyright (C) 2003 Takuro Ashie <ashie@homa.ne.jp>
 *
 *  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.
 *
 *  $Id: kz-bookmark-item.c,v 1.10 2005/04/22 04:44:38 ikezoe Exp $
 */

#include "kz-bookmark-item.h"

#include <gtk/gtk.h>
#include <glib/gi18n.h>

#include "gobject-utils.h"
#include "kazehakase.h"
#include "kz-bookmark-file.h"
#include "kz-bookmark-menu.h"
#include "kz-bookmark-editor.h"
#include "kz-icons.h"
#include "kz-actions.h"
#include "gtk-utils.h"
#include "kz-input-event-box.h"

enum {
      PROP_0,
      PROP_BOOKMARK,
      PROP_KZ_WINDOW
};

enum {
      TARGET_KAZEHAKASE_BOOKMARKS,
};

static GtkTargetEntry dnd_types[] = {
      {"_KAZEHAKASE_BOOKMARKS", 0, TARGET_KAZEHAKASE_BOOKMARKS},
};

static const gint dnd_types_num = G_N_ELEMENTS(dnd_types);

static void     kz_bookmark_item_class_init       (KzBookmarkItemClass *klass);
static void     kz_bookmark_item_init             (KzBookmarkItem *menu);

/* object class methods */
static GObject* kz_bookmark_item_constructor      (GType           type,
                                       guint           n_props,
                                       GObjectConstructParam *props);
static void     kz_bookmark_item_dispose          (GObject        *object);
static void     kz_bookmark_item_set_property     (GObject        *object,
                                       guint           prop_id,
                                       const GValue   *value,
                                       GParamSpec     *pspec);
static void     kz_bookmark_item_get_property     (GObject        *object,
                                       guint           prop_id,
                                       GValue         *value,
                                       GParamSpec     *pspec);
/* widget class methods */
static void     kz_bookmark_item_drag_data_get    (GtkWidget        *widget,
                                       GdkDragContext   *context,
                                       GtkSelectionData *seldata,
                                       guint             info,
                                       guint             time);
static void     kz_bookmark_item_drag_begin       (GtkWidget        *widget,
                                       GdkDragContext   *context);

/* private methods */
static void     kz_bookmark_item_reset_submenu    (KzBookmarkItem *menu);

/* callback for bookmark objects */
static void     cb_bookmark_load_start            (KzBookmark *bookmark,
                                       KzBookmarkItem *menu);
static void     cb_bookmark_load_stop             (KzBookmark *bookmark,
                                       KzBookmarkItem *menu);
static void     cb_bookmark_load_error            (KzBookmark *bookmark,
                                       const gchar *error,
                                       KzBookmarkItem *menu);
static void     bookmark_weak_ref                 (gpointer data,
                                       GObject *obj);

/* callbacks for child widgets */
static gboolean cb_bookmark_menu_release          (GtkWidget        *widget,
                                       GdkEventButton   *event,
                                       KzBookmarkItem   *menu);
static void     cb_update_button_clicked          (GtkWidget        *widget,
                                       KzBookmarkItem   *menu);
static void     cb_menuitem_destroy               (GtkWidget        *widget,
                                       KzBookmark       *item);

/* manage life cycle of both menuitems and bookmarks */
static void     connect_observe_signals           (GtkWidget *widget,
                                       KzBookmark *item);


static GtkHBoxClass *parent_class = NULL;


KZ_OBJECT_GET_TYPE(kz_bookmark_item, "KzBookmarkItem", KzBookmarkItem,
               kz_bookmark_item_class_init, kz_bookmark_item_init,
               GTK_TYPE_HBOX)

static void
kz_bookmark_item_class_init (KzBookmarkItemClass *klass)
{
      GObjectClass *gobject_class;
      GtkWidgetClass *widget_class;

      parent_class = g_type_class_peek_parent (klass);

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

      /* GObject signals */
      gobject_class->dispose      = kz_bookmark_item_dispose;
      gobject_class->constructor  = kz_bookmark_item_constructor;
      gobject_class->set_property = kz_bookmark_item_set_property;
      gobject_class->get_property = kz_bookmark_item_get_property;

      widget_class->drag_data_get = kz_bookmark_item_drag_data_get;
      widget_class->drag_begin    = kz_bookmark_item_drag_begin;

      g_object_class_install_property
            (gobject_class,
             PROP_BOOKMARK,
             g_param_spec_object ("bookmark",
                              _("Bookmark"),
                              _("The boomark to show"),
                              KZ_TYPE_BOOKMARK,
                              G_PARAM_READWRITE |
                              G_PARAM_CONSTRUCT_ONLY));
      g_object_class_install_property
            (gobject_class,
             PROP_KZ_WINDOW,
             g_param_spec_object ("kz-window",
                              _("KzWindow"),
                              _("The KzWindow to add a home button"),
                              KZ_TYPE_WINDOW,
                              G_PARAM_READWRITE |
                              G_PARAM_CONSTRUCT_ONLY));
}


static void
kz_bookmark_item_init (KzBookmarkItem *menu)
{
      menu->kz            = NULL;
      menu->bookmark      = NULL;
      menu->sub_menu      = NULL;
      menu->update_button = NULL;
      menu->image         = NULL;
}


static GObject*
kz_bookmark_item_constructor (GType                  type,
                        guint                  n_props,
                        GObjectConstructParam *props)
{
      KzBookmarkItem *menu;
      GtkWidget *button, *image, *eventbox;
      GtkBox *hbox;
      GtkRcStyle *style;
      GObject *object;
      GObjectClass *klass = G_OBJECT_CLASS(parent_class);
      KzBookmarkFileState state;
      gboolean is_file, is_folder;

      object = klass->constructor(type, n_props, props);

      hbox = GTK_BOX(object);
      menu = KZ_BOOKMARK_ITEM(object);
      is_file = KZ_IS_BOOKMARK_FILE(menu->bookmark);
      is_folder = kz_bookmark_is_folder(menu->bookmark);
      
      gtk_container_set_border_width(GTK_CONTAINER(menu), 2);

      /* button */
      menu->update_button = button = gtk_button_new();
      gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
      gtk_box_pack_start(hbox, button, FALSE, FALSE, 0);
      if (is_file)
      {
            g_signal_connect(button, "clicked", 
                         G_CALLBACK(cb_update_button_clicked),
                         menu);
            menu->image = image
                  = gtk_image_new_from_stock(KZ_STOCK_GREEN,
                                       KZ_ICON_SIZE_BOOKMARK_MENU);
      }
      else
      {
            g_signal_connect(button, "button_release_event",
                         G_CALLBACK(cb_bookmark_menu_release), menu);
            if(is_folder)
            {
                  menu->image = image
                        = gtk_image_new_from_stock(KZ_STOCK_FOLDER,
                                             KZ_ICON_SIZE_BOOKMARK_MENU);
            }
            else
            {
                  KzFavicon *kzfav;
                  GtkWidget *favicon = NULL;

                  /* favicon */
                  kzfav = kz_favicon_get_instance();
                  favicon     = kz_favicon_get_widget(kzfav,
                                          kz_bookmark_get_link(menu->bookmark),
                                          KZ_ICON_SIZE_BOOKMARK_MENU);
                  if (favicon)
                  {
                        menu->image = image = favicon;
                  }
                  else
                  {
                        menu->image = image
                              = gtk_image_new_from_stock(KZ_STOCK_BOOKMARK,
                                                   KZ_ICON_SIZE_BOOKMARK_MENU);
                  }
                  g_object_unref(kzfav);
            }
      }
      gtk_container_add(GTK_CONTAINER(button), image);
      gtk_widget_show(image);
      gtk_widget_show(button);
      style = gtk_rc_style_new ();
      style->xthickness = style->ythickness = 0;
      gtk_widget_modify_style (button, style);
      gtk_rc_style_unref (style);

      if (is_file)
      {
            g_signal_connect(menu->bookmark,
                         "load_start", 
                         G_CALLBACK(cb_bookmark_load_start),
                         menu);
            g_signal_connect(menu->bookmark,
                         "load_completed", 
                         G_CALLBACK(cb_bookmark_load_stop),
                         menu);
            g_signal_connect(menu->bookmark,
                         "error", 
                         G_CALLBACK(cb_bookmark_load_error),
                         menu);

            state = kz_bookmark_file_get_state(KZ_BOOKMARK_FILE(menu->bookmark));
            if (state == KZ_BOOKMARK_FILE_STATE_LOADING)
                  cb_bookmark_load_start(menu->bookmark, menu);
      }
      /* label */
      eventbox = kz_input_event_box_new();
      menu->eventbox = eventbox;
      gtk_box_pack_start(hbox, eventbox, FALSE, FALSE, 0);
      g_signal_connect(eventbox, "button_release_event",
                   G_CALLBACK(cb_bookmark_menu_release), menu);
      gtk_widget_show (eventbox);

      menu->label = gtk_label_new(kz_bookmark_get_title(menu->bookmark));
      gtk_container_add(GTK_CONTAINER(eventbox), menu->label);
      gtk_widget_show (menu->label);

      gtk_drag_source_set(GTK_WIDGET(menu),
                      GDK_BUTTON1_MASK |
                      GDK_BUTTON2_MASK |
                      GDK_BUTTON3_MASK,
                      dnd_types,
                      dnd_types_num,
                      GDK_ACTION_ASK  | GDK_ACTION_COPY
                      | GDK_ACTION_MOVE | GDK_ACTION_LINK);
      /* submenu */
      kz_bookmark_item_reset_submenu(menu);

      connect_observe_signals(GTK_WIDGET(menu), menu->bookmark);

      return object;
}


static void
kz_bookmark_item_dispose (GObject *object)
{
      KzBookmarkItem *menu;

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

      menu = KZ_BOOKMARK_ITEM(object);

      if (menu->bookmark)
      {
            if (KZ_IS_BOOKMARK_FILE(menu->bookmark))
            {
                  g_signal_handlers_disconnect_by_func(
                        menu->bookmark,
                        cb_bookmark_load_start,
                        menu);
                  g_signal_handlers_disconnect_by_func(
                        menu->bookmark,
                        cb_bookmark_load_stop,
                        menu);
                  g_signal_handlers_disconnect_by_func(
                        menu->bookmark,
                        cb_bookmark_load_error,
                        menu);
            }
            g_object_unref(menu->bookmark);
            menu->bookmark = NULL;
      }

      if (menu->sub_menu)
      {
            g_object_unref(G_OBJECT(menu->sub_menu));
            menu->sub_menu = NULL;
      }

      if (menu->kz)
            g_object_unref(menu->kz);
      menu->kz = NULL;
}


static void
kz_bookmark_item_set_property (GObject         *object,
                         guint            prop_id,
                         const GValue    *value,
                         GParamSpec      *pspec)
{
      KzBookmarkItem *menu = KZ_BOOKMARK_ITEM(object);
  
      switch (prop_id)
      {
      case PROP_BOOKMARK:
            menu->bookmark = g_object_ref(g_value_get_object(value));
            break;
      case PROP_KZ_WINDOW:
            menu->kz = g_object_ref(g_value_get_object(value));
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
      }
}


static void
kz_bookmark_item_get_property (GObject         *object,
                         guint            prop_id,
                         GValue          *value,
                         GParamSpec      *pspec)
{
      KzBookmarkItem *item = KZ_BOOKMARK_ITEM(object);

      switch (prop_id)
      {
      case PROP_BOOKMARK:
            g_value_set_object(value, item->bookmark);
            break;
      case PROP_KZ_WINDOW:
            g_value_set_object(value, item->kz);
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
      }
}


GtkWidget *
kz_bookmark_item_new (KzWindow *kz, KzBookmark *bookmark)
{
      KzBookmarkItem *menu;

      g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);
      g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);

      menu = g_object_new(KZ_TYPE_BOOKMARK_ITEM,
                     "kz-window", kz,
                     "bookmark",  bookmark,
                     NULL);

      return GTK_WIDGET(menu);
}


/*****************************************************************************
 *                                                                           *
 *                            Private methods                                *
 *                                                                           *
 *****************************************************************************/
static void
kz_bookmark_item_reset_submenu (KzBookmarkItem *menu)
{
      GtkWidget *submenu;

      if (!kz_bookmark_is_folder(menu->bookmark))
            return;

      submenu = kz_bookmark_menu_create_submenu(menu->bookmark, menu->kz);
      if (menu->sub_menu)
            g_object_unref(menu->sub_menu);
      menu->sub_menu = submenu;
      g_object_ref(G_OBJECT(menu->sub_menu));
      gtk_object_sink(GTK_OBJECT(menu->sub_menu));
}


/*****************************************************************************
 *                                                                           *
 *                                Callbacks                                  *
 *                                                                           *
 *****************************************************************************/
static void 
cb_bookmark_load_start (KzBookmark *bookmark, KzBookmarkItem *menu)
{
      g_return_if_fail(KZ_IS_BOOKMARK_ITEM(menu));

      gtk_image_set_from_stock(GTK_IMAGE(menu->image),
                         KZ_STOCK_RED,
                         KZ_ICON_SIZE_BOOKMARK_MENU);
}


static void 
cb_bookmark_load_stop (KzBookmark *bookmark, KzBookmarkItem *menu)
{
      gboolean update = TRUE;
      g_return_if_fail(KZ_IS_BOOKMARK_ITEM(menu));

      kz_bookmark_item_reset_submenu(menu);

      if (KZ_IS_BOOKMARK_FILE(bookmark))
            update = kz_bookmark_file_is_update(KZ_BOOKMARK_FILE(bookmark));

      if (update)
      {
            gtk_image_set_from_stock(GTK_IMAGE(menu->image),
                               KZ_STOCK_YELLOW,
                               KZ_ICON_SIZE_BOOKMARK_MENU);
      }
      else
      {
            gtk_image_set_from_stock(GTK_IMAGE(menu->image),
                               KZ_STOCK_GREEN,
                               KZ_ICON_SIZE_BOOKMARK_MENU);
      }
}


static void 
cb_bookmark_load_error (KzBookmark *bookmark, const gchar *error, KzBookmarkItem *menu)
{
      g_return_if_fail(KZ_IS_BOOKMARK_ITEM(menu));

      gtk_image_set_from_stock(GTK_IMAGE(menu->image),
                         KZ_STOCK_GRAY,
                         KZ_ICON_SIZE_BOOKMARK_MENU);
}


static void
cb_notify_title (GObject *object, GParamSpec *pspec,
             KzBookmarkItem *menu)
{
      const gchar *title;

      title = kz_bookmark_get_title(KZ_BOOKMARK(object));
      gtk_label_set_text(GTK_LABEL(menu->label), title);
}


static void
bookmark_weak_ref (gpointer data, GObject *obj)
{
      KzBookmark *item = KZ_BOOKMARK(obj);
      GtkWidget *widget = data;

      if (!widget) return;

      g_signal_handlers_disconnect_by_func(widget,
                                   G_CALLBACK(cb_menuitem_destroy),
                                   item);
}


static gboolean
cb_bookmark_menu_release (GtkWidget *widget, GdkEventButton *event,
                    KzBookmarkItem *menu)
{
      KzWindow *kz;
      GdkEventButton *event_button;

      kz = menu->kz;

      event_button = (GdkEventButton *)event;

      switch(event_button->button)
      {
      case 1:
            if (kz_bookmark_is_folder(menu->bookmark))
            {
                  if (!GTK_IS_MENU(menu->sub_menu))
                        return FALSE;

                  gtk_menu_popup(GTK_MENU(menu->sub_menu), NULL, NULL, 
                               gtkutil_menu_position_under_widget,
                               GTK_WIDGET(menu),
                               0, event_button->time);
            }
            else
            {
                  const gchar *uri = kz_bookmark_get_link(menu->bookmark);
                  if (uri)
                        kz_window_load_url(kz, uri);
            }
            break;
      case 2:
            if (kz_bookmark_is_folder(menu->bookmark))
            {
                  GtkAction *action;
                  kz_actions_set_bookmark_for_action(kz, menu->bookmark);
                  action = gtk_action_group_get_action(kz->actions,
                                               "OpenAllBookmarks");
                  if (action)
                        gtk_action_activate(action);
                  kz_actions_set_bookmark_for_action(kz, NULL);
            }
            else
            {
                  const gchar *uri = kz_bookmark_get_link(menu->bookmark);
                  if (uri)
                        kz_window_open_new_tab(kz, uri);
            }
            break;
      case 3:
            kz_actions_popup_bookmark_menu_modal(kz, menu->bookmark,
                                         event->button,
                                         event->time);
            break;
      default:
            break;
      }

      return TRUE;
}


static void
cb_update_button_clicked (GtkWidget *widget, KzBookmarkItem *menu)
{
      g_return_if_fail(KZ_IS_BOOKMARK_ITEM(menu));

      kz_bookmark_file_load_start(KZ_BOOKMARK_FILE(menu->bookmark));
}


static void
cb_menuitem_destroy(GtkWidget *widget, KzBookmark *item)
{
      g_signal_handlers_disconnect_by_func(item,
                                   G_CALLBACK(cb_notify_title),
                                   widget);
      g_object_weak_unref(G_OBJECT(item), bookmark_weak_ref, widget);
}


static void
kz_bookmark_item_drag_data_get (GtkWidget *widget,
                        GdkDragContext *context,
                        GtkSelectionData *seldata,
                        guint info,
                        guint time)
{
      switch (info)
      {
      case TARGET_KAZEHAKASE_BOOKMARKS:
            gtk_selection_data_set(seldata, seldata->target,
                               8, (const guchar*)"dummy", strlen("dummy"));
            break;
      }
}


static void
kz_bookmark_item_drag_begin (GtkWidget *widget, GdkDragContext *context)
{
      KzBookmarkItem *item;
      KzBookmark *bookmark;
      const gchar *stock_id;

      item = KZ_BOOKMARK_ITEM(widget);
      bookmark = item->bookmark;

      if (KZ_IS_BOOKMARK_FILE(bookmark))
            stock_id = KZ_STOCK_REMOTE_BOOKMARK;
      else if (kz_bookmark_is_folder(bookmark))
            stock_id = KZ_STOCK_FOLDER;
      else
            stock_id = KZ_STOCK_BOOKMARK;

      gtk_drag_source_set_icon_stock(widget, stock_id);
}


static void
connect_observe_signals (GtkWidget *widget, KzBookmark *item)
{
      g_signal_connect(item, "notify::title",
                   G_CALLBACK(cb_notify_title), widget);
      g_object_weak_ref(G_OBJECT(item), bookmark_weak_ref, widget);

      g_signal_connect(widget, "destroy",
                   G_CALLBACK(cb_menuitem_destroy), item);
}

Generated by  Doxygen 1.6.0   Back to index