1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 * Copyright (C) 2001, 2002 Anders Carlsson <andersca@gnu.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "gconf-tree-model.h"
25 typedef struct _Node Node;
27 #define NODE(x) ((Node *)(x))
29 static void gconf_tree_model_class_init (GConfTreeModelClass *klass);
30 static void gconf_tree_model_init (GConfTreeModel *model);
31 static void gconf_tree_model_tree_model_init (GtkTreeModelIface *iface);
32 static void gconf_tree_model_clear_node (GtkTreeModel *tree_model, Node *node);
34 G_DEFINE_TYPE_WITH_CODE (GConfTreeModel, gconf_tree_model, G_TYPE_OBJECT,
35 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, gconf_tree_model_tree_model_init));
50 gconf_tree_model_get_tree_path_from_gconf_path (GConfTreeModel *tree_model, const char *key)
52 GtkTreePath *path = NULL;
53 GtkTreeIter iter, child_iter, found_iter;
59 g_assert (key[0] == '/');
61 /* special case root node */
62 if (strlen (key) == 1 && key[0] == '/')
63 return gtk_tree_path_new_from_string ("0");
65 key_array = g_strsplit (key + 1, "/", 0);
67 if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree_model), &iter)) {
69 /* Ugh, something is terribly wrong */
70 g_strfreev (key_array);
74 for (i = 0; key_array[i] != NULL; i++) {
75 /* FIXME: this will build the level if it isn't there. But,
76 * the level can also be there, possibly incomplete. This
77 * code isn't handling those incomplete levels yet (that
78 * needs some current level/gconf directory comparing code)
80 if (!gtk_tree_model_iter_children (GTK_TREE_MODEL (tree_model), &child_iter, &iter))
85 gtk_tree_model_get (GTK_TREE_MODEL (tree_model), &child_iter,
86 GCONF_TREE_MODEL_NAME_COLUMN, &tmp_str,
89 if (strcmp (tmp_str, key_array[i]) == 0) {
90 found_iter = child_iter;
96 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (tree_model), &child_iter));
103 path = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_model), &found_iter);
105 g_strfreev (key_array);
112 gconf_tree_model_get_gconf_path (GConfTreeModel *tree_model, GtkTreeIter *iter)
114 Node *node = iter->user_data;
116 return g_strdup (node->path);
120 gconf_tree_model_get_gconf_name (GConfTreeModel *tree_model, GtkTreeIter *iter)
123 Node *node = iter->user_data;
125 ptr = node->path + strlen (node->path);
127 while (ptr[-1] != '/')
130 return g_strdup (ptr);
134 gconf_tree_model_build_level (GConfTreeModel *model, Node *parent_node, gboolean emit_signals)
137 Node *tmp_node = NULL;
140 if (parent_node->children)
143 list = gconf_client_all_dirs (model->client, parent_node->path, NULL);
148 for (tmp = list; tmp; tmp = tmp->next, i++) {
151 node = g_new0 (Node, 1);
153 node->parent = parent_node;
154 node->path = tmp->data;
157 tmp_node->next = node;
158 node->prev = tmp_node;
160 /* set parent node's children */
161 parent_node->children = node;
166 /* let the model know things have changed */
168 GtkTreeIter tmp_iter;
169 GtkTreePath *tmp_path;
172 tmp_iter.stamp = model->stamp;
173 tmp_iter.user_data = tmp_node;
174 tmp_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &tmp_iter);
175 gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), tmp_path, &tmp_iter);
176 gtk_tree_path_free (tmp_path);
186 gconf_tree_model_get_n_columns (GtkTreeModel *tree_model)
188 return GCONF_TREE_MODEL_NUM_COLUMNS;
192 gconf_tree_model_get_column_type (GtkTreeModel *tree_model, gint index)
195 case GCONF_TREE_MODEL_NAME_COLUMN:
196 return G_TYPE_STRING;
198 return G_TYPE_INVALID;
203 gconf_tree_model_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
208 GConfTreeModel *model;
210 model = (GConfTreeModel *)tree_model;
212 indices = gtk_tree_path_get_indices (path);
213 depth = gtk_tree_path_get_depth (path);
215 parent.stamp = model->stamp;
216 parent.user_data = NULL;
218 if (!gtk_tree_model_iter_nth_child (tree_model, iter, NULL, indices[0]))
221 for (i = 1; i < depth; i++) {
224 if (!gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
232 gconf_tree_model_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter)
234 GConfTreeModel *model = (GConfTreeModel *)tree_model;
236 GtkTreePath *tree_path;
239 tmp_node = iter->user_data;
241 if (NODE (iter->user_data)->parent == NULL) {
242 tree_path = gtk_tree_path_new ();
243 tmp_node = model->root;
246 GtkTreeIter tmp_iter = *iter;
248 tmp_iter.user_data = NODE (iter->user_data)->parent;
250 tree_path = gconf_tree_model_get_path (tree_model, &tmp_iter);
252 tmp_node = NODE (iter->user_data)->parent->children;
255 for (; tmp_node; tmp_node = tmp_node->next) {
256 if (tmp_node == NODE (iter->user_data))
262 gtk_tree_path_append_index (tree_path, i);
269 gconf_tree_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value)
271 Node *node = iter->user_data;
274 case GCONF_TREE_MODEL_NAME_COLUMN:
275 g_value_init (value, G_TYPE_STRING);
277 if (node == NULL || node->parent == NULL)
278 g_value_set_string (value, "/");
282 ptr = node->path + strlen (node->path);
284 while (ptr[-1] != '/')
287 g_value_set_string (value, ptr);
296 gconf_tree_model_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n)
298 GConfTreeModel *model;
300 Node *parent_node = NULL;
302 model = (GConfTreeModel *)tree_model;
304 g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
305 g_return_val_if_fail (parent == NULL || parent->stamp == model->stamp, FALSE);
310 parent_node = (Node *)parent->user_data;
311 node = parent_node->children;
314 if (!node && parent && gconf_tree_model_build_level (model, parent_node, FALSE)) {
315 node = parent_node->children;
318 for (; node != NULL; node = node->next)
319 if (node->offset == n) {
320 iter->stamp = model->stamp;
321 iter->user_data = node;
332 gconf_tree_model_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter)
334 if (NODE (iter->user_data)->next != NULL) {
335 iter->user_data = NODE (iter->user_data)->next;
344 gconf_tree_model_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent)
346 GConfTreeModel *model = (GConfTreeModel *)tree_model;
347 Node *parent_node = parent->user_data;
349 if (parent_node->children != NULL) {
350 iter->stamp = model->stamp;
351 iter->user_data = parent_node->children;
356 if (!gconf_tree_model_build_level (model, parent_node, TRUE)) {
358 iter->user_data = NULL;
363 iter->stamp = model->stamp;
364 iter->user_data = parent_node->children;
370 gconf_tree_model_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter)
372 GConfTreeModel *model = (GConfTreeModel *)tree_model;
377 g_return_val_if_fail (GCONF_IS_TREE_MODEL (tree_model), 0);
378 if (iter) g_return_val_if_fail (model->stamp == iter->stamp, 0);
383 node = ((Node *)iter->user_data)->children;
385 if (!node && iter && gconf_tree_model_iter_children (tree_model, &tmp, iter)) {
386 g_return_val_if_fail (tmp.stamp == model->stamp, 0);
387 node = ((Node *)tmp.user_data);
393 for (; node != NULL; node = node->next)
400 gconf_tree_model_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child)
402 Node *child_node = child->user_data;
404 if (child_node->parent == NULL)
407 iter->stamp = ((GConfTreeModel *)tree_model)->stamp;
408 iter->user_data = child_node->parent;
414 gconf_tree_model_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
416 GConfTreeModel *model = (GConfTreeModel *)tree_model;
417 Node *node = iter->user_data;
420 list = gconf_client_all_dirs (model->client, node->path, NULL);
425 g_slist_foreach (list, (GFunc) g_free, NULL);
433 gconf_tree_model_ref_node (GtkTreeModel *tree_model, GtkTreeIter *iter)
435 Node *node = iter->user_data;
437 node->ref_count += 1;
441 gconf_tree_model_free_node (GtkTreeModel *tree_model, Node *node)
443 gconf_tree_model_clear_node (tree_model, node);
450 gconf_tree_model_clear_node (GtkTreeModel *tree_model, Node *node)
454 children = node->children;
455 node->children = NULL;
457 Node *next = children->next;
458 gconf_tree_model_free_node (tree_model, children);
464 gconf_tree_model_unref_node (GtkTreeModel *tree_model, GtkTreeIter *iter)
466 Node *node = iter->user_data;
467 node->ref_count -= 1;
469 if (node->ref_count == 0)
470 gconf_tree_model_clear_node (tree_model, node);
474 gconf_tree_model_tree_model_init (GtkTreeModelIface *iface)
476 iface->get_n_columns = gconf_tree_model_get_n_columns;
477 iface->get_column_type = gconf_tree_model_get_column_type;
478 iface->get_iter = gconf_tree_model_get_iter;
479 iface->get_path = gconf_tree_model_get_path;
480 iface->get_value = gconf_tree_model_get_value;
481 iface->iter_nth_child = gconf_tree_model_iter_nth_child;
482 iface->iter_next = gconf_tree_model_iter_next;
483 iface->iter_has_child = gconf_tree_model_iter_has_child;
484 iface->iter_n_children = gconf_tree_model_iter_n_children;
485 iface->iter_children = gconf_tree_model_iter_children;
486 iface->iter_parent = gconf_tree_model_iter_parent;
487 iface->ref_node = gconf_tree_model_ref_node;
488 iface->unref_node = gconf_tree_model_unref_node;
492 gconf_tree_model_finalize (GObject *obj)
494 GConfTreeModel *model = GCONF_TREE_MODEL (obj);
497 g_object_unref (model->client);
498 model->client = NULL;
501 G_OBJECT_CLASS (gconf_tree_model_parent_class)->finalize (obj);
505 gconf_tree_model_class_init (GConfTreeModelClass *klass)
507 G_OBJECT_CLASS (klass)->finalize = gconf_tree_model_finalize;
511 gconf_tree_model_init (GConfTreeModel *model)
515 root = g_new0 (Node, 1);
516 root->path = g_strdup ("/");
520 model->client = gconf_client_get_default ();
524 gconf_tree_model_set_client (GConfTreeModel *model, GConfClient *client)
526 if (model->client != NULL) {
527 g_object_unref (model->client);
530 model->client = g_object_ref (client);
534 gconf_tree_model_new (void)
536 return GTK_TREE_MODEL (g_object_new (GCONF_TYPE_TREE_MODEL, NULL));