Logo Search packages:      
Sourcecode: kazehakase version File versions

kz-bookmarks-view.c

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

/*
 *  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.
 *
 *  $Id: kz-bookmarks-view.c,v 1.25 2005/04/22 04:44:38 ikezoe Exp $
 */

#include "kz-bookmarks-view.h"
#include <glib/gi18n.h>

#include "gobject-utils.h"
#include "kz-bookmark-file.h"
#include "kz-smart-bookmark.h"
#include "kz-favicon.h"


enum {
      COLUMN_TITLE_EDITABLE,
      COLUMN_LOCATION_EDITABLE,
      COLUMN_BOOKMARK,
      COLUMN_ICON,
      COLUMN_TITLE,
      COLUMN_LOCATION,
      N_COLUMNS
};
#define TERMINATOR -1


enum {
      TARGET_KAZEHAKASE_BOOKMARKS,
};


struct _KzBookmarksViewPriv
{
      gboolean include_top;
      gboolean folder_only;
      gboolean tree_mode;
      gboolean editable;
};


static void     kz_bookmarks_view_class_init (KzBookmarksViewClass *klass);
static void     kz_bookmarks_view_init       (KzBookmarksView      *view);
static void     kz_bookmarks_view_dispose    (GObject              *object);

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

static GtkTreePath *find_row                 (GtkTreeModel  *model,
                                    KzBookmark    *bookmark);
static void     insert_bookmark              (KzBookmarksView *view,
                                    gboolean         folder_only,
                                    KzBookmark      *bookmark,
                                    KzBookmark      *parent,
                                    KzBookmark      *sibling);
static void     remove_bookmark              (KzBookmarksView *view,
                                    KzBookmark      *bookmark);
static void     expand_parent                (GtkTreeView     *treeview,
                                    GtkTreePath     *path);

static void     cb_bookmark_title_edited     (GtkCellRendererText *cell,
                                    const gchar      *path_str,
                                    const gchar      *new_text,
                                    KzBookmarksView  *view);
static void     cb_bookmark_location_edited  (GtkCellRendererText *cell,
                                    const gchar      *path_str,
                                    const gchar      *new_text,
                                    KzBookmarksView  *view);

static gboolean cb_drag_motion               (GtkWidget *widget,
                                    GdkDragContext *drag_context,
                                    gint x,
                                    gint y,
                                    guint time,
                                    KzBookmarksView  *view);
static void     cb_drag_data_get             (GtkWidget        *widget,
                                    GdkDragContext   *context,
                                    GtkSelectionData *seldata,
                                    guint             info,
                                    guint             time,
                                    KzBookmarksView  *view);
static void     cb_drag_data_received        (GtkWidget        *widget,
                                    GdkDragContext   *context,
                                    gint x, gint y,
                                    GtkSelectionData *seldata,
                                    guint             info,
                                    guint32           time,
                                    KzBookmarksView  *view);

static GtkTargetEntry dnd_types[] = {
      {"_KAZEHAKASE_BOOKMARKS", 0, TARGET_KAZEHAKASE_BOOKMARKS},
};
static const gint dnd_types_num = G_N_ELEMENTS(dnd_types);


static GtkTreeViewClass *parent_class = NULL;


KZ_OBJECT_GET_TYPE(kz_bookmarks_view, "KzBookmarksView", KzBookmarksView,
               kz_bookmarks_view_class_init, kz_bookmarks_view_init,
               GTK_TYPE_TREE_VIEW)
KZ_OBJECT_FINALIZE(kz_bookmarks_view, KzBookmarksView)


static void
kz_bookmarks_view_class_init (KzBookmarksViewClass *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->dispose      = kz_bookmarks_view_dispose;
      gobject_class->finalize     = kz_bookmarks_view_finalize;
#if 0
      gobject_class->set_property = kz_bookmarks_view_set_property;
      gobject_class->get_property = kz_bookmarks_view_get_property;

      g_object_class_install_property
            (gobject_class,
             PROP_ROOT_FOLDER,
             g_param_spec_object (
                   "root-folder",
                   _("Root Folder"),
                   _("The root bookmark folder to show"),
                   KZ_TYPE_BOOKMARK,
                   G_PARAM_READWRITE));

      g_object_class_install_property(
            gobject_class,
            PROP_TREE_MODE,
            g_param_spec_boolean(
                  "tree-mode",
                  _("Tree mode"),
                  _("Whether use tree mode or not "
                    "for bookmark view"),
                  TRUE,
                  G_PARAM_READWRITE));
#endif
}


