Logo Search packages:      
Sourcecode: kazehakase version File versions

kz-bookmark-menu.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
 *
 *  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-menu.c,v 1.6 2005/04/21 20:47:45 ikezoe Exp $
 */

#include "kz-bookmark-menu.h"

#include <glib/gi18n.h>

#include "kazehakase.h"
#include "kz-bookmark-editor.h"
#include "kz-actions.h"
#include "kz-favicon.h"
#include "utils.h"

#define KZ_BOOKMARK_MENU_BOOKMARK_KEY "KzBookmarkMenu::Bookmark"
#define KZ_BOOKMARK_MENU_WINDOW_KEY   "KzBookmarkMenu::Window"
#define KZ_BOOKMARK_MENU_TOOLTIP_KEY  "KzBookmarkMenu::ToolTips"
#define KZ_BOOKMARK_MENU_EMPTY_KEY    "KzBookmarkMEnu::Empty"
#define KZ_BOOKMARK_MENU_PROXY_KEY    "KzBookmarkMenu::IsFolderProxy"
#define KZ_BOOKMARK_MENU_BUTTON_KEY   "KzBookmarkMenu::MouseButton"


static gboolean   cb_menu_item_button_press      (GtkWidget      *widget,
                                      GdkEventButton *event,
                                      KzWindow       *kz);
static gboolean   cb_menu_item_button_release    (GtkWidget      *widget,
                                      GdkEventButton *event,
                                      KzWindow       *kz);
static void       cb_menu_item_activate          (GtkWidget      *widget,
                                      KzWindow       *kz);

static void       connect_bookmark_signals       (GtkWidget      *widget,
                                      KzBookmark     *item);
static void       disconnect_bookmark_signals    (GtkWidget      *widget,
                                      KzBookmark     *item);
static void       disconnect_menuitem_signals    (GtkWidget      *widget,
                                      KzBookmark     *item);

static void       connect_folder_signals         (KzBookmark     *folder,
                                      GtkMenuShell   *shell);
static void       disconnect_folder_signals      (KzBookmark     *folder,
                                      GtkMenuShell   *shell);
static void       disconnect_menu_signals        (KzBookmark     *folder,
                                      GtkMenuShell   *shell);

