Logo Search packages:      
Sourcecode: galeon version File versions

bookmarks-tree-model.c

/* -*- mode: c; c-style: k&r; c-basic-offset: 8 -*- */
/* 
 *  Copyright (C) 2002  Ricardo Fernándezs Pascual <ric@users.sourceforge.net>
 *
 *  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

#include "bookmarks-tree-model.h"
#include "galeon-debug.h"
#include "galeon-dnd.h"
#include <gtk/gtktreednd.h>
#include <glib-object.h>

#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);

#define DEBUG_PATH(path) \
      { \
            gchar *s_patch = gtk_tree_path_to_string (path); \
            LOG (#path " = %s\n", s_patch); \
            g_free (s_patch); \
      }


      

#define VALID_ITER(iter, tree_model)      (iter!= NULL && iter->user_data != NULL \
                              && tree_model->stamp == iter->stamp)

static void       gb_tree_model_init            (GbTreeModel *btree_model);
static void       gb_tree_model_class_init      (GbTreeModelClass *btree_model_class);
static void       gb_tree_model_tree_model_init (GtkTreeModelIface *iface);
static void       gb_tree_model_drag_source_init      (GtkTreeDragSourceIface *iface);
static void       gb_tree_model_drag_dest_init  (GtkTreeDragDestIface *iface);
static void       gb_tree_model_finalize_impl   (GObject *object);
static guint            gb_tree_model_get_flags       (GtkTreeModel *tree_model);
static gint       gb_tree_model_get_n_columns   (GtkTreeModel *tree_model);
static GType            gb_tree_model_get_column_type (GtkTreeModel *tree_model,
                                           gint index);
static gboolean         gb_tree_model_get_iter        (GtkTreeModel *tree_model,
                                           GtkTreeIter *iter,
                                           GtkTreePath *path);
static GtkTreePath *    gb_tree_model_get_path        (GtkTreeModel *tree_model,
                                           GtkTreeIter *iter);
static void       gb_tree_model_get_value       (GtkTreeModel *tree_model,
                                           GtkTreeIter *iter,
                                           gint column,
                                           GValue *value);
static gboolean         gb_tree_model_iter_next       (GtkTreeModel *tree_model,
                                           GtkTreeIter *iter);
static gboolean         gb_tree_model_iter_children   (GtkTreeModel *tree_model,
                                           GtkTreeIter *iter,
                                           GtkTreeIter *parent);
static gboolean         gb_tree_model_iter_has_child  (GtkTreeModel *tree_model,
                                           GtkTreeIter *iter);
static gint       gb_tree_model_iter_n_children (GtkTreeModel *tree_model,
                                           GtkTreeIter *iter);
static gboolean         gb_tree_model_iter_nth_child  (GtkTreeModel *tree_model,
                                           GtkTreeIter *iter,
                                           GtkTreeIter *parent,
                                           gint n);
static gboolean         gb_tree_model_iter_parent     (GtkTreeModel *tree_model,
                                           GtkTreeIter *iter,
                                           GtkTreeIter *child);

static void       gb_tree_model_set_roots       (GbTreeModel *btree_model,
                                           GSList *roots);


/* DND interfaces */
static gboolean         gb_tree_model_drag_data_delete      (GtkTreeDragSource *drag_source,
                                           GtkTreePath *path);
static gboolean         gb_tree_model_drag_data_get   (GtkTreeDragSource *drag_source,
                                           GtkTreePath *path,
                                           GtkSelectionData *selection_data);
static gboolean         gb_tree_model_drag_data_received (GtkTreeDragDest *drag_dest,
                                            GtkTreePath *dest,
                                            GtkSelectionData *selection_data);
static gboolean         gb_tree_model_row_drop_possible     (GtkTreeDragDest *drag_dest,
                                           GtkTreePath *dest_path,
                                           GtkSelectionData *selection_data);

/* helper functions */
static gboolean         gb_tree_model_is_root         (GbTreeModel *m, GbBookmark *f, int *i);
static GbBookmark *     gb_tree_model_get_nth_root    (GbTreeModel *m, int i);

static void       gb_tree_model_descendant_modified_cb (GbFolder *f, GbBookmark *b, gpointer data);
static void       gb_tree_model_modified_cb (GbBookmark *b, gpointer data);
static void             gb_tree_model_descendant_added_cb (GbFolder *f, GbFolder *p, GbBookmark *b,
                                             int pos, gpointer data);
static void             gb_tree_model_descendant_removed_cb (GbFolder *f, GbFolder *p, GbBookmark *b, 
                                               int pos, gpointer data);


static GObjectClass *parent_class = NULL;


GtkType
gb_tree_model_get_type (void)
{
      static GType btree_model_type = 0;
      
      if (!btree_model_type)
      {
            static const GTypeInfo btree_model_info =
                  {
                        sizeof (GbTreeModelClass),
                        NULL,       /* base_init */
                        NULL,       /* base_finalize */
                        (GClassInitFunc) gb_tree_model_class_init,
                        NULL,       /* class_finalize */
                        NULL,       /* class_data */
                        sizeof (GbTreeModel),
                        0, /* n_preallocs */
                        (GInstanceInitFunc) gb_tree_model_init
                  };
            
            static const GInterfaceInfo tree_model_info =
                  {
                        (GInterfaceInitFunc) gb_tree_model_tree_model_init,
                        NULL,
                        NULL
                  };
            
            static const GInterfaceInfo drag_source_info =
                  {
                        (GInterfaceInitFunc) gb_tree_model_drag_source_init,
                        NULL,
                        NULL
                  };
            
            static const GInterfaceInfo drag_dest_info =
                  {
                        (GInterfaceInitFunc) gb_tree_model_drag_dest_init,
                        NULL,
                        NULL
                  };
            
            btree_model_type = g_type_register_static (G_TYPE_OBJECT, "GbTreeModel", 
                                             &btree_model_info, 0);
            
            g_type_add_interface_static (btree_model_type,
                                   GTK_TYPE_TREE_MODEL,
                                   &tree_model_info);
            g_type_add_interface_static (btree_model_type,
                                   GTK_TYPE_TREE_DRAG_SOURCE,
                                   &drag_source_info);
            g_type_add_interface_static (btree_model_type,
                                   GTK_TYPE_TREE_DRAG_DEST,
                                   &drag_dest_info);
            
      }
      
      return btree_model_type;
}

static void
gb_tree_model_class_init (GbTreeModelClass *class)
{
      GObjectClass *object_class;
      
      parent_class = g_type_class_peek_parent (class);
      object_class = (GObjectClass *) class;
      
      object_class->finalize = gb_tree_model_finalize_impl;
}