static void
kz_bookmarks_view_init (KzBookmarksView *view)
{
      view->root_folder = NULL;

      view->priv = g_new0(KzBookmarksViewPriv, 1);
      view->priv->include_top = TRUE;
      view->priv->folder_only = FALSE;
      view->priv->tree_mode   = TRUE;
      view->priv->editable    = TRUE;
}


static void
kz_bookmarks_view_dispose (GObject *object)
{
      KzBookmarksView *view = KZ_BOOKMARKS_VIEW(object);

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

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


GtkWidget *
kz_bookmarks_view_new (void)
{
      KzBookmarksView *view;
      GtkTreeStore *store;
      GtkCellRenderer *cell;
      GtkTreeViewColumn *column;

      view = KZ_BOOKMARKS_VIEW(g_object_new(KZ_TYPE_BOOKMARKS_VIEW,
                                    NULL));

      store = gtk_tree_store_new(N_COLUMNS,
                           G_TYPE_BOOLEAN,
                           G_TYPE_BOOLEAN,
                           G_TYPE_POINTER,
                           GDK_TYPE_PIXBUF,
                           G_TYPE_STRING,
                           G_TYPE_STRING);
      gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
      g_object_unref(store);

      gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);

      /* Title column */
      column = gtk_tree_view_column_new();
      cell = gtk_cell_renderer_pixbuf_new();
      gtk_tree_view_column_pack_start(column, cell, FALSE);
      gtk_tree_view_column_add_attribute(column, cell,
                                 "pixbuf", COLUMN_ICON);
      cell = gtk_cell_renderer_text_new();
      g_signal_connect(cell, "edited",
                   G_CALLBACK(cb_bookmark_title_edited), view);
      gtk_tree_view_column_pack_start(column, cell, TRUE);
      gtk_tree_view_column_set_attributes(column, cell,
                                  "editable", COLUMN_TITLE_EDITABLE,
                                  "text",     COLUMN_TITLE,
                                  NULL);
      gtk_tree_view_column_set_title(column, _("Title"));

      gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
      gtk_tree_view_column_set_fixed_width (column, 200);
      gtk_tree_view_column_set_resizable(column, TRUE);
      gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);

      /* Location column */
      cell = gtk_cell_renderer_text_new();
      g_signal_connect(cell, "edited",
                   G_CALLBACK(cb_bookmark_location_edited), view);
      column = gtk_tree_view_column_new_with_attributes
                  (_("Location"), cell,
                   "editable", COLUMN_LOCATION_EDITABLE,
                   "text",     COLUMN_LOCATION,
                   NULL);
      gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
      gtk_tree_view_column_set_fixed_width (column, 250);
      gtk_tree_view_column_set_resizable(column, TRUE);
      gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);

      /* DnD */
      gtk_tree_view_enable_model_drag_source
            (GTK_TREE_VIEW(view),
             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);
      gtk_tree_view_enable_model_drag_dest
            (GTK_TREE_VIEW(view),
             dnd_types,
             dnd_types_num,
             GDK_ACTION_ASK  | GDK_ACTION_COPY |
             GDK_ACTION_MOVE | GDK_ACTION_LINK);
      g_signal_connect(view, "drag-motion",
                   G_CALLBACK(cb_drag_motion), view);
      g_signal_connect(view, "drag-data-get",
                   G_CALLBACK(cb_drag_data_get), view);
      g_signal_connect(view, "drag-data-received",
                   G_CALLBACK(cb_drag_data_received), view);

      return GTK_WIDGET(view);
}


