Logo Search packages:      
Sourcecode: kazehakase version File versions

kz-bookmark-bar.c

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

/*
 *  Copyright (C) 2003 Hiroyuki Ikezoe
 *  Copyright (C) 2003 - 2004 Takuro Ashie
 *
 *  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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <glib/gi18n.h>

#include "kazehakase.h"
#include "gobject-utils.h"
#include "kz-root-bookmark.h"
#include "kz-bookmark-bar.h"
#include "kz-bookmark-menu.h"
#include "kz-bookmark-item.h"
#include "kz-bookmark.h"
#include "kz-bookmark-file.h"
#include "kz-actions.h"
#include "utils.h"
#include "glib-utils.h"

enum {
      PROP_0,
      PROP_KZ_WINDOW,
      PROP_BOOKMARK_LIST
};

enum {
      TARGET_KAZEHAKASE_BOOKMARKS,
      TARGET_NETSCAPE_URL,
      TARGET_TEXT_URI_LIST
};

static GtkTargetEntry url_drag_types [] = 
{
      {"_KAZEHAKASE_BOOKMARKS", 0, TARGET_KAZEHAKASE_BOOKMARKS},
        { "_NETSCAPE_URL",        0, TARGET_NETSCAPE_URL},
      { "text/uri-list",        0, TARGET_TEXT_URI_LIST}
};

static guint n_url_drag_types = G_N_ELEMENTS (url_drag_types);

static void     kz_bookmark_bar_class_init   (KzBookmarkBarClass *klass);
static void     kz_bookmark_bar_init         (KzBookmarkBar *bar);
static GObject* kz_bookmark_bar_constructor  (GType           type,
                                    guint           n_props,
                                    GObjectConstructParam *props);
static void     kz_bookmark_bar_dispose      (GObject *object);
static void     kz_bookmark_bar_set_property (GObject       *object,
                                    guint          prop_id,
                                    const GValue  *value,
                                    GParamSpec    *pspec);
static void     kz_bookmark_bar_get_property (GObject       *object,
                                    guint          prop_id,
                                    GValue        *value,
                                    GParamSpec    *pspec);

static gboolean kz_bookmark_bar_button_release (GtkWidget      *widget,
                                      GdkEventButton *event);
static void     kz_bookmark_bar_drag_data_received
                                   (GtkWidget *widget,
                                    GdkDragContext *context,
                                    gint x, gint y,
                                    GtkSelectionData *data,
                                    guint info,
                                    guint time);
#if 0
static gboolean kz_bookmark_bar_drag_motion  (GtkWidget *widget,
                                    GdkDragContext *context,
                                    gint x, gint y,
                                    guint time);
#endif
static void     kz_bookmark_bar_refresh_all  (KzBookmarkBar *bar);

static void     kz_bookmark_bar_connect_signal    (KzBookmarkBar *bar);
static void     kz_bookmark_bar_disconnect_signal (KzBookmarkBar *bar);


static void     cb_bookmark_list_updated         (KzBookmark *folder,
                                      KzBookmarkBar *bar);
static void     cb_bookmark_list_remove_child    (KzBookmark *folder,
                                      KzBookmark *child,
                                      KzBookmarkBar *bar);
static void     cb_bookmark_list_insert_child    (KzBookmark *folder,
                                      KzBookmark *child,
                                      KzBookmark *sibling,
                                      KzBookmarkBar *bar);

static GtkToolItem *create_tool_item (KzBookmarkBar *bar,
                              KzBookmark *child);

static GtkEventBoxClass *parent_class = NULL;


KZ_OBJECT_GET_TYPE(kz_bookmark_bar, "KzBookmarkBar", KzBookmarkBar,
               kz_bookmark_bar_class_init, kz_bookmark_bar_init,
               GTK_TYPE_EVENT_BOX)


static void
kz_bookmark_bar_class_init (KzBookmarkBarClass *klass)
{
      GObjectClass *gobject_class;
      GtkWidgetClass *widget_class;

      parent_class = g_type_class_peek_parent (klass);

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

      /* GObject class */
      gobject_class->constructor  = kz_bookmark_bar_constructor;
      gobject_class->dispose      = kz_bookmark_bar_dispose;
      gobject_class->set_property = kz_bookmark_bar_set_property;
      gobject_class->get_property = kz_bookmark_bar_get_property;

      widget_class->button_release_event = kz_bookmark_bar_button_release;
      widget_class->drag_data_received   = kz_bookmark_bar_drag_data_received;
