aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/table/e-tree-model.c
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/table/e-tree-model.c')
-rw-r--r--widgets/table/e-tree-model.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/widgets/table/e-tree-model.c b/widgets/table/e-tree-model.c
new file mode 100644
index 0000000000..d67e59f3f5
--- /dev/null
+++ b/widgets/table/e-tree-model.c
@@ -0,0 +1,316 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * e-tree-model.c: a Tree Model
+ *
+ * Author:
+ * Chris Toshok (toshok@helixcode.com)
+ *
+ * Adapted from the gtree code and ETableModel.
+ *
+ * (C) 2000 Helix Code, Inc.
+ */
+#include <config.h>
+#include <gtk/gtksignal.h>
+#include "e-util/e-util.h"
+#include "e-tree-model.h"
+
+#define ETM_CLASS(e) ((ETreeModelClass *)((GtkObject *)e)->klass)
+
+#define PARENT_TYPE E_TABLE_MODEL_TYPE
+
+static ETableModel *e_tree_model_parent_class;
+
+/* virtual methods */
+
+static ETreePath*
+etree_get_root (ETreeModel *etm)
+{
+ /* shouldn't be called */
+ g_assert(0);
+ return NULL;
+}
+
+static void*
+etree_value_at (ETreeModel *etm, ETreePath* node, int col)
+{
+ /* shouldn't be called */
+ g_assert(0);
+ return NULL;
+}
+
+static void
+etree_set_value_at (ETreeModel *etm, ETreePath* node, int col, const void *val)
+{
+ /* shouldn't be called */
+ g_assert(0);
+}
+
+static gboolean
+etree_is_editable (ETreeModel *etm, ETreePath* node, int col)
+{
+ /* shouldn't be called */
+ g_assert(0);
+ return FALSE;
+}
+
+static gboolean
+etree_is_expanded (ETreeModel *etm, ETreePath* node)
+{
+ /* shouldn't be called */
+ g_assert(0);
+ return FALSE;
+}
+
+static guint
+etree_get_children (ETreeModel *etm, ETreePath* node, ETreePath ***paths)
+{
+ /* shouldn't be called */
+ g_assert(0);
+ return 0;
+}
+
+static void
+etree_release_paths (ETreeModel *etm, ETreePath **paths, guint num_paths)
+{
+ /* shouldn't be called */
+ g_assert(0);
+}
+
+static void
+etree_set_expanded (ETreeModel *etm, ETreePath* node, gboolean expanded)
+{
+ /* shouldn't be called */
+ g_assert(0);
+}
+
+static void
+etree_destroy (GtkObject *object)
+{
+}
+
+guint
+e_tree_model_node_num_visible_descendents (ETreeModel *etm, ETreePath *node)
+{
+ int count = 1;
+ if (e_tree_model_node_is_expanded (etm, node)) {
+ ETreePath **paths;
+ int i;
+ int num_paths;
+
+ num_paths = e_tree_model_node_get_children (etm, node, &paths);
+
+ for (i = 0; i < num_paths; i ++)
+ count += e_tree_model_node_num_visible_descendents(etm, paths[i]);
+
+ e_tree_model_release_paths (etm, paths, num_paths);
+ }
+
+ return count;
+}
+
+static int
+etable_row_count (ETableModel *etm)
+{
+ return e_tree_model_node_num_visible_descendents (E_TREE_MODEL (etm), e_tree_model_get_root (E_TREE_MODEL (etm)));
+}
+
+static void *
+etable_value_at (ETableModel *etm, int col, int row)
+{
+ ETreeModel *etree = E_TREE_MODEL(etm);
+ ETreeModelClass *et_class = ETM_CLASS(etm);
+ ETreePath* node = e_tree_model_node_at_row (etree, row);
+
+ g_return_val_if_fail (node, NULL);
+
+ if (col == -1)
+ return node;
+ else if (col == -2)
+ return etm;
+ else
+ return et_class->value_at (etree, node, col);
+}
+
+static void
+etable_set_value_at (ETableModel *etm, int col, int row, const void *val)
+{
+ ETreeModel *etree = E_TREE_MODEL(etm);
+ ETreeModelClass *et_class = ETM_CLASS(etm);
+ ETreePath* node = e_tree_model_node_at_row (etree, row);
+
+ g_return_if_fail (node);
+
+ et_class->set_value_at (etree, node, col, val);
+}
+
+static gboolean
+etable_is_cell_editable (ETableModel *etm, int col, int row)
+{
+ ETreeModel *etree = E_TREE_MODEL(etm);
+ ETreeModelClass *et_class = ETM_CLASS(etm);
+ ETreePath* node = e_tree_model_node_at_row (etree, row);
+
+ g_return_val_if_fail (node, FALSE);
+
+ return et_class->is_editable (etree, node, col);
+}
+
+static void
+e_tree_model_class_init (GtkObjectClass *klass)
+{
+ ETableModelClass *table_class = (ETableModelClass *) klass;
+ ETreeModelClass *tree_class = (ETreeModelClass *) klass;
+
+ e_tree_model_parent_class = gtk_type_class (PARENT_TYPE);
+
+ klass->destroy = etree_destroy;
+
+ table_class->row_count = etable_row_count;
+ table_class->value_at = etable_value_at;
+ table_class->set_value_at = etable_set_value_at;
+ table_class->is_cell_editable = etable_is_cell_editable;
+#if 0
+ table_class->duplicate_value = etable_duplicate_value;
+ table_class->free_value = etable_free_value;
+ table_class->initialize_value = etable_initialize_value;
+ table_class->value_is_empty = etable_value_is_empty;
+ table_class->thaw = etable_thaw;
+#endif
+
+ tree_class->get_root = etree_get_root;
+ tree_class->value_at = etree_value_at;
+ tree_class->set_value_at = etree_set_value_at;
+ tree_class->is_editable = etree_is_editable;
+
+ tree_class->get_children = etree_get_children;
+ tree_class->release_paths = etree_release_paths;
+ tree_class->is_expanded = etree_is_expanded;
+ tree_class->set_expanded = etree_set_expanded;
+}
+
+E_MAKE_TYPE(e_tree_model, "ETreeModel", ETreeModel, e_tree_model_class_init, NULL, PARENT_TYPE)
+
+/* signals */
+
+ETreeModel *
+e_tree_model_new ()
+{
+ ETreeModel *et;
+
+ et = gtk_type_new (e_tree_model_get_type ());
+
+ return et;
+}
+
+static ETreePath *
+e_tree_model_node_at_row_1 (ETreeModel *etree, int *row, ETreePath *node)
+{
+ ETreePath *ret = NULL;
+
+ if (*row == 0)
+ ret = node;
+ else if (e_tree_model_node_is_expanded (etree, node)) {
+ int num_children;
+ int i;
+ ETreePath **paths;
+
+ num_children = e_tree_model_node_get_children (etree, node, &paths);
+
+ for (i = 0; i < num_children; i ++) {
+ ETreePath *p;
+
+ (*row) --;
+
+ p = e_tree_model_node_at_row_1 (etree, row, paths[i]);
+
+ if (p) {
+ ret = p;
+ break;
+ }
+ }
+
+ /* XXX need to find why this release is causing problems */
+ /* e_tree_model_release_paths (etree, paths, num_children); */
+ }
+
+ return ret;
+}
+
+ETreePath *
+e_tree_model_get_root (ETreeModel *etree)
+{
+ return ETM_CLASS(etree)->get_root(etree);
+}
+
+ETreePath *
+e_tree_model_node_at_row (ETreeModel *etree, int row)
+{
+ /* XXX icky, perform a depth first search of the tree. we need this optimized sorely */
+ return e_tree_model_node_at_row_1 (etree, &row, ETM_CLASS(etree)->get_root(etree));
+}
+
+ETreePath *
+e_tree_model_node_get_next (ETreeModel *etree, ETreePath *node)
+{
+ return ETM_CLASS(etree)->get_next(etree, node);
+}
+
+ETreePath *
+e_tree_model_node_get_prev (ETreeModel *etree, ETreePath *node)
+{
+ return ETM_CLASS(etree)->get_prev(etree, node);
+}
+
+guint
+e_tree_model_node_depth (ETreeModel *etree, ETreePath *path)
+{
+ return g_list_length (path) - 1;
+}
+
+ETreePath *
+e_tree_model_node_get_parent (ETreeModel *etree, ETreePath *path)
+{
+ g_return_val_if_fail (path, NULL);
+
+ if (path->next == NULL)
+ return NULL;
+ else
+ return g_list_copy (path->next);
+}
+
+gboolean
+e_tree_model_node_is_root (ETreeModel *etree, ETreePath *path)
+{
+ return (e_tree_model_node_depth (etree, path) == 0);
+}
+
+gboolean
+e_tree_model_node_is_expandable (ETreeModel *etree, ETreePath *path)
+{
+ return (e_tree_model_node_get_children (etree, path, NULL) > 0);
+}
+
+gboolean
+e_tree_model_node_is_expanded (ETreeModel *etree, ETreePath *path)
+{
+ return ETM_CLASS(etree)->is_expanded (etree, path);
+}
+
+void
+e_tree_model_node_set_expanded (ETreeModel *etree, ETreePath *path, gboolean expanded)
+{
+ ETM_CLASS(etree)->set_expanded (etree, path, expanded);
+}
+
+guint
+e_tree_model_node_get_children (ETreeModel *etree, ETreePath *path, ETreePath ***paths)
+{
+ return ETM_CLASS(etree)->get_children (etree, path, paths);
+}
+
+void
+e_tree_model_release_paths (ETreeModel *etree, ETreePath **paths, guint num_paths)
+{
+ ETM_CLASS(etree)->release_paths (etree, paths, num_paths);
+}
+