GtkWidget *
kz_bookmark_menu_create_menuitem (KzBookmark *bookmark, KzWindow *kz,
                          gboolean is_folder_proxy)
{
      GtkWidget *menu_item;
      const gchar *title = NULL, *desc;
      gchar *tooltip_text = NULL;
      gint bookmark_max_strnum = 0;
      GtkTooltips *tooltip = NULL;
      GtkWidget *favicon;
      KzFavicon *kzfav;

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

      /* separator */
      if (kz_bookmark_is_separator(bookmark))
      {
            menu_item = gtk_separator_menu_item_new();
            g_object_set_data(G_OBJECT(menu_item),
                          KZ_BOOKMARK_MENU_BOOKMARK_KEY,
                          bookmark);
            g_object_set_data(G_OBJECT(menu_item),
                          KZ_BOOKMARK_MENU_WINDOW_KEY,
                          kz);
            return menu_item;
      }

      if (is_folder_proxy)
            title = kz_bookmark_get_document_title(bookmark);
      if (!title || !* title)
            title = kz_bookmark_get_title(bookmark);
      if (!title)
            title = "";
      desc = kz_bookmark_get_description(bookmark);
      if (desc)
            tooltip_text = remove_tag(desc, strlen(desc));
      
      KZ_CONF_GET("Global" , "bookmark_cutoff_strnum" , bookmark_max_strnum , INT);

      if(bookmark_max_strnum> 0 && (g_utf8_strlen(title , -1) > bookmark_max_strnum))
      {
            gint len = g_utf8_offset_to_pointer(title, bookmark_max_strnum) - title;
            gchar *short_title = g_alloca (len + 3 + 1);
            /* 3 for "..." , 1 for '\0' */

            g_utf8_strncpy(short_title , title , bookmark_max_strnum);
            short_title[len-3] = '.';
            short_title[len-2] = '.';
            short_title[len-1] = '.';
            short_title[len] = '\0';
            menu_item = gtk_image_menu_item_new_with_label(short_title);
      }
      else
            menu_item = gtk_image_menu_item_new_with_label(title);

      g_object_set_data(G_OBJECT(menu_item),
                    KZ_BOOKMARK_MENU_BOOKMARK_KEY,
                    bookmark);
      g_object_set_data(G_OBJECT(menu_item),
                    KZ_BOOKMARK_MENU_WINDOW_KEY,
                    kz);
      g_object_set_data(G_OBJECT(menu_item),
                    KZ_BOOKMARK_MENU_PROXY_KEY,
                    GINT_TO_POINTER(is_folder_proxy));

      g_signal_connect(menu_item, "button_press_event",
                   G_CALLBACK(cb_menu_item_button_press),
                   kz);
      g_signal_connect(menu_item, "button_release_event",
                   G_CALLBACK(cb_menu_item_button_release),
                   kz);
      g_signal_connect(menu_item, "activate",
                   G_CALLBACK(cb_menu_item_activate),
                   kz);

      /* submenu */
      if (kz_bookmark_is_folder(bookmark) && !is_folder_proxy)
      {
            GtkWidget *submenu, *image;
      
            submenu = kz_bookmark_menu_create_submenu(bookmark, kz);
            gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
            image = gtk_image_new_from_stock(KZ_STOCK_FOLDER,
                                     KZ_ICON_SIZE_BOOKMARK_MENU);
            gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
                                    image);
      }
      
      /* favicon */
      kzfav = kz_favicon_get_instance();
      favicon = kz_favicon_get_widget(kzfav,
                              kz_bookmark_get_link(bookmark),
                              KZ_ICON_SIZE_BOOKMARK_MENU);
      if (favicon)
      {
            gtk_widget_show(favicon);
            gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
                                    favicon);
      }
      g_object_unref(kzfav);

      /* tooltips */
      tooltip = gtk_tooltips_new();
      g_object_ref(G_OBJECT(tooltip));
      gtk_object_sink(GTK_OBJECT(tooltip));
      if (tooltip_text)
      {
            gtk_tooltips_set_tip(tooltip, menu_item, tooltip_text, NULL);
            g_free(tooltip_text);
      }
      g_object_set_data_full(G_OBJECT(menu_item),
                         KZ_BOOKMARK_MENU_TOOLTIP_KEY,
                         tooltip,
                         (GDestroyNotify) g_object_unref);
      connect_bookmark_signals(menu_item, bookmark);

      return menu_item;
}


GtkWidget *
kz_bookmark_menu_create_submenu (KzBookmark *folder, KzWindow *kz)
{
      GtkWidget *submenu, *menu_item;

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

      /* create submenu  */
      submenu = gtk_menu_new();

      menu_item = kz_bookmark_menu_create_menuitem(folder, kz, TRUE);
      if (menu_item)
      {
            gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menu_item);
            gtk_widget_show(menu_item);
      }

      /* separator */
      menu_item = gtk_separator_menu_item_new();
      gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menu_item);
      gtk_widget_show(menu_item);

      /* children */
      kz_bookmark_menu_append_menuitems(GTK_MENU_SHELL(submenu), kz, folder);

      return submenu;
}


void
kz_bookmark_menu_append_menuitems (GtkMenuShell *shell, KzWindow *kz, 
                           KzBookmark *folder)
{
      KzBookmark *prev_folder;
      GList *children, *node;

      g_return_if_fail(GTK_IS_MENU_SHELL(shell));
      g_return_if_fail(KZ_BOOKMARK(folder));
      g_return_if_fail(kz_bookmark_is_folder(folder));

      prev_folder = g_object_get_data(G_OBJECT(shell),
                              KZ_BOOKMARK_MENU_BOOKMARK_KEY);
      if (prev_folder)
      {
            disconnect_folder_signals(prev_folder, shell);
            disconnect_menu_signals(prev_folder, shell);
      }

      children = kz_bookmark_get_children(folder);

      /* empty label */
      {
            GtkWidget *widget;

            widget = gtk_image_menu_item_new_with_label(_("Empty Folder"));
            gtk_menu_shell_append(shell, widget);
            if (!children)
                  gtk_widget_show(widget);
            gtk_widget_set_sensitive(widget, FALSE);
            g_object_set_data(G_OBJECT(widget),
                          KZ_BOOKMARK_MENU_WINDOW_KEY,
                          kz);
            g_object_set_data(G_OBJECT(shell),
                          KZ_BOOKMARK_MENU_EMPTY_KEY,
                          widget);
      }


      /* children */
      for (node = children; node; node = g_list_next(node))
      {
            KzBookmark *bookmark = node->data;
            GtkWidget *widget;

            widget = kz_bookmark_menu_create_menuitem(bookmark, kz,
                                            FALSE);
            gtk_menu_shell_append(shell, widget);
            gtk_widget_show(widget);
      }

      g_list_free(children);

      connect_folder_signals(folder, shell);

      g_object_set_data(G_OBJECT(shell),
                    KZ_BOOKMARK_MENU_BOOKMARK_KEY,
                    folder);
      g_object_set_data(G_OBJECT(shell),
                    KZ_BOOKMARK_MENU_WINDOW_KEY,
                    kz);
}