static void
gb_tree_model_tree_model_init (GtkTreeModelIface *iface)
{
      iface->get_flags = gb_tree_model_get_flags;
      iface->get_n_columns = gb_tree_model_get_n_columns;
      iface->get_column_type = gb_tree_model_get_column_type;
      iface->get_iter = gb_tree_model_get_iter;
      iface->get_path = gb_tree_model_get_path;
      iface->get_value = gb_tree_model_get_value;
      iface->iter_next = gb_tree_model_iter_next;
      iface->iter_children = gb_tree_model_iter_children;
      iface->iter_has_child = gb_tree_model_iter_has_child;
      iface->iter_n_children = gb_tree_model_iter_n_children;
      iface->iter_nth_child = gb_tree_model_iter_nth_child;
      iface->iter_parent = gb_tree_model_iter_parent;
}

static void
gb_tree_model_drag_source_init (GtkTreeDragSourceIface *iface)
{
      iface->drag_data_delete = gb_tree_model_drag_data_delete;
      iface->drag_data_get = gb_tree_model_drag_data_get;
}

static void
gb_tree_model_drag_dest_init (GtkTreeDragDestIface *iface)
{
      iface->drag_data_received = gb_tree_model_drag_data_received;
      iface->row_drop_possible = gb_tree_model_row_drop_possible;
}

static gboolean
gb_tree_model_default_check_func (GbBookmark *b, gpointer data)
{
      return FALSE;
}

static void
gb_tree_model_init (GbTreeModel *btree_model)
{
      btree_model->roots = NULL;
      btree_model->only_folders = FALSE;
      btree_model->hide_roots = FALSE;
      btree_model->check_func = gb_tree_model_default_check_func;
      btree_model->check_func_data = NULL;
      do
      {
            btree_model->stamp = g_random_int ();
      }
      while (btree_model->stamp == 0);
}
#include <string.h>

static void
gb_tree_model_set_only_folders_recursively_emit_signals (GbTreeModel *tm, GbBookmark *lb, int rootindex)
{
      GtkTreeIter iter;
      GtkTreePath *path;
#if 0
      static int ind = 0;
#define D(msg,n,path) { \
      gchar *t = g_strdup (n); \
      int j;\
      if (strlen (t) > 10) t[10] = '\0'; \
      for (j = 0; j < ind; ++j) g_print ("    ");\
      g_print (msg, t); \
      for (j = 10 - ind; j > 0; --j) g_print ("    ");\
      DEBUG_PATH (path); \
      g_free (t);\
      ind++;\
}
#endif
      
      iter.user_data = lb;
      iter.user_data2 = GINT_TO_POINTER (rootindex);
      iter.stamp = tm->stamp;
      
      path = gb_tree_model_get_path ((GtkTreeModel *) tm, &iter);

#if 0
      {
            GtkTreeIter ij;
            gb_tree_model_get_iter ((GtkTreeIter *) tm, &ij, path);
            g_assert (ij.stamp == iter.stamp);
            g_assert (ij.user_data == iter.user_data);
            D ("+%-10s ", lb->name, path);
      }
#endif      
      gtk_tree_model_row_has_child_toggled ((GtkTreeModel *) tm,
                                    path,
                                    &iter);
      
      if (GB_IS_FOLDER (lb) && (!gb_bookmark_is_alias (lb) || gb_tree_model_get_nth_root (tm, rootindex) == lb))
      {
            GbBookmark *bi;
            gtk_tree_path_append_index (path, 0);
            for (bi = GB_FOLDER (lb)->child; bi; bi = bi->next)
            {
                  GtkTreeIter iterbi;
                  iterbi.user_data = bi;
                  iterbi.stamp = tm->stamp;

                  if (GB_IS_FOLDER (bi))
                  {
                        gtk_tree_model_row_has_child_toggled ((GtkTreeModel *) tm,
                                                      path,
                                                      &iterbi);
                        gtk_tree_path_next (path);
                  }
                  else
                  {
                        if (tm->only_folders)
                        {
                              gtk_tree_model_row_deleted ((GtkTreeModel *) tm, path);
                        }
                        else
                        {
                              
                              gtk_tree_model_row_inserted ((GtkTreeModel *) tm, path, &iterbi);
                              gtk_tree_path_next (path);
                        }
                  }
            }
            gtk_tree_path_up (path);

            for (bi = GB_FOLDER (lb)->child; bi; bi = bi->next)
            {
                  if (GB_IS_FOLDER (bi))
                  {
                        gb_tree_model_set_only_folders_recursively_emit_signals (tm, bi, rootindex);
                  }
            }
      }
      
      gtk_tree_path_free (path);
#if 0
      ind--;
#endif
}

void
gb_tree_model_set_only_folders (GbTreeModel *tm, gboolean value)
{
      if (tm->only_folders != value)
      {
            int i = 0;
            GSList *l;
            tm->only_folders = value;
            
            for (l = tm->roots; l; l = l->next)
            {
                  {
                        int j;
                        g_assert (gb_tree_model_is_root (tm, l->data, &j));
                        g_assert (i == j);
                  }
                  gb_tree_model_set_only_folders_recursively_emit_signals (tm, l->data, i);
                  ++i;
            }
      }
}

gboolean
gb_tree_model_get_only_folders (GbTreeModel *tm)
{
      return tm->only_folders;
}

void
gb_tree_model_set_hide_roots (GbTreeModel *tm, gboolean value)
{
      if (tm->hide_roots != value)
      {
            GSList *l;
            tm->hide_roots = value;
            
            for (l = tm->roots; l; l = l->next)
            {
                  /* TODO: should notify the listeners of the lots of changes! */
            }
      }
}

gboolean
gb_tree_model_get_hide_roots (GbTreeModel *tm)
{
      return tm->hide_roots;
}

/**
 * gb_tree_model_new:
 * @root: the root bookmark for this model
 *
 * Return value: a new #GbTreeModel
 **/
GbTreeModel *
gb_tree_model_new (GSList *roots)
{
      GbTreeModel *retval;
      
      retval = GB_TREE_MODEL (g_object_new (GB_TYPE_TREE_MODEL, NULL));
      gb_tree_model_set_roots (retval, roots);
      
      return retval;
}