void
kz_bookmarks_view_set_root_folder (KzBookmarksView *view,
                           KzBookmark *top_folder,
                           gboolean tree_mode,
                           gboolean include_top,
                           gboolean folder_only,
                           gboolean editable)
{
      GtkTreeModel *model;

      g_return_if_fail(KZ_IS_BOOKMARKS_VIEW(view));
      g_return_if_fail(!top_folder || kz_bookmark_is_folder(top_folder));

      model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
      gtk_tree_store_clear(GTK_TREE_STORE(model));

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

      view->priv->tree_mode   = tree_mode;
      view->priv->include_top = include_top;
      view->priv->folder_only = folder_only;
      view->priv->editable    = editable;

      if (!top_folder) return;

      view->root_folder = top_folder;
      g_object_ref(view->root_folder);
      connect_bookmark_signals(view, view->root_folder);

      if (include_top)
      {
            insert_bookmark(view, folder_only, top_folder,
                        NULL, NULL);
      }
      else
      {
            GList *children, *node;

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

            /* FIXME! expand? */
      }
}


KzBookmark *
kz_bookmarks_view_get_bookmark(GtkTreeModel *model, GtkTreeIter *iter)
{
      KzBookmark *bookmark = NULL;

      g_return_val_if_fail(GTK_IS_TREE_MODEL(model), NULL);
      g_return_val_if_fail(iter, NULL);

      gtk_tree_model_get(model, iter,
                     COLUMN_BOOKMARK, &bookmark,
                     TERMINATOR);

      return bookmark;
}


void
kz_bookmarks_view_select(KzBookmarksView *view,
                   KzBookmark *bookmark)
{
      GtkTreeModel *model;
      GtkTreePath *path;

      g_return_if_fail(KZ_IS_BOOKMARKS_VIEW(view));

      model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
      path = find_row (model, bookmark);
      if (!path) return;

      expand_parent(GTK_TREE_VIEW(view), path);
      gtk_tree_view_set_cursor(GTK_TREE_VIEW(view),
                         path, NULL, FALSE);
      gtk_tree_path_free(path);
}


typedef struct _FindRow
{
      KzBookmark *bookmark;
      GtkTreePath *path;
} FindRow;


static gboolean
find_row_func (GtkTreeModel *model,
             GtkTreePath *path, GtkTreeIter *iter,
             gpointer data)
{
      FindRow *findrow = data;
      KzBookmark *bookmark;

      gtk_tree_model_get(model, iter,
                     COLUMN_BOOKMARK, &bookmark,
                     TERMINATOR);

      if (findrow->bookmark == bookmark)
      {
            findrow->path = gtk_tree_path_copy(path);
            return TRUE;
      }

      return FALSE;
}


static GtkTreePath *
find_row (GtkTreeModel *model, KzBookmark *bookmark)
{
      FindRow findrow;

      g_return_val_if_fail(GTK_IS_TREE_MODEL(model), NULL);
      if (!bookmark) return NULL;
      g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);

      findrow.bookmark = bookmark;
      findrow.path = NULL;
      gtk_tree_model_foreach(model, find_row_func, &findrow);

      return findrow.path;
}


static KzBookmark *
find_folder_sibling (KzBookmark *parent, KzBookmark *sibling)
{
      GList *children, *node;

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

      if (!sibling) return NULL;

      children = kz_bookmark_get_children(parent);

      node = g_list_find(children, sibling);
      g_return_val_if_fail(node, NULL);

      for (; node; node = g_list_next(node))
      {
            KzBookmark *bookmark = node->data;

            if (!bookmark) continue;

            if (kz_bookmark_is_folder(bookmark))
                  return bookmark;
      }

      g_list_free(children);

      return NULL;
}


static gboolean
needs_refresh (KzBookmarksView *view, KzBookmark *bookmark)
{
      KzBookmark *parent;

      if (!view->root_folder)
            return FALSE;

      if (view->root_folder == bookmark)
            return TRUE;

      /* FIXME! */
      if (view->priv->tree_mode)
            return TRUE;
      else
            return FALSE;

      for (parent = bookmark;
           parent;
           parent = kz_bookmark_get_parent(parent))
      {
            if (parent == view->root_folder)
                  return TRUE;
      }

      return FALSE;
}