void
kz_bookmark_menu_remove_menuitems (GtkMenuShell *shell, KzWindow *kz)
{
      KzBookmark *folder;
      GList *children, *node;

      g_return_if_fail(GTK_IS_MENU_SHELL(shell));

      folder = g_object_get_data(G_OBJECT(shell),
                           KZ_BOOKMARK_MENU_BOOKMARK_KEY);
      if (KZ_IS_BOOKMARK(folder))
      {
            disconnect_folder_signals(folder, shell);
            disconnect_menu_signals(folder, shell);
      }

      children = g_list_copy(shell->children);

      for (node = children; node; node = g_list_next(node))
      {
            GtkWidget *menuitem = node->data;
            KzWindow *kz;
            gpointer p;
            gboolean is_folder_proxy;

            kz = g_object_get_data(G_OBJECT(menuitem),
                               KZ_BOOKMARK_MENU_WINDOW_KEY);
            p = g_object_get_data(G_OBJECT(menuitem),
                              KZ_BOOKMARK_MENU_PROXY_KEY);
            is_folder_proxy = GPOINTER_TO_INT(p);
            if (kz && !is_folder_proxy)
                  gtk_widget_destroy(menuitem);
      }

      g_list_free(children);

      g_object_set_data(G_OBJECT(shell),
                    KZ_BOOKMARK_MENU_BOOKMARK_KEY,
                    NULL);
      g_object_set_data(G_OBJECT(shell),
                    KZ_BOOKMARK_MENU_WINDOW_KEY,
                    NULL);
}


/*****************************************************************************
 *                                                                           *
 *                                Callbacks                                  *
 *                                                                           *
 *****************************************************************************/

static gint
find_menu_item (gconstpointer a, gconstpointer b)
{
      const KzBookmark *bookmark1, *bookmark2 = b;

      bookmark1 = g_object_get_data(G_OBJECT(a),
                              KZ_BOOKMARK_MENU_BOOKMARK_KEY);

      return bookmark1 - bookmark2;
}


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

      title = kz_bookmark_get_title(KZ_BOOKMARK(object));
      if (GTK_IS_LABEL(GTK_BIN(widget)->child))
            gtk_label_set_text(GTK_LABEL(GTK_BIN(widget)->child), title);
}


static void
cb_notify_desc (GObject *object, GParamSpec *pspec,
            GtkWidget *widget)
{
      GtkTooltips *tooltip;
      const gchar *desc;
      gchar *tooltip_text = NULL;
      
      desc = kz_bookmark_get_description(KZ_BOOKMARK(object));
      if (desc)
            tooltip_text = remove_tag(desc, strlen(desc));
      tooltip = g_object_get_data(G_OBJECT(widget),
                            KZ_BOOKMARK_MENU_TOOLTIP_KEY);
      if (GTK_IS_TOOLTIPS(tooltip) && tooltip_text)
      {
            gtk_tooltips_set_tip(tooltip, widget, tooltip_text, NULL);
            g_free(tooltip_text);
      }
}


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

      if (!widget) return;

      disconnect_menuitem_signals (widget, item);
}


static void
cb_menuitem_destroy(GtkWidget *widget, KzBookmark *item)
{
      disconnect_bookmark_signals(widget, item);
}