/*    widget_class->drag_motion          = kz_bookmark_bar_drag_motion; */

      g_object_class_install_property
            (gobject_class,
             PROP_KZ_WINDOW,
             g_param_spec_object ("kz-window",
                              _("KzWindow"),
                              _("The parent kazehakase window"),
                              KZ_TYPE_WINDOW,
                              G_PARAM_READWRITE |
                              G_PARAM_CONSTRUCT_ONLY));

      g_object_class_install_property
            (gobject_class,
             PROP_BOOKMARK_LIST,
             g_param_spec_object ("bookmark-folder",
                              _("BookmarkFolder"),
                              _("Bookmarks list to show"),
                              KZ_TYPE_BOOKMARK,
                              G_PARAM_READWRITE |
                              G_PARAM_CONSTRUCT_ONLY));
}


static void
kz_bookmark_bar_init (KzBookmarkBar *bar)
{
      bar->toolbar = gtk_toolbar_new();
      bar->kz      = NULL;
      bar->folder  = NULL;

      gtk_container_add(GTK_CONTAINER(bar), bar->toolbar);
      gtk_widget_show(bar->toolbar);

      gtk_drag_dest_set(GTK_WIDGET(bar), 
                    GTK_DEST_DEFAULT_ALL, 
                          url_drag_types, n_url_drag_types,
                    GDK_ACTION_LINK | GDK_ACTION_MOVE);
}


static void
kz_bookmark_bar_dispose (GObject *object)
{
      KzBookmarkBar *bar = KZ_BOOKMARK_BAR(object);

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

      if (bar->folder)
      {
            kz_bookmark_bar_disconnect_signal(bar);
            g_object_unref(bar->folder);
            bar->folder = NULL;
      }

      if (bar->kz)
      {
            g_object_unref(bar->kz);
            bar->kz = NULL;
      }
}


static GObject*
kz_bookmark_bar_constructor (GType                  type,
                       guint                  n_props,
                       GObjectConstructParam *props)
{
      KzBookmarkBar *bar;

      GObject *object;
      GObjectClass *klass = G_OBJECT_CLASS(parent_class);

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

      bar = KZ_BOOKMARK_BAR(object);

      kz_bookmark_bar_refresh_all(bar);
      return object;
}


static void
kz_bookmark_bar_set_property (GObject         *object,
                        guint            prop_id,
                        const GValue    *value,
                        GParamSpec      *pspec)
{
      KzBookmarkBar *bar = KZ_BOOKMARK_BAR(object);
  
      switch (prop_id)
      {
      case PROP_KZ_WINDOW:
            bar->kz = g_object_ref(g_value_get_object(value));
            break;
      case PROP_BOOKMARK_LIST:
            bar->folder = g_object_ref(g_value_get_object(value));
            kz_bookmark_bar_connect_signal(bar);
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
      }
}


static void
kz_bookmark_bar_get_property (GObject         *object,
                        guint            prop_id,
                        GValue          *value,
                        GParamSpec      *pspec)
{
      KzBookmarkBar *bar = KZ_BOOKMARK_BAR(object);

      switch (prop_id)
      {
      case PROP_KZ_WINDOW:
            g_value_set_object(value, bar->kz);
            break;
      case PROP_BOOKMARK_LIST:
            g_value_set_object(value, bar->folder);
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
      }
}


static gboolean
kz_bookmark_bar_button_release (GtkWidget *widget, GdkEventButton *event)
{
      KzBookmarkBar *bar;

      bar = KZ_BOOKMARK_BAR(widget);

      switch (event->button)
      {
      case 1:
            break;
      case 2:
            break;
      case 3:
            kz_actions_popup_bookmark_menu_modal(bar->kz,
                                         bar->folder,
                                         event->button,
                                         event->time);
            break;
      default:
            break;
      }
      return FALSE;
}


GtkWidget *
kz_bookmark_bar_new (KzWindow *kz, KzBookmark *folder)
{
      GObject *obj;

      g_return_val_if_fail(KZ_IS_BOOKMARK(folder), NULL);
      g_return_val_if_fail(kz_bookmark_is_folder(folder), NULL);

      obj = g_object_new(KZ_TYPE_BOOKMARK_BAR,
                     "kz-window",       kz,
                     "bookmark-folder", folder,
                     NULL);

      return GTK_WIDGET(obj);
}


static void
remove_item (GtkWidget *child, gpointer data)
{
      gtk_container_remove(GTK_CONTAINER(child->parent), child);
}