static void 
insert_bookmark(KzBookmarksView *view,
            gboolean folder_only,
            KzBookmark *bookmark,
            KzBookmark *parent, KzBookmark *sibling)
{
      GtkTreeModel *model;
      GtkTreePath *path;
      GtkTreeIter iter, tmp1, tmp2;
      GtkTreeIter *parent_iter = NULL, *sibling_iter = NULL;
      const gchar *title, *uri;
      GdkPixbuf *favicon;
      gboolean title_is_editable = TRUE, location_is_editable = TRUE;

      g_return_if_fail(KZ_IS_BOOKMARKS_VIEW(view));

      model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));

      /* get parent iter */
      if (parent)
      {
            path = find_row(model, parent);
            if (path)
            {
                  gtk_tree_model_get_iter(model, &tmp1, path);
                  parent_iter = &tmp1;
                  gtk_tree_path_free(path);
            }
      }

      /* get sibling iter */
      if (sibling)
      {
            if (folder_only)
                  sibling = find_folder_sibling(parent, sibling);

            path = find_row(model, sibling);
            if (path)
            {
                  gtk_tree_model_get_iter(model, &tmp2, path);
                  sibling_iter = &tmp2;
                  gtk_tree_path_free(path);
            }
      }

      /* get attrs */
      title = kz_bookmark_get_title(bookmark);
      uri = KZ_IS_BOOKMARK_FILE(bookmark)
            ? kz_bookmark_file_get_location(KZ_BOOKMARK_FILE(bookmark))
            : kz_bookmark_get_link(bookmark);

      if (KZ_IS_BOOKMARK_FILE(bookmark) ||
          kz_bookmark_is_folder(bookmark))
      {
            GtkWidget *image;
            const gchar *icon;

            icon = KZ_IS_BOOKMARK_FILE(bookmark)
                  ? KZ_STOCK_REMOTE_BOOKMARK : KZ_STOCK_FOLDER;
            image = gtk_image_new_from_stock(icon,
                                     GTK_ICON_SIZE_MENU);
            g_object_ref(G_OBJECT(image));
            gtk_object_sink(GTK_OBJECT(image));
            favicon = gtk_widget_render_icon(image, icon,
                                     GTK_ICON_SIZE_MENU,
                                     NULL);
            g_object_unref(G_OBJECT(image));
      }
      else if (KZ_IS_SMART_BOOKMARK(bookmark))
      {
            GtkWidget *image;

            image = gtk_image_new_from_stock(KZ_STOCK_SMART_BOOKMARK,
                                     GTK_ICON_SIZE_MENU);
            g_object_ref(G_OBJECT(image));
            gtk_object_sink(GTK_OBJECT(image));
            favicon = gtk_widget_render_icon(image, KZ_STOCK_SMART_BOOKMARK,
                                     GTK_ICON_SIZE_MENU,
                                     NULL);
            g_object_unref(image);
      }
      else if (kz_bookmark_is_separator(bookmark))
      {
            favicon = NULL;
      }
      else
      {
            KzFavicon *kz_favicon = kz_favicon_get_instance();

            favicon = kz_favicon_get_pixbuf(kz_favicon, uri,
                                    GTK_ICON_SIZE_MENU);
            
            if (!favicon)
            {
                  GtkWidget *image;
                  image = gtk_image_new_from_stock(KZ_STOCK_BOOKMARK,
                                           GTK_ICON_SIZE_MENU);
                  g_object_ref(G_OBJECT(image));
                  gtk_object_sink(GTK_OBJECT(image));
                  favicon = gtk_widget_render_icon(image, KZ_STOCK_BOOKMARK,
                                           GTK_ICON_SIZE_MENU,
                                           NULL);
                  g_object_unref(image);
            }
            g_object_unref(kz_favicon);
      }

      if (view->priv->editable)
      {
            if (!kz_bookmark_is_editable(bookmark))
            {
                  title_is_editable    = FALSE;
                  location_is_editable = FALSE;
            }
            else if (kz_bookmark_is_separator(bookmark))
            {
                  title_is_editable    = FALSE;
                  location_is_editable = FALSE;
            }
            else if (!KZ_IS_BOOKMARK_FILE(bookmark) &&
                   kz_bookmark_is_pure_folder(bookmark))
            {
                  location_is_editable = FALSE;
            }
      }
      else
      {
            title_is_editable    = FALSE;
            location_is_editable = FALSE;
      }

      /* insert */
      gtk_tree_store_insert_before(GTK_TREE_STORE(model), &iter,
                             parent_iter, sibling_iter);
      gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
                     COLUMN_TITLE_EDITABLE,    title_is_editable,
                     COLUMN_LOCATION_EDITABLE, location_is_editable,
                     COLUMN_ICON,              favicon,
                     COLUMN_TITLE,             title,
                     COLUMN_LOCATION,          uri,
                     COLUMN_BOOKMARK,          bookmark,
                     TERMINATOR);
      if (favicon)
            g_object_unref(favicon);

      /* append children */
      if (kz_bookmark_is_folder(bookmark) &&
          (folder_only ||
           needs_refresh(view, bookmark)))
      {
            GList *children, *node;

            children = kz_bookmark_get_children(bookmark);
            for (node = children; node; node = g_list_next(node))
            {
                  if (!KZ_IS_BOOKMARK(node->data))
                        continue;
                  if (folder_only && !kz_bookmark_is_folder(node->data))
                        continue;

                  insert_bookmark(view, folder_only,
                              node->data, bookmark, NULL);
            }
            g_list_free(children);
      }

      /* expand */
      if (!kz_bookmark_get_folded(bookmark))
      {
            path = gtk_tree_model_get_path(model, &iter);
            gtk_tree_view_expand_row(GTK_TREE_VIEW(view), path, FALSE);
            gtk_tree_path_free(path);
      }
}