static void
connect_bookmark_signals (GtkWidget *widget, KzBookmark *item)
{
      g_signal_connect(item, "notify::title",
                   G_CALLBACK(cb_notify_title),
                   widget);
      g_signal_connect(item, "notify::description",
                   G_CALLBACK(cb_notify_desc),
                   widget);

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


static void
disconnect_bookmark_signals (GtkWidget *widget, KzBookmark *item)
{
      g_signal_handlers_disconnect_by_func(item,
                                   G_CALLBACK(cb_notify_title),
                                   widget);
      g_signal_handlers_disconnect_by_func(item,
                                   G_CALLBACK(cb_notify_desc),
                                   widget);

      g_object_weak_unref(G_OBJECT(item), bookmark_weak_ref, widget);
}


static void
disconnect_menuitem_signals (GtkWidget *widget, KzBookmark *item)
{
      g_signal_handlers_disconnect_by_func(widget,
                                   G_CALLBACK(cb_menuitem_destroy),
                                   item);
}


static void 
cb_menu_item_activate (GtkWidget *widget, KzWindow *kz)
{
      KzBookmark *item;
      const gchar *uri;
      gint button;
      gboolean is_folder_proxy;

      g_return_if_fail(KZ_IS_WINDOW(kz));

      item = g_object_get_data(G_OBJECT(widget),
                         KZ_BOOKMARK_MENU_BOOKMARK_KEY);
      g_return_if_fail(item);

      button = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
                           KZ_BOOKMARK_MENU_BUTTON_KEY));

      is_folder_proxy = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
                        KZ_BOOKMARK_MENU_PROXY_KEY));

      if (kz_bookmark_is_folder(item) && !is_folder_proxy)
            return;

      uri = kz_bookmark_get_link(item);
      
      switch (button)
      {
      case 2:
            if (uri)
                  kz_window_open_new_tab(kz, uri);
            break;
      default:
            if (uri)
            {
                  kz_window_load_url(kz, uri);
            }
            else if (kz_bookmark_is_folder(item))
            {
                  GtkWidget *editor;

                  editor = kz_bookmark_editor_new(item);
                  gtk_widget_show(editor);
            }
            break;
      }

      button = 0;
      g_object_set_data(G_OBJECT(widget),
                    KZ_BOOKMARK_MENU_BUTTON_KEY,
                    GINT_TO_POINTER(button));
}



static gboolean
cb_menu_item_button_press (GtkWidget *widget, GdkEventButton *event,
                     KzWindow *kz)
{
      return FALSE;
}


static gboolean
cb_menu_item_button_release (GtkWidget *widget, GdkEventButton *event,
                      KzWindow *kz)
{
      KzBookmark *item;
      const gchar *uri;
      gboolean keep = FALSE;
      gint button = event->button;

      g_return_val_if_fail(KZ_IS_WINDOW(kz), FALSE);

      item = g_object_get_data(G_OBJECT(widget),
                         KZ_BOOKMARK_MENU_BOOKMARK_KEY);
      g_return_val_if_fail(item, FALSE);

      uri = kz_bookmark_get_link(item);

      g_object_set_data(G_OBJECT(widget),
                    KZ_BOOKMARK_MENU_BUTTON_KEY,
                    GINT_TO_POINTER(button));

      switch (button)
      {
      case 2:
            KZ_CONF_GET("Global", "keep_bookmark_menu", keep, BOOL);
            if (!keep)
                  return FALSE;
            if (uri)
                  kz_window_open_new_tab(kz, uri);
            /* reset release button state */
            button = 0;
            g_object_set_data(G_OBJECT(widget),
                          KZ_BOOKMARK_MENU_BUTTON_KEY,
                          GINT_TO_POINTER(button));

            return TRUE;
            break;
      case 3:
            kz_actions_popup_bookmark_menu_modal(kz, item,
                                         event->button,
                                         event->time);
            /* return TRUE; */
            break;
      default:
            break;
      }

      return FALSE;
}


/*****************************************************************************
 *                                                                           *
 *                               for  menu                                   *
 *                                                                           *
 *****************************************************************************/