static void
kz_bookmark_bar_refresh_all (KzBookmarkBar *bar)
{
      GList *children, *node;

      gtk_container_foreach (GTK_CONTAINER (GTK_TOOLBAR(bar->toolbar)),
                         remove_item, NULL);

      children = kz_bookmark_get_children(bar->folder);
      for (node = children; node; node = g_list_next(node))
      {
            GtkToolItem *toolitem;
            KzBookmark *bookmark = node->data;
            
            toolitem = create_tool_item(bar, bookmark);
            gtk_toolbar_insert(GTK_TOOLBAR(bar->toolbar),
                           toolitem, -1);
      }
      g_list_free(children);

      gtk_widget_queue_resize(GTK_WIDGET(bar));
}


static void
kz_bookmark_bar_connect_signal (KzBookmarkBar *bar)
{
      g_signal_connect(bar->folder, "children-reordered",
                   G_CALLBACK(cb_bookmark_list_updated),
                   bar);      
      g_signal_connect(bar->folder, "insert-child",
                   G_CALLBACK(cb_bookmark_list_insert_child),
                   bar);
      g_signal_connect(bar->folder, "remove-child",
                   G_CALLBACK(cb_bookmark_list_remove_child),
                   bar);      
}


static void
kz_bookmark_bar_disconnect_signal (KzBookmarkBar *bar)
{
      g_signal_handlers_disconnect_by_func
            (bar->folder,
             G_CALLBACK(cb_bookmark_list_updated), bar);
      g_signal_handlers_disconnect_by_func
            (bar->folder,
             G_CALLBACK(cb_bookmark_list_insert_child), bar);
      g_signal_handlers_disconnect_by_func
            (bar->folder,
             G_CALLBACK(cb_bookmark_list_remove_child), bar);
}


static void
kz_bookmark_bar_drag_data_received (GtkWidget *widget,
                            GdkDragContext *context,
                            gint x, gint y,
                            GtkSelectionData *data,
                            guint info,
                            guint time)
{
      KzBookmarkBar *bar;
      KzBookmark *bookmark, *sibling, *parent;
      gchar **strings = NULL; 
      GtkWidget *src_widget;
      const gchar *title;
      gchar *utf8_title = NULL;
      GList *children;
      gint index;

      bar = KZ_BOOKMARK_BAR(widget);
      index = gtk_toolbar_get_drop_index(GTK_TOOLBAR(bar->toolbar),
                                 x, y);

      children = kz_bookmark_get_children(bar->folder);
      sibling = g_list_nth_data(children, index);
      g_list_free(children);

      switch (info)
      {
       case TARGET_KAZEHAKASE_BOOKMARKS:
            src_widget = gtk_drag_get_source_widget(context);
            
            if (!KZ_IS_BOOKMARK_ITEM(src_widget))
                  break;

            bookmark = KZ_BOOKMARK_ITEM(src_widget)->bookmark;
            if (bookmark == sibling)
                  break;
      
            g_object_ref(bookmark);

            parent = kz_bookmark_get_parent(bookmark);
            kz_bookmark_remove(parent, bookmark);

            if (sibling)
            {
                  kz_bookmark_insert_before(bar->folder,
                                      bookmark,
                                      sibling);
            }
            else
            {
                  kz_bookmark_append(bar->folder, bookmark);
            }
            kz_bookmark_file_save(KZ_BOOKMARK_FILE(bar->folder));
            gtk_drag_finish(context, TRUE, FALSE, time);
            break;
       case TARGET_NETSCAPE_URL:
       case TARGET_TEXT_URI_LIST:
            if (data->length < 0) return;
            strings = g_strsplit((const gchar*)data->data, "\n", 2);
            if (!strings) return;
            if (strings[1] != NULL)
            {
                  utf8_title = g_locale_to_utf8(strings[1],
                                          strlen(strings[1]),
                                          NULL,
                                          NULL,
                                          NULL);
            }
            if (utf8_title && g_utf8_validate(utf8_title, -1, NULL))
                  title = utf8_title;
            else 
                  title = _("title");
            
            /* FIXME! we should also add normal bookmark. */
            /* Create New KzBookmark */
            if (strstr(strings[0], "xml") ||
                strstr(strings[0], "rss") ||
                strstr(strings[0], "rdf"))
            {
                  bookmark = KZ_BOOKMARK(kz_bookmark_file_new(strings[0],
                                          title,
                                          NULL));
            }
            else
            {
                  bookmark = kz_bookmark_new_with_attrs(title,
                                                strings[0],
                                                NULL);
            }
            if (sibling)
            {
                  kz_bookmark_insert_before(bar->folder,
                                      bookmark,
                                      sibling);
            }
            else
            {
                  kz_bookmark_append(bar->folder, bookmark);
            }
            g_strfreev(strings);
            if (utf8_title)
                  g_free(utf8_title);
            g_object_unref(bookmark);
            kz_bookmark_file_save(KZ_BOOKMARK_FILE(bar->folder));
            gtk_drag_finish(context, TRUE, FALSE, time);
            break;
       default:
            gtk_drag_finish(context, FALSE, FALSE, time);
            break;
      }
}