static void 
remove_bookmark(KzBookmarksView *view,
            KzBookmark *bookmark)
{
      GtkTreeView *treeview;
      GtkTreeModel *model;
      GtkTreePath *path;
      GtkTreeIter iter;
      
      treeview = GTK_TREE_VIEW(view);
      model = gtk_tree_view_get_model(treeview);
      /* get iter */
      if (bookmark)
      {
            path = find_row(model, bookmark);
            if (!path) return;

            gtk_tree_model_get_iter(model, &iter, path);
            gtk_tree_path_free(path);
      }     
      
      /* remove row */
      gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
}


static KzBookmark *
find_next_current_folder (KzBookmark *bookmark)
{
      KzBookmark *next;

      g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);

      for (next = kz_bookmark_next(bookmark);
           next;
           next = kz_bookmark_next(next))
      {
            if (kz_bookmark_is_folder(next))
                  return next;
      }

      for (next = kz_bookmark_prev(bookmark);
           next;
           next = kz_bookmark_prev(next))
      {
            if (kz_bookmark_is_folder(next))
                  return next;
      }

      return kz_bookmark_get_parent(bookmark);
}


static void
ensure_cursor (KzBookmarksView *view, KzBookmark *bookmark)
{
      GtkTreeView *treeview;
      GtkTreeModel *model;
      GtkTreePath *path = NULL;

      g_return_if_fail(KZ_IS_BOOKMARKS_VIEW(view));
      g_return_if_fail(KZ_IS_BOOKMARK(bookmark));

      /* set folder view's cursor */
      treeview = GTK_TREE_VIEW(view);
      model = gtk_tree_view_get_model(treeview);

      gtk_tree_view_get_cursor (treeview, &path, NULL);
      if (path)
      {
            GtkTreeIter iter;
            KzBookmark *folder = NULL;

            gtk_tree_model_get_iter(model, &iter, path);
            gtk_tree_model_get (model, &iter,
                            COLUMN_BOOKMARK, &folder,
                            TERMINATOR);
            gtk_tree_path_free(path);

            if (folder == bookmark)
            {
                  folder = find_next_current_folder(bookmark);
                  if (folder)
                  {
                        kz_bookmarks_view_select(view, folder);
                        return;
                  }
            }
      }

      /* set bookmarks view's cursor */
      treeview = GTK_TREE_VIEW(view);
      model = gtk_tree_view_get_model(treeview);

      gtk_tree_view_get_cursor (treeview, &path, NULL);
      if (path)
      {
            GtkTreeIter iter;
            KzBookmark *selected = NULL;

            gtk_tree_model_get_iter(model, &iter, path);
            gtk_tree_model_get (model, &iter,
                            COLUMN_BOOKMARK, &selected,
                            TERMINATOR);
            gtk_tree_path_free(path);

            if (selected == bookmark)
            {
                  selected = kz_bookmark_next(bookmark);
                  if (!selected)
                        selected = kz_bookmark_prev(bookmark);
                  if (selected)
                        kz_bookmarks_view_select(view, selected);
            }
      }
}


