diff options
Diffstat (limited to 'e-util/e-tree-model.c')
-rw-r--r-- | e-util/e-tree-model.c | 814 |
1 files changed, 814 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..b03824d153 --- /dev/null +++ b/e-util/e-tree-model.c @@ -0,0 +1,814 @@ +/* + * e-tree-model.c + * + * 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/> + * + */ + +#include "e-tree-model.h" + +enum { + PRE_CHANGE, + NODE_CHANGED, + NODE_DATA_CHANGED, + NODE_INSERTED, + NODE_REMOVED, + NODE_DELETED, + REBUILT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_INTERFACE (ETreeModel, e_tree_model, G_TYPE_OBJECT) + +static void +e_tree_model_default_init (ETreeModelInterface *interface) +{ + signals[PRE_CHANGE] = g_signal_new ( + "pre_change", + G_TYPE_FROM_INTERFACE (interface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ETreeModelInterface, pre_change), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + signals[REBUILT] = g_signal_new ( + "rebuilt", + G_TYPE_FROM_INTERFACE (interface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ETreeModelInterface, rebuilt), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + signals[NODE_CHANGED] = g_signal_new ( + "node_changed", + G_TYPE_FROM_INTERFACE (interface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ETreeModelInterface, node_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + signals[NODE_DATA_CHANGED] = g_signal_new ( + "node_data_changed", + G_TYPE_FROM_INTERFACE (interface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ETreeModelInterface, node_data_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + signals[NODE_INSERTED] = g_signal_new ( + "node_inserted", + G_TYPE_FROM_INTERFACE (interface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ETreeModelInterface, node_inserted), + NULL, NULL, NULL, + G_TYPE_NONE, 2, + G_TYPE_POINTER, + G_TYPE_POINTER); + + signals[NODE_REMOVED] = g_signal_new ( + "node_removed", + G_TYPE_FROM_INTERFACE (interface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ETreeModelInterface, node_removed), + NULL, NULL, NULL, + G_TYPE_NONE, 3, + G_TYPE_POINTER, + G_TYPE_POINTER, + G_TYPE_INT); + + signals[NODE_DELETED] = g_signal_new ( + "node_deleted", + G_TYPE_FROM_INTERFACE (interface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ETreeModelInterface, node_deleted), + NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_POINTER); +} + +/** + * e_tree_model_pre_change: + * @tree_model: + * + * 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_rebuilt: + * @tree_model: + * + * 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: + * @path: + * + * + * + * Return value: + **/ +void +e_tree_model_node_changed (ETreeModel *tree_model, + ETreePath path) +{ + g_return_if_fail (E_IS_TREE_MODEL (tree_model)); + + g_signal_emit (tree_model, signals[NODE_CHANGED], 0, path); +} + +/** + * e_tree_model_node_data_changed: + * @tree_model: + * @path: + * + * + * + * Return value: + **/ +void +e_tree_model_node_data_changed (ETreeModel *tree_model, + ETreePath path) +{ + g_return_if_fail (E_IS_TREE_MODEL (tree_model)); + + g_signal_emit (tree_model, signals[NODE_DATA_CHANGED], 0, path); +} + +/** + * e_tree_model_node_inserted: + * @tree_model: + * @parent_path: + * @inserted_path: + * + * + **/ +void +e_tree_model_node_inserted (ETreeModel *tree_model, + ETreePath parent_path, + ETreePath inserted_path) +{ + g_return_if_fail (E_IS_TREE_MODEL (tree_model)); + + g_signal_emit ( + tree_model, signals[NODE_INSERTED], 0, + parent_path, inserted_path); +} + +/** + * e_tree_model_node_removed: + * @tree_model: + * @parent_path: + * @removed_path: + * + * + **/ +void +e_tree_model_node_removed (ETreeModel *tree_model, + ETreePath parent_path, + ETreePath removed_path, + gint old_position) +{ + g_return_if_fail (E_IS_TREE_MODEL (tree_model)); + + g_signal_emit ( + tree_model, signals[NODE_REMOVED], 0, + parent_path, removed_path, old_position); +} + +/** + * e_tree_model_node_deleted: + * @tree_model: + * @deleted_path: + * + * + **/ +void +e_tree_model_node_deleted (ETreeModel *tree_model, + ETreePath deleted_path) +{ + g_return_if_fail (E_IS_TREE_MODEL (tree_model)); + + g_signal_emit (tree_model, signals[NODE_DELETED], 0, deleted_path); +} + +/** + * e_tree_model_get_root + * @tree_model: the ETreeModel of which we want the root node. + * + * Accessor for the root node of @tree_model. + * + * return values: the ETreePath corresponding to the root node. + */ +ETreePath +e_tree_model_get_root (ETreeModel *tree_model) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->get_root != NULL, NULL); + + return interface->get_root (tree_model); +} + +/** + * e_tree_model_node_get_parent: + * @tree_model: + * @path: + * + * + * + * Return value: + **/ +ETreePath +e_tree_model_node_get_parent (ETreeModel *tree_model, + ETreePath path) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->get_parent != NULL, NULL); + + return interface->get_parent (tree_model, path); +} + +/** + * e_tree_model_node_get_first_child: + * @tree_model: + * @path: + * + * + * + * Return value: + **/ +ETreePath +e_tree_model_node_get_first_child (ETreeModel *tree_model, + ETreePath path) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->get_first_child != NULL, NULL); + + return interface->get_first_child (tree_model, path); +} + +/** + * e_tree_model_node_get_next: + * @tree_model: + * @path: + * + * + * + * Return value: + **/ +ETreePath +e_tree_model_node_get_next (ETreeModel *tree_model, + ETreePath path) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->get_next != NULL, NULL); + + return interface->get_next (tree_model, path); +} + +/** + * e_tree_model_node_is_root: + * @tree_model: + * @path: + * + * + * + * Return value: + **/ +gboolean +e_tree_model_node_is_root (ETreeModel *tree_model, + ETreePath path) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), FALSE); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->is_root != NULL, FALSE); + + return interface->is_root (tree_model, path); +} + +/** + * e_tree_model_node_is_expandable: + * @tree_model: + * @path: + * + * + * + * Return value: + **/ +gboolean +e_tree_model_node_is_expandable (ETreeModel *tree_model, + ETreePath path) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), FALSE); + g_return_val_if_fail (path != NULL, FALSE); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->is_expandable != NULL, FALSE); + + return interface->is_expandable (tree_model, path); +} + +guint +e_tree_model_node_get_n_nodes (ETreeModel *tree_model) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), 0); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->get_n_nodes != NULL, 0); + + return interface->get_n_nodes (tree_model); +} + +guint +e_tree_model_node_get_n_children (ETreeModel *tree_model, + ETreePath path) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), 0); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->get_n_children != NULL, 0); + + return interface->get_n_children (tree_model, path); +} + +/** + * e_tree_model_node_depth: + * @tree_model: + * @path: + * + * + * + * Return value: + **/ +guint +e_tree_model_node_depth (ETreeModel *tree_model, + ETreePath path) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), 0); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->depth != NULL, 0); + + return interface->depth (tree_model, path); +} + +/** + * e_tree_model_get_expanded_default + * @tree_model: The ETreeModel. + * + * XXX docs here. + * + * return values: Whether nodes should be expanded by default. + */ +gboolean +e_tree_model_get_expanded_default (ETreeModel *tree_model) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), FALSE); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->get_expanded_default != NULL, FALSE); + + return interface->get_expanded_default (tree_model); +} + +/** + * e_tree_model_column_count + * @tree_model: The ETreeModel. + * + * XXX docs here. + * + * return values: The number of columns + */ +gint +e_tree_model_column_count (ETreeModel *tree_model) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), 0); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->column_count != NULL, 0); + + return interface->column_count (tree_model); +} + +/** + * e_tree_model_get_save_id + * @tree_model: The ETreeModel. + * @path: The ETreePath. + * + * XXX docs here. + * + * return values: The save id for this path. + */ +gchar * +e_tree_model_get_save_id (ETreeModel *tree_model, + ETreePath path) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->get_save_id != NULL, NULL); + + return interface->get_save_id (tree_model, path); +} + +/** + * e_tree_model_get_node_by_id + * @tree_model: The ETreeModel. + * @save_id: + * + * 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 *tree_model, + const gchar *save_id) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->get_node_by_id != NULL, NULL); + + return interface->get_node_by_id (tree_model, save_id); +} + +/** + * e_tree_model_sort_value_at: + * @tree_model: The ETreeModel. + * @path: 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 + * @tree_model in column @col and node @path. 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 *tree_model, + ETreePath path, + gint col) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->sort_value_at != NULL, NULL); + + return interface->sort_value_at (tree_model, path, col); +} + +/** + * e_tree_model_value_at: + * @tree_model: The ETreeModel. + * @path: 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 + * @tree_model in column @col and node @path. 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 *tree_model, + ETreePath path, + gint col) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->value_at != NULL, NULL); + + return interface->value_at (tree_model, path, col); +} + +/** + * e_tree_model_duplicate_value: + * @tree_model: + * @col: + * @value: + * + * + * Return value: + **/ +gpointer +e_tree_model_duplicate_value (ETreeModel *tree_model, + gint col, + gconstpointer value) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->duplicate_value != NULL, NULL); + + return interface->duplicate_value (tree_model, col, value); +} + +/** + * e_tree_model_free_value: + * @tree_model: + * @col: + * @value: + * + * + * Return value: + **/ +void +e_tree_model_free_value (ETreeModel *tree_model, + gint col, + gpointer value) +{ + ETreeModelInterface *interface; + + g_return_if_fail (E_IS_TREE_MODEL (tree_model)); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_if_fail (interface->free_value != NULL); + + interface->free_value (tree_model, col, value); +} + +/** + * e_tree_model_initialize_value: + * @tree_model: + * @col: + * + * + * + * Return value: + **/ +gpointer +e_tree_model_initialize_value (ETreeModel *tree_model, + gint col) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->initialize_value != NULL, NULL); + + return interface->initialize_value (tree_model, col); +} + +/** + * e_tree_model_value_is_empty: + * @tree_model: + * @col: + * @value: + * + * + * Return value: + **/ +gboolean +e_tree_model_value_is_empty (ETreeModel *tree_model, + gint col, + gconstpointer value) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), TRUE); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->value_is_empty != NULL, TRUE); + + return interface->value_is_empty (tree_model, col, value); +} + +/** + * e_tree_model_value_to_string: + * @tree_model: + * @col: + * @value: + * + * + * Return value: + **/ +gchar * +e_tree_model_value_to_string (ETreeModel *tree_model, + gint col, + gconstpointer value) +{ + ETreeModelInterface *interface; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + interface = E_TREE_MODEL_GET_INTERFACE (tree_model); + g_return_val_if_fail (interface->value_to_string != NULL, NULL); + + return interface->value_to_string (tree_model, col, value); +} + +/** + * e_tree_model_node_traverse: + * @tree_model: + * @path: + * @func: + * @data: + * + * + **/ +void +e_tree_model_node_traverse (ETreeModel *tree_model, + ETreePath path, + ETreePathFunc func, + gpointer data) +{ + ETreePath child; + + g_return_if_fail (E_IS_TREE_MODEL (tree_model)); + g_return_if_fail (path != NULL); + + child = e_tree_model_node_get_first_child (tree_model, path); + + while (child) { + ETreePath next_child; + + next_child = e_tree_model_node_get_next (tree_model, child); + e_tree_model_node_traverse (tree_model, child, func, data); + if (func (tree_model, child, data)) + return; + + child = next_child; + } +} + +static ETreePath +e_tree_model_node_real_traverse (ETreeModel *model, + ETreePath path, + ETreePath end_path, + 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); + + child = e_tree_model_node_get_first_child (model, path); + + while (child) { + ETreePath result; + + if (child == end_path || func (model, child, data)) + return child; + + if ((result = e_tree_model_node_real_traverse ( + model, child, end_path, func, data))) + return result; + + child = e_tree_model_node_get_next (model, child); + } + + return NULL; +} + +/** + * e_tree_model_node_find: + * @tree_model: + * @path: + * @end_path: + * @func: + * @data: + * + * + **/ +ETreePath +e_tree_model_node_find (ETreeModel *tree_model, + ETreePath path, + ETreePath end_path, + ETreePathFunc func, + gpointer data) +{ + ETreePath result; + ETreePath next; + + g_return_val_if_fail (E_IS_TREE_MODEL (tree_model), NULL); + + /* Just search the whole tree in this case. */ + if (path == NULL) { + ETreePath root; + root = e_tree_model_get_root (tree_model); + + if (end_path == root || func (tree_model, root, data)) + return root; + + result = e_tree_model_node_real_traverse ( + tree_model, root, end_path, func, data); + if (result) + return result; + + return NULL; + } + + while (1) { + + if ((result = e_tree_model_node_real_traverse ( + tree_model, path, end_path, func, data))) + return result; + next = e_tree_model_node_get_next (tree_model, path); + + while (next == NULL) { + path = e_tree_model_node_get_parent (tree_model, path); + + if (path == NULL) + return NULL; + + next = e_tree_model_node_get_next (tree_model, path); + } + + if (end_path == next || func (tree_model, next, data)) + return next; + + path = next; + } +} + |