1/* gtktreestore.c
2 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include "gtktreemodelcssnode.h"
21#include "gtk/gtkcsstransientnodeprivate.h"
22
23#if !GLIB_CHECK_VERSION (2, 67, 3)
24# define g_memdup2(mem,size) g_memdup((mem), (size))
25#endif
26
27struct _GtkTreeModelCssNodePrivate
28{
29 GtkTreeModelCssNodeGetFunc get_func;
30 int n_columns;
31 GType *column_types;
32
33 GtkCssNode *root;
34};
35
36static void gtk_tree_model_css_node_connect_node (GtkTreeModelCssNode *model,
37 GtkCssNode *node,
38 gboolean emit_signal);
39
40static void gtk_tree_model_css_node_disconnect_node (GtkTreeModelCssNode *model,
41 GtkCssNode *node,
42 gboolean emit_signal,
43 GtkCssNode *parent,
44 GtkCssNode *previous);
45
46static void gtk_tree_model_css_node_tree_model_init (GtkTreeModelIface *iface);
47
48G_DEFINE_TYPE_WITH_CODE (GtkTreeModelCssNode, gtk_tree_model_css_node, G_TYPE_OBJECT,
49 G_ADD_PRIVATE (GtkTreeModelCssNode)
50 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
51 gtk_tree_model_css_node_tree_model_init))
52
53static GtkCssNode *
54get_nth_child (GtkCssNode *node,
55 int i)
56{
57 for (node = gtk_css_node_get_first_child (cssnode: node);
58 node != NULL && i > 0;
59 node = gtk_css_node_get_next_sibling (cssnode: node))
60 i--;
61
62 return node;
63}
64
65static int
66get_node_index (GtkCssNode *node)
67{
68 int result = 0;
69
70 while ((node = gtk_css_node_get_previous_sibling (cssnode: node)))
71 result++;
72
73 return result;
74}
75
76static GtkTreeModelFlags
77gtk_tree_model_css_node_get_flags (GtkTreeModel *tree_model)
78{
79 return GTK_TREE_MODEL_ITERS_PERSIST;
80}
81
82static int
83gtk_tree_model_css_node_get_n_columns (GtkTreeModel *tree_model)
84{
85 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
86 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
87
88 return priv->n_columns;
89}
90
91static GType
92gtk_tree_model_css_node_get_column_type (GtkTreeModel *tree_model,
93 int column)
94{
95 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
96 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
97
98 g_return_val_if_fail (column < priv->n_columns, G_TYPE_INVALID);
99
100 return priv->column_types[column];
101}
102
103static gboolean
104gtk_tree_model_css_node_get_iter (GtkTreeModel *tree_model,
105 GtkTreeIter *iter,
106 GtkTreePath *path)
107{
108 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
109 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
110 GtkCssNode *node;
111 int *indices;
112 int depth, i;
113
114 if (priv->root == NULL)
115 return FALSE;
116
117 indices = gtk_tree_path_get_indices (path);
118 depth = gtk_tree_path_get_depth (path);
119
120 if (depth < 1 || indices[0] != 0)
121 return FALSE;
122
123 node = priv->root;
124 for (i = 1; i < depth; i++)
125 {
126 node = get_nth_child (node, i: indices[i]);
127 if (node == NULL)
128 return FALSE;
129 }
130
131 gtk_tree_model_css_node_get_iter_from_node (model: nodemodel, iter, node);
132 return TRUE;
133}
134
135static GtkTreePath *
136gtk_tree_model_css_node_get_path (GtkTreeModel *tree_model,
137 GtkTreeIter *iter)
138{
139 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
140 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
141 GtkCssNode *node;
142 GtkTreePath *path;
143
144 g_return_val_if_fail (priv->root != NULL, NULL);
145
146 path = gtk_tree_path_new ();
147 node = gtk_tree_model_css_node_get_node_from_iter (model: nodemodel, iter);
148
149 while (node != priv->root)
150 {
151 gtk_tree_path_prepend_index (path, index_: get_node_index (node));
152 node = gtk_css_node_get_parent (cssnode: node);
153 }
154
155 gtk_tree_path_prepend_index (path, index_: 0);
156
157 return path;
158}
159
160static void
161gtk_tree_model_css_node_get_value (GtkTreeModel *tree_model,
162 GtkTreeIter *iter,
163 int column,
164 GValue *value)
165{
166 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
167 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
168
169 g_value_init (value, g_type: priv->column_types[column]);
170 priv->get_func (nodemodel,
171 gtk_tree_model_css_node_get_node_from_iter (model: nodemodel, iter),
172 column,
173 value);
174}
175
176static gboolean
177gtk_tree_model_css_node_iter_next (GtkTreeModel *tree_model,
178 GtkTreeIter *iter)
179{
180 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
181 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
182 GtkCssNode *node;
183
184 node = gtk_tree_model_css_node_get_node_from_iter (model: nodemodel, iter);
185 if (node == priv->root)
186 return FALSE;
187
188 node = gtk_css_node_get_next_sibling (cssnode: node);
189 if (node == NULL)
190 return FALSE;
191
192 gtk_tree_model_css_node_get_iter_from_node (model: nodemodel, iter, node);
193 return TRUE;
194}
195
196static gboolean
197gtk_tree_model_css_node_iter_previous (GtkTreeModel *tree_model,
198 GtkTreeIter *iter)
199{
200 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
201 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
202 GtkCssNode *node;
203
204 node = gtk_tree_model_css_node_get_node_from_iter (model: nodemodel, iter);
205 if (node == priv->root)
206 return FALSE;
207
208 node = gtk_css_node_get_previous_sibling (cssnode: node);
209 if (node == NULL)
210 return FALSE;
211
212 gtk_tree_model_css_node_get_iter_from_node (model: nodemodel, iter, node);
213 return TRUE;
214}
215
216static gboolean
217gtk_tree_model_css_node_iter_children (GtkTreeModel *tree_model,
218 GtkTreeIter *iter,
219 GtkTreeIter *parent)
220{
221 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
222 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
223 GtkCssNode *node;
224
225 if (parent == NULL)
226 {
227 node = priv->root;
228 }
229 else
230 {
231 node = gtk_tree_model_css_node_get_node_from_iter (model: nodemodel, iter: parent);
232 node = gtk_css_node_get_first_child (cssnode: node);
233 }
234 if (node == NULL)
235 return FALSE;
236
237 gtk_tree_model_css_node_get_iter_from_node (model: nodemodel, iter, node);
238 return TRUE;
239}
240
241static gboolean
242gtk_tree_model_css_node_iter_has_child (GtkTreeModel *tree_model,
243 GtkTreeIter *iter)
244{
245 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
246 GtkCssNode *node;
247
248 node = gtk_tree_model_css_node_get_node_from_iter (model: nodemodel, iter);
249
250 return gtk_css_node_get_first_child (cssnode: node) != NULL;
251}
252
253static int
254gtk_tree_model_css_node_iter_n_children (GtkTreeModel *tree_model,
255 GtkTreeIter *iter)
256{
257 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
258 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
259 GtkCssNode *node;
260
261 if (iter == NULL)
262 return priv->root ? 1 : 0;
263
264 node = gtk_tree_model_css_node_get_node_from_iter (model: nodemodel, iter);
265
266 node = gtk_css_node_get_last_child (cssnode: node);
267 if (node == NULL)
268 return 0;
269
270 return get_node_index (node) + 1;
271}
272
273static gboolean
274gtk_tree_model_css_node_iter_nth_child (GtkTreeModel *tree_model,
275 GtkTreeIter *iter,
276 GtkTreeIter *parent,
277 int n)
278{
279 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
280 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
281 GtkCssNode *node;
282
283 if (parent == NULL)
284 {
285 if (n > 0)
286 return FALSE;
287
288 node = priv->root;
289 }
290 else
291 {
292 node = gtk_tree_model_css_node_get_node_from_iter (model: nodemodel, iter: parent);
293 node = get_nth_child (node, i: n);
294 }
295
296 if (node == NULL)
297 return FALSE;
298
299 gtk_tree_model_css_node_get_iter_from_node (model: nodemodel, iter, node);
300 return TRUE;
301}
302
303static gboolean
304gtk_tree_model_css_node_iter_parent (GtkTreeModel *tree_model,
305 GtkTreeIter *iter,
306 GtkTreeIter *child)
307{
308 GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
309 GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
310 GtkCssNode *node;
311
312 node = gtk_tree_model_css_node_get_node_from_iter (model: nodemodel, iter: child);
313 if (node == priv->root)
314 return FALSE;
315
316 node = gtk_css_node_get_parent (cssnode: node);
317
318 gtk_tree_model_css_node_get_iter_from_node (model: nodemodel, iter, node);
319 return TRUE;
320}
321
322static void
323gtk_tree_model_css_node_tree_model_init (GtkTreeModelIface *iface)
324{
325 iface->get_flags = gtk_tree_model_css_node_get_flags;
326 iface->get_n_columns = gtk_tree_model_css_node_get_n_columns;
327 iface->get_column_type = gtk_tree_model_css_node_get_column_type;
328 iface->get_iter = gtk_tree_model_css_node_get_iter;
329 iface->get_path = gtk_tree_model_css_node_get_path;
330 iface->get_value = gtk_tree_model_css_node_get_value;
331 iface->iter_next = gtk_tree_model_css_node_iter_next;
332 iface->iter_previous = gtk_tree_model_css_node_iter_previous;
333 iface->iter_children = gtk_tree_model_css_node_iter_children;
334 iface->iter_has_child = gtk_tree_model_css_node_iter_has_child;
335 iface->iter_n_children = gtk_tree_model_css_node_iter_n_children;
336 iface->iter_nth_child = gtk_tree_model_css_node_iter_nth_child;
337 iface->iter_parent = gtk_tree_model_css_node_iter_parent;
338}
339
340static void
341gtk_tree_model_css_node_finalize (GObject *object)
342{
343 GtkTreeModelCssNode *model = GTK_TREE_MODEL_CSS_NODE (object);
344 GtkTreeModelCssNodePrivate *priv = model->priv;
345
346 if (priv->root)
347 {
348 gtk_tree_model_css_node_disconnect_node (model, node: priv->root, FALSE, NULL, NULL);
349 priv->root = NULL;
350 }
351
352 g_free (mem: priv->column_types);
353
354 G_OBJECT_CLASS (gtk_tree_model_css_node_parent_class)->finalize (object);
355}
356
357static void
358gtk_tree_model_css_node_class_init (GtkTreeModelCssNodeClass *class)
359{
360 GObjectClass *object_class = G_OBJECT_CLASS (class);
361
362 object_class->finalize = gtk_tree_model_css_node_finalize;
363}
364
365static void
366gtk_tree_model_css_node_init (GtkTreeModelCssNode *nodemodel)
367{
368 nodemodel->priv = gtk_tree_model_css_node_get_instance_private (self: nodemodel);
369}
370
371GtkTreeModel *
372gtk_tree_model_css_node_new (GtkTreeModelCssNodeGetFunc get_func,
373 int n_columns,
374 ...)
375{
376 GtkTreeModel *result;
377 va_list args;
378 GType *types;
379 int i;
380
381 g_return_val_if_fail (get_func != NULL, NULL);
382 g_return_val_if_fail (n_columns > 0, NULL);
383
384 types = g_new (GType, n_columns);
385 va_start (args, n_columns);
386
387 for (i = 0; i < n_columns; i++)
388 {
389 types[i] = va_arg (args, GType);
390 }
391
392 va_end (args);
393
394 result = gtk_tree_model_css_node_newv (get_func, n_columns, types);
395
396 g_free (mem: types);
397
398 return result;
399}
400
401GtkTreeModel *
402gtk_tree_model_css_node_newv (GtkTreeModelCssNodeGetFunc get_func,
403 int n_columns,
404 GType *types)
405{
406 GtkTreeModelCssNode *result;
407 GtkTreeModelCssNodePrivate *priv;
408 gsize columns_size;
409
410 g_return_val_if_fail (get_func != NULL, NULL);
411 g_return_val_if_fail (n_columns > 0, NULL);
412 g_return_val_if_fail (n_columns <= G_MAXSIZE / sizeof (GType), NULL);
413 g_return_val_if_fail (types != NULL, NULL);
414
415 result = g_object_new (GTK_TYPE_TREE_MODEL_CSS_NODE, NULL);
416
417 priv = result->priv;
418
419 columns_size = n_columns * sizeof (GType);
420
421 priv->get_func = get_func;
422 priv->n_columns = n_columns;
423 priv->column_types = g_memdup2 (mem: types, byte_size: columns_size);
424
425 return GTK_TREE_MODEL (result);
426}
427
428static void
429child_added_cb (GtkCssNode *node,
430 GtkCssNode *child,
431 GtkCssNode *previous,
432 GtkTreeModelCssNode *model)
433{
434 gtk_tree_model_css_node_connect_node (model, node: child, TRUE);
435}
436
437static void
438child_removed_cb (GtkCssNode *node,
439 GtkCssNode *child,
440 GtkCssNode *previous,
441 GtkTreeModelCssNode *model)
442{
443 gtk_tree_model_css_node_disconnect_node (model, node: child, TRUE, parent: node, previous);
444}
445
446static void
447notify_cb (GtkCssNode *node,
448 GParamSpec *pspec,
449 GtkTreeModelCssNode *model)
450{
451 GtkTreeIter iter;
452 GtkTreePath *path;
453
454 gtk_tree_model_css_node_get_iter_from_node (model, iter: &iter, node);
455 path = gtk_tree_model_css_node_get_path (GTK_TREE_MODEL (model), iter: &iter);
456
457 gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, iter: &iter);
458
459 gtk_tree_path_free (path);
460}
461
462static void
463style_changed_cb (GtkCssNode *node,
464 GtkCssStyleChange *change,
465 GtkTreeModelCssNode *model)
466{
467 GtkTreeIter iter;
468 GtkTreePath *path;
469
470 gtk_tree_model_css_node_get_iter_from_node (model, iter: &iter, node);
471 path = gtk_tree_model_css_node_get_path (GTK_TREE_MODEL (model), iter: &iter);
472
473 gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, iter: &iter);
474
475 gtk_tree_path_free (path);
476}
477
478static void
479gtk_tree_model_css_node_connect_node (GtkTreeModelCssNode *model,
480 GtkCssNode *node,
481 gboolean emit_signal)
482{
483 GtkCssNode *child;
484
485 if (GTK_IS_CSS_TRANSIENT_NODE (node))
486 return;
487
488 g_object_ref (node);
489
490 g_signal_connect_after (node, "node-added", G_CALLBACK (child_added_cb), model);
491 g_signal_connect_after (node, "node-removed", G_CALLBACK (child_removed_cb), model);
492 g_signal_connect_after (node, "notify", G_CALLBACK (notify_cb), model);
493 g_signal_connect_after (node, "style-changed", G_CALLBACK (style_changed_cb), model);
494
495 for (child = gtk_css_node_get_first_child (cssnode: node);
496 child;
497 child = gtk_css_node_get_next_sibling (cssnode: child))
498 {
499 gtk_tree_model_css_node_connect_node (model, node: child, FALSE);
500 }
501
502 if (emit_signal)
503 {
504 GtkTreeIter iter;
505 GtkTreePath *path;
506
507 if (node != model->priv->root &&
508 gtk_css_node_get_previous_sibling (cssnode: node) == NULL &&
509 gtk_css_node_get_next_sibling (cssnode: node) == NULL)
510 {
511 /* We're the first child of the parent */
512 gtk_tree_model_css_node_get_iter_from_node (model, iter: &iter, node: gtk_css_node_get_parent (cssnode: node));
513 path = gtk_tree_model_css_node_get_path (GTK_TREE_MODEL (model), iter: &iter);
514 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, iter: &iter);
515 gtk_tree_path_free (path);
516 }
517
518 gtk_tree_model_css_node_get_iter_from_node (model, iter: &iter, node);
519 path = gtk_tree_model_css_node_get_path (GTK_TREE_MODEL (model), iter: &iter);
520 gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, iter: &iter);
521 if (gtk_css_node_get_first_child (cssnode: node))
522 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, iter: &iter);
523
524 gtk_tree_path_free (path);
525 }
526}
527
528static void
529gtk_tree_model_css_node_disconnect_node (GtkTreeModelCssNode *model,
530 GtkCssNode *node,
531 gboolean emit_signal,
532 GtkCssNode *parent,
533 GtkCssNode *previous)
534{
535 GtkCssNode *child;
536
537 if (GTK_IS_CSS_TRANSIENT_NODE (node))
538 return;
539
540 g_signal_handlers_disconnect_by_func (node, G_CALLBACK (child_added_cb), model);
541 g_signal_handlers_disconnect_by_func (node, G_CALLBACK (child_removed_cb), model);
542 g_signal_handlers_disconnect_by_func (node, G_CALLBACK (notify_cb), model);
543 g_signal_handlers_disconnect_by_func (node, G_CALLBACK (style_changed_cb), model);
544
545 for (child = gtk_css_node_get_first_child (cssnode: node);
546 child;
547 child = gtk_css_node_get_next_sibling (cssnode: child))
548 {
549 gtk_tree_model_css_node_disconnect_node (model, node: child, FALSE, NULL, NULL);
550 }
551
552 if (emit_signal)
553 {
554 GtkTreeIter iter;
555 GtkTreePath *path;
556
557 if (parent)
558 {
559 gtk_tree_model_css_node_get_iter_from_node (model, iter: &iter, node: parent);
560 path = gtk_tree_model_css_node_get_path (GTK_TREE_MODEL (model), iter: &iter);
561 }
562 else
563 {
564 path = gtk_tree_path_new ();
565 }
566 if (previous)
567 gtk_tree_path_append_index (path, index_: get_node_index (node: previous) + 1);
568 else
569 gtk_tree_path_append_index (path, index_: 0);
570
571 gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
572
573 if (parent && gtk_css_node_get_first_child (cssnode: parent) == NULL)
574 {
575 gtk_tree_path_up (path);
576 gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, iter: &iter);
577 }
578
579 gtk_tree_path_free (path);
580 }
581
582 g_object_unref (object: node);
583}
584
585void
586gtk_tree_model_css_node_set_root_node (GtkTreeModelCssNode *model,
587 GtkCssNode *node)
588{
589 GtkTreeModelCssNodePrivate *priv;
590
591 g_return_if_fail (GTK_IS_TREE_MODEL_CSS_NODE (model));
592 g_return_if_fail (node == NULL || GTK_IS_CSS_NODE (node));
593
594 priv = model->priv;
595
596 if (priv->root == node)
597 return;
598
599 if (priv->root)
600 {
601 gtk_tree_model_css_node_disconnect_node (model, node: priv->root, TRUE, NULL, NULL);
602 priv->root = NULL;
603 }
604
605 if (node)
606 {
607 priv->root = node;
608 gtk_tree_model_css_node_connect_node (model, node, TRUE);
609 }
610}
611
612GtkCssNode *
613gtk_tree_model_css_node_get_root_node (GtkTreeModelCssNode *model)
614{
615 g_return_val_if_fail (GTK_IS_TREE_MODEL_CSS_NODE (model), NULL);
616
617 return model->priv->root;
618}
619
620GtkCssNode *
621gtk_tree_model_css_node_get_node_from_iter (GtkTreeModelCssNode *model,
622 GtkTreeIter *iter)
623{
624 g_return_val_if_fail (GTK_IS_TREE_MODEL_CSS_NODE (model), NULL);
625 g_return_val_if_fail (iter != NULL, NULL);
626 g_return_val_if_fail (iter->user_data == model, NULL);
627 g_return_val_if_fail (GTK_IS_CSS_NODE (iter->user_data2), NULL);
628
629 return iter->user_data2;
630}
631
632void
633gtk_tree_model_css_node_get_iter_from_node (GtkTreeModelCssNode *model,
634 GtkTreeIter *iter,
635 GtkCssNode *node)
636{
637 g_return_if_fail (GTK_IS_TREE_MODEL_CSS_NODE (model));
638 g_return_if_fail (iter != NULL);
639 g_return_if_fail (GTK_IS_CSS_NODE (node));
640
641 iter->user_data = model;
642 iter->user_data2 = node;
643}
644

source code of gtk/gtk/inspector/gtktreemodelcssnode.c