static void
sync_bookmark_properties (KzBookmarksView *view, KzBookmark *bookmark)
{
      GtkTreeView *treeview;
      GtkTreeModel *model;
      GtkTreePath *path = NULL;
      GtkTreeIter iter;
      const gchar *title, *uri;

      g_return_if_fail(KZ_IS_BOOKMARKS_VIEW(view));
      g_return_if_fail(KZ_IS_BOOKMARK(bookmark));

      title = kz_bookmark_get_title(bookmark);
      uri = KZ_IS_BOOKMARK_FILE(bookmark)
            ? kz_bookmark_file_get_location(KZ_BOOKMARK_FILE(bookmark))
            : kz_bookmark_get_link(bookmark);

      treeview = GTK_TREE_VIEW(view);
      model = gtk_tree_view_get_model(treeview);
      path = find_row(model, bookmark);
      if (path)
      {
            gtk_tree_model_get_iter(model, &iter, path);
            gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
                           COLUMN_TITLE,    title,
                           COLUMN_LOCATION, uri,
                           TERMINATOR);
            gtk_tree_path_free(path);
            path = NULL;
      }
}


static void
expand_parent(GtkTreeView *treeview, GtkTreePath *path)
{
      GtkTreePath *parent = gtk_tree_path_copy(path);

      if (gtk_tree_path_up(parent))
      {
            expand_parent(treeview, parent);
            gtk_tree_view_expand_row(treeview, parent, FALSE);
      }

      gtk_tree_path_free(parent);
}


static void
cb_bookmark_insert_child (KzBookmark *bookmark,
                    KzBookmark *child, KzBookmark *sibling,
                    KzBookmarksView *view)
{
      if (!needs_refresh(view, bookmark))
            return;

      connect_bookmark_signals (view, child);

      if (!view->priv->folder_only || kz_bookmark_is_folder(child))
            insert_bookmark(view, view->priv->folder_only,
                        child, bookmark, sibling);
}


static void
cb_bookmark_remove_child (KzBookmark *bookmark, KzBookmark *child,
                    KzBookmarksView *view)
{
      disconnect_bookmark_signals (view, child);

      /* set selection */
      ensure_cursor(view, child);

      remove_bookmark(view, child);
}


static void
cb_bookmark_notify (GObject *object, GParamSpec *pspec,
                KzBookmarksView *view)
{
      KzBookmark *bookmark;

      g_return_if_fail(KZ_IS_BOOKMARK(object));
      bookmark = KZ_BOOKMARK(object);

      sync_bookmark_properties(view, bookmark);
}


static void
connect_bookmark_signals (KzBookmarksView *view,
                    KzBookmark *bookmark)
{
      GList *children, *node;

      g_return_if_fail(KZ_IS_BOOKMARK(bookmark));

      g_signal_connect_after(bookmark, "insert-child",
                         G_CALLBACK(cb_bookmark_insert_child), view);
      g_signal_connect(bookmark, "remove-child",
                   G_CALLBACK(cb_bookmark_remove_child), view);
      g_signal_connect(bookmark, "notify",
                   G_CALLBACK(cb_bookmark_notify), view);

      if (!kz_bookmark_is_folder(bookmark)) return;

      children = kz_bookmark_get_children(bookmark);
      for (node = children; node; node = g_list_next(node))
            connect_bookmark_signals (view, node->data);
      g_list_free(children);
}


static void
disconnect_bookmark_signals (KzBookmarksView *view,
                       KzBookmark *bookmark)
{
      GList *children, *node;

      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);
      g_signal_handlers_disconnect_by_func
            (bookmark,
             G_CALLBACK(cb_bookmark_notify), view);

      if (!kz_bookmark_is_folder(bookmark)) return;

      children = kz_bookmark_get_children(bookmark);
      for (node = children; node; node = g_list_next(node))
            disconnect_bookmark_signals (view, node->data);
      g_list_free(children);
}