GbTreeModel *
gb_tree_model_new_for_set (GbBookmarkSet *set)
{
      GbTreeModel *ret;
      GSList *l;
      
      g_return_val_if_fail (GB_IS_BOOKMARK_SET (set), NULL);

      l = g_slist_prepend (NULL, set->root);
      ret = gb_tree_model_new (l);
      g_slist_free (l);
      return ret;
}

static void 
gb_tree_model_set_roots (GbTreeModel *btree_model, GSList *roots)
{
      GSList *l;

      /* call this only once, without NULL as roots */
      g_return_if_fail (btree_model->roots == NULL);
      g_return_if_fail (roots != NULL);

      btree_model->roots = g_slist_copy (roots);
      if (btree_model->roots)
      {
            if (GB_BOOKMARK (btree_model->roots->data)->set)
            {
                  btree_model->set = GB_BOOKMARK (btree_model->roots->data)->set;
                  g_object_ref (G_OBJECT (btree_model->set));
            }
      }
      else
      {
            btree_model->set = NULL;
      }

      for (l = btree_model->roots; l != NULL; l = l->next)
      {
            if (GB_IS_FOLDER (l->data))
            {
                  g_signal_connect (l->data, "descendant-modified", 
                                G_CALLBACK (gb_tree_model_descendant_modified_cb), btree_model);
                  g_signal_connect (l->data, "descendant-added", 
                                G_CALLBACK (gb_tree_model_descendant_added_cb), btree_model);
                  g_signal_connect (l->data, "descendant-removed", 
                                G_CALLBACK (gb_tree_model_descendant_removed_cb), btree_model);
            }
            g_signal_connect (l->data, "modified", 
                          G_CALLBACK (gb_tree_model_modified_cb), btree_model);
            g_object_ref (l->data);
      }
}

static void
gb_tree_model_finalize_impl (GObject *object)
{
      GSList *l;
      GbTreeModel *m = GB_TREE_MODEL (object);
      
      LOG ("Finalizing a GbTreeModel");

      if (m->set)
      {
            g_object_unref (G_OBJECT (m->set));
      }
      for (l = m->roots; l != NULL; l = l->next)
      {
            g_signal_handlers_disconnect_matched (l->data, G_SIGNAL_MATCH_DATA, 0, 0, 
                                          NULL, NULL, m);
            g_object_unref (G_OBJECT (l->data));
      }
      g_slist_free (m->roots);
      (* parent_class->finalize) (object);
}

/* fulfill the GtkTreeModel requirements */

static guint
gb_tree_model_get_flags (GtkTreeModel *tree_model)
{
      return 0;
}

static gint
gb_tree_model_get_n_columns (GtkTreeModel *tree_model)
{
      return GB_TREE_MODEL_NUM_COLUMS;
}

static GType
gb_tree_model_get_column_type (GtkTreeModel *tree_model,
                         gint index)
{
      g_return_val_if_fail (GB_IS_TREE_MODEL (tree_model), G_TYPE_INVALID);
      g_return_val_if_fail ((index < GB_TREE_MODEL_NUM_COLUMS) && (index >= 0), G_TYPE_INVALID);
      
      switch (index)
      {
      case GB_TREE_MODEL_COL_ICON:
            return GDK_TYPE_PIXBUF;
            break;
      case GB_TREE_MODEL_COL_TITLE:
      case GB_TREE_MODEL_COL_URL:
            return G_TYPE_STRING;
            break;
      case GB_TREE_MODEL_COL_CHECK:
            return G_TYPE_BOOLEAN;
      default:
            g_assert_not_reached ();
            return G_TYPE_INVALID;
            break;
      }
}

