/*
* 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 <gtk/gtktreednd.h>
#include <glib-object.h>
#include <string.h>
#include "ephy-toolbar-tree-model.h"
#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);
//#define DEBUG_MSG(x) g_print x
#define DEBUG_MSG(x)
#define VALID_ITER(iter, tb_tree_model) (iter!= NULL && iter->user_data != NULL \
&& tb_tree_model->stamp == iter->stamp)
/**
* Private data
*/
struct _EphyTbTreeModelPrivate
{
EphyToolbar *tb;
GSList *curr_items;
};
/**
* Private functions
*/
static void ephy_tb_tree_model_init (EphyTbTreeModel *tb_tree_model);
static void ephy_tb_tree_model_class_init (EphyTbTreeModelClass *tb_tree_model_class);
static void ephy_tb_tree_model_tb_tree_model_init (GtkTreeModelIface *iface);
static void ephy_tb_tree_model_drag_source_init (GtkTreeDragSourceIface *iface);
static void ephy_tb_tree_model_drag_dest_init (GtkTreeDragDestIface *iface);
static void ephy_tb_tree_model_finalize_impl (GObject *object);
static guint ephy_tb_tree_model_get_flags_impl (GtkTreeModel *tb_tree_model);
static gint ephy_tb_tree_model_get_n_columns_impl (GtkTreeModel *tb_tree_model);
static GType ephy_tb_tree_model_get_column_type_impl (GtkTreeModel *tb_tree_model,
gint index);
static gboolean ephy_tb_tree_model_get_iter_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter,
GtkTreePath *path);
static GtkTreePath * ephy_tb_tree_model_get_path_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter);
static void ephy_tb_tree_model_get_value_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter,
gint column,
GValue *value);
static gboolean ephy_tb_tree_model_iter_next_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter);
static gboolean ephy_tb_tree_model_iter_children_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent);
static gboolean ephy_tb_tree_model_iter_has_child_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter);
static gint ephy_tb_tree_model_iter_n_children_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter);
static gboolean ephy_tb_tree_model_iter_nth_child_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent,
gint n);
static gboolean ephy_tb_tree_model_iter_parent_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter,
GtkTreeIter *child);
/* DND interfaces */
static gboolean ephy_tb_tree_model_drag_data_delete_impl(GtkTreeDragSource *drag_source,
GtkTreePath *path);
static gboolean ephy_tb_tree_model_drag_data_get_impl (GtkTreeDragSource *drag_source,
GtkTreePath *path,
GtkSelectionData *selection_data);
static gboolean ephy_tb_tree_model_drag_data_received_impl (GtkTreeDragDest *drag_dest,
GtkTreePath *dest,
GtkSelectionData *selection_data);
static gboolean ephy_tb_tree_model_row_drop_possible_impl (GtkTreeDragDest *drag_dest,
GtkTreePath *dest_path,
GtkSelectionData *selection_data);
/* helper functions */
static void ephy_tb_tree_model_toolbar_changed_cb (EphyToolbar *tb, EphyTbTreeModel *tm);
static void ephy_tb_tree_model_update (EphyTbTreeModel *tm);
static GObjectClass *parent_class = NULL;
GtkType
ephy_tb_tree_model_get_type (void)
{
static GType tb_tree_model_type = 0;
if (!tb_tree_model_type)
{
static const GTypeInfo tb_tree_model_info =
{
sizeof (EphyTbTreeModelClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) ephy_tb_tree_model_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (EphyTbTreeModel),
0, /* n_preallocs */
(GInstanceInitFunc) ephy_tb_tree_model_init
};
static const GInterfaceInfo tb_gtk_tree_model_info =
{
(GInterfaceInitFunc) ephy_tb_tree_model_tb_tree_model_init,
NULL,
NULL
};
static const GInterfaceInfo drag_source_info =
{
(GInterfaceInitFunc) ephy_tb_tree_model_drag_source_init,
NULL,
NULL
};
static const GInterfaceInfo drag_dest_info =
{
(GInterfaceInitFunc) ephy_tb_tree_model_drag_dest_init,
NULL,
NULL
};
tb_tree_model_type = g_type_register_static (G_TYPE_OBJECT, "EphyTbTreeModel",
&tb_tree_model_info, 0);
g_type_add_interface_static (tb_tree_model_type,
GTK_TYPE_TREE_MODEL,
&tb_gtk_tree_model_info);
g_type_add_interface_static (tb_tree_model_type,
GTK_TYPE_TREE_DRAG_SOURCE,
&drag_source_info);
g_type_add_interface_static (tb_tree_model_type,
GTK_TYPE_TREE_DRAG_DEST,
&drag_dest_info);
}
return tb_tree_model_type;
}
static void
ephy_tb_tree_model_class_init (EphyTbTreeModelClass *class)
{
GObjectClass *object_class;
parent_class = g_type_class_peek_parent (class);
object_class = (GObjectClass *) class;
object_class->finalize = ephy_tb_tree_model_finalize_impl;
}
static void
ephy_tb_tree_model_tb_tree_model_init (GtkTreeModelIface *iface)
{
iface->get_flags = ephy_tb_tree_model_get_flags_impl;
iface->get_n_columns = ephy_tb_tree_model_get_n_columns_impl;
iface->get_column_type = ephy_tb_tree_model_get_column_type_impl;
iface->get_iter = ephy_tb_tree_model_get_iter_impl;
iface->get_path = ephy_tb_tree_model_get_path_impl;
iface->get_value = ephy_tb_tree_model_get_value_impl;
iface->iter_next = ephy_tb_tree_model_iter_next_impl;
iface->iter_children = ephy_tb_tree_model_iter_children_impl;
iface->iter_has_child = ephy_tb_tree_model_iter_has_child_impl;
iface->iter_n_children = ephy_tb_tree_model_iter_n_children_impl;
iface->iter_nth_child = ephy_tb_tree_model_iter_nth_child_impl;
iface->iter_parent = ephy_tb_tree_model_iter_parent_impl;
}
static void
ephy_tb_tree_model_drag_source_init (GtkTreeDragSourceIface *iface)
{
iface->drag_data_delete = ephy_tb_tree_model_drag_data_delete_impl;
iface->drag_data_get = ephy_tb_tree_model_drag_data_get_impl;
}
static void
ephy_tb_tree_model_drag_dest_init (GtkTreeDragDestIface *iface)
{
iface->drag_data_received = ephy_tb_tree_model_drag_data_received_impl;
iface->row_drop_possible = ephy_tb_tree_model_row_drop_possible_impl;
}
static void
ephy_tb_tree_model_init (EphyTbTreeModel *tb_tree_model)
{
EphyTbTreeModelPrivate *p = g_new0 (EphyTbTreeModelPrivate, 1);
tb_tree_model->priv = p;
do
{
tb_tree_model->stamp = g_random_int ();
}
while (tb_tree_model->stamp == 0);
}
EphyTbTreeModel *
ephy_tb_tree_model_new (void)
{
EphyTbTreeModel *ret = EPHY_TB_TREE_MODEL (g_object_new (EPHY_TYPE_TB_TREE_MODEL, NULL));
return ret;
}
void
ephy_tb_tree_model_set_toolbar (EphyTbTreeModel *tm, EphyToolbar *tb)
{
EphyTbTreeModelPrivate *p;
g_return_if_fail (EPHY_IS_TB_TREE_MODEL (tm));
g_return_if_fail (EPHY_IS_TOOLBAR (tb));
p = tm->priv;
if (p->tb)
{
g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0,
NULL, NULL, tm);
g_object_unref (p->tb);
}
p->tb = g_object_ref (tb);
g_signal_connect (p->tb, "changed", G_CALLBACK (ephy_tb_tree_model_toolbar_changed_cb), tm);
ephy_tb_tree_model_update (tm);
}
static void
ephy_tb_tree_model_finalize_impl (GObject *object)
{
EphyTbTreeModel *tm = EPHY_TB_TREE_MODEL (object);
EphyTbTreeModelPrivate *p = tm->priv;
DEBUG_MSG (("Finalizing a EphyTbTreeModel\n"));
if (p->tb)
{
g_signal_handlers_disconnect_matched (p->tb, G_SIGNAL_MATCH_DATA, 0, 0,
NULL, NULL, tm);
g_object_unref (p->tb);
}
g_slist_foreach (p->curr_items, (GFunc) g_object_unref, NULL);
g_slist_free (p->curr_items);
g_free (p);
(* parent_class->finalize) (object);
}
/* fulfill the GtkTreeModel requirements */
static guint
ephy_tb_tree_model_get_flags_impl (GtkTreeModel *tb_tree_model)
{
return 0;
}
static gint
ephy_tb_tree_model_get_n_columns_impl (GtkTreeModel *tb_tree_model)
{
return EPHY_TB_TREE_MODEL_NUM_COLUMS;
}
static GType
ephy_tb_tree_model_get_column_type_impl (GtkTreeModel *tb_tree_model,
gint index)
{
g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model), G_TYPE_INVALID);
g_return_val_if_fail ((index < EPHY_TB_TREE_MODEL_NUM_COLUMS) && (index >= 0), G_TYPE_INVALID);
switch (index)
{
case EPHY_TB_TREE_MODEL_COL_ICON:
return GDK_TYPE_PIXBUF;
break;
case EPHY_TB_TREE_MODEL_COL_NAME:
return G_TYPE_STRING;
break;
default:
g_assert_not_reached ();
return G_TYPE_INVALID;
break;
}
}
static gboolean
ephy_tb_tree_model_get_iter_impl (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreePath *path)
{
EphyTbTreeModel *tb_tree_model = (EphyTbTreeModel *) tree_model;
EphyTbTreeModelPrivate *p;
GSList *li;
gint i;
g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model), FALSE);
g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
p = tb_tree_model->priv;
i = gtk_tree_path_get_indices (path)[0];
li = g_slist_nth (p->curr_items, i);
if (!li)
{
return FALSE;
}
iter->stamp = tb_tree_model->stamp;
iter->user_data = li;
return TRUE;
}
static GtkTreePath *
ephy_tb_tree_model_get_path_impl (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
EphyTbTreeModel *tb_tree_model = (EphyTbTreeModel *) tree_model;
EphyTbTreeModelPrivate *p;
gint i;
g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tb_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 == tb_tree_model->stamp, NULL);
p = tb_tree_model->priv;
i = g_slist_position (p->curr_items, iter->user_data);
if (i < 0)
{
return NULL;
}
else
{
GtkTreePath *retval;
retval = gtk_tree_path_new ();
gtk_tree_path_append_index (retval, i);
return retval;
}
}
static void
ephy_tb_tree_model_get_value_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter,
gint column,
GValue *value)
{
EphyTbItem *it;
GdkPixbuf *pb;
gchar *s;
g_return_if_fail (EPHY_IS_TB_TREE_MODEL (tb_tree_model));
g_return_if_fail (iter != NULL);
g_return_if_fail (iter->stamp == EPHY_TB_TREE_MODEL (tb_tree_model)->stamp);
g_return_if_fail (EPHY_IS_TB_ITEM (((GSList *) iter->user_data)->data));
g_return_if_fail (column < EPHY_TB_TREE_MODEL_NUM_COLUMS);
it = ((GSList *) iter->user_data)->data;
switch (column) {
case EPHY_TB_TREE_MODEL_COL_ICON:
g_value_init (value, GDK_TYPE_PIXBUF);
pb = ephy_tb_item_get_icon (it);
g_value_set_object (value, pb);
break;
case EPHY_TB_TREE_MODEL_COL_NAME:
g_value_init (value, G_TYPE_STRING);
s = ephy_tb_item_get_name_human (it);
g_value_set_string_take_ownership (value, s);
break;
default:
g_assert_not_reached ();
break;
}
}
static gboolean
ephy_tb_tree_model_iter_next_impl (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tree_model), FALSE);
g_return_val_if_fail (EPHY_TB_TREE_MODEL (tree_model)->stamp == iter->stamp, FALSE);
iter->user_data = ((GSList *) (iter->user_data))->next;
return (iter->user_data != NULL);
}
static gboolean
ephy_tb_tree_model_iter_children_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent)
{
if (parent)
{
/* this is a list, nodes have no children */
return FALSE;
}
else
{
/* but if parent == NULL we return the list itself as children of the
* "root"
*/
EphyTbTreeModel *tm = EPHY_TB_TREE_MODEL (tb_tree_model);
EphyTbTreeModelPrivate *p = tm->priv;
iter->stamp = tm->stamp;
iter->user_data = p->curr_items;
return (p->curr_items != NULL);
}
}
static gboolean
ephy_tb_tree_model_iter_has_child_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter)
{
return FALSE;
}
static gint
ephy_tb_tree_model_iter_n_children_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter)
{
EphyTbTreeModel *tm = (EphyTbTreeModel *) tb_tree_model;
EphyTbTreeModelPrivate *p;
g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tm), -1);
p = tm->priv;
if (iter == NULL)
{
return g_slist_length (p->curr_items);
}
g_return_val_if_fail (tm->stamp == iter->stamp, -1);
return 0;
}
static gboolean
ephy_tb_tree_model_iter_nth_child_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent,
gint n)
{
EphyTbTreeModel *tm = (EphyTbTreeModel *) tb_tree_model;
EphyTbTreeModelPrivate *p;
g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (tm), FALSE);
p = tm->priv;
if (parent)
{
return FALSE;
}
else
{
GSList *li = g_slist_nth (p->curr_items, n);
if (li)
{
iter->stamp = tm->stamp;
iter->user_data = li;
return TRUE;
}
else
{
return FALSE;
}
}
}
static gboolean
ephy_tb_tree_model_iter_parent_impl (GtkTreeModel *tb_tree_model,
GtkTreeIter *iter,
GtkTreeIter *child)
{
return FALSE;
}
/* DND */
static gboolean
ephy_tb_tree_model_drag_data_delete_impl (GtkTreeDragSource *drag_source,
GtkTreePath *path)
{
GtkTreeIter iter;
EphyTbTreeModel *tm;
g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_source), FALSE);
tm = EPHY_TB_TREE_MODEL (drag_source);
DEBUG_MSG (("in ephy_tb_tree_model_drag_data_delete_impl\n"));
if (ephy_tb_tree_model_get_iter_impl (GTK_TREE_MODEL (tm), &iter, path))
{
EphyTbTreeModelPrivate *p = tm->priv;
EphyTbItem *it = ephy_tb_tree_model_item_from_iter (tm, &iter);
EphyTbItem *delete_hack;
if ((delete_hack = g_object_get_data (G_OBJECT (tm),
"gul-toolbar-tree-model-dnd-delete-hack")) != NULL)
{
g_return_val_if_fail (EPHY_IS_TB_ITEM (delete_hack), FALSE);
g_object_ref (delete_hack);
g_object_set_data (G_OBJECT (tm),
"gul-toolbar-tree-model-dnd-delete-hack", NULL);
if (!strcmp (delete_hack->id, it->id))
{
g_object_unref (delete_hack);
return FALSE;
}
g_object_unref (delete_hack);
}
ephy_toolbar_remove_item (p->tb, it);
return TRUE;
}
else
{
return FALSE;
}
}
static gboolean
ephy_tb_tree_model_drag_data_get_impl (GtkTreeDragSource *drag_source,
GtkTreePath *path,
GtkSelectionData *selection_data)
{
g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_source), FALSE);
/* Note that we don't need to handle the GTK_TB_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
{
/* to string ? */
}
return FALSE;
}
static gboolean
ephy_tb_tree_model_drag_data_received_impl (GtkTreeDragDest *drag_dest,
GtkTreePath *dest,
GtkSelectionData *selection_data)
{
EphyTbTreeModel *tbm;
GtkTreeModel *src_model = NULL;
GtkTreePath *src_path = NULL;
g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_dest), FALSE);
g_return_val_if_fail (gtk_tree_path_get_depth (dest) == 1, FALSE);
tbm = EPHY_TB_TREE_MODEL (drag_dest);
DEBUG_MSG (("in ephy_tb_tree_model_drag_data_received_impl\n"));
if (gtk_tree_get_row_drag_data (selection_data,
&src_model,
&src_path)
&& EPHY_IS_TB_TREE_MODEL (src_model))
{
/* copy the item */
GtkTreeIter src_iter;
EphyTbItem *it;
int idx = gtk_tree_path_get_indices (dest)[0];
if (!gtk_tree_model_get_iter (src_model,
&src_iter,
src_path))
{
gtk_tree_path_free (src_path);
return FALSE;
}
gtk_tree_path_free (src_path);
if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drag_dest),
"gtk-tree-model-drop-append")))
{
++idx;
}
it = ephy_tb_item_clone (EPHY_TB_ITEM (((GSList *)src_iter.user_data)->data));
ephy_toolbar_add_item (tbm->priv->tb, it, idx);
/* hack */
if (src_model == GTK_TREE_MODEL (drag_dest)
&& ephy_toolbar_get_check_unique (EPHY_TB_TREE_MODEL (src_model)->priv->tb)
&& ephy_tb_item_is_unique (it))
{
g_object_set_data_full (G_OBJECT (src_model),
"gul-toolbar-tree-model-dnd-delete-hack", it,
g_object_unref);
}
else
{
g_object_unref (it);
}
g_object_set_data (G_OBJECT (drag_dest), "gtk-tree-model-drop-append", NULL);
return TRUE;
}
return FALSE;
}
static gboolean
ephy_tb_tree_model_row_drop_possible_impl (GtkTreeDragDest *drag_dest,
GtkTreePath *dest_path,
GtkSelectionData *selection_data)
{
GtkTreeModel *src_model = NULL;
GtkTreePath *src_path = NULL;
gboolean retval = FALSE;
EphyTbTreeModel *tm;
EphyTbTreeModelPrivate *p;
g_return_val_if_fail (EPHY_IS_TB_TREE_MODEL (drag_dest), FALSE);
tm = EPHY_TB_TREE_MODEL (drag_dest);
p = tm->priv;
if (gtk_tree_path_get_depth (dest_path) != 1)
{
return FALSE;
}
if (!gtk_tree_get_row_drag_data (selection_data,
&src_model,
&src_path))
{
return FALSE;
}
/* can drop before any existing node, or before one past any existing. */
retval = (gtk_tree_path_get_indices (dest_path)[0] <= (gint) g_slist_length (p->curr_items));
gtk_tree_path_free (src_path);
return retval;
}
EphyTbItem *
ephy_tb_tree_model_item_from_iter (EphyTbTreeModel *tm, GtkTreeIter *iter)
{
return iter ? EPHY_TB_ITEM (((GSList *) iter->user_data)->data) : NULL;
}
static void
ephy_tb_tree_model_toolbar_changed_cb (EphyToolbar *tb, EphyTbTreeModel *tm)
{
ephy_tb_tree_model_update (tm);
}
static void
ephy_tb_tree_model_update (EphyTbTreeModel *tm)
{
EphyTbTreeModelPrivate *p;
GSList *new_items;
GSList *old_items;
GSList *li;
GSList *lj;
int i;
g_return_if_fail (EPHY_IS_TB_TREE_MODEL (tm));
p = tm->priv;
g_return_if_fail (EPHY_IS_TOOLBAR (p->tb));
old_items = p->curr_items;
new_items = g_slist_copy ((GSList *) ephy_toolbar_get_item_list (p->tb));
g_slist_foreach (new_items, (GFunc) g_object_ref, NULL);
p->curr_items = new_items;
li = new_items;
lj = old_items;
i = 0;
while (li && lj)
{
if (li->data == lj->data)
{
li = li->next;
lj = lj->next;
++i;
}
else if (lj->next && lj->next->data == li->data)
{
GtkTreePath *p = gtk_tree_path_new ();
gtk_tree_path_append_index (p, i);
gtk_tree_model_row_deleted (GTK_TREE_MODEL (tm), p);
gtk_tree_path_free (p);
lj = lj->next;
}
else if (li->next && li->next->data == lj->data)
{
GtkTreePath *p = gtk_tree_path_new ();
GtkTreeIter iter;
iter.stamp = tm->stamp;
iter.user_data = li;
gtk_tree_path_append_index (p, i);
gtk_tree_model_row_inserted (GTK_TREE_MODEL (tm), p, &iter);
gtk_tree_path_free (p);
li = li->next;
++i;
}
else
{
GtkTreePath *p = gtk_tree_path_new ();
GtkTreeIter iter;
iter.stamp = tm->stamp;
iter.user_data = li;
gtk_tree_path_append_index (p, i);
gtk_tree_model_row_deleted (GTK_TREE_MODEL (tm), p);
gtk_tree_model_row_inserted (GTK_TREE_MODEL (tm), p, &iter);
gtk_tree_path_free (p);
lj = lj->next;
li = li->next;
++i;
}
}
while (li)
{
GtkTreePath *p = gtk_tree_path_new ();
GtkTreeIter iter;
iter.stamp = tm->stamp;
iter.user_data = li;
gtk_tree_path_append_index (p, i);
gtk_tree_model_row_inserted (GTK_TREE_MODEL (tm), p, &iter);
gtk_tree_path_free (p);
li = li->next;
++i;
}
while (lj)
{
GtkTreePath *p = gtk_tree_path_new ();
gtk_tree_path_append_index (p, i);
gtk_tree_model_row_deleted (GTK_TREE_MODEL (tm), p);
gtk_tree_path_free (p);
lj = lj->next;
}
g_slist_foreach (old_items, (GFunc) g_object_unref, NULL);
g_slist_free (old_items);
}