fix .desktop file
[gconf-editor] / src / gconf-tree-model.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Copyright (C) 2001, 2002 Anders Carlsson <andersca@gnu.org>
4  *
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.
9  *
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.
14  *
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.
18  */
19
20 #include <config.h>
21
22 #include <string.h>
23 #include "gconf-tree-model.h"
24
25 typedef struct _Node Node;
26
27 #define NODE(x) ((Node *)(x))
28
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);
33
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));
36
37 struct _Node {
38         gint ref_count;
39         gint offset;
40         gchar *path;
41
42         Node *parent;
43         Node *children;
44         Node *next;
45         Node *prev;
46 };
47
48
49 GtkTreePath *
50 gconf_tree_model_get_tree_path_from_gconf_path (GConfTreeModel *tree_model, const char *key)
51 {
52         GtkTreePath *path = NULL;
53         GtkTreeIter iter, child_iter, found_iter;
54         gchar *tmp_str;
55         gchar **key_array;
56         int i;
57         gboolean found;
58
59         g_assert (key[0] == '/');
60
61         /* special case root node */
62         if (strlen (key) == 1 && key[0] == '/')
63                 return gtk_tree_path_new_from_string ("0");
64
65         key_array = g_strsplit (key + 1, "/", 0);
66
67         if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree_model), &iter)) {
68
69                 /* Ugh, something is terribly wrong */
70                 g_strfreev (key_array);
71                 return NULL;
72         }
73
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)
79                  */
80                 if (!gtk_tree_model_iter_children (GTK_TREE_MODEL (tree_model), &child_iter, &iter))
81                         break;
82
83                 found = FALSE;
84                 do {
85                         gtk_tree_model_get (GTK_TREE_MODEL (tree_model), &child_iter,
86                                             GCONF_TREE_MODEL_NAME_COLUMN, &tmp_str,
87                                             -1);
88
89                         if (strcmp (tmp_str, key_array[i]) == 0) {
90                                 found_iter = child_iter;
91                                 found = TRUE;
92                                 g_free (tmp_str);
93                                 break;
94                         } else
95                                 g_free (tmp_str);
96                 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (tree_model), &child_iter));
97
98                 if (!found)
99                         break;
100                 iter = child_iter;
101         }
102
103         path = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_model), &found_iter);
104
105         g_strfreev (key_array);
106
107         return path;
108 }
109
110
111 gchar *
112 gconf_tree_model_get_gconf_path (GConfTreeModel *tree_model, GtkTreeIter *iter)
113 {
114         Node *node = iter->user_data;
115
116         return g_strdup (node->path);
117 }
118
119 gchar *
120 gconf_tree_model_get_gconf_name (GConfTreeModel *tree_model, GtkTreeIter *iter)
121 {
122         gchar *ptr;
123         Node *node = iter->user_data;
124
125         ptr = node->path + strlen (node->path);
126
127         while (ptr[-1] != '/')
128                 ptr--;
129
130         return g_strdup (ptr);
131 }
132
133 static gboolean
134 gconf_tree_model_build_level (GConfTreeModel *model, Node *parent_node, gboolean emit_signals)
135 {
136         GSList *list, *tmp;
137         Node *tmp_node = NULL;
138         gint i = 0;
139
140         if (parent_node->children)
141                 return FALSE;
142
143         list = gconf_client_all_dirs (model->client, parent_node->path, NULL);
144
145         if (!list)
146                 return FALSE;
147
148         for (tmp = list; tmp; tmp = tmp->next, i++) {
149                 Node *node;
150
151                 node = g_new0 (Node, 1);
152                 node->offset = i;
153                 node->parent = parent_node;
154                 node->path = tmp->data;
155
156                 if (tmp_node) {
157                         tmp_node->next = node;
158                         node->prev = tmp_node;
159                 } else {
160                         /* set parent node's children */
161                         parent_node->children = node;
162                 }
163
164                 tmp_node = node;
165
166                 /* let the model know things have changed */
167                 if (emit_signals) {
168                         GtkTreeIter tmp_iter;
169                         GtkTreePath *tmp_path;
170
171                         model->stamp++;
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);
177                 }
178         }
179
180         g_slist_free (list);
181
182         return TRUE;
183 }
184
185 static gint
186 gconf_tree_model_get_n_columns (GtkTreeModel *tree_model)
187 {
188         return GCONF_TREE_MODEL_NUM_COLUMNS;
189 }
190
191 static GType
192 gconf_tree_model_get_column_type (GtkTreeModel *tree_model, gint index)
193 {
194         switch (index) {
195         case GCONF_TREE_MODEL_NAME_COLUMN:
196                 return G_TYPE_STRING;
197         default:
198                 return G_TYPE_INVALID;
199         }
200 }
201
202 static gboolean
203 gconf_tree_model_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
204 {
205         gint *indices;
206         gint depth, i;
207         GtkTreeIter parent;
208         GConfTreeModel *model;
209
210         model = (GConfTreeModel *)tree_model;
211
212         indices = gtk_tree_path_get_indices (path);
213         depth = gtk_tree_path_get_depth (path);
214
215         parent.stamp = model->stamp;
216         parent.user_data = NULL;
217
218         if (!gtk_tree_model_iter_nth_child (tree_model, iter, NULL, indices[0]))
219                 return FALSE;
220
221         for (i = 1; i < depth; i++) {
222                 parent = *iter;
223
224                 if (!gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
225                         return FALSE;
226         }
227
228         return TRUE;
229 }
230
231 static GtkTreePath *
232 gconf_tree_model_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter)
233 {
234         GConfTreeModel *model = (GConfTreeModel *)tree_model;
235         Node *tmp_node;
236         GtkTreePath *tree_path;
237         gint i = 0;
238
239         tmp_node = iter->user_data;
240
241         if (NODE (iter->user_data)->parent == NULL) {
242                 tree_path = gtk_tree_path_new ();
243                 tmp_node = model->root;
244         }
245         else {
246                 GtkTreeIter tmp_iter = *iter;
247
248                 tmp_iter.user_data = NODE (iter->user_data)->parent;
249
250                 tree_path = gconf_tree_model_get_path (tree_model, &tmp_iter);
251
252                 tmp_node = NODE (iter->user_data)->parent->children;
253         }
254
255         for (; tmp_node; tmp_node = tmp_node->next) {
256                 if (tmp_node == NODE (iter->user_data))
257                         break;
258
259                 i++;
260         }
261
262         gtk_tree_path_append_index (tree_path, i);
263
264         return tree_path;
265 }
266
267
268 static void
269 gconf_tree_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value)
270 {
271         Node *node = iter->user_data;
272
273         switch (column) {
274         case GCONF_TREE_MODEL_NAME_COLUMN:
275                 g_value_init (value, G_TYPE_STRING);
276
277                 if (node == NULL || node->parent == NULL)
278                         g_value_set_string (value, "/");
279                 else {
280                         gchar *ptr;
281
282                         ptr = node->path + strlen (node->path);
283
284                         while (ptr[-1] != '/')
285                                 ptr--;
286
287                         g_value_set_string (value, ptr);
288                 }
289                 break;
290         default:
291                 break;
292         }
293 }
294
295 static gboolean
296 gconf_tree_model_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n)
297 {
298         GConfTreeModel *model;
299         Node *node;
300         Node *parent_node = NULL;
301
302         model = (GConfTreeModel *)tree_model;
303
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);
306
307         if (parent == NULL)
308                 node = model->root;
309         else {
310                 parent_node = (Node *)parent->user_data;
311                 node = parent_node->children;
312         }
313
314         if (!node && parent && gconf_tree_model_build_level (model, parent_node, FALSE)) {
315                 node = parent_node->children;
316         }
317
318         for (; node != NULL; node = node->next)
319                 if (node->offset == n) {
320                         iter->stamp = model->stamp;
321                         iter->user_data = node;
322
323                         return TRUE;
324                 }
325
326         iter->stamp = 0;
327
328         return FALSE;
329 }
330
331 static gboolean
332 gconf_tree_model_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter)
333 {
334         if (NODE (iter->user_data)->next != NULL) {
335                 iter->user_data = NODE (iter->user_data)->next;
336
337                 return TRUE;
338         }
339         else
340                 return FALSE;
341 }
342
343 static gboolean
344 gconf_tree_model_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent)
345 {
346         GConfTreeModel *model = (GConfTreeModel *)tree_model;
347         Node *parent_node = parent->user_data;
348
349         if (parent_node->children != NULL) {
350                 iter->stamp = model->stamp;
351                 iter->user_data = parent_node->children;
352
353                 return TRUE;
354         }
355
356         if (!gconf_tree_model_build_level (model, parent_node, TRUE)) {
357                 iter->stamp = 0;
358                 iter->user_data = NULL;
359
360                 return FALSE;
361         }
362
363         iter->stamp = model->stamp;
364         iter->user_data = parent_node->children;
365
366         return TRUE;
367 }
368
369 static gint
370 gconf_tree_model_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter)
371 {
372         GConfTreeModel *model = (GConfTreeModel *)tree_model;
373         Node *node;
374         GtkTreeIter tmp;
375         gint i = 0;
376
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);
379
380         if (iter == NULL)
381                 node = model->root;
382         else
383                 node = ((Node *)iter->user_data)->children;
384
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);
388         }
389
390         if (!node)
391                 return 0;
392
393         for (; node != NULL; node = node->next)
394                 i++;
395
396         return i;
397 }
398
399 static gboolean
400 gconf_tree_model_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child)
401 {
402         Node *child_node = child->user_data;
403
404         if (child_node->parent == NULL)
405                 return FALSE;
406
407         iter->stamp = ((GConfTreeModel *)tree_model)->stamp;
408         iter->user_data = child_node->parent;
409
410         return TRUE;
411 }
412
413 static gboolean
414 gconf_tree_model_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
415 {
416         GConfTreeModel *model = (GConfTreeModel *)tree_model;
417         Node *node = iter->user_data;
418         GSList *list;
419
420         list = gconf_client_all_dirs (model->client, node->path, NULL);
421
422         if (list == NULL)
423                 return FALSE;
424         else {
425                 g_slist_foreach (list, (GFunc) g_free, NULL);
426                 g_slist_free (list);
427
428                 return TRUE;
429         }
430 }
431
432 static void
433 gconf_tree_model_ref_node (GtkTreeModel *tree_model, GtkTreeIter *iter)
434 {
435         Node *node = iter->user_data;
436
437         node->ref_count += 1;
438 }
439
440 static void
441 gconf_tree_model_free_node (GtkTreeModel *tree_model, Node *node)
442 {
443         gconf_tree_model_clear_node (tree_model, node);
444         if (node->path)
445                 g_free (node->path);
446         g_free (node);
447 }
448
449 static void
450 gconf_tree_model_clear_node (GtkTreeModel *tree_model, Node *node)
451 {
452         Node *children;
453
454         children = node->children;
455         node->children = NULL;
456         while (children) {
457                 Node *next = children->next;
458                 gconf_tree_model_free_node (tree_model, children);
459                 children = next;
460         }
461 }
462
463 static void
464 gconf_tree_model_unref_node (GtkTreeModel *tree_model, GtkTreeIter *iter)
465 {
466         Node *node = iter->user_data;
467         node->ref_count -= 1;
468
469         if (node->ref_count == 0)
470                 gconf_tree_model_clear_node (tree_model, node);
471 }
472
473 static void
474 gconf_tree_model_tree_model_init (GtkTreeModelIface *iface)
475 {
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;
489 }
490
491 static void
492 gconf_tree_model_finalize (GObject *obj)
493 {
494         GConfTreeModel *model = GCONF_TREE_MODEL (obj);
495
496         if (model->client) {
497                 g_object_unref (model->client);
498                 model->client = NULL;
499         }
500
501         G_OBJECT_CLASS (gconf_tree_model_parent_class)->finalize (obj);
502 }
503
504 static void
505 gconf_tree_model_class_init (GConfTreeModelClass *klass)
506 {
507         G_OBJECT_CLASS (klass)->finalize = gconf_tree_model_finalize;
508 }
509
510 static void
511 gconf_tree_model_init (GConfTreeModel *model)
512 {
513         Node *root;
514
515         root = g_new0 (Node, 1);
516         root->path = g_strdup ("/");
517         root->offset = 0;
518
519         model->root = root;
520         model->client = gconf_client_get_default ();
521 }
522
523 void
524 gconf_tree_model_set_client (GConfTreeModel *model, GConfClient *client)
525 {
526         if (model->client != NULL) {
527                 g_object_unref (model->client);
528         }
529
530         model->client = g_object_ref (client);
531 }
532
533 GtkTreeModel *
534 gconf_tree_model_new (void)
535 {
536         return GTK_TREE_MODEL (g_object_new (GCONF_TYPE_TREE_MODEL, NULL));
537 }