static gboolean
gb_tree_model_get_iter (GtkTreeModel *tree_model,
                  GtkTreeIter *iter,
                  GtkTreePath *path)
{
      GbTreeModel *btree_model = (GbTreeModel *) tree_model;
      GtkTreeIter parent;
      gint *indices;
      gint depth, i;
      
      g_return_val_if_fail (GB_IS_TREE_MODEL (btree_model), FALSE);
      
      indices = gtk_tree_path_get_indices (path);
      depth = gtk_tree_path_get_depth (path);
      
      iter->stamp = btree_model->stamp;
      iter->user_data = btree_model->roots;
      iter->user_data2 = NULL; /* does not really matter here */
      
      for (i = 0; i < depth; i++)
      {
            parent = *iter;
            if (! gb_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
            {
                  return FALSE;
            }
      }
      return TRUE;
}

static int 
gb_tree_model_bookmark_child_index (GbTreeModel *btree_model, GbBookmark *child)
{
      GbFolder *parent = child->parent;

      if (btree_model->only_folders)
      {
            GbBookmark *c;
            gint i = 0;
            for  (c = parent->child; c && c != child; c = c->next)
            {
                  if (GB_IS_FOLDER (c))
                  {
                        ++i;
                  }
            }
            return i;
      }
      else
      {
            return gb_folder_get_child_index (parent, child);
      }
}

static GtkTreePath *
gb_tree_model_get_path (GtkTreeModel *tree_model,
                  GtkTreeIter *iter)
{
      GtkTreePath *retval;
      GbBookmark *b_it;
      int rootindex;
      GbBookmark *root;
      GbBookmark *realroot;
      gint i = 0;
      GbTreeModel *btree_model = (GbTreeModel *) tree_model;
      
      g_return_val_if_fail (GB_IS_TREE_MODEL (tree_model), NULL);
      g_return_val_if_fail (iter != NULL, NULL);
      g_return_val_if_fail (iter->user_data != NULL, NULL);
      g_return_val_if_fail (iter->stamp == btree_model->stamp, NULL);
      
      if (iter->user_data == btree_model->roots)
      {
            return gtk_tree_path_new ();
      }
      
      b_it = iter->user_data;
      rootindex = GPOINTER_TO_INT (iter->user_data2);
      root = gb_tree_model_get_nth_root (btree_model, rootindex);
      realroot = gb_bookmark_real_bookmark (root);

      if (root == b_it || realroot == b_it)
      {
            retval = gtk_tree_path_new ();
            g_return_val_if_fail (!btree_model->hide_roots, retval);
            gtk_tree_path_append_index (retval, rootindex);
      }
      else
      {
            GbFolder *parent = b_it->parent;
            GtkTreeIter tmp_iter = *iter;

            g_assert (parent != NULL);
            g_assert (!gb_bookmark_is_alias (parent));

            tmp_iter.user_data = parent;
            tmp_iter.user_data2 = GINT_TO_POINTER (rootindex);
            
            if (btree_model->hide_roots && ((((GbBookmark *) parent) == root)
                                    ||((GbBookmark *) parent) == realroot))
            {
                  int nprevs = 0;
                  GSList *sli;
                  GtkTreeIter riter;
                  int rrootindex = 0;
                  riter.stamp = btree_model->stamp;
                  for (sli = btree_model->roots; 
                       sli && gb_bookmark_real_bookmark (sli->data) != (GbBookmark *) parent; 
                       sli = sli->next)
                  {
                        riter.user_data = sli->data;
                        riter.user_data2 = GINT_TO_POINTER (rrootindex);
                        nprevs += gb_tree_model_iter_n_children (tree_model, &riter);
                        rrootindex++;
                  }
                  g_assert (rrootindex == rootindex);
                  retval = gtk_tree_path_new ();
                  gtk_tree_path_append_index (retval, 
                                        nprevs + gb_tree_model_bookmark_child_index (btree_model, b_it));
            }
            else
            {
                  retval = gb_tree_model_get_path (tree_model, &tmp_iter);
            
                  if (retval != NULL) 
                  {
                        i = gb_tree_model_bookmark_child_index (btree_model, b_it);
                        gtk_tree_path_append_index (retval, i);
                  }
            }
      }

      return retval;
}

static void
gb_tree_model_get_value (GtkTreeModel *tree_model,
                   GtkTreeIter *iter,
                   gint column,
                   GValue *value)
{
      GbBookmark *b;
      GdkPixbuf *pb;
      GbTreeModel *btree_model = (GbTreeModel *) tree_model;
      g_return_if_fail (GB_IS_TREE_MODEL (btree_model));
      g_return_if_fail (iter != NULL);
      g_return_if_fail (iter->stamp == btree_model->stamp);
      g_return_if_fail (GB_IS_BOOKMARK (iter->user_data));
      g_return_if_fail (column < GB_TREE_MODEL_NUM_COLUMS);
      
      b = iter->user_data;
      
      switch (column) {
      case GB_TREE_MODEL_COL_ICON:
            g_value_init (value, GDK_TYPE_PIXBUF);
            pb = gb_bookmark_get_icon (b);
            g_value_set_object (value, pb);
            break;
      case GB_TREE_MODEL_COL_TITLE:
            g_value_init (value, G_TYPE_STRING);
            if (GB_IS_SEPARATOR (b))
            {
                  g_value_set_string (value, "-----");
            }
            else
            {
                  g_value_set_string (value, b->name);
            }
            break;
      case GB_TREE_MODEL_COL_URL:
            g_value_init (value, G_TYPE_STRING);
            if (GB_IS_SITE (b))
            {
                  g_value_set_string (value, ((GbSite *) b)->url);
            }
            break;
      case GB_TREE_MODEL_COL_CHECK:
            g_value_init (value, G_TYPE_BOOLEAN);
            g_value_set_boolean (value, btree_model->check_func (b, btree_model->check_func_data));
            break;
      default:
            g_assert_not_reached ();
            break;
      }
}

static gboolean
gb_tree_model_iter_next (GtkTreeModel *tree_model,
                   GtkTreeIter *iter)
{
      GbBookmark *b;
      int rootindex;
      GbTreeModel *btree_model = (GbTreeModel *) tree_model;
      g_return_val_if_fail (iter != NULL, FALSE);
      g_return_val_if_fail (iter->user_data != NULL, FALSE);
      g_return_val_if_fail (iter->stamp == GB_TREE_MODEL (tree_model)->stamp, FALSE);
      
      b = iter->user_data;
      rootindex = GPOINTER_TO_INT (iter->user_data2);
      
      if (b == gb_tree_model_get_nth_root (btree_model, rootindex))
      {
            GbBookmark *nb;
            ++rootindex;
            nb = gb_tree_model_get_nth_root (btree_model, rootindex);

            g_return_val_if_fail (!btree_model->hide_roots, FALSE);
            
            if (nb != NULL) 
            {
                  iter->user_data = nb;
                  iter->user_data2 = GINT_TO_POINTER (rootindex);
                  return TRUE;
            }
            else
            {
                  return FALSE;
            }
      }
      else
      {
            GbBookmark *n = b->next;
      search:
            if (btree_model->only_folders)
            {
                  for ( ; n && !GB_IS_FOLDER (n); n = n->next) ;
            }
            
            if (n != NULL) 
            {
                  iter->user_data = n;
                  iter->user_data2 = GINT_TO_POINTER (rootindex);
                  return TRUE;
            }
            else
            {
                  if (btree_model->hide_roots
                      && ((GbBookmark *) b->parent) == gb_tree_model_get_nth_root (btree_model, rootindex))
                  {
                        GbBookmark *nb;
                        ++rootindex;
                        nb = gb_tree_model_get_nth_root (btree_model, rootindex);
                        
                        if (nb != NULL && GB_IS_FOLDER (nb)) 
                        {
                              n = GB_FOLDER (nb)->child;
                              goto search;
                        }
                  }
                  return FALSE;
            }
      }
}

static gboolean
gb_tree_model_iter_children (GtkTreeModel *tree_model,
                       GtkTreeIter *iter,
                       GtkTreeIter *parent)
{
      GbTreeModel *btree_model = (GbTreeModel *) tree_model;
      GbBookmark *c1 = NULL;
      int rootindex = 0;

      g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
      g_return_val_if_fail (parent == NULL || parent->stamp == btree_model->stamp, FALSE);
      
      if (!parent || parent->user_data == btree_model->roots) 
      {
            if (btree_model->hide_roots)
            {
                  GSList *li;
                  rootindex = 0;
                  for (li = btree_model->roots; li; li = li->next)
                  {
                        if (GB_IS_FOLDER (li->data))
                        {
                              c1 = GB_FOLDER (li->data)->child;
                              break;
                        }
                        ++rootindex;
                  }
            }
            else
            {
                  c1 = btree_model->roots->data;
            }
      }
      else if (GB_IS_FOLDER (parent->user_data))
      {
            GbFolder *p = GB_FOLDER (parent->user_data);
            rootindex = GPOINTER_TO_INT (parent->user_data2);
            if (!gb_bookmark_is_alias (p) ||
                    gb_tree_model_get_nth_root (btree_model, rootindex) == (GbBookmark *) p)
            {
                  if (btree_model->only_folders)
                  {
                        for (c1 = p->child; c1 && !GB_IS_FOLDER (c1); c1 = c1->next) ;
                  }
                  else
                  {
                        c1 = p->child;
                  }
            }
      }
      
      if (c1)
      {
            iter->stamp = GB_TREE_MODEL (tree_model)->stamp;
            iter->user_data = c1;
            iter->user_data2 = GINT_TO_POINTER (rootindex);
            return TRUE;
      }
      else
      {
            return FALSE;
      }
}

static gboolean
gb_tree_model_iter_has_child (GtkTreeModel *tree_model,
                        GtkTreeIter *iter)
{
      GbTreeModel *btree_model = (GbTreeModel *) tree_model;
      GbFolder *b_it;
      int rootindex;
      
      g_return_val_if_fail (GB_IS_TREE_MODEL (btree_model), FALSE);
      g_return_val_if_fail (iter->stamp == btree_model->stamp, FALSE);
      g_return_val_if_fail (iter->user_data != NULL, FALSE);
      
      if (!GB_IS_FOLDER (iter->user_data))
            return FALSE;

      b_it = iter->user_data;
      rootindex = GPOINTER_TO_INT (iter->user_data2);

      if (gb_bookmark_is_alias (b_it) && gb_tree_model_get_nth_root (btree_model, rootindex) != (GbBookmark *) b_it)
      {
            return FALSE;
      }
      else if (btree_model->only_folders)
      {
            GbBookmark *b;
            for (b = b_it->child; b; b = b->next)
            {
                  if (GB_IS_FOLDER (b))
                  {
                        return TRUE;
                  }
            }
            return FALSE;
      }
      else
      {
            return b_it->child != NULL;
      }
}

static int 
gb_tree_model_bookmark_n_children (GbTreeModel *btree_model, GbBookmark *b, int rootindex)
{
      int i = 0;
      if (GB_IS_FOLDER (b)
          && (!gb_bookmark_is_alias (b) || gb_tree_model_get_nth_root (btree_model, rootindex) == b))
      {
            gboolean no_foders = ! btree_model->only_folders;
            GbBookmark *c = GB_FOLDER (b)->child;
            while (c != NULL)
            {
                  if (no_foders || GB_IS_FOLDER (c))
                  {
                        i++;
                  }
                  c = c->next;
            }
      }
      return i;
}

static gint
gb_tree_model_iter_n_children (GtkTreeModel *tree_model,
                         GtkTreeIter *iter)
{
      GbTreeModel *btree_model = (GbTreeModel *) tree_model;

      g_return_val_if_fail (GB_IS_TREE_MODEL (tree_model), 0);
      g_return_val_if_fail (iter == NULL || iter->user_data != NULL, 0);
      
      if (iter == NULL || iter->user_data == GB_TREE_MODEL (tree_model)->roots)
      {
            if (btree_model->hide_roots)
            {
                  GSList *l;
                  int nch = 0;
                  int rootindex = 0;
                  for (l = btree_model->roots; l; l = l->next)
                  {
                        nch += gb_tree_model_bookmark_n_children (btree_model, l->data, rootindex);
                        ++rootindex;
                  }
                  return nch;
            }
            else
            {
                  if (GB_TREE_MODEL (tree_model)->only_folders)
                  {
                        int i = 0;
                        GSList *l;

                        for (l = btree_model->roots; l; l = l->next)
                        {
                              if (GB_IS_FOLDER (l->data))
                              {
                                    ++i;
                              }
                        }
                        return i;
                  }
                  else
                  {
                        return g_slist_length (btree_model->roots);
                  }
            }
      }
      else 
      {
            int rootindex = GPOINTER_TO_INT (iter->user_data2);
            return gb_tree_model_bookmark_n_children (btree_model, iter->user_data, rootindex);
      }
}

static GbBookmark *
gb_tree_model_bookmark_nth_child (GbTreeModel *btree_model, GbFolder *parent, gint index)
{
      gboolean no_folders = ! btree_model->only_folders;
      int i = 0;
      GbBookmark *c;
            
      for (c = parent->child; c; c = c->next)
      {
            if (i == index && (no_folders || GB_IS_FOLDER (c)))
            {
                  break;
            }
            else if (no_folders || GB_IS_FOLDER (c))
            {
                  i++;
            }
      }
      return c;
}

static gboolean
gb_tree_model_iter_nth_child (GtkTreeModel *tree_model,
                        GtkTreeIter *iter,
                        GtkTreeIter *parent,
                        gint n)
{
      GbTreeModel *btree_model = (GbTreeModel *) tree_model;
      g_return_val_if_fail (GB_IS_TREE_MODEL (tree_model), FALSE);
      g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
      g_return_val_if_fail (iter != NULL, FALSE);
      
      if (parent == NULL || parent->user_data == GB_TREE_MODEL (tree_model)->roots)
      {
            if (btree_model->hide_roots)
            {
                  GbBookmark *c = NULL;
                  GSList *sli;
                  int rootindex = 0;
                  for (sli = btree_model->roots; sli && !c && n >= 0; sli = sli->next)
                  {
                        c = gb_tree_model_bookmark_nth_child (btree_model, sli->data, n);
                        if (c)
                        {
                              iter->stamp = btree_model->stamp;
                              iter->user_data = c;
                              iter->user_data2 = GINT_TO_POINTER (rootindex);
                              return TRUE;
                        }
                        else
                        {
                              n -= gb_tree_model_bookmark_n_children (btree_model, sli->data, rootindex);
                              ++rootindex;
                        }
                  }
                  return FALSE;
            }
            else
            {
                  GSList *l = g_slist_nth (btree_model->roots, n);
                  if (l != NULL)
                  {
                        iter->user_data = l->data;
                        iter->user_data2 = GINT_TO_POINTER (n);
                        iter->stamp = btree_model->stamp;
                        return TRUE;
                  }
                  else
                  {
                        return FALSE;
                  }
            }
      }
      else 
      {
            GbFolder *b = parent->user_data;
            int rootindex = GPOINTER_TO_INT (parent->user_data2);
            if (GB_IS_FOLDER (b) && (!gb_bookmark_is_alias (b)
                               || gb_tree_model_get_nth_root (btree_model, rootindex) == (GbBookmark *) b))
            {
                  GbBookmark *c = gb_tree_model_bookmark_nth_child (btree_model, b, n);

                  if (c)
                  {
                        iter->user_data = c;
                        iter->user_data2 = parent->user_data2;
                        iter->stamp = btree_model->stamp;
                        return TRUE;
                  }
                  else
                  {
                        return FALSE;
                  }
            }
            else 
            {
                  return FALSE;
            }
      }
}

static gboolean
gb_tree_model_iter_parent (GtkTreeModel *tree_model,
                     GtkTreeIter *iter,
                     GtkTreeIter *child)
{
      GbTreeModel *btree_model = (GbTreeModel *) tree_model;
      g_return_val_if_fail (iter != NULL, FALSE);
      g_return_val_if_fail (child != NULL, FALSE);
      g_return_val_if_fail (child->user_data != NULL, FALSE);
      g_return_val_if_fail (child->stamp == GB_TREE_MODEL (tree_model)->stamp, FALSE);
      
      if (child->user_data == btree_model->roots)
      {
            return FALSE;
      }
      else 
      {
            GbBookmark *bit = child->user_data;
            int rootindex = GPOINTER_TO_INT (child->user_data2);
            
            if (gb_tree_model_get_nth_root (btree_model, rootindex) == bit)
            {
                  iter->user_data = btree_model->roots;
                  iter->stamp = btree_model->stamp;
                  
                  g_return_val_if_fail (!btree_model->hide_roots, TRUE);
                  return TRUE;
            }
            else 
            {
                  GbFolder *parent = GB_FOLDER (bit->parent);
                  g_assert (parent != NULL);
                  
                  if (btree_model->hide_roots
                      && ((GbBookmark *) parent) == gb_tree_model_get_nth_root (btree_model, rootindex))
                  {
                        iter->user_data = btree_model->roots;
                        iter->stamp = btree_model->stamp;
                  }
                  else
                  {
                        iter->user_data = parent;
                        iter->user_data2 = GINT_TO_POINTER (rootindex);
                        iter->stamp = btree_model->stamp;
                  }
                  return TRUE;
            }
      }
}

/**
 * gb_tree_model_iter_depth:
 * @btree_model: A #GbTreeModel
 * @iter: A valid #GtkTreeIter
 * 
 * Returns the depth of @iter. This will be 0 for anything on the root level, 1
 * for anything down a level, etc.
 * 
 * Return value: The depth of @iter
 **/
gint
gb_tree_model_iter_depth (GbTreeModel *btree_model,
                    GtkTreeIter *iter)
{
      gint depth = 0;
      GbBookmark *b_it;
      GbBookmark *root;
      gint rootindex;

      g_return_val_if_fail (GB_IS_TREE_MODEL (btree_model), 0);
      g_return_val_if_fail (VALID_ITER (iter, btree_model), 0);
      
      b_it = iter->user_data;
      rootindex = GPOINTER_TO_INT (iter->user_data2);
      root = gb_tree_model_get_nth_root (btree_model, rootindex);
      while (b_it->parent && !(b_it == root
                         || (btree_model->hide_roots 
                             && ((GbBookmark *) b_it->parent) == root)))
      {
            depth++;
            b_it = (GbBookmark *) b_it->parent;
      }
      return depth;
}




/* DND */


static gboolean
gb_tree_model_drag_data_delete (GtkTreeDragSource *drag_source,
                        GtkTreePath *path)
{
      GtkTreeIter iter;
      GbTreeModel *tm;

      g_return_val_if_fail (GB_IS_TREE_MODEL (drag_source), FALSE);

      tm = GB_TREE_MODEL (drag_source);

      if (gb_tree_model_get_iter (GTK_TREE_MODEL (tm), &iter, path))
      {
            GbBookmark *b = gb_tree_model_bookmark_from_iter (tm, &iter);
            gb_bookmark_unparent_safe (b);
            return TRUE;
      }
      else
      {
            return FALSE;
      }
}

static gboolean
gb_tree_model_drag_data_get (GtkTreeDragSource *drag_source,
                       GtkTreePath *path,
                       GtkSelectionData *selection_data)
{
      g_return_val_if_fail (GB_IS_TREE_MODEL (drag_source), FALSE);
      
      /* Note that we don't need to handle the GTK_TREE_MODEL_ROW
       * target, because the default handler does it for us, but
       * we do anyway for the convenience of someone maybe overriding the
       * default handler.
       */
      
      if (gtk_tree_set_row_drag_data (selection_data,
                              GTK_TREE_MODEL (drag_source),
                              path))
      {
            return TRUE;
      }
      else
      {
            /* export XBEL */
      }

      return FALSE;
}

typedef struct 
{
      GbBookmarkSet *set;
      GSList *list;
} GbTreeModelDragDataReceivedInfo;

static void 
gb_tree_model_drag_data_received_aux (const char *url, const char *title,
                              gpointer data)
{
      GbTreeModelDragDataReceivedInfo *i = data;
      GbSite *s = gb_site_new (i->set, title, url);
      i->list = g_slist_prepend (i->list, s);
}

static gboolean
gb_tree_model_drag_data_received (GtkTreeDragDest *drag_dest,
                          GtkTreePath *dest,
                          GtkSelectionData *selection_data)
{
      GbTreeModel *gtm;
      GtkTreeModel *src_model = NULL;
      GtkTreePath *src_path = NULL;
      GSList *blist = NULL;
      const GSList *li = NULL;
      GbBookmark *bparent;
      gint bindex;
      
      g_return_val_if_fail (GB_IS_TREE_MODEL (drag_dest), FALSE);

      LOG ("in gb_tree_model_drag_data_received");

      gtm = GB_TREE_MODEL (drag_dest);
      
      /* get the bookmark */
      if (gtk_tree_get_row_drag_data (selection_data,
                              &src_model,
                              &src_path))
      {
            GbBookmark *b = NULL;
            /* in the same process */

            /* Copy the given row to a new position */
            GtkTreeIter src_iter;
            GbBookmark *srcb;
            
            if (!gtk_tree_model_get_iter (src_model, &src_iter, src_path))
            {
                  gtk_tree_path_free (src_path);
                  return FALSE;
            }

            srcb = gb_tree_model_bookmark_from_iter (gtm, &src_iter);
            if (gb_bookmark_is_alias (srcb))
            {
                  /* if the source bookmark is an alias, we create an alias to it instead 
                     of copying it. This avoid turning aliases into normal bookmarks when 
                     moving them */
                  b = gb_bookmark_alias_create (srcb, NULL);
            }
            else
            {
                  b = gb_bookmark_copy (srcb);
            }
            gtk_tree_path_free (src_path);

            if (b)
            {
                  blist = g_slist_prepend (blist, b);
            }
      }
      else
      {
            GbTreeModelDragDataReceivedInfo data;
            guint info;

            data.list = NULL;
            data.set = gb_tree_model_get_set (gtm);

            if (selection_data->target == gdk_atom_intern (GALEON_DND_URL_TYPE, FALSE))
            {
                  info = GALEON_DND_URL;
            }
            else if (selection_data->target == gdk_atom_intern (GALEON_DND_URI_LIST_TYPE, FALSE))
            {
                  info = GALEON_DND_URI_LIST;
            }
            else
            {
                  return FALSE;
            }
            galeon_dnd_drag_data_receive (NULL, NULL, -1, -1, selection_data, 
                                    info, 0, &data, gb_tree_model_drag_data_received_aux);
            blist = g_slist_reverse (data.list);
      }

      if (!blist)
      {
            return FALSE;
      }

      /*
        DEBUG_PATH (dest);
      */
            
      /* get the destination */
      {
            GtkTreePath *dest_parent_path = gtk_tree_path_copy (dest);
            GtkTreeIter dest_parent_iter; 
            if (gtk_tree_path_up (dest_parent_path))
            {
                  if ((gtk_tree_path_get_depth (dest_parent_path) > 0)
                      && (gtk_tree_model_get_iter (GTK_TREE_MODEL (gtm),
                                           &dest_parent_iter, dest_parent_path)))
                  {
                        bparent = gb_tree_model_bookmark_from_iter (gtm, &dest_parent_iter);
                  }
                  else
                  {
                        bparent = NULL;
                  }
            }
            else
            {
                  bparent = NULL;
            }
            gtk_tree_path_free (dest_parent_path);
      }

      if (!bparent)
      {
            
            bparent = gb_tree_model_get_first_root (gtm);
            LOG ("Defaulting the parent to the first root...");

            /* this is broken, specially when hide roots is TRUE */
      }

      g_return_val_if_fail (bparent, FALSE);

      if (!GB_IS_FOLDER (bparent))
      {
            bparent = (GbBookmark *) bparent->parent;
      }

      g_return_val_if_fail (GB_IS_FOLDER (bparent), FALSE);

      if (g_object_get_data (G_OBJECT (gtm),
                         "gtk-tree-model-drop-append"))
      {
            bindex = -1;
            g_object_set_data (G_OBJECT (gtm), "gtk-tree-model-drop-append", NULL);
      }
      else if (gtk_tree_path_get_depth (dest) > 0)
      {
            bindex = gtk_tree_path_get_indices (dest)[gtk_tree_path_get_depth (dest) - 1];
      }
      else
      {
            bindex = -1;
      }
      
      if (bindex > 0 && gtm->only_folders)
      {
            gint realindex = 0;
            GbBookmark *c;
            for (c = GB_FOLDER (bparent)->child; c && bindex > 0; c = c->next)
            {
                  ++realindex;
                  if (GB_IS_FOLDER (c))
                  {
                        --bindex;
                  }
            }
            bindex = realindex;
      }

      LOG ("will insert into %s (at %d)", bparent->name, bindex);

      for (li = blist; li; li = li->next)
      {
            GbBookmark *b = GB_BOOKMARK (li->data);
            gb_folder_add_child (GB_FOLDER (bparent), b, bindex);
            g_object_unref (b);
            ++bindex;
      }
      g_slist_free (blist);

      return TRUE;
}


static gboolean 
gb_tree_model_row_drop_possible_aux (GbTreeModel *drag_dest, GtkTreePath *path)
{
      GtkTreeIter iter;

      /* DEBUG_PATH (path); */

      if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_dest), &iter, path))
      {
            GbBookmark *b = gb_tree_model_bookmark_from_iter (GB_TREE_MODEL (drag_dest), &iter);
            if (b)
            {
                  GbFolder *parent = b->parent;
                  LOG ("b = %s\n", b->name);
                  LOG ("parent = %s\n", parent ? GB_BOOKMARK (parent)->name : "(null)");

                  return parent != NULL && !gb_folder_is_autogenerated (parent);
            }
      }

      /* try the parent */
      {
            GtkTreePath *tmp = gtk_tree_path_copy (path);
            gboolean ret = FALSE;
            if (gtk_tree_path_up (tmp))
            {
                  /* DEBUG_PATH (tmp); */
                  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_dest), &iter, tmp))
                  {
                        GbBookmark *p = gb_tree_model_bookmark_from_iter (GB_TREE_MODEL (drag_dest), &iter);
                        LOG ("p = %s\n", p ? p->name : "(null)");
                        if (p && GB_IS_FOLDER (p))
                        {
                              ret = !gb_folder_is_autogenerated (GB_FOLDER (p));
                        }
                  }
            }
            gtk_tree_path_free (tmp);
            return ret;
      }
}