static void
cb_bookmark_title_edited (GtkCellRendererText *cell,
                    const gchar *path_str,
                    const gchar *new_text,
                    KzBookmarksView *view)
{
      GtkTreeModel *model;
        GtkTreeIter  iter;
      KzBookmark *bookmark = NULL;

      g_return_if_fail(KZ_IS_BOOKMARKS_VIEW(view));

      model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
        if(!gtk_tree_model_get_iter_from_string(model, &iter, path_str))
            return;
      gtk_tree_model_get(model, &iter,
                     COLUMN_BOOKMARK, &bookmark,
                     TERMINATOR);
      g_return_if_fail(KZ_IS_BOOKMARK(bookmark));

      kz_bookmark_set_title(bookmark, new_text);
}


static void
cb_bookmark_location_edited (GtkCellRendererText *cell,
                       const gchar *path_str,
                       const gchar *new_text,
                       KzBookmarksView *view)
{
      GtkTreeModel *model;
        GtkTreeIter  iter;
      KzBookmark *bookmark = NULL;

      g_return_if_fail(KZ_IS_BOOKMARKS_VIEW(view));

      model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
        gtk_tree_model_get_iter_from_string(model, &iter, path_str);
      gtk_tree_model_get(model, &iter,
                     COLUMN_BOOKMARK, &bookmark,
                     TERMINATOR);
      g_return_if_fail(KZ_IS_BOOKMARK(bookmark));

      if (KZ_IS_BOOKMARK_FILE(bookmark))
      {
            kz_bookmark_file_set_location(KZ_BOOKMARK_FILE(bookmark), new_text);
            kz_bookmark_file_load_start(KZ_BOOKMARK_FILE(bookmark));
      }
      else
      {
            kz_bookmark_set_link(bookmark, new_text);
      }
}


static gboolean
cb_drag_motion (GtkWidget *widget,
            GdkDragContext *drag_context,
            gint x, gint y, guint time,
            KzBookmarksView *view)
{
      GtkTreeModel *model;
      GtkTreeIter iter;
      GtkTreePath *dest_path = NULL;
      GtkTreeViewDropPosition pos;
      KzBookmark *bookmark = NULL;
      gboolean success, retval = FALSE;

      g_return_val_if_fail(KZ_IS_BOOKMARKS_VIEW(view), TRUE);

      success = gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget),
                                        x, y,
                                        &dest_path, &pos);
      if (!success) return FALSE;

      model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
      gtk_tree_model_get_iter(model, &iter, dest_path);
      gtk_tree_model_get(model, &iter,
                     COLUMN_BOOKMARK, &bookmark,
                     TERMINATOR);

      if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
          pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
      {
            if ((KZ_IS_BOOKMARK_FILE(bookmark) &&
                 !kz_bookmark_file_is_editable(KZ_BOOKMARK_FILE(bookmark))) ||
                (!KZ_IS_BOOKMARK_FILE(bookmark) &&
                 !kz_bookmark_is_editable(bookmark)))
            {
                  gdk_drag_status(drag_context, 0, time);
                  retval = TRUE;
            }
            else
            {
                  gdk_drag_status(drag_context, GDK_ACTION_MOVE, time);
            }
      }
      else if (pos == GTK_TREE_VIEW_DROP_BEFORE ||
             pos == GTK_TREE_VIEW_DROP_AFTER)
      {
            if (bookmark == view->root_folder ||
                !kz_bookmark_is_editable(bookmark))
            {
                  gdk_drag_status(drag_context, 0, time);
                  retval = TRUE;
            }
      }
#if 0 /* FIXME */
      else if (!kz_bookmark_is_folder(src_bookmark))
      {
            gdk_drag_status(drag_context, 0, time);
            retval = TRUE;
      }
#endif

      if (dest_path)
            gtk_tree_path_free(dest_path);

      return retval;
}


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