static void
cb_folder_insert_child (KzBookmark *item,
                  KzBookmark *child, KzBookmark *sibling,
                  GtkMenuShell *shell)
{
      KzWindow *kz;
      GtkWidget *menuitem, *empty_label;
      GList *list, *node;
      gint n;

      kz = g_object_get_data(G_OBJECT(shell), KZ_BOOKMARK_MENU_WINDOW_KEY);
      list = shell->children;

      menuitem = kz_bookmark_menu_create_menuitem(child, kz, FALSE);
      gtk_widget_show(menuitem);

      if (sibling)
      {
            node = g_list_find_custom(list, sibling, find_menu_item);
            g_return_if_fail(node);

            n = g_list_position(list, node);
            gtk_menu_shell_insert(shell, menuitem, n);
      }
      else
      {
            gtk_menu_shell_append(shell, menuitem);
      }

      empty_label = g_object_get_data(G_OBJECT(shell),
                              KZ_BOOKMARK_MENU_EMPTY_KEY);
      if (GTK_IS_WIDGET(empty_label))
            gtk_widget_hide(empty_label);
}


static void
cb_folder_remove_child (KzBookmark *item,
                  KzBookmark *child, GtkMenuShell *shell)
{
      KzWindow *kz;
      GList *list, *node;

      kz = g_object_get_data(G_OBJECT(shell), KZ_BOOKMARK_MENU_WINDOW_KEY);
      list = shell->children;

      node = g_list_find_custom(list, child, find_menu_item);
      g_return_if_fail(node);
      gtk_widget_destroy(node->data);

      if (!kz_bookmark_has_children(item))
      {
            GtkWidget *empty_label;

            empty_label = g_object_get_data(G_OBJECT(shell),
                                    KZ_BOOKMARK_MENU_EMPTY_KEY);
            if (GTK_IS_WIDGET(empty_label))
                  gtk_widget_show(empty_label);
      }
}


static void
cb_folder_reordered (KzBookmark *item, GtkMenuShell *shell)
{
      KzWindow *kz;

      kz = g_object_get_data(G_OBJECT(shell), KZ_BOOKMARK_MENU_WINDOW_KEY);
      kz_bookmark_menu_remove_menuitems(shell, kz);
      kz_bookmark_menu_append_menuitems(shell, kz, item);
}


static void
folder_weak_ref (gpointer data, GObject *obj)
{
      KzBookmark *folder = KZ_BOOKMARK(obj);
      GtkMenuShell *shell = data;

      disconnect_menu_signals(folder, GTK_MENU_SHELL(shell));
}


static void
cb_root_menu_destroy(GtkWidget *widget, KzBookmark *folder)
{
      disconnect_folder_signals(folder, GTK_MENU_SHELL(widget));
}


static void
connect_folder_signals (KzBookmark *folder, GtkMenuShell *shell)
{
      g_signal_connect_after(folder, "insert-child",
                         G_CALLBACK(cb_folder_insert_child),
                         shell);
      g_signal_connect_after(folder, "remove-child",
                         G_CALLBACK(cb_folder_remove_child),
                         shell);
      g_signal_connect_after(folder, "children-reordered",
                         G_CALLBACK(cb_folder_reordered),
                         shell);

      g_signal_connect(shell, "destroy",
                   G_CALLBACK(cb_root_menu_destroy), folder);
      g_object_weak_ref(G_OBJECT(folder), folder_weak_ref, shell);
}


static void
disconnect_folder_signals (KzBookmark *folder, GtkMenuShell *shell)
{
      g_signal_handlers_disconnect_by_func
            (folder,
             G_CALLBACK(cb_folder_insert_child),
             shell);
      g_signal_handlers_disconnect_by_func
            (folder,
             G_CALLBACK(cb_folder_remove_child),
             shell);
      g_signal_handlers_disconnect_by_func
            (folder,
             G_CALLBACK(cb_folder_reordered),
             shell);

      g_object_weak_unref(G_OBJECT(folder), folder_weak_ref, shell);
}


static void
disconnect_menu_signals (KzBookmark *folder, GtkMenuShell *shell)
{
      g_signal_handlers_disconnect_by_func
            (shell,
             G_CALLBACK(cb_root_menu_destroy),
             folder);
}

Generated by  Doxygen 1.6.0   Back to index