static gboolean
gb_tree_model_row_drop_possible (GtkTreeDragDest *drag_dest,
                         GtkTreePath *dest_path,
                         GtkSelectionData *selection_data)
{
      GtkTreeModel *src_model = NULL;
      GtkTreePath *src_path = NULL;
      gboolean retval = TRUE;
      
      if (gtk_tree_get_row_drag_data (selection_data,
                              &src_model,
                              &src_path))
      {     
            /* in-process drag */

            if (src_model == GTK_TREE_MODEL (drag_dest))
            {
                  /* in the same tree model */
      
                  /* Can't drop into ourself. */
                  if (gtk_tree_path_is_ancestor (src_path,
                                           dest_path))
                  {
                        retval = FALSE;
                  }
                  else
                  {
                        retval = TRUE;
                  }
            }
            else
            {
                  retval = TRUE;
            }
            gtk_tree_path_free (src_path);
      }

      if (retval)
      {
            /* Can't drop if dest_path's parent doesn't exist and is a folder */
            retval = gb_tree_model_row_drop_possible_aux (GB_TREE_MODEL (drag_dest), dest_path);
      }
      
      LOG ("gb_tree_model_row_drop_possible () = %s", retval ? "TRUE" : "FALSE");
      
      return retval;
      
}

static GbBookmark *
gb_tree_model_get_nth_root (GbTreeModel *m, int i)
{
        GSList *sli = g_slist_nth (m->roots, i);
      return sli ? sli->data : NULL;
}