static void
cb_drag_data_received (GtkWidget *widget,
                       GdkDragContext *context,
                       gint x, gint y,
                       GtkSelectionData *seldata,
                       guint info,
                       guint32 time,
                       KzBookmarksView *view)
{
      KzBookmarksView *src_view = NULL;
      GtkTreeView *treeview = GTK_TREE_VIEW(widget);
      GtkTreeModel *model = gtk_tree_view_get_model(treeview);
      GtkTreePath *src_path = NULL, *dest_path = NULL;
      GtkTreeIter src_iter, dest_iter;
      GtkTreeViewDropPosition pos;
      GtkWidget *src_widget;
      KzBookmark *src, *dest, *parent;
      KzBookmark *file;

      /* get dest bookmark */
      gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(widget),
                                x, y,
                                &dest_path, &pos);
      if (!dest_path) return;
      gtk_tree_model_get_iter(model, &dest_iter, dest_path);
      gtk_tree_model_get(model, &dest_iter,
                     COLUMN_BOOKMARK, &dest,
                     TERMINATOR);
      if (!dest) goto ERROR;

      /* get src bookmark */
      /* FIXME */
      src_widget = gtk_drag_get_source_widget(context);
      if (KZ_IS_BOOKMARKS_VIEW(src_widget))
            src_view = KZ_BOOKMARKS_VIEW(src_widget);
      if (!src_view || !GTK_IS_TREE_VIEW(src_widget)) goto ERROR;

      /* FIXME! detect src widget type */
      /* FIXME! enable multiple dragging */
      model = gtk_tree_view_get_model(GTK_TREE_VIEW(src_widget));
      gtk_tree_view_get_cursor (GTK_TREE_VIEW(src_widget), &src_path, NULL);
      if (src_path)
      {
            gtk_tree_model_get_iter(model, &src_iter, src_path);
            gtk_tree_model_get(model, &src_iter,
                           COLUMN_BOOKMARK, &src,
                           TERMINATOR);
      }
      if (!src_path || !src) goto ERROR;
      if (src == dest) goto ERROR;

      /* move the bookmark(s?) */
      switch (info)
      {
      case TARGET_KAZEHAKASE_BOOKMARKS:
            parent = kz_bookmark_get_parent(src);
            if (!parent) goto ERROR;
            g_object_ref(src);
            kz_bookmark_remove(parent, src);
            
            if (KZ_IS_BOOKMARK_FILE(parent))
                  file = parent;
            else
                  file = kz_bookmark_get_parent_file(parent);
      
            if (kz_bookmark_file_has_xmlrpc(KZ_BOOKMARK_FILE(file)))
            {
                  kz_bookmark_file_xmlrpc_remove(KZ_BOOKMARK_FILE(file),
                                           src);
            }

            if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
                 pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) &&
                kz_bookmark_is_folder(dest))
            {
                  /* move the src bookmark into the dest folder */
                  parent = dest;
                  dest = NULL;
            }
            else
            {
                  /* move the bookmark before or after the dest bookmark */
                  parent = kz_bookmark_get_parent(dest);

                  if ((pos == GTK_TREE_VIEW_DROP_AFTER ||
                       pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER))
                  {
                        GList *children, *node;

                        children = kz_bookmark_get_children(parent);
                        node = g_list_find(children, dest);
                        node = g_list_next(node);
                        if (node)
                              dest = node->data;
                        else
                              dest = NULL;
                        g_list_free(children);
                  }
            }

            if (!parent) goto ERROR;

            kz_bookmark_insert_before(parent, src, dest);
            
            if (KZ_IS_BOOKMARK_FILE(parent))
                  file = parent;
            else
                  file = kz_bookmark_get_parent_file(parent);
      
            if (kz_bookmark_file_has_xmlrpc(KZ_BOOKMARK_FILE(file)))
            {
                  kz_bookmark_file_xmlrpc_insert(KZ_BOOKMARK_FILE(file),
                                           parent,
                                           dest,
                                           src);
            }
            g_object_unref(src);
            gtk_drag_finish(context, TRUE, FALSE, time);
            break;
      default:
            break;
      }

      gtk_tree_path_free(src_path);
ERROR:
      gtk_tree_path_free(dest_path);
}

Generated by  Doxygen 1.6.0   Back to index