2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU Lesser General Public License as published by
4 * the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful, but
7 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 * Chris Lahey <clahey@ximian.com>
17 * Chris Toshok <toshok@ximian.com>
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
23 #include "e-tree-table-adapter.h"
28 #include <glib/gstdio.h>
30 #include <libxml/tree.h>
31 #include <libxml/parser.h>
33 #include <libedataserver/libedataserver.h>
35 #include "e-marshal.h"
36 #include "e-table-sorting-utils.h"
37 #include "e-xml-utils.h"
39 #define E_TREE_TABLE_ADAPTER_GET_PRIVATE(obj) \
40 (G_TYPE_INSTANCE_GET_PRIVATE \
41 ((obj), E_TYPE_TREE_TABLE_ADAPTER, ETreeTableAdapterPrivate))
45 #define INCREMENT_AMOUNT 100
49 guint32 num_visible_children
;
54 guint expandable_set
: 1;
57 struct _ETreeTableAdapterPrivate
{
58 ETreeModel
*source_model
;
59 gulong pre_change_handler_id
;
60 gulong rebuilt_handler_id
;
61 gulong node_changed_handler_id
;
62 gulong node_data_changed_handler_id
;
63 gulong node_inserted_handler_id
;
64 gulong node_removed_handler_id
;
66 ETableSortInfo
*sort_info
;
67 gulong sort_info_changed_handler_id
;
68 ETableSortInfo
*children_sort_info
;
69 gboolean sort_children_ascending
;
74 gint n_vals_allocated
;
79 guint root_visible
: 1;
80 guint remap_needed
: 1;
86 gint force_expanded_state
; /* use this instead of model's default if not 0; <0 ... collapse, >0 ... expand */
94 PROP_SORT_CHILDREN_ASCENDING
102 /* Forward Declarations */
103 static void e_tree_table_adapter_table_model_init
104 (ETableModelInterface
*iface
);
106 static guint signals
[LAST_SIGNAL
];
108 G_DEFINE_TYPE_WITH_CODE (
110 e_tree_table_adapter
,
112 G_IMPLEMENT_INTERFACE (
114 e_tree_table_adapter_table_model_init
))
117 lookup_gnode (ETreeTableAdapter
*etta
,
125 gnode
= g_hash_table_lookup (etta
->priv
->nodes
, path
);
131 resize_map (ETreeTableAdapter
*etta
,
134 if (size
> etta
->priv
->n_vals_allocated
) {
135 etta
->priv
->n_vals_allocated
= MAX (etta
->priv
->n_vals_allocated
+ INCREMENT_AMOUNT
, size
);
136 etta
->priv
->map_table
= g_renew (node_t
*, etta
->priv
->map_table
, etta
->priv
->n_vals_allocated
);
139 etta
->priv
->n_map
= size
;
143 move_map_elements (ETreeTableAdapter
*etta
,
148 if (count
<= 0 || from
>= etta
->priv
->n_map
)
150 memmove (etta
->priv
->map_table
+ to
, etta
->priv
->map_table
+ from
, count
* sizeof (node_t
*));
151 etta
->priv
->remap_needed
= TRUE
;
155 fill_map (ETreeTableAdapter
*etta
,
161 if ((gnode
!= etta
->priv
->root
) || etta
->priv
->root_visible
)
162 etta
->priv
->map_table
[index
++] = gnode
->data
;
164 for (p
= gnode
->children
; p
; p
= p
->next
)
165 index
= fill_map (etta
, index
, p
);
167 etta
->priv
->remap_needed
= TRUE
;
172 remap_indices (ETreeTableAdapter
*etta
)
175 for (i
= 0; i
< etta
->priv
->n_map
; i
++)
176 etta
->priv
->map_table
[i
]->index
= i
;
177 etta
->priv
->remap_needed
= FALSE
;
181 get_node (ETreeTableAdapter
*etta
,
184 GNode
*gnode
= lookup_gnode (etta
, path
);
189 return (node_t
*) gnode
->data
;
193 resort_node (ETreeTableAdapter
*etta
,
197 node_t
*node
= (node_t
*) gnode
->data
;
198 ETreePath
*paths
, path
;
201 gboolean sort_needed
;
203 g_return_if_fail (node
!= NULL
);
205 if (node
->num_visible_children
== 0)
208 sort_needed
= etta
->priv
->sort_info
&& e_table_sort_info_sorting_get_count (etta
->priv
->sort_info
) > 0;
210 for (i
= 0, path
= e_tree_model_node_get_first_child (etta
->priv
->source_model
, node
->path
); path
;
211 path
= e_tree_model_node_get_next (etta
->priv
->source_model
, path
), i
++);
217 paths
= g_new0 (ETreePath
, count
);
219 for (i
= 0, path
= e_tree_model_node_get_first_child (etta
->priv
->source_model
, node
->path
); path
;
220 path
= e_tree_model_node_get_next (etta
->priv
->source_model
, path
), i
++)
223 if (count
> 1 && sort_needed
) {
224 ETableSortInfo
*use_sort_info
;
226 use_sort_info
= etta
->priv
->sort_info
;
228 if (etta
->priv
->sort_children_ascending
&& gnode
->parent
) {
229 if (!etta
->priv
->children_sort_info
) {
232 etta
->priv
->children_sort_info
= e_table_sort_info_duplicate (etta
->priv
->sort_info
);
234 len
= e_table_sort_info_sorting_get_count (etta
->priv
->children_sort_info
);
236 for (i
= 0; i
< len
; i
++) {
237 ETableColumnSpecification
*spec
;
238 GtkSortType sort_type
;
240 spec
= e_table_sort_info_sorting_get_nth (etta
->priv
->children_sort_info
, i
, &sort_type
);
242 if (sort_type
== GTK_SORT_DESCENDING
)
243 e_table_sort_info_sorting_set_nth (etta
->priv
->children_sort_info
, i
, spec
, GTK_SORT_ASCENDING
);
248 use_sort_info
= etta
->priv
->children_sort_info
;
251 e_table_sorting_utils_tree_sort (etta
->priv
->source_model
, use_sort_info
, etta
->priv
->header
, paths
, count
);
255 for (i
= 0; i
< count
; i
++) {
256 curr
= lookup_gnode (etta
, paths
[i
]);
263 gnode
->children
= curr
;
269 resort_node (etta
, curr
, recurse
);
276 kill_gnode (GNode
*node
,
277 ETreeTableAdapter
*etta
)
279 g_hash_table_remove (etta
->priv
->nodes
, ((node_t
*) node
->data
)->path
);
281 while (node
->children
) {
282 GNode
*next
= node
->children
->next
;
283 kill_gnode (node
->children
, etta
);
284 node
->children
= next
;
288 if (node
== etta
->priv
->root
)
289 etta
->priv
->root
= NULL
;
290 g_node_destroy (node
);
294 update_child_counts (GNode
*gnode
,
298 node_t
*node
= (node_t
*) gnode
->data
;
299 node
->num_visible_children
+= delta
;
300 gnode
= gnode
->parent
;
305 delete_children (ETreeTableAdapter
*etta
,
308 node_t
*node
= (node_t
*) gnode
->data
;
309 gint to_remove
= node
? node
->num_visible_children
: 0;
314 while (gnode
->children
) {
315 GNode
*next
= gnode
->children
->next
;
316 kill_gnode (gnode
->children
, etta
);
317 gnode
->children
= next
;
324 delete_node (ETreeTableAdapter
*etta
,
329 gint parent_row
= e_tree_table_adapter_row_of_node (etta
, parent
);
330 gint row
= e_tree_table_adapter_row_of_node (etta
, path
);
331 GNode
*gnode
= lookup_gnode (etta
, path
);
332 GNode
*parent_gnode
= lookup_gnode (etta
, parent
);
334 e_table_model_pre_change (E_TABLE_MODEL (etta
));
337 e_table_model_no_change (E_TABLE_MODEL (etta
));
341 to_remove
+= delete_children (etta
, gnode
);
342 kill_gnode (gnode
, etta
);
344 move_map_elements (etta
, row
, row
+ to_remove
, etta
->priv
->n_map
- row
- to_remove
);
345 resize_map (etta
, etta
->priv
->n_map
- to_remove
);
347 if (parent_gnode
!= NULL
) {
348 node_t
*parent_node
= parent_gnode
->data
;
349 gboolean expandable
= e_tree_model_node_is_expandable (etta
->priv
->source_model
, parent
);
351 update_child_counts (parent_gnode
, - to_remove
);
352 if (parent_node
->expandable
!= expandable
) {
353 e_table_model_pre_change (E_TABLE_MODEL (etta
));
354 parent_node
->expandable
= expandable
;
355 e_table_model_row_changed (E_TABLE_MODEL (etta
), parent_row
);
358 resort_node (etta
, parent_gnode
, FALSE
);
361 e_table_model_rows_deleted (E_TABLE_MODEL (etta
), row
, to_remove
);
365 create_gnode (ETreeTableAdapter
*etta
,
371 node
= g_new0 (node_t
, 1);
374 node
->expanded
= etta
->priv
->force_expanded_state
== 0 ? e_tree_model_get_expanded_default (etta
->priv
->source_model
) : etta
->priv
->force_expanded_state
> 0;
375 node
->expandable
= e_tree_model_node_is_expandable (etta
->priv
->source_model
, path
);
376 node
->expandable_set
= 1;
377 node
->num_visible_children
= 0;
378 gnode
= g_node_new (node
);
379 g_hash_table_insert (etta
->priv
->nodes
, path
, gnode
);
384 insert_children (ETreeTableAdapter
*etta
,
391 path
= ((node_t
*) gnode
->data
)->path
;
392 for (tmp
= e_tree_model_node_get_first_child (etta
->priv
->source_model
, path
);
394 tmp
= e_tree_model_node_get_next (etta
->priv
->source_model
, tmp
), pos
++) {
395 GNode
*child
= create_gnode (etta
, tmp
);
396 node_t
*node
= (node_t
*) child
->data
;
398 node
->num_visible_children
= insert_children (etta
, child
);
399 g_node_prepend (gnode
, child
);
400 count
+= node
->num_visible_children
+ 1;
402 g_node_reverse_children (gnode
);
407 generate_tree (ETreeTableAdapter
*etta
,
414 e_table_model_pre_change (E_TABLE_MODEL (etta
));
416 g_return_if_fail (e_tree_model_node_is_root (etta
->priv
->source_model
, path
));
418 if (etta
->priv
->root
)
419 kill_gnode (etta
->priv
->root
, etta
);
420 resize_map (etta
, 0);
422 gnode
= create_gnode (etta
, path
);
423 node
= (node_t
*) gnode
->data
;
424 node
->expanded
= TRUE
;
425 node
->num_visible_children
= insert_children (etta
, gnode
);
426 if (etta
->priv
->sort_info
&& e_table_sort_info_sorting_get_count (etta
->priv
->sort_info
) > 0)
427 resort_node (etta
, gnode
, TRUE
);
429 etta
->priv
->root
= gnode
;
430 size
= etta
->priv
->root_visible
? node
->num_visible_children
+ 1 : node
->num_visible_children
;
431 resize_map (etta
, size
);
432 fill_map (etta
, 0, gnode
);
433 e_table_model_changed (E_TABLE_MODEL (etta
));
437 insert_node (ETreeTableAdapter
*etta
,
441 GNode
*gnode
, *parent_gnode
;
442 node_t
*node
, *parent_node
;
446 e_table_model_pre_change (E_TABLE_MODEL (etta
));
448 if (get_node (etta
, path
)) {
449 e_table_model_no_change (E_TABLE_MODEL (etta
));
453 parent_gnode
= lookup_gnode (etta
, parent
);
455 ETreePath grandparent
= e_tree_model_node_get_parent (etta
->priv
->source_model
, parent
);
456 if (e_tree_model_node_is_root (etta
->priv
->source_model
, parent
))
457 generate_tree (etta
, parent
);
459 insert_node (etta
, grandparent
, parent
);
460 e_table_model_changed (E_TABLE_MODEL (etta
));
464 parent_node
= (node_t
*) parent_gnode
->data
;
466 if (parent_gnode
!= etta
->priv
->root
) {
467 expandable
= e_tree_model_node_is_expandable (etta
->priv
->source_model
, parent
);
468 if (parent_node
->expandable
!= expandable
) {
469 e_table_model_pre_change (E_TABLE_MODEL (etta
));
470 parent_node
->expandable
= expandable
;
471 parent_node
->expandable_set
= 1;
472 e_table_model_row_changed (E_TABLE_MODEL (etta
), parent_node
->index
);
476 if (!e_tree_table_adapter_node_is_expanded (etta
, parent
)) {
477 e_table_model_no_change (E_TABLE_MODEL (etta
));
481 gnode
= create_gnode (etta
, path
);
482 node
= (node_t
*) gnode
->data
;
485 node
->num_visible_children
= insert_children (etta
, gnode
);
487 g_node_append (parent_gnode
, gnode
);
488 update_child_counts (parent_gnode
, node
->num_visible_children
+ 1);
489 resort_node (etta
, parent_gnode
, FALSE
);
490 resort_node (etta
, gnode
, TRUE
);
492 size
= node
->num_visible_children
+ 1;
493 resize_map (etta
, etta
->priv
->n_map
+ size
);
494 if (parent_gnode
== etta
->priv
->root
)
497 gint new_size
= parent_node
->num_visible_children
+ 1;
498 gint old_size
= new_size
- size
;
499 row
= parent_node
->index
;
500 move_map_elements (etta
, row
+ new_size
, row
+ old_size
, etta
->priv
->n_map
- row
- new_size
);
502 fill_map (etta
, row
, parent_gnode
);
503 e_table_model_rows_inserted (
504 E_TABLE_MODEL (etta
),
505 e_tree_table_adapter_row_of_node (etta
, path
), size
);
511 } check_expanded_closure
;
514 check_expanded (GNode
*gnode
,
517 check_expanded_closure
*closure
= (check_expanded_closure
*) data
;
518 node_t
*node
= (node_t
*) gnode
->data
;
520 if (node
->expanded
!= closure
->expanded
)
521 closure
->paths
= g_slist_prepend (closure
->paths
, node
->path
);
527 update_node (ETreeTableAdapter
*etta
,
530 check_expanded_closure closure
;
531 ETreePath parent
= e_tree_model_node_get_parent (etta
->priv
->source_model
, path
);
532 GNode
*gnode
= lookup_gnode (etta
, path
);
535 closure
.expanded
= e_tree_model_get_expanded_default (etta
->priv
->source_model
);
536 closure
.paths
= NULL
;
539 g_node_traverse (gnode
, G_POST_ORDER
, G_TRAVERSE_ALL
, -1, check_expanded
, &closure
);
541 if (e_tree_model_node_is_root (etta
->priv
->source_model
, path
))
542 generate_tree (etta
, path
);
544 delete_node (etta
, parent
, path
);
545 insert_node (etta
, parent
, path
);
548 for (l
= closure
.paths
; l
; l
= l
->next
)
549 if (lookup_gnode (etta
, l
->data
))
550 e_tree_table_adapter_node_set_expanded (etta
, l
->data
, !closure
.expanded
);
552 g_slist_free (closure
.paths
);
556 tree_table_adapter_sort_info_changed_cb (ETableSortInfo
*sort_info
,
557 ETreeTableAdapter
*etta
)
559 g_clear_object (&etta
->priv
->children_sort_info
);
561 if (!etta
->priv
->root
)
564 /* the function is called also internally, with sort_info = NULL,
565 * thus skip those in signal emit */
567 gboolean handled
= FALSE
;
569 g_signal_emit (etta
, signals
[SORTING_CHANGED
], 0, &handled
);
575 e_table_model_pre_change (E_TABLE_MODEL (etta
));
576 resort_node (etta
, etta
->priv
->root
, TRUE
);
577 fill_map (etta
, 0, etta
->priv
->root
);
578 e_table_model_changed (E_TABLE_MODEL (etta
));
582 tree_table_adapter_source_model_pre_change_cb (ETreeModel
*source_model
,
583 ETreeTableAdapter
*etta
)
585 e_table_model_pre_change (E_TABLE_MODEL (etta
));
589 tree_table_adapter_source_model_rebuilt_cb (ETreeModel
*source_model
,
590 ETreeTableAdapter
*etta
)
592 if (!etta
->priv
->root
)
595 kill_gnode (etta
->priv
->root
, etta
);
596 etta
->priv
->root
= NULL
;
598 g_hash_table_remove_all (etta
->priv
->nodes
);
602 tree_table_adapter_resort_model_idle_cb (gpointer user_data
)
604 ETreeTableAdapter
*etta
;
606 etta
= E_TREE_TABLE_ADAPTER (user_data
);
607 tree_table_adapter_sort_info_changed_cb (NULL
, etta
);
608 etta
->priv
->resort_idle_id
= 0;
614 tree_table_adapter_source_model_node_changed_cb (ETreeModel
*source_model
,
616 ETreeTableAdapter
*etta
)
618 update_node (etta
, path
);
619 e_table_model_changed (E_TABLE_MODEL (etta
));
621 /* FIXME: Really it shouldnt be required. But a lot of thread
622 * which were supposed to be present in the list is way below
624 if (etta
->priv
->resort_idle_id
== 0)
625 etta
->priv
->resort_idle_id
= g_idle_add (
626 tree_table_adapter_resort_model_idle_cb
, etta
);
630 tree_table_adapter_source_model_node_data_changed_cb (ETreeModel
*source_model
,
632 ETreeTableAdapter
*etta
)
634 gint row
= e_tree_table_adapter_row_of_node (etta
, path
);
637 e_table_model_no_change (E_TABLE_MODEL (etta
));
641 e_table_model_row_changed (E_TABLE_MODEL (etta
), row
);
645 tree_table_adapter_source_model_node_inserted_cb (ETreeModel
*etm
,
648 ETreeTableAdapter
*etta
)
650 if (e_tree_model_node_is_root (etm
, child
))
651 generate_tree (etta
, child
);
653 insert_node (etta
, parent
, child
);
655 e_table_model_changed (E_TABLE_MODEL (etta
));
659 tree_table_adapter_source_model_node_removed_cb (ETreeModel
*etm
,
663 ETreeTableAdapter
*etta
)
665 delete_node (etta
, parent
, child
);
666 e_table_model_changed (E_TABLE_MODEL (etta
));
670 tree_table_adapter_set_header (ETreeTableAdapter
*etta
,
671 ETableHeader
*header
)
676 g_return_if_fail (E_IS_TABLE_HEADER (header
));
677 g_return_if_fail (etta
->priv
->header
== NULL
);
679 etta
->priv
->header
= g_object_ref (header
);
683 tree_table_adapter_set_source_model (ETreeTableAdapter
*etta
,
684 ETreeModel
*source_model
)
686 g_return_if_fail (E_IS_TREE_MODEL (source_model
));
687 g_return_if_fail (etta
->priv
->source_model
== NULL
);
689 etta
->priv
->source_model
= g_object_ref (source_model
);
693 tree_table_adapter_set_property (GObject
*object
,
698 switch (property_id
) {
700 tree_table_adapter_set_header (
701 E_TREE_TABLE_ADAPTER (object
),
702 g_value_get_object (value
));
706 e_tree_table_adapter_set_sort_info (
707 E_TREE_TABLE_ADAPTER (object
),
708 g_value_get_object (value
));
711 case PROP_SOURCE_MODEL
:
712 tree_table_adapter_set_source_model (
713 E_TREE_TABLE_ADAPTER (object
),
714 g_value_get_object (value
));
717 case PROP_SORT_CHILDREN_ASCENDING
:
718 e_tree_table_adapter_set_sort_children_ascending (
719 E_TREE_TABLE_ADAPTER (object
),
720 g_value_get_boolean (value
));
724 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
728 tree_table_adapter_get_property (GObject
*object
,
733 switch (property_id
) {
737 e_tree_table_adapter_get_header (
738 E_TREE_TABLE_ADAPTER (object
)));
744 e_tree_table_adapter_get_sort_info (
745 E_TREE_TABLE_ADAPTER (object
)));
748 case PROP_SOURCE_MODEL
:
751 e_tree_table_adapter_get_source_model (
752 E_TREE_TABLE_ADAPTER (object
)));
755 case PROP_SORT_CHILDREN_ASCENDING
:
756 g_value_set_boolean (
758 e_tree_table_adapter_get_sort_children_ascending (
759 E_TREE_TABLE_ADAPTER (object
)));
763 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
767 tree_table_adapter_dispose (GObject
*object
)
769 ETreeTableAdapterPrivate
*priv
;
771 priv
= E_TREE_TABLE_ADAPTER_GET_PRIVATE (object
);
773 if (priv
->pre_change_handler_id
> 0) {
774 g_signal_handler_disconnect (
776 priv
->pre_change_handler_id
);
777 priv
->pre_change_handler_id
= 0;
780 if (priv
->rebuilt_handler_id
> 0) {
781 g_signal_handler_disconnect (
783 priv
->rebuilt_handler_id
);
784 priv
->rebuilt_handler_id
= 0;
787 if (priv
->node_changed_handler_id
> 0) {
788 g_signal_handler_disconnect (
790 priv
->node_changed_handler_id
);
791 priv
->node_changed_handler_id
= 0;
794 if (priv
->node_data_changed_handler_id
> 0) {
795 g_signal_handler_disconnect (
797 priv
->node_data_changed_handler_id
);
798 priv
->node_data_changed_handler_id
= 0;
801 if (priv
->node_inserted_handler_id
> 0) {
802 g_signal_handler_disconnect (
804 priv
->node_inserted_handler_id
);
805 priv
->node_inserted_handler_id
= 0;
808 if (priv
->node_removed_handler_id
> 0) {
809 g_signal_handler_disconnect (
811 priv
->node_removed_handler_id
);
812 priv
->node_removed_handler_id
= 0;
815 if (priv
->sort_info_changed_handler_id
> 0) {
816 g_signal_handler_disconnect (
818 priv
->sort_info_changed_handler_id
);
819 priv
->sort_info_changed_handler_id
= 0;
822 g_clear_object (&priv
->source_model
);
823 g_clear_object (&priv
->sort_info
);
824 g_clear_object (&priv
->children_sort_info
);
825 g_clear_object (&priv
->header
);
827 /* Chain up to parent's dispose() method. */
828 G_OBJECT_CLASS (e_tree_table_adapter_parent_class
)->dispose (object
);
832 tree_table_adapter_finalize (GObject
*object
)
834 ETreeTableAdapterPrivate
*priv
;
836 priv
= E_TREE_TABLE_ADAPTER_GET_PRIVATE (object
);
838 if (priv
->resort_idle_id
) {
839 g_source_remove (priv
->resort_idle_id
);
840 priv
->resort_idle_id
= 0;
844 kill_gnode (priv
->root
, E_TREE_TABLE_ADAPTER (object
));
848 g_hash_table_destroy (priv
->nodes
);
850 g_free (priv
->map_table
);
852 /* Chain up to parent's finalize() method. */
853 G_OBJECT_CLASS (e_tree_table_adapter_parent_class
)->finalize (object
);
857 tree_table_adapter_constructed (GObject
*object
)
859 ETreeTableAdapter
*etta
;
860 ETreeModel
*source_model
;
864 etta
= E_TREE_TABLE_ADAPTER (object
);
866 /* Chain up to parent's constructed() method. */
867 G_OBJECT_CLASS (e_tree_table_adapter_parent_class
)->constructed (object
);
869 source_model
= e_tree_table_adapter_get_source_model (etta
);
871 root
= e_tree_model_get_root (source_model
);
873 generate_tree (etta
, root
);
875 handler_id
= g_signal_connect (
876 source_model
, "pre_change",
877 G_CALLBACK (tree_table_adapter_source_model_pre_change_cb
),
879 etta
->priv
->pre_change_handler_id
= handler_id
;
881 handler_id
= g_signal_connect (
882 source_model
, "rebuilt",
883 G_CALLBACK (tree_table_adapter_source_model_rebuilt_cb
),
885 etta
->priv
->rebuilt_handler_id
= handler_id
;
887 handler_id
= g_signal_connect (
888 source_model
, "node_changed",
889 G_CALLBACK (tree_table_adapter_source_model_node_changed_cb
),
891 etta
->priv
->node_changed_handler_id
= handler_id
;
893 handler_id
= g_signal_connect (
894 source_model
, "node_data_changed",
895 G_CALLBACK (tree_table_adapter_source_model_node_data_changed_cb
),
897 etta
->priv
->node_data_changed_handler_id
= handler_id
;
899 handler_id
= g_signal_connect (
900 source_model
, "node_inserted",
901 G_CALLBACK (tree_table_adapter_source_model_node_inserted_cb
),
903 etta
->priv
->node_inserted_handler_id
= handler_id
;
905 handler_id
= g_signal_connect (
906 source_model
, "node_removed",
907 G_CALLBACK (tree_table_adapter_source_model_node_removed_cb
),
909 etta
->priv
->node_removed_handler_id
= handler_id
;
913 tree_table_adapter_column_count (ETableModel
*etm
)
915 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
917 return e_tree_model_column_count (etta
->priv
->source_model
);
921 tree_table_adapter_has_save_id (ETableModel
*etm
)
927 tree_table_adapter_get_save_id (ETableModel
*etm
,
930 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
932 return e_tree_model_get_save_id (
933 etta
->priv
->source_model
,
934 e_tree_table_adapter_node_at_row (etta
, row
));
938 tree_table_adapter_row_count (ETableModel
*etm
)
940 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
942 return etta
->priv
->n_map
;
946 tree_table_adapter_value_at (ETableModel
*etm
,
950 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
956 return e_tree_table_adapter_node_at_row (etta
, row
);
958 return etta
->priv
->source_model
;
962 return e_tree_model_value_at (
963 etta
->priv
->source_model
,
964 e_tree_table_adapter_node_at_row (etta
, row
), col
);
969 tree_table_adapter_set_value_at (ETableModel
*etm
,
974 g_warn_if_reached ();
978 tree_table_adapter_is_cell_editable (ETableModel
*etm
,
986 tree_table_adapter_append_row (ETableModel
*etm
,
993 tree_table_adapter_duplicate_value (ETableModel
*etm
,
997 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
999 return e_tree_model_duplicate_value (etta
->priv
->source_model
, col
, value
);
1003 tree_table_adapter_free_value (ETableModel
*etm
,
1007 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
1009 e_tree_model_free_value (etta
->priv
->source_model
, col
, value
);
1013 tree_table_adapter_initialize_value (ETableModel
*etm
,
1016 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
1018 return e_tree_model_initialize_value (etta
->priv
->source_model
, col
);
1022 tree_table_adapter_value_is_empty (ETableModel
*etm
,
1024 gconstpointer value
)
1026 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
1028 return e_tree_model_value_is_empty (etta
->priv
->source_model
, col
, value
);
1032 tree_table_adapter_value_to_string (ETableModel
*etm
,
1034 gconstpointer value
)
1036 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
1038 return e_tree_model_value_to_string (etta
->priv
->source_model
, col
, value
);
1042 e_tree_table_adapter_class_init (ETreeTableAdapterClass
*class)
1044 GObjectClass
*object_class
;
1046 g_type_class_add_private (class, sizeof (ETreeTableAdapterPrivate
));
1048 object_class
= G_OBJECT_CLASS (class);
1049 object_class
->set_property
= tree_table_adapter_set_property
;
1050 object_class
->get_property
= tree_table_adapter_get_property
;
1051 object_class
->dispose
= tree_table_adapter_dispose
;
1052 object_class
->finalize
= tree_table_adapter_finalize
;
1053 object_class
->constructed
= tree_table_adapter_constructed
;
1055 g_object_class_install_property (
1058 g_param_spec_object (
1062 E_TYPE_TABLE_HEADER
,
1064 G_PARAM_CONSTRUCT_ONLY
|
1065 G_PARAM_STATIC_STRINGS
));
1067 g_object_class_install_property (
1070 g_param_spec_object (
1074 E_TYPE_TABLE_SORT_INFO
,
1077 G_PARAM_STATIC_STRINGS
));
1079 g_object_class_install_property (
1082 g_param_spec_object (
1088 G_PARAM_CONSTRUCT_ONLY
|
1089 G_PARAM_STATIC_STRINGS
));
1091 g_object_class_install_property (
1093 PROP_SORT_CHILDREN_ASCENDING
,
1094 g_param_spec_boolean (
1095 "sort-children-ascending",
1096 "Sort Children Ascending",
1101 G_PARAM_STATIC_STRINGS
));
1103 signals
[SORTING_CHANGED
] = g_signal_new (
1105 G_OBJECT_CLASS_TYPE (object_class
),
1107 G_STRUCT_OFFSET (ETreeTableAdapterClass
, sorting_changed
),
1109 e_marshal_BOOLEAN__NONE
,
1115 e_tree_table_adapter_table_model_init (ETableModelInterface
*iface
)
1117 iface
->column_count
= tree_table_adapter_column_count
;
1118 iface
->row_count
= tree_table_adapter_row_count
;
1119 iface
->append_row
= tree_table_adapter_append_row
;
1121 iface
->value_at
= tree_table_adapter_value_at
;
1122 iface
->set_value_at
= tree_table_adapter_set_value_at
;
1123 iface
->is_cell_editable
= tree_table_adapter_is_cell_editable
;
1125 iface
->has_save_id
= tree_table_adapter_has_save_id
;
1126 iface
->get_save_id
= tree_table_adapter_get_save_id
;
1128 iface
->duplicate_value
= tree_table_adapter_duplicate_value
;
1129 iface
->free_value
= tree_table_adapter_free_value
;
1130 iface
->initialize_value
= tree_table_adapter_initialize_value
;
1131 iface
->value_is_empty
= tree_table_adapter_value_is_empty
;
1132 iface
->value_to_string
= tree_table_adapter_value_to_string
;
1136 e_tree_table_adapter_init (ETreeTableAdapter
*etta
)
1138 etta
->priv
= E_TREE_TABLE_ADAPTER_GET_PRIVATE (etta
);
1140 etta
->priv
->nodes
= g_hash_table_new (NULL
, NULL
);
1142 etta
->priv
->root_visible
= TRUE
;
1143 etta
->priv
->remap_needed
= TRUE
;
1147 e_tree_table_adapter_new (ETreeModel
*source_model
,
1148 ETableSortInfo
*sort_info
,
1149 ETableHeader
*header
)
1151 g_return_val_if_fail (E_IS_TREE_MODEL (source_model
), NULL
);
1153 if (sort_info
!= NULL
)
1154 g_return_val_if_fail (E_IS_TABLE_SORT_INFO (sort_info
), NULL
);
1157 g_return_val_if_fail (E_IS_TABLE_HEADER (header
), NULL
);
1159 return g_object_new (
1160 E_TYPE_TREE_TABLE_ADAPTER
,
1161 "source-model", source_model
,
1162 "sort-info", sort_info
,
1168 e_tree_table_adapter_get_header (ETreeTableAdapter
*etta
)
1170 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1172 return etta
->priv
->header
;
1176 e_tree_table_adapter_get_sort_info (ETreeTableAdapter
*etta
)
1178 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1180 return etta
->priv
->sort_info
;
1184 e_tree_table_adapter_set_sort_info (ETreeTableAdapter
*etta
,
1185 ETableSortInfo
*sort_info
)
1187 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1189 if (sort_info
!= NULL
) {
1190 g_return_if_fail (E_IS_TABLE_SORT_INFO (sort_info
));
1191 g_object_ref (sort_info
);
1194 if (etta
->priv
->sort_info
!= NULL
) {
1195 g_signal_handler_disconnect (
1196 etta
->priv
->sort_info
,
1197 etta
->priv
->sort_info_changed_handler_id
);
1198 etta
->priv
->sort_info_changed_handler_id
= 0;
1200 g_clear_object (&etta
->priv
->sort_info
);
1203 etta
->priv
->sort_info
= sort_info
;
1205 if (etta
->priv
->sort_info
!= NULL
) {
1208 handler_id
= g_signal_connect (
1209 etta
->priv
->sort_info
, "sort_info_changed",
1210 G_CALLBACK (tree_table_adapter_sort_info_changed_cb
),
1212 etta
->priv
->sort_info_changed_handler_id
= handler_id
;
1215 g_clear_object (&etta
->priv
->children_sort_info
);
1217 g_object_notify (G_OBJECT (etta
), "sort-info");
1219 if (etta
->priv
->root
== NULL
)
1222 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1223 resort_node (etta
, etta
->priv
->root
, TRUE
);
1224 fill_map (etta
, 0, etta
->priv
->root
);
1225 e_table_model_changed (E_TABLE_MODEL (etta
));
1229 e_tree_table_adapter_get_sort_children_ascending (ETreeTableAdapter
*etta
)
1231 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), FALSE
);
1233 return etta
->priv
->sort_children_ascending
;
1237 e_tree_table_adapter_set_sort_children_ascending (ETreeTableAdapter
*etta
,
1238 gboolean sort_children_ascending
)
1240 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1242 if ((etta
->priv
->sort_children_ascending
? 1 : 0) == (sort_children_ascending
? 1 : 0))
1245 etta
->priv
->sort_children_ascending
= sort_children_ascending
;
1246 g_clear_object (&etta
->priv
->children_sort_info
);
1248 g_object_notify (G_OBJECT (etta
), "sort-children-ascending");
1250 if (!etta
->priv
->root
)
1253 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1254 resort_node (etta
, etta
->priv
->root
, TRUE
);
1255 fill_map (etta
, 0, etta
->priv
->root
);
1256 e_table_model_changed (E_TABLE_MODEL (etta
));
1260 e_tree_table_adapter_get_source_model (ETreeTableAdapter
*etta
)
1262 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1264 return etta
->priv
->source_model
;
1269 gboolean expanded_default
;
1274 save_expanded_state_func (gpointer keyp
,
1278 ETreePath path
= keyp
;
1279 node_t
*node
= ((GNode
*) value
)->data
;
1280 TreeAndRoot
*tar
= data
;
1283 if (node
->expanded
!= tar
->expanded_default
) {
1284 gchar
*save_id
= e_tree_model_get_save_id (tar
->model
, path
);
1285 xmlnode
= xmlNewChild (tar
->root
, NULL
, (const guchar
*)"node", NULL
);
1286 e_xml_set_string_prop_by_name (xmlnode
, (const guchar
*)"id", save_id
);
1292 e_tree_table_adapter_save_expanded_state_xml (ETreeTableAdapter
*etta
)
1298 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1300 doc
= xmlNewDoc ((const guchar
*)"1.0");
1301 root
= xmlNewDocNode (doc
, NULL
, (const guchar
*)"expanded_state", NULL
);
1302 xmlDocSetRootElement (doc
, root
);
1304 tar
.model
= etta
->priv
->source_model
;
1306 tar
.expanded_default
= e_tree_model_get_expanded_default (etta
->priv
->source_model
);
1308 e_xml_set_integer_prop_by_name (root
, (const guchar
*)"vers", 2);
1309 e_xml_set_bool_prop_by_name (root
, (const guchar
*)"default", tar
.expanded_default
);
1311 g_hash_table_foreach (etta
->priv
->nodes
, save_expanded_state_func
, &tar
);
1317 e_tree_table_adapter_save_expanded_state (ETreeTableAdapter
*etta
,
1318 const gchar
*filename
)
1322 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1324 doc
= e_tree_table_adapter_save_expanded_state_xml (etta
);
1326 e_xml_save_file (filename
, doc
);
1332 open_file (ETreeTableAdapter
*etta
,
1333 const gchar
*filename
)
1338 gboolean model_default
, saved_default
;
1340 if (!g_file_test (filename
, G_FILE_TEST_EXISTS
))
1345 gchar
*locale_filename
= g_win32_locale_filename_from_utf8 (filename
);
1346 doc
= xmlParseFile (locale_filename
);
1347 g_free (locale_filename
);
1350 doc
= xmlParseFile (filename
);
1356 root
= xmlDocGetRootElement (doc
);
1357 if (root
== NULL
|| strcmp ((gchar
*) root
->name
, "expanded_state")) {
1362 vers
= e_xml_get_integer_prop_by_name_with_default (root
, (const guchar
*)"vers", 0);
1367 model_default
= e_tree_model_get_expanded_default (etta
->priv
->source_model
);
1368 saved_default
= e_xml_get_bool_prop_by_name_with_default (root
, (const guchar
*)"default", !model_default
);
1369 if (saved_default
!= model_default
) {
1377 /* state: <0 ... collapse; 0 ... use default; >0 ... expand */
1379 e_tree_table_adapter_force_expanded_state (ETreeTableAdapter
*etta
,
1382 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1384 etta
->priv
->force_expanded_state
= state
;
1388 e_tree_table_adapter_load_expanded_state_xml (ETreeTableAdapter
*etta
,
1391 xmlNode
*root
, *child
;
1392 gboolean model_default
;
1393 gboolean file_default
= FALSE
;
1395 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1396 g_return_if_fail (doc
!= NULL
);
1398 root
= xmlDocGetRootElement (doc
);
1400 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1402 model_default
= e_tree_model_get_expanded_default (etta
->priv
->source_model
);
1404 if (!strcmp ((gchar
*) root
->name
, "expanded_state")) {
1407 state
= e_xml_get_string_prop_by_name_with_default (root
, (const guchar
*)"default", "");
1409 if (state
[0] == 't')
1410 file_default
= TRUE
;
1412 file_default
= FALSE
; /* Even unspecified we'll consider as false */
1417 /* Incase the default is changed, lets forget the changes and stick to default */
1419 if (file_default
!= model_default
) {
1424 for (child
= root
->xmlChildrenNode
; child
; child
= child
->next
) {
1428 if (strcmp ((gchar
*) child
->name
, "node")) {
1429 d (g_warning ("unknown node '%s' in %s", child
->name
, filename
));
1433 id
= e_xml_get_string_prop_by_name_with_default (child
, (const guchar
*)"id", "");
1435 if (!strcmp (id
, "")) {
1440 path
= e_tree_model_get_node_by_id (etta
->priv
->source_model
, id
);
1442 e_tree_table_adapter_node_set_expanded (etta
, path
, !model_default
);
1447 e_table_model_changed (E_TABLE_MODEL (etta
));
1451 e_tree_table_adapter_load_expanded_state (ETreeTableAdapter
*etta
,
1452 const gchar
*filename
)
1456 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1458 doc
= open_file (etta
, filename
);
1462 e_tree_table_adapter_load_expanded_state_xml (etta
, doc
);
1468 e_tree_table_adapter_root_node_set_visible (ETreeTableAdapter
*etta
,
1473 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1475 if (etta
->priv
->root_visible
== visible
)
1478 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1480 etta
->priv
->root_visible
= visible
;
1482 ETreePath root
= e_tree_model_get_root (etta
->priv
->source_model
);
1484 e_tree_table_adapter_node_set_expanded (etta
, root
, TRUE
);
1486 size
= (visible
? 1 : 0) + (etta
->priv
->root
? ((node_t
*) etta
->priv
->root
->data
)->num_visible_children
: 0);
1487 resize_map (etta
, size
);
1488 if (etta
->priv
->root
)
1489 fill_map (etta
, 0, etta
->priv
->root
);
1490 e_table_model_changed (E_TABLE_MODEL (etta
));
1494 e_tree_table_adapter_node_set_expanded (ETreeTableAdapter
*etta
,
1502 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1504 gnode
= lookup_gnode (etta
, path
);
1506 if (!expanded
&& (!gnode
|| (e_tree_model_node_is_root (etta
->priv
->source_model
, path
) && !etta
->priv
->root_visible
)))
1509 if (!gnode
&& expanded
) {
1510 ETreePath parent
= e_tree_model_node_get_parent (etta
->priv
->source_model
, path
);
1511 g_return_if_fail (parent
!= NULL
);
1512 e_tree_table_adapter_node_set_expanded (etta
, parent
, expanded
);
1513 gnode
= lookup_gnode (etta
, path
);
1515 g_return_if_fail (gnode
!= NULL
);
1517 node
= (node_t
*) gnode
->data
;
1519 if (expanded
== node
->expanded
)
1522 node
->expanded
= expanded
;
1524 row
= e_tree_table_adapter_row_of_node (etta
, path
);
1528 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1529 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1530 e_table_model_row_changed (E_TABLE_MODEL (etta
), row
);
1533 gint num_children
= insert_children (etta
, gnode
);
1534 update_child_counts (gnode
, num_children
);
1535 if (etta
->priv
->sort_info
&& e_table_sort_info_sorting_get_count (etta
->priv
->sort_info
) > 0)
1536 resort_node (etta
, gnode
, TRUE
);
1537 resize_map (etta
, etta
->priv
->n_map
+ num_children
);
1538 move_map_elements (etta
, row
+ 1 + num_children
, row
+ 1, etta
->priv
->n_map
- row
- 1 - num_children
);
1539 fill_map (etta
, row
, gnode
);
1540 if (num_children
!= 0) {
1541 e_table_model_rows_inserted (E_TABLE_MODEL (etta
), row
+ 1, num_children
);
1543 e_table_model_no_change (E_TABLE_MODEL (etta
));
1545 gint num_children
= delete_children (etta
, gnode
);
1546 if (num_children
== 0) {
1547 e_table_model_no_change (E_TABLE_MODEL (etta
));
1550 move_map_elements (etta
, row
+ 1, row
+ 1 + num_children
, etta
->priv
->n_map
- row
- 1 - num_children
);
1551 update_child_counts (gnode
, - num_children
);
1552 resize_map (etta
, etta
->priv
->n_map
- num_children
);
1553 e_table_model_rows_deleted (E_TABLE_MODEL (etta
), row
+ 1, num_children
);
1558 e_tree_table_adapter_node_set_expanded_recurse (ETreeTableAdapter
*etta
,
1564 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1566 e_tree_table_adapter_node_set_expanded (etta
, path
, expanded
);
1568 for (children
= e_tree_model_node_get_first_child (etta
->priv
->source_model
, path
);
1570 children
= e_tree_model_node_get_next (etta
->priv
->source_model
, children
)) {
1571 e_tree_table_adapter_node_set_expanded_recurse (etta
, children
, expanded
);
1576 e_tree_table_adapter_node_at_row (ETreeTableAdapter
*etta
,
1579 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1581 if (row
== -1 && etta
->priv
->n_map
> 0)
1582 row
= etta
->priv
->n_map
- 1;
1583 else if (row
< 0 || row
>= etta
->priv
->n_map
)
1586 return etta
->priv
->map_table
[row
]->path
;
1590 e_tree_table_adapter_row_of_node (ETreeTableAdapter
*etta
,
1595 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), -1);
1597 node
= get_node (etta
, path
);
1601 if (etta
->priv
->remap_needed
)
1602 remap_indices (etta
);
1608 e_tree_table_adapter_root_node_is_visible (ETreeTableAdapter
*etta
)
1610 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), FALSE
);
1612 return etta
->priv
->root_visible
;
1616 e_tree_table_adapter_show_node (ETreeTableAdapter
*etta
,
1621 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1623 parent
= e_tree_model_node_get_parent (etta
->priv
->source_model
, path
);
1626 e_tree_table_adapter_node_set_expanded (etta
, parent
, TRUE
);
1627 parent
= e_tree_model_node_get_parent (etta
->priv
->source_model
, parent
);
1632 e_tree_table_adapter_node_is_expanded (ETreeTableAdapter
*etta
,
1637 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), FALSE
);
1639 node
= get_node (etta
, path
);
1640 if (!e_tree_model_node_is_expandable (etta
->priv
->source_model
, path
) || !node
)
1643 return node
->expanded
;
1647 e_tree_table_adapter_node_get_next (ETreeTableAdapter
*etta
,
1652 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1654 node
= lookup_gnode (etta
, path
);
1656 if (node
&& node
->next
)
1657 return ((node_t
*) node
->next
->data
)->path
;