static gboolean
gb_tree_model_is_root (GbTreeModel *m, GbBookmark *b, int *i)
{
      GSList *l = m->roots;
      int j = 0;
      while (l != NULL)
      {
            if (l->data == b)
            {
                  if (i != NULL)
                  {
                        *i = j;
                  }
                  return TRUE;
            }
            j++;
            l = l->next;
      }
      return FALSE;
}

GbBookmark *
gb_tree_model_bookmark_from_iter (GbTreeModel *m, GtkTreeIter *iter)
{
      if (iter->user_data == m->roots)
      {
            return NULL;
      }
      else
      {
            return GB_BOOKMARK (iter->user_data);
      }
}

gboolean
gb_tree_model_iter_from_bookmark (GbTreeModel *model, GbBookmark *b, GtkTreeIter *iter)
{
      int rootindex = 0;
      GSList *sli;
      gboolean ret = FALSE;

      if (model->only_folders && !GB_IS_FOLDER (b))
      {
            return FALSE;
      }

      for (sli = model->roots; sli; sli = sli->next)
      {
            GbBookmark *r = sli->data;
            if (r == b || (GB_IS_FOLDER (r) && gb_folder_is_ancestor (GB_FOLDER (r), b)))
            {
                  ret = TRUE;
                  break;
            }
            else
            {
                  ++rootindex;
            }
      }

      if (ret)
      {
            iter->stamp = model->stamp;
            iter->user_data = b;
            iter->user_data2 = GINT_TO_POINTER (rootindex);
      }
      return ret;
}