#if 0
static gboolean 
kz_bookmark_bar_drag_motion (GtkWidget *widget,
                       GdkDragContext *context,
                       gint x, gint y,
                       guint time)
{
      KzBookmarkBar *bar;
      gint index;
      
      bar = KZ_BOOKMARK_BAR(widget);
      index = gtk_toolbar_get_drop_index(GTK_TOOLBAR(bar->toolbar),
                                 x, y);
      
      gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(bar->toolbar),
                                  NULL, index);
      
      gdk_drag_status(context, context->suggested_action, time);

      return TRUE;
}
#endif

static void
cb_toolitem_destroy(GtkWidget *widget, GtkWidget *proxy)
{
      gtk_widget_destroy(proxy);
}


static GtkToolItem *
create_tool_item (KzBookmarkBar *bar, KzBookmark *child)
{
      GtkToolItem *toolitem;
      
      g_return_val_if_fail(KZ_IS_BOOKMARK(child), NULL);
      g_return_val_if_fail(KZ_IS_BOOKMARK_BAR(bar), NULL);

      if (kz_bookmark_is_separator(child))
      {
            toolitem = gtk_separator_tool_item_new();
      }
      else
      {
            GtkWidget *widget, *proxy;

            widget = kz_bookmark_item_new(bar->kz, child);
            gtk_widget_show(widget);
            toolitem = gtk_tool_item_new();
            gtk_container_add(GTK_CONTAINER(toolitem),
                          GTK_WIDGET(widget));
            proxy = kz_bookmark_menu_create_menuitem(child, bar->kz, FALSE);
            gtk_tool_item_set_proxy_menu_item(GTK_TOOL_ITEM(toolitem),
                                      "bookmark", proxy);
            /*
             * We need to connect "destroy" signal to disconnect signals 
             * to bookmark folder associated with proxy.
             */
            g_signal_connect(toolitem, "destroy",
                         G_CALLBACK(cb_toolitem_destroy), proxy);
            
            gtk_widget_show(proxy);
      }
      gtk_widget_show(GTK_WIDGET(toolitem));
      return toolitem;  
}


static void
cb_bookmark_list_updated (KzBookmark *folder, KzBookmarkBar *bar)
{
      g_return_if_fail(KZ_IS_BOOKMARK_BAR(bar));

      kz_bookmark_bar_refresh_all(bar);
}


static void
cb_bookmark_list_insert_child  (KzBookmark *folder,
                        KzBookmark *child,
                        KzBookmark *sibling,
                        KzBookmarkBar *bar)
{
      gint index = -1;
      GList *children;
      GtkToolItem *toolitem;
      
      g_return_if_fail(KZ_IS_BOOKMARK(child));
      g_return_if_fail(KZ_IS_BOOKMARK_BAR(bar));

      if (sibling)
      {
            children = kz_bookmark_get_children(folder);
            index = g_list_index(children, sibling); 
            g_list_free(children);
      }

      toolitem = create_tool_item(bar, child);
      
      gtk_toolbar_insert(GTK_TOOLBAR(bar->toolbar),
                     toolitem, index);
}


static void
cb_bookmark_list_remove_child  (KzBookmark *folder,
                        KzBookmark *child,
                        KzBookmarkBar *bar)
{
      gint index;
      GList *children;
      GtkToolItem *toolitem;

      g_return_if_fail(KZ_IS_BOOKMARK(child));
      g_return_if_fail(KZ_IS_BOOKMARK_BAR(bar));

      children = kz_bookmark_get_children(folder);
      index = g_list_index(children, child); 
      g_list_free(children);

      if (index == -1) return;
      
      toolitem = gtk_toolbar_get_nth_item(GTK_TOOLBAR(bar->toolbar),
                                  index);
      if (!toolitem) return;
      gtk_widget_destroy(GTK_WIDGET(toolitem));
}


Generated by  Doxygen 1.6.0   Back to index