aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-tree-model.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-tree-model.c')
-rw-r--r--e-util/e-tree-model.c1177
1 files changed, 1177 insertions, 0 deletions
diff --git a/e-util/e-tree-model.c b/e-util/e-tree-model.c
new file mode 100644
index 0000000000..db763cf782
--- /dev/null
+++ b/e-util/e-tree-model.c
@@ -0,0 +1,1177 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Lahey <clahey@ximian.com>
+ * Chris Toshok <toshok@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-tree-model.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+
+#include "e-marshal.h"
+#include "e-xml-utils.h"
+
+#define ETM_CLASS(e) (E_TREE_MODEL_GET_CLASS(e))
+
+#define d(x)
+
+G_DEFINE_TYPE (ETreeModel, e_tree_model, G_TYPE_OBJECT)
+
+enum {
+ PRE_CHANGE,
+ NO_CHANGE,
+ NODE_CHANGED,
+ NODE_DATA_CHANGED,
+ NODE_COL_CHANGED,
+ NODE_INSERTED,
+ NODE_REMOVED,
+ NODE_DELETED,
+ NODE_REQUEST_COLLAPSE,
+ REBUILT,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0, };
+
+static void
+e_tree_model_class_init (ETreeModelClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ signals[PRE_CHANGE] = g_signal_new (
+ "pre_change",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETreeModelClass, pre_change),
+ (GSignalAccumulator) NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[NO_CHANGE] = g_signal_new (
+ "no_change",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETreeModelClass, no_change),
+ (GSignalAccumulator) NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[REBUILT] = g_signal_new (
+ "rebuilt",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETreeModelClass, rebuilt),
+ (GSignalAccumulator) NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[NODE_CHANGED] = g_signal_new (
+ "node_changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETreeModelClass, node_changed),
+ (GSignalAccumulator) NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+
+ signals[NODE_DATA_CHANGED] = g_signal_new (
+ "node_data_changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETreeModelClass, node_data_changed),
+ (GSignalAccumulator) NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+
+ signals[NODE_COL_CHANGED] = g_signal_new (
+ "node_col_changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETreeModelClass, node_col_changed),
+ (GSignalAccumulator) NULL, NULL,
+ e_marshal_VOID__POINTER_INT,
+ G_TYPE_NONE, 2,
+ G_TYPE_POINTER,
+ G_TYPE_INT);
+
+ signals[NODE_INSERTED] = g_signal_new (
+ "node_inserted",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETreeModelClass, node_inserted),
+ (GSignalAccumulator) NULL, NULL,
+ e_marshal_VOID__POINTER_POINTER,
+ G_TYPE_NONE, 2,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER);
+
+ signals[NODE_REMOVED] = g_signal_new (
+ "node_removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETreeModelClass, node_removed),
+ (GSignalAccumulator) NULL, NULL,
+ e_marshal_VOID__POINTER_POINTER_INT,
+ G_TYPE_NONE, 3,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER,
+ G_TYPE_INT);
+
+ signals[NODE_DELETED] = g_signal_new (
+ "node_deleted",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETreeModelClass, node_deleted),
+ (GSignalAccumulator) NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+
+ signals[NODE_REQUEST_COLLAPSE] = g_signal_new (
+ "node_request_collapse",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETreeModelClass, node_request_collapse),
+ (GSignalAccumulator) NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+
+ class->get_root = NULL;
+
+ class->get_parent = NULL;
+ class->get_first_child = NULL;
+ class->get_last_child = NULL;
+ class->get_next = NULL;
+ class->get_prev = NULL;
+
+ class->is_root = NULL;
+ class->is_expandable = NULL;
+ class->get_children = NULL;
+ class->depth = NULL;
+
+ class->icon_at = NULL;
+
+ class->get_expanded_default = NULL;
+ class->column_count = NULL;
+
+ class->has_save_id = NULL;
+ class->get_save_id = NULL;
+ class->has_get_node_by_id = NULL;
+ class->get_node_by_id = NULL;
+
+ class->has_change_pending = NULL;
+
+ class->sort_value_at = NULL;
+ class->value_at = NULL;
+ class->set_value_at = NULL;
+ class->is_editable = NULL;
+
+ class->duplicate_value = NULL;
+ class->free_value = NULL;
+ class->initialize_value = NULL;
+ class->value_is_empty = NULL;
+ class->value_to_string = NULL;
+
+ class->pre_change = NULL;
+ class->no_change = NULL;
+ class->rebuilt = NULL;
+ class->node_changed = NULL;
+ class->node_data_changed = NULL;
+ class->node_col_changed = NULL;
+ class->node_inserted = NULL;
+ class->node_removed = NULL;
+ class->node_deleted = NULL;
+ class->node_request_collapse = NULL;
+}
+
+static void
+e_tree_model_init (ETreeModel *tree_model)
+{
+ /* nothing to do */
+}
+
+/* signals */
+
+/**
+ * e_tree_model_node_changed:
+ * @tree_model:
+ * @node:
+ *
+ *
+ *
+ * Return value:
+ **/
+void
+e_tree_model_pre_change (ETreeModel *tree_model)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (tree_model));
+
+ g_signal_emit (tree_model, signals[PRE_CHANGE], 0);
+}
+
+/**
+ * e_tree_model_node_changed:
+ * @tree_model:
+ * @node:
+ *
+ *
+ *
+ * Return value:
+ **/
+void
+e_tree_model_no_change (ETreeModel *tree_model)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (tree_model));
+
+ g_signal_emit (tree_model, signals[NO_CHANGE], 0);
+}
+
+/**
+ * e_tree_model_rebuilt:
+ * @tree_model:
+ * @node:
+ *
+ *
+ *
+ * Return value:
+ **/
+void
+e_tree_model_rebuilt (ETreeModel *tree_model)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (tree_model));
+
+ g_signal_emit (tree_model, signals[REBUILT], 0);
+}
+/**
+ * e_tree_model_node_changed:
+ * @tree_model:
+ * @node:
+ *
+ *
+ *
+ * Return value:
+ **/
+void
+e_tree_model_node_changed (ETreeModel *tree_model,
+ ETreePath node)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (tree_model));
+
+ g_signal_emit (tree_model, signals[NODE_CHANGED], 0, node);
+}
+
+/**
+ * e_tree_model_node_data_changed:
+ * @tree_model:
+ * @node:
+ *
+ *
+ *
+ * Return value:
+ **/
+void
+e_tree_model_node_data_changed (ETreeModel *tree_model,
+ ETreePath node)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (tree_model));
+
+ g_signal_emit (tree_model, signals[NODE_DATA_CHANGED], 0, node);
+}
+
+/**
+ * e_tree_model_node_col_changed:
+ * @tree_model:
+ * @node:
+ *
+ *
+ *
+ * Return value:
+ **/
+void
+e_tree_model_node_col_changed (ETreeModel *tree_model,
+ ETreePath node,
+ gint col)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (tree_model));
+
+ g_signal_emit (tree_model, signals[NODE_COL_CHANGED], 0, node, col);
+}
+
+/**
+ * e_tree_model_node_inserted:
+ * @tree_model:
+ * @parent_node:
+ * @inserted_node:
+ *
+ *
+ **/
+void
+e_tree_model_node_inserted (ETreeModel *tree_model,
+ ETreePath parent_node,
+ ETreePath inserted_node)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (tree_model));
+
+ g_signal_emit (
+ tree_model, signals[NODE_INSERTED], 0,
+ parent_node, inserted_node);
+}
+
+/**
+ * e_tree_model_node_removed:
+ * @tree_model:
+ * @parent_node:
+ * @removed_node:
+ *
+ *
+ **/
+void
+e_tree_model_node_removed (ETreeModel *tree_model,
+ ETreePath parent_node,
+ ETreePath removed_node,
+ gint old_position)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (tree_model));
+
+ g_signal_emit (
+ tree_model, signals[NODE_REMOVED], 0,
+ parent_node, removed_node, old_position);
+}
+
+/**
+ * e_tree_model_node_deleted:
+ * @tree_model:
+ * @deleted_node:
+ *
+ *
+ **/
+void
+e_tree_model_node_deleted (ETreeModel *tree_model,
+ ETreePath deleted_node)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (tree_model));
+
+ g_signal_emit (tree_model, signals[NODE_DELETED], 0, deleted_node);
+}
+
+/**
+ * e_tree_model_node_request_collapse:
+ * @tree_model:
+ * @collapsed_node:
+ *
+ *
+ **/
+void
+e_tree_model_node_request_collapse (ETreeModel *tree_model,
+ ETreePath collapsed_node)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (tree_model));
+
+ g_signal_emit (tree_model, signals[NODE_REQUEST_COLLAPSE], 0, collapsed_node);
+}
+
+/**
+ * e_tree_model_new
+ *
+ * XXX docs here.
+ *
+ * return values: a newly constructed ETreeModel.
+ */
+ETreeModel *
+e_tree_model_new (void)
+{
+ return g_object_new (E_TYPE_TREE_MODEL, NULL);
+}
+
+/**
+ * e_tree_model_get_root
+ * @etree: the ETreeModel of which we want the root node.
+ *
+ * Accessor for the root node of @etree.
+ *
+ * return values: the ETreePath corresponding to the root node.
+ */
+ETreePath
+e_tree_model_get_root (ETreeModel *etree)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->get_root)
+ return ETM_CLASS (etree)->get_root (etree);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_node_get_parent:
+ * @etree:
+ * @path:
+ *
+ *
+ *
+ * Return value:
+ **/
+ETreePath
+e_tree_model_node_get_parent (ETreeModel *etree,
+ ETreePath node)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->get_parent)
+ return ETM_CLASS (etree)->get_parent (etree, node);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_node_get_first_child:
+ * @etree:
+ * @node:
+ *
+ *
+ *
+ * Return value:
+ **/
+ETreePath
+e_tree_model_node_get_first_child (ETreeModel *etree,
+ ETreePath node)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->get_first_child)
+ return ETM_CLASS (etree)->get_first_child (etree, node);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_node_get_last_child:
+ * @etree:
+ * @node:
+ *
+ *
+ *
+ * Return value:
+ **/
+ETreePath
+e_tree_model_node_get_last_child (ETreeModel *etree,
+ ETreePath node)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->get_last_child)
+ return ETM_CLASS (etree)->get_last_child (etree, node);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_node_get_next:
+ * @etree:
+ * @node:
+ *
+ *
+ *
+ * Return value:
+ **/
+ETreePath
+e_tree_model_node_get_next (ETreeModel *etree,
+ ETreePath node)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->get_next)
+ return ETM_CLASS (etree)->get_next (etree, node);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_node_get_prev:
+ * @etree:
+ * @node:
+ *
+ *
+ *
+ * Return value:
+ **/
+ETreePath
+e_tree_model_node_get_prev (ETreeModel *etree,
+ ETreePath node)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->get_prev)
+ return ETM_CLASS (etree)->get_prev (etree, node);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_node_is_root:
+ * @etree:
+ * @path:
+ *
+ *
+ *
+ * Return value:
+ **/
+gboolean
+e_tree_model_node_is_root (ETreeModel *etree,
+ ETreePath node)
+{
+ g_return_val_if_fail (etree != NULL, FALSE);
+
+ if (ETM_CLASS (etree)->is_root)
+ return ETM_CLASS (etree)->is_root (etree, node);
+ else
+ return FALSE;
+}
+
+/**
+ * e_tree_model_node_is_expandable:
+ * @etree:
+ * @path:
+ *
+ *
+ *
+ * Return value:
+ **/
+gboolean
+e_tree_model_node_is_expandable (ETreeModel *etree,
+ ETreePath node)
+{
+ g_return_val_if_fail (etree != NULL, FALSE);
+ g_return_val_if_fail (node != NULL, FALSE);
+
+ if (ETM_CLASS (etree)->is_expandable)
+ return ETM_CLASS (etree)->is_expandable (etree, node);
+ else
+ return FALSE;
+}
+
+guint
+e_tree_model_node_get_children (ETreeModel *etree,
+ ETreePath node,
+ ETreePath **nodes)
+{
+ g_return_val_if_fail (etree != NULL, 0);
+ if (ETM_CLASS (etree)->get_children)
+ return ETM_CLASS (etree)->get_children (etree, node, nodes);
+ else
+ return 0;
+}
+
+/**
+ * e_tree_model_node_depth:
+ * @etree:
+ * @path:
+ *
+ *
+ *
+ * Return value:
+ **/
+guint
+e_tree_model_node_depth (ETreeModel *etree,
+ ETreePath node)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), 0);
+
+ if (ETM_CLASS (etree)->depth)
+ return ETM_CLASS (etree)->depth (etree, node);
+ else
+ return 0;
+}
+
+/**
+ * e_tree_model_icon_at
+ * @etree: The ETreeModel.
+ * @path: The ETreePath to the node we're getting the icon of.
+ *
+ * XXX docs here.
+ *
+ * return values: the GdkPixbuf associated with this node.
+ */
+GdkPixbuf *
+e_tree_model_icon_at (ETreeModel *etree,
+ ETreePath node)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->icon_at)
+ return ETM_CLASS (etree)->icon_at (etree, node);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_get_expanded_default
+ * @etree: The ETreeModel.
+ *
+ * XXX docs here.
+ *
+ * return values: Whether nodes should be expanded by default.
+ */
+gboolean
+e_tree_model_get_expanded_default (ETreeModel *etree)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), FALSE);
+
+ if (ETM_CLASS (etree)->get_expanded_default)
+ return ETM_CLASS (etree)->get_expanded_default (etree);
+ else
+ return FALSE;
+}
+
+/**
+ * e_tree_model_column_count
+ * @etree: The ETreeModel.
+ *
+ * XXX docs here.
+ *
+ * return values: The number of columns
+ */
+gint
+e_tree_model_column_count (ETreeModel *etree)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), 0);
+
+ if (ETM_CLASS (etree)->column_count)
+ return ETM_CLASS (etree)->column_count (etree);
+ else
+ return 0;
+}
+
+/**
+ * e_tree_model_has_save_id
+ * @etree: The ETreeModel.
+ *
+ * XXX docs here.
+ *
+ * return values: Whether this tree has valid save id data.
+ */
+gboolean
+e_tree_model_has_save_id (ETreeModel *etree)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), FALSE);
+
+ if (ETM_CLASS (etree)->has_save_id)
+ return ETM_CLASS (etree)->has_save_id (etree);
+ else
+ return FALSE;
+}
+
+/**
+ * e_tree_model_get_save_id
+ * @etree: The ETreeModel.
+ * @node: The ETreePath.
+ *
+ * XXX docs here.
+ *
+ * return values: The save id for this path.
+ */
+gchar *
+e_tree_model_get_save_id (ETreeModel *etree,
+ ETreePath node)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->get_save_id)
+ return ETM_CLASS (etree)->get_save_id (etree, node);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_has_get_node_by_id
+ * @etree: The ETreeModel.
+ *
+ * XXX docs here.
+ *
+ * return values: Whether this tree can quickly get a node from its save id.
+ */
+gboolean
+e_tree_model_has_get_node_by_id (ETreeModel *etree)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), FALSE);
+
+ if (ETM_CLASS (etree)->has_get_node_by_id)
+ return ETM_CLASS (etree)->has_get_node_by_id (etree);
+ else
+ return FALSE;
+}
+
+/**
+ * e_tree_model_get_node_by_id
+ * @etree: The ETreeModel.
+ * @node: The ETreePath.
+ *
+ * get_node_by_id(get_save_id(node)) should be the original node.
+ * Likewise if get_node_by_id is not NULL, then
+ * get_save_id(get_node_by_id(string)) should be a copy of the
+ * original string.
+ *
+ * return values: The path for this save id.
+ */
+ETreePath
+e_tree_model_get_node_by_id (ETreeModel *etree,
+ const gchar *save_id)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->get_node_by_id)
+ return ETM_CLASS (etree)->get_node_by_id (etree, save_id);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_has_change_pending
+ * @etree: The ETreeModel.
+ *
+ * XXX docs here.
+ *
+ * return values: Whether this tree has valid save id data.
+ */
+gboolean
+e_tree_model_has_change_pending (ETreeModel *etree)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), FALSE);
+
+ if (ETM_CLASS (etree)->has_change_pending)
+ return ETM_CLASS (etree)->has_change_pending (etree);
+ else
+ return FALSE;
+}
+
+/**
+ * e_tree_model_sort_value_at:
+ * @etree: The ETreeModel.
+ * @node: The ETreePath to the node we're getting the data from.
+ * @col: the column to retrieve data from
+ *
+ * Return value: This function returns the value that is stored by the
+ * @etree in column @col and node @node. The data returned can be a
+ * pointer or any data value that can be stored inside a pointer.
+ *
+ * The data returned is typically used by an sort renderer if it wants
+ * to proxy the data of cell value_at at a better sorting order.
+ *
+ * The data returned must be valid until the model sends a signal that
+ * affect that piece of data. node_changed and node_deleted affect
+ * all data in tha t node and all nodes under that node.
+ * node_data_changed affects the data in that node. node_col_changed
+ * affects the data in that node for that column. node_inserted,
+ * node_removed, and no_change don't affect any data in this way.
+ **/
+gpointer
+e_tree_model_sort_value_at (ETreeModel *etree,
+ ETreePath node,
+ gint col)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->sort_value_at)
+ return ETM_CLASS (etree)->sort_value_at (etree, node, col);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_value_at:
+ * @etree: The ETreeModel.
+ * @node: The ETreePath to the node we're getting the data from.
+ * @col: the column to retrieve data from
+ *
+ * Return value: This function returns the value that is stored by the
+ * @etree in column @col and node @node. The data returned can be a
+ * pointer or any data value that can be stored inside a pointer.
+ *
+ * The data returned is typically used by an ECell renderer.
+ *
+ * The data returned must be valid until the model sends a signal that
+ * affect that piece of data. node_changed and node_deleted affect
+ * all data in tha t node and all nodes under that node.
+ * node_data_changed affects the data in that node. node_col_changed
+ * affects the data in that node for that column. node_inserted,
+ * node_removed, and no_change don't affect any data in this way.
+ **/
+gpointer
+e_tree_model_value_at (ETreeModel *etree,
+ ETreePath node,
+ gint col)
+{
+ g_return_val_if_fail (E_IS_TREE_MODEL (etree), NULL);
+
+ if (ETM_CLASS (etree)->value_at)
+ return ETM_CLASS (etree)->value_at (etree, node, col);
+ else
+ return NULL;
+}
+
+void
+e_tree_model_set_value_at (ETreeModel *etree,
+ ETreePath node,
+ gint col,
+ gconstpointer val)
+{
+ g_return_if_fail (E_IS_TREE_MODEL (etree));
+
+ if (ETM_CLASS (etree)->set_value_at)
+ ETM_CLASS (etree)->set_value_at (etree, node, col, val);
+}
+
+/**
+ * e_tree_model_node_is_editable:
+ * @etree:
+ * @path:
+ *
+ *
+ *
+ * Return value:
+ **/
+gboolean
+e_tree_model_node_is_editable (ETreeModel *etree,
+ ETreePath node,
+ gint col)
+{
+ g_return_val_if_fail (etree != NULL, FALSE);
+
+ if (ETM_CLASS (etree)->is_editable)
+ return ETM_CLASS (etree)->is_editable (etree, node, col);
+ else
+ return FALSE;
+}
+
+/**
+ * e_tree_model_duplicate_value:
+ * @etree:
+ * @path:
+ *
+ *
+ *
+ * Return value:
+ **/
+gpointer
+e_tree_model_duplicate_value (ETreeModel *etree,
+ gint col,
+ gconstpointer value)
+{
+ g_return_val_if_fail (etree != NULL, NULL);
+
+ if (ETM_CLASS (etree)->duplicate_value)
+ return ETM_CLASS (etree)->duplicate_value (etree, col, value);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_free_value:
+ * @etree:
+ * @path:
+ *
+ *
+ *
+ * Return value:
+ **/
+void
+e_tree_model_free_value (ETreeModel *etree,
+ gint col,
+ gpointer value)
+{
+ g_return_if_fail (etree != NULL);
+
+ if (ETM_CLASS (etree)->free_value)
+ ETM_CLASS (etree)->free_value (etree, col, value);
+}
+
+/**
+ * e_tree_model_initialize_value:
+ * @etree:
+ * @path:
+ *
+ *
+ *
+ * Return value:
+ **/
+gpointer
+e_tree_model_initialize_value (ETreeModel *etree,
+ gint col)
+{
+ g_return_val_if_fail (etree != NULL, NULL);
+
+ if (ETM_CLASS (etree)->initialize_value)
+ return ETM_CLASS (etree)->initialize_value (etree, col);
+ else
+ return NULL;
+}
+
+/**
+ * e_tree_model_value_is_empty:
+ * @etree:
+ * @path:
+ *
+ *
+ *
+ * Return value:
+ **/
+gboolean
+e_tree_model_value_is_empty (ETreeModel *etree,
+ gint col,
+ gconstpointer value)
+{
+ g_return_val_if_fail (etree != NULL, TRUE);
+
+ if (ETM_CLASS (etree)->value_is_empty)
+ return ETM_CLASS (etree)->value_is_empty (etree, col, value);
+ else
+ return TRUE;
+}
+
+/**
+ * e_tree_model_value_to_string:
+ * @etree:
+ * @path:
+ *
+ *
+ *
+ * Return value:
+ **/
+gchar *
+e_tree_model_value_to_string (ETreeModel *etree,
+ gint col,
+ gconstpointer value)
+{
+ g_return_val_if_fail (etree != NULL, g_strdup (""));
+
+ if (ETM_CLASS (etree)->value_to_string)
+ return ETM_CLASS (etree)->value_to_string (etree, col, value);
+ else
+ return g_strdup ("");
+}
+
+/**
+ * e_tree_model_node_traverse:
+ * @model:
+ * @path:
+ * @func:
+ * @data:
+ *
+ *
+ **/
+void
+e_tree_model_node_traverse (ETreeModel *model,
+ ETreePath path,
+ ETreePathFunc func,
+ gpointer data)
+{
+ ETreePath child;
+
+ g_return_if_fail (E_IS_TREE_MODEL (model));
+ g_return_if_fail (path != NULL);
+
+ child = e_tree_model_node_get_first_child (model, path);
+
+ while (child) {
+ ETreePath next_child;
+
+ next_child = e_tree_model_node_get_next (model, child);
+ e_tree_model_node_traverse (model, child, func, data);
+ if (func (model, child, data))
+ return;
+
+ child = next_child;
+ }
+}
+
+/**
+ * e_tree_model_node_traverse_preorder:
+ * @model:
+ * @path:
+ * @func:
+ * @data:
+ *
+ *
+ **/
+void
+e_tree_model_node_traverse_preorder (ETreeModel *model,
+ ETreePath path,
+ ETreePathFunc func,
+ gpointer data)
+{
+ ETreePath child;
+
+ g_return_if_fail (E_IS_TREE_MODEL (model));
+ g_return_if_fail (path != NULL);
+
+ child = e_tree_model_node_get_first_child (model, path);
+
+ while (child) {
+ ETreePath next_child;
+
+ if (func (model, child, data))
+ return;
+
+ next_child = e_tree_model_node_get_next (model, child);
+ e_tree_model_node_traverse_preorder (model, child, func, data);
+
+ child = next_child;
+ }
+}
+
+/**
+ * e_tree_model_node_traverse_preorder:
+ * @model:
+ * @path:
+ * @func:
+ * @data:
+ *
+ *
+ **/
+static ETreePath
+e_tree_model_node_real_traverse (ETreeModel *model,
+ ETreePath path,
+ ETreePath end_path,
+ gboolean forward_direction,
+ ETreePathFunc func,
+ gpointer data)
+{
+ ETreePath child;
+
+ g_return_val_if_fail (E_IS_TREE_MODEL (model), NULL);
+ g_return_val_if_fail (path != NULL, NULL);
+
+ if (forward_direction)
+ child = e_tree_model_node_get_first_child (model, path);
+ else
+ child = e_tree_model_node_get_last_child (model, path);
+
+ while (child) {
+ ETreePath result;
+
+ if (forward_direction && (child == end_path || func (model, child, data)))
+ return child;
+
+ if ((result = e_tree_model_node_real_traverse (
+ model, child, end_path,
+ forward_direction, func, data)))
+ return result;
+
+ if (!forward_direction && (child == end_path || func (model, child, data)))
+ return child;
+
+ if (forward_direction)
+ child = e_tree_model_node_get_next (model, child);
+ else
+ child = e_tree_model_node_get_prev (model, child);
+ }
+ return NULL;
+}
+
+/**
+ * e_tree_model_node_traverse_preorder:
+ * @model:
+ * @path:
+ * @func:
+ * @data:
+ *
+ *
+ **/
+ETreePath
+e_tree_model_node_find (ETreeModel *model,
+ ETreePath path,
+ ETreePath end_path,
+ gboolean forward_direction,
+ ETreePathFunc func,
+ gpointer data)
+{
+ ETreePath result;
+ ETreePath next;
+
+ g_return_val_if_fail (E_IS_TREE_MODEL (model), NULL);
+
+ /* Just search the whole tree in this case. */
+ if (path == NULL) {
+ ETreePath root;
+ root = e_tree_model_get_root (model);
+
+ if (forward_direction && (end_path == root || func (model, root, data)))
+ return root;
+
+ result = e_tree_model_node_real_traverse (
+ model, root, end_path, forward_direction, func, data);
+ if (result)
+ return result;
+
+ if (!forward_direction && (end_path == root || func (model, root, data)))
+ return root;
+
+ return NULL;
+ }
+
+ while (1) {
+
+ if (forward_direction) {
+ if ((result = e_tree_model_node_real_traverse (
+ model, path, end_path,
+ forward_direction, func, data)))
+ return result;
+ next = e_tree_model_node_get_next (model, path);
+ } else {
+ next = e_tree_model_node_get_prev (model, path);
+ if (next && (result = e_tree_model_node_real_traverse (
+ model, next, end_path,
+ forward_direction, func, data)))
+ return result;
+ }
+
+ while (next == NULL) {
+ path = e_tree_model_node_get_parent (model, path);
+
+ if (path == NULL)
+ return NULL;
+
+ if (forward_direction)
+ next = e_tree_model_node_get_next (model, path);
+ else
+ next = path;
+ }
+
+ if (end_path == next || func (model, next, data))
+ return next;
+
+ path = next;
+ }
+}
+