static void
gb_tree_model_row_changed_helper (GbTreeModel *m, GtkTreeIter *it)
{
      GtkTreePath *p = gb_tree_model_get_path ((GtkTreeModel *) m, it);
      gtk_tree_model_row_changed ((GtkTreeModel *) m, p, it);
      gtk_tree_path_free (p);
}

static void 
gb_tree_model_descendant_modified_cb (GbFolder *f, GbBookmark *b, gpointer data)
{
      GbTreeModel *m = data;

      if (!m->only_folders || GB_IS_FOLDER (b))
      {
            int rootindex = g_slist_index (m->roots, f);
            GtkTreeIter it;
            
            g_assert (rootindex >= 0);

            it.user_data = b;
            it.user_data2 = GINT_TO_POINTER (rootindex);
            it.stamp = m->stamp;

            gb_tree_model_row_changed_helper (m, &it);
      }
}

static void
gb_tree_model_modified_cb (GbBookmark *b, gpointer data)
{
      GbTreeModel *m = data;

      if (!m->hide_roots)
      {
            int rootindex = g_slist_index (m->roots, b);
            GtkTreeIter it;

            it.user_data = b;
            it.user_data2 = GINT_TO_POINTER (rootindex);
            it.stamp = m->stamp;

            gb_tree_model_row_changed_helper (m, &it);
      }     
}

