diff options
Diffstat (limited to 'e-util/e-tree-model.c')
-rw-r--r-- | e-util/e-tree-model.c | 1177 |
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; + } +} + |