/* * 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 * */ #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; } }