static void
gb_tree_model_row_inserted_helper (GbTreeModel *m, GtkTreeIter *it)
{
      GtkTreePath *path = gb_tree_model_get_path ((GtkTreeModel *) m, it);
      gtk_tree_model_row_inserted ((GtkTreeModel *) m, path, it);
      gtk_tree_path_free (path);
}

static void
gb_tree_model_descendant_added_cb (GbFolder *f, GbFolder *p, GbBookmark *b, int pos, gpointer data)
{
      GbTreeModel *m = data;
      int rootindex = g_slist_index (m->roots, f);
      GtkTreeIter it;

      g_assert (rootindex >= 0);
            
      if ((!gb_bookmark_is_alias (p) || f == p) 
          && (!m->only_folders || GB_IS_FOLDER (b)))
      {
            it.user_data = b;
            it.user_data2 = GINT_TO_POINTER (rootindex);
            it.stamp = m->stamp;
            
            gb_tree_model_row_inserted_helper (m, &it);

            /* probably this could be done less inneficient */
            if (GB_IS_FOLDER (b) && !gb_bookmark_is_alias (b)) /* note that b can't be root */
            {
                  GbBookmark *bi;
                  int i = 0;
                  for (bi = GB_FOLDER (b)->child; bi; bi = bi->next)
                  {
                        gb_tree_model_descendant_added_cb (f, bi->parent, bi, i, data);
                        ++i;
                  }
            }
      }

      /* the following is needed because the check_func value may change when a child is added */
      if (!(m->hide_roots && f == p))
      {
            it.user_data = p;
            it.user_data2 = GINT_TO_POINTER (rootindex);
            it.stamp = m->stamp;

            gb_tree_model_row_changed_helper (m, &it);
      }
}

static void
gb_tree_model_descendant_removed_cb (GbFolder *f, GbFolder *p, GbBookmark *b, int pos, gpointer data)
{
      GbTreeModel *m = data;
      int rootindex = g_slist_index (m->roots, f);
      GtkTreeIter it;
      
      g_assert (rootindex >= 0);
      
      if (!(m->only_folders && !GB_IS_FOLDER (b))
          && (!gb_bookmark_is_alias (p) || p == f))
      {
            GtkTreePath *path;
            gint realpos;

            if (m->only_folders)
            {
                  int i = 0;
                  GbBookmark *x;
                  realpos = 0;
                  
                  for (x = p->child; x && i < pos; x = x->next)
                  {
                        ++i;
                        if (GB_IS_FOLDER (x))
                        {
                              ++realpos;
                        }
                  }
            }
            else
            {
                  realpos = pos;
            }

            if (f == p && m->hide_roots)
            {
                  it.user_data = m->roots;
            }
            else 
            {
                  it.user_data = p;
                  it.user_data2 = GINT_TO_POINTER (rootindex);
            }
            
            it.stamp = m->stamp;
                  
            path = gb_tree_model_get_path ((GtkTreeModel *) m, &it);
            
            gtk_tree_path_append_index (path, realpos);
            
            gtk_tree_model_row_deleted ((GtkTreeModel *) m, path);
            
            gtk_tree_path_up (path);
            gtk_tree_model_row_has_child_toggled ((GtkTreeModel *) m, path, &it);
            
            gtk_tree_path_free (path);
      }

      /* the following is needed because the check_func value may change when a child is removed */
      if (!(m->hide_roots && f == p))
      {
            it.user_data = p;
            it.user_data2 = GINT_TO_POINTER (rootindex);
            it.stamp = m->stamp;

            gb_tree_model_row_changed_helper (m, &it);
      }
}

GbBookmark *
gb_tree_model_get_first_root (GbTreeModel *model)
{
      if (model->roots)
      {
            return model->roots->data;
      }
      else
      {
            return NULL;
      }
}

GbBookmarkSet *
gb_tree_model_get_set (GbTreeModel *model)
{
      return model->set;
}

const GSList *
gb_tree_model_get_roots (GbTreeModel *model)
{
      return model->roots;
}

void
gb_tree_model_set_check (GbTreeModel *model, GbTreeModelCheckFunc cf, gpointer data)
{
      model->check_func = cf ? cf : gb_tree_model_default_check_func;
      model->check_func_data = data;
}


Generated by  Doxygen 1.6.0   Back to index