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
;
72 gint n_vals_allocated
;
77 guint root_visible
: 1;
78 guint remap_needed
: 1;
84 gint force_expanded_state
; /* use this instead of model's default if not 0; <0 ... collapse, >0 ... expand */
99 /* Forward Declarations */
100 static void e_tree_table_adapter_table_model_init
101 (ETableModelInterface
*iface
);
103 static guint signals
[LAST_SIGNAL
];
105 G_DEFINE_TYPE_WITH_CODE (
107 e_tree_table_adapter
,
109 G_IMPLEMENT_INTERFACE (
111 e_tree_table_adapter_table_model_init
))
114 lookup_gnode (ETreeTableAdapter
*etta
,
122 gnode
= g_hash_table_lookup (etta
->priv
->nodes
, path
);
128 resize_map (ETreeTableAdapter
*etta
,
131 if (size
> etta
->priv
->n_vals_allocated
) {
132 etta
->priv
->n_vals_allocated
= MAX (etta
->priv
->n_vals_allocated
+ INCREMENT_AMOUNT
, size
);
133 etta
->priv
->map_table
= g_renew (node_t
*, etta
->priv
->map_table
, etta
->priv
->n_vals_allocated
);
136 etta
->priv
->n_map
= size
;
140 move_map_elements (ETreeTableAdapter
*etta
,
145 if (count
<= 0 || from
>= etta
->priv
->n_map
)
147 memmove (etta
->priv
->map_table
+ to
, etta
->priv
->map_table
+ from
, count
* sizeof (node_t
*));
148 etta
->priv
->remap_needed
= TRUE
;
152 fill_map (ETreeTableAdapter
*etta
,
158 if ((gnode
!= etta
->priv
->root
) || etta
->priv
->root_visible
)
159 etta
->priv
->map_table
[index
++] = gnode
->data
;
161 for (p
= gnode
->children
; p
; p
= p
->next
)
162 index
= fill_map (etta
, index
, p
);
164 etta
->priv
->remap_needed
= TRUE
;
169 remap_indices (ETreeTableAdapter
*etta
)
172 for (i
= 0; i
< etta
->priv
->n_map
; i
++)
173 etta
->priv
->map_table
[i
]->index
= i
;
174 etta
->priv
->remap_needed
= FALSE
;
178 get_node (ETreeTableAdapter
*etta
,
181 GNode
*gnode
= lookup_gnode (etta
, path
);
186 return (node_t
*) gnode
->data
;
190 resort_node (ETreeTableAdapter
*etta
,
194 node_t
*node
= (node_t
*) gnode
->data
;
195 ETreePath
*paths
, path
;
198 gboolean sort_needed
;
200 if (node
->num_visible_children
== 0)
203 sort_needed
= etta
->priv
->sort_info
&& e_table_sort_info_sorting_get_count (etta
->priv
->sort_info
) > 0;
205 for (i
= 0, path
= e_tree_model_node_get_first_child (etta
->priv
->source_model
, node
->path
); path
;
206 path
= e_tree_model_node_get_next (etta
->priv
->source_model
, path
), i
++);
212 paths
= g_new0 (ETreePath
, count
);
214 for (i
= 0, path
= e_tree_model_node_get_first_child (etta
->priv
->source_model
, node
->path
); path
;
215 path
= e_tree_model_node_get_next (etta
->priv
->source_model
, path
), i
++)
218 if (count
> 1 && sort_needed
)
219 e_table_sorting_utils_tree_sort (etta
->priv
->source_model
, etta
->priv
->sort_info
, etta
->priv
->header
, paths
, count
);
222 for (i
= 0; i
< count
; i
++) {
223 curr
= lookup_gnode (etta
, paths
[i
]);
230 gnode
->children
= curr
;
236 resort_node (etta
, curr
, recurse
);
243 kill_gnode (GNode
*node
,
244 ETreeTableAdapter
*etta
)
246 g_hash_table_remove (etta
->priv
->nodes
, ((node_t
*) node
->data
)->path
);
248 while (node
->children
) {
249 GNode
*next
= node
->children
->next
;
250 kill_gnode (node
->children
, etta
);
251 node
->children
= next
;
255 if (node
== etta
->priv
->root
)
256 etta
->priv
->root
= NULL
;
257 g_node_destroy (node
);
261 update_child_counts (GNode
*gnode
,
265 node_t
*node
= (node_t
*) gnode
->data
;
266 node
->num_visible_children
+= delta
;
267 gnode
= gnode
->parent
;
272 delete_children (ETreeTableAdapter
*etta
,
275 node_t
*node
= (node_t
*) gnode
->data
;
276 gint to_remove
= node
? node
->num_visible_children
: 0;
281 while (gnode
->children
) {
282 GNode
*next
= gnode
->children
->next
;
283 kill_gnode (gnode
->children
, etta
);
284 gnode
->children
= next
;
291 delete_node (ETreeTableAdapter
*etta
,
296 gint parent_row
= e_tree_table_adapter_row_of_node (etta
, parent
);
297 gint row
= e_tree_table_adapter_row_of_node (etta
, path
);
298 GNode
*gnode
= lookup_gnode (etta
, path
);
299 GNode
*parent_gnode
= lookup_gnode (etta
, parent
);
301 e_table_model_pre_change (E_TABLE_MODEL (etta
));
304 e_table_model_no_change (E_TABLE_MODEL (etta
));
308 to_remove
+= delete_children (etta
, gnode
);
309 kill_gnode (gnode
, etta
);
311 move_map_elements (etta
, row
, row
+ to_remove
, etta
->priv
->n_map
- row
- to_remove
);
312 resize_map (etta
, etta
->priv
->n_map
- to_remove
);
314 if (parent_gnode
!= NULL
) {
315 node_t
*parent_node
= parent_gnode
->data
;
316 gboolean expandable
= e_tree_model_node_is_expandable (etta
->priv
->source_model
, parent
);
318 update_child_counts (parent_gnode
, - to_remove
);
319 if (parent_node
->expandable
!= expandable
) {
320 e_table_model_pre_change (E_TABLE_MODEL (etta
));
321 parent_node
->expandable
= expandable
;
322 e_table_model_row_changed (E_TABLE_MODEL (etta
), parent_row
);
325 resort_node (etta
, parent_gnode
, FALSE
);
328 e_table_model_rows_deleted (E_TABLE_MODEL (etta
), row
, to_remove
);
332 create_gnode (ETreeTableAdapter
*etta
,
338 node
= g_new0 (node_t
, 1);
341 node
->expanded
= etta
->priv
->force_expanded_state
== 0 ? e_tree_model_get_expanded_default (etta
->priv
->source_model
) : etta
->priv
->force_expanded_state
> 0;
342 node
->expandable
= e_tree_model_node_is_expandable (etta
->priv
->source_model
, path
);
343 node
->expandable_set
= 1;
344 node
->num_visible_children
= 0;
345 gnode
= g_node_new (node
);
346 g_hash_table_insert (etta
->priv
->nodes
, path
, gnode
);
351 insert_children (ETreeTableAdapter
*etta
,
358 path
= ((node_t
*) gnode
->data
)->path
;
359 for (tmp
= e_tree_model_node_get_first_child (etta
->priv
->source_model
, path
);
361 tmp
= e_tree_model_node_get_next (etta
->priv
->source_model
, tmp
), pos
++) {
362 GNode
*child
= create_gnode (etta
, tmp
);
363 node_t
*node
= (node_t
*) child
->data
;
365 node
->num_visible_children
= insert_children (etta
, child
);
366 g_node_prepend (gnode
, child
);
367 count
+= node
->num_visible_children
+ 1;
369 g_node_reverse_children (gnode
);
374 generate_tree (ETreeTableAdapter
*etta
,
381 e_table_model_pre_change (E_TABLE_MODEL (etta
));
383 g_return_if_fail (e_tree_model_node_is_root (etta
->priv
->source_model
, path
));
385 if (etta
->priv
->root
)
386 kill_gnode (etta
->priv
->root
, etta
);
387 resize_map (etta
, 0);
389 gnode
= create_gnode (etta
, path
);
390 node
= (node_t
*) gnode
->data
;
391 node
->expanded
= TRUE
;
392 node
->num_visible_children
= insert_children (etta
, gnode
);
393 if (etta
->priv
->sort_info
&& e_table_sort_info_sorting_get_count (etta
->priv
->sort_info
) > 0)
394 resort_node (etta
, gnode
, TRUE
);
396 etta
->priv
->root
= gnode
;
397 size
= etta
->priv
->root_visible
? node
->num_visible_children
+ 1 : node
->num_visible_children
;
398 resize_map (etta
, size
);
399 fill_map (etta
, 0, gnode
);
400 e_table_model_changed (E_TABLE_MODEL (etta
));
404 insert_node (ETreeTableAdapter
*etta
,
408 GNode
*gnode
, *parent_gnode
;
409 node_t
*node
, *parent_node
;
413 e_table_model_pre_change (E_TABLE_MODEL (etta
));
415 if (get_node (etta
, path
)) {
416 e_table_model_no_change (E_TABLE_MODEL (etta
));
420 parent_gnode
= lookup_gnode (etta
, parent
);
422 ETreePath grandparent
= e_tree_model_node_get_parent (etta
->priv
->source_model
, parent
);
423 if (e_tree_model_node_is_root (etta
->priv
->source_model
, parent
))
424 generate_tree (etta
, parent
);
426 insert_node (etta
, grandparent
, parent
);
427 e_table_model_changed (E_TABLE_MODEL (etta
));
431 parent_node
= (node_t
*) parent_gnode
->data
;
433 if (parent_gnode
!= etta
->priv
->root
) {
434 expandable
= e_tree_model_node_is_expandable (etta
->priv
->source_model
, parent
);
435 if (parent_node
->expandable
!= expandable
) {
436 e_table_model_pre_change (E_TABLE_MODEL (etta
));
437 parent_node
->expandable
= expandable
;
438 parent_node
->expandable_set
= 1;
439 e_table_model_row_changed (E_TABLE_MODEL (etta
), parent_node
->index
);
443 if (!e_tree_table_adapter_node_is_expanded (etta
, parent
)) {
444 e_table_model_no_change (E_TABLE_MODEL (etta
));
448 gnode
= create_gnode (etta
, path
);
449 node
= (node_t
*) gnode
->data
;
452 node
->num_visible_children
= insert_children (etta
, gnode
);
454 g_node_append (parent_gnode
, gnode
);
455 update_child_counts (parent_gnode
, node
->num_visible_children
+ 1);
456 resort_node (etta
, parent_gnode
, FALSE
);
457 resort_node (etta
, gnode
, TRUE
);
459 size
= node
->num_visible_children
+ 1;
460 resize_map (etta
, etta
->priv
->n_map
+ size
);
461 if (parent_gnode
== etta
->priv
->root
)
464 gint new_size
= parent_node
->num_visible_children
+ 1;
465 gint old_size
= new_size
- size
;
466 row
= parent_node
->index
;
467 move_map_elements (etta
, row
+ new_size
, row
+ old_size
, etta
->priv
->n_map
- row
- new_size
);
469 fill_map (etta
, row
, parent_gnode
);
470 e_table_model_rows_inserted (
471 E_TABLE_MODEL (etta
),
472 e_tree_table_adapter_row_of_node (etta
, path
), size
);
478 } check_expanded_closure
;
481 check_expanded (GNode
*gnode
,
484 check_expanded_closure
*closure
= (check_expanded_closure
*) data
;
485 node_t
*node
= (node_t
*) gnode
->data
;
487 if (node
->expanded
!= closure
->expanded
)
488 closure
->paths
= g_slist_prepend (closure
->paths
, node
->path
);
494 update_node (ETreeTableAdapter
*etta
,
497 check_expanded_closure closure
;
498 ETreePath parent
= e_tree_model_node_get_parent (etta
->priv
->source_model
, path
);
499 GNode
*gnode
= lookup_gnode (etta
, path
);
502 closure
.expanded
= e_tree_model_get_expanded_default (etta
->priv
->source_model
);
503 closure
.paths
= NULL
;
506 g_node_traverse (gnode
, G_POST_ORDER
, G_TRAVERSE_ALL
, -1, check_expanded
, &closure
);
508 if (e_tree_model_node_is_root (etta
->priv
->source_model
, path
))
509 generate_tree (etta
, path
);
511 delete_node (etta
, parent
, path
);
512 insert_node (etta
, parent
, path
);
515 for (l
= closure
.paths
; l
; l
= l
->next
)
516 if (lookup_gnode (etta
, l
->data
))
517 e_tree_table_adapter_node_set_expanded (etta
, l
->data
, !closure
.expanded
);
519 g_slist_free (closure
.paths
);
523 tree_table_adapter_sort_info_changed_cb (ETableSortInfo
*sort_info
,
524 ETreeTableAdapter
*etta
)
526 if (!etta
->priv
->root
)
529 /* the function is called also internally, with sort_info = NULL,
530 * thus skip those in signal emit */
532 gboolean handled
= FALSE
;
534 g_signal_emit (etta
, signals
[SORTING_CHANGED
], 0, &handled
);
540 e_table_model_pre_change (E_TABLE_MODEL (etta
));
541 resort_node (etta
, etta
->priv
->root
, TRUE
);
542 fill_map (etta
, 0, etta
->priv
->root
);
543 e_table_model_changed (E_TABLE_MODEL (etta
));
547 tree_table_adapter_source_model_pre_change_cb (ETreeModel
*source_model
,
548 ETreeTableAdapter
*etta
)
550 e_table_model_pre_change (E_TABLE_MODEL (etta
));
554 tree_table_adapter_source_model_rebuilt_cb (ETreeModel
*source_model
,
555 ETreeTableAdapter
*etta
)
557 if (!etta
->priv
->root
)
560 kill_gnode (etta
->priv
->root
, etta
);
561 etta
->priv
->root
= NULL
;
563 g_hash_table_remove_all (etta
->priv
->nodes
);
567 tree_table_adapter_resort_model_idle_cb (gpointer user_data
)
569 ETreeTableAdapter
*etta
;
571 etta
= E_TREE_TABLE_ADAPTER (user_data
);
572 tree_table_adapter_sort_info_changed_cb (NULL
, etta
);
573 etta
->priv
->resort_idle_id
= 0;
579 tree_table_adapter_source_model_node_changed_cb (ETreeModel
*source_model
,
581 ETreeTableAdapter
*etta
)
583 update_node (etta
, path
);
584 e_table_model_changed (E_TABLE_MODEL (etta
));
586 /* FIXME: Really it shouldnt be required. But a lot of thread
587 * which were supposed to be present in the list is way below
589 if (etta
->priv
->resort_idle_id
== 0)
590 etta
->priv
->resort_idle_id
= g_idle_add (
591 tree_table_adapter_resort_model_idle_cb
, etta
);
595 tree_table_adapter_source_model_node_data_changed_cb (ETreeModel
*source_model
,
597 ETreeTableAdapter
*etta
)
599 gint row
= e_tree_table_adapter_row_of_node (etta
, path
);
602 e_table_model_no_change (E_TABLE_MODEL (etta
));
606 e_table_model_row_changed (E_TABLE_MODEL (etta
), row
);
610 tree_table_adapter_source_model_node_inserted_cb (ETreeModel
*etm
,
613 ETreeTableAdapter
*etta
)
615 if (e_tree_model_node_is_root (etm
, child
))
616 generate_tree (etta
, child
);
618 insert_node (etta
, parent
, child
);
620 e_table_model_changed (E_TABLE_MODEL (etta
));
624 tree_table_adapter_source_model_node_removed_cb (ETreeModel
*etm
,
628 ETreeTableAdapter
*etta
)
630 delete_node (etta
, parent
, child
);
631 e_table_model_changed (E_TABLE_MODEL (etta
));
635 tree_table_adapter_set_header (ETreeTableAdapter
*etta
,
636 ETableHeader
*header
)
641 g_return_if_fail (E_IS_TABLE_HEADER (header
));
642 g_return_if_fail (etta
->priv
->header
== NULL
);
644 etta
->priv
->header
= g_object_ref (header
);
648 tree_table_adapter_set_source_model (ETreeTableAdapter
*etta
,
649 ETreeModel
*source_model
)
651 g_return_if_fail (E_IS_TREE_MODEL (source_model
));
652 g_return_if_fail (etta
->priv
->source_model
== NULL
);
654 etta
->priv
->source_model
= g_object_ref (source_model
);
658 tree_table_adapter_set_property (GObject
*object
,
663 switch (property_id
) {
665 tree_table_adapter_set_header (
666 E_TREE_TABLE_ADAPTER (object
),
667 g_value_get_object (value
));
671 e_tree_table_adapter_set_sort_info (
672 E_TREE_TABLE_ADAPTER (object
),
673 g_value_get_object (value
));
676 case PROP_SOURCE_MODEL
:
677 tree_table_adapter_set_source_model (
678 E_TREE_TABLE_ADAPTER (object
),
679 g_value_get_object (value
));
683 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
687 tree_table_adapter_get_property (GObject
*object
,
692 switch (property_id
) {
696 e_tree_table_adapter_get_header (
697 E_TREE_TABLE_ADAPTER (object
)));
703 e_tree_table_adapter_get_sort_info (
704 E_TREE_TABLE_ADAPTER (object
)));
707 case PROP_SOURCE_MODEL
:
710 e_tree_table_adapter_get_source_model (
711 E_TREE_TABLE_ADAPTER (object
)));
715 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
719 tree_table_adapter_dispose (GObject
*object
)
721 ETreeTableAdapterPrivate
*priv
;
723 priv
= E_TREE_TABLE_ADAPTER_GET_PRIVATE (object
);
725 if (priv
->pre_change_handler_id
> 0) {
726 g_signal_handler_disconnect (
728 priv
->pre_change_handler_id
);
729 priv
->pre_change_handler_id
= 0;
732 if (priv
->rebuilt_handler_id
> 0) {
733 g_signal_handler_disconnect (
735 priv
->rebuilt_handler_id
);
736 priv
->rebuilt_handler_id
= 0;
739 if (priv
->node_changed_handler_id
> 0) {
740 g_signal_handler_disconnect (
742 priv
->node_changed_handler_id
);
743 priv
->node_changed_handler_id
= 0;
746 if (priv
->node_data_changed_handler_id
> 0) {
747 g_signal_handler_disconnect (
749 priv
->node_data_changed_handler_id
);
750 priv
->node_data_changed_handler_id
= 0;
753 if (priv
->node_inserted_handler_id
> 0) {
754 g_signal_handler_disconnect (
756 priv
->node_inserted_handler_id
);
757 priv
->node_inserted_handler_id
= 0;
760 if (priv
->node_removed_handler_id
> 0) {
761 g_signal_handler_disconnect (
763 priv
->node_removed_handler_id
);
764 priv
->node_removed_handler_id
= 0;
767 if (priv
->sort_info_changed_handler_id
> 0) {
768 g_signal_handler_disconnect (
770 priv
->sort_info_changed_handler_id
);
771 priv
->sort_info_changed_handler_id
= 0;
774 g_clear_object (&priv
->source_model
);
775 g_clear_object (&priv
->sort_info
);
776 g_clear_object (&priv
->header
);
778 /* Chain up to parent's dispose() method. */
779 G_OBJECT_CLASS (e_tree_table_adapter_parent_class
)->dispose (object
);
783 tree_table_adapter_finalize (GObject
*object
)
785 ETreeTableAdapterPrivate
*priv
;
787 priv
= E_TREE_TABLE_ADAPTER_GET_PRIVATE (object
);
789 if (priv
->resort_idle_id
) {
790 g_source_remove (priv
->resort_idle_id
);
791 priv
->resort_idle_id
= 0;
795 kill_gnode (priv
->root
, E_TREE_TABLE_ADAPTER (object
));
799 g_hash_table_destroy (priv
->nodes
);
801 g_free (priv
->map_table
);
803 /* Chain up to parent's finalize() method. */
804 G_OBJECT_CLASS (e_tree_table_adapter_parent_class
)->finalize (object
);
808 tree_table_adapter_constructed (GObject
*object
)
810 ETreeTableAdapter
*etta
;
811 ETreeModel
*source_model
;
815 etta
= E_TREE_TABLE_ADAPTER (object
);
817 /* Chain up to parent's constructed() method. */
818 G_OBJECT_CLASS (e_tree_table_adapter_parent_class
)->constructed (object
);
820 source_model
= e_tree_table_adapter_get_source_model (etta
);
822 root
= e_tree_model_get_root (source_model
);
824 generate_tree (etta
, root
);
826 handler_id
= g_signal_connect (
827 source_model
, "pre_change",
828 G_CALLBACK (tree_table_adapter_source_model_pre_change_cb
),
830 etta
->priv
->pre_change_handler_id
= handler_id
;
832 handler_id
= g_signal_connect (
833 source_model
, "rebuilt",
834 G_CALLBACK (tree_table_adapter_source_model_rebuilt_cb
),
836 etta
->priv
->rebuilt_handler_id
= handler_id
;
838 handler_id
= g_signal_connect (
839 source_model
, "node_changed",
840 G_CALLBACK (tree_table_adapter_source_model_node_changed_cb
),
842 etta
->priv
->node_changed_handler_id
= handler_id
;
844 handler_id
= g_signal_connect (
845 source_model
, "node_data_changed",
846 G_CALLBACK (tree_table_adapter_source_model_node_data_changed_cb
),
848 etta
->priv
->node_data_changed_handler_id
= handler_id
;
850 handler_id
= g_signal_connect (
851 source_model
, "node_inserted",
852 G_CALLBACK (tree_table_adapter_source_model_node_inserted_cb
),
854 etta
->priv
->node_inserted_handler_id
= handler_id
;
856 handler_id
= g_signal_connect (
857 source_model
, "node_removed",
858 G_CALLBACK (tree_table_adapter_source_model_node_removed_cb
),
860 etta
->priv
->node_removed_handler_id
= handler_id
;
864 tree_table_adapter_column_count (ETableModel
*etm
)
866 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
868 return e_tree_model_column_count (etta
->priv
->source_model
);
872 tree_table_adapter_has_save_id (ETableModel
*etm
)
878 tree_table_adapter_get_save_id (ETableModel
*etm
,
881 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
883 return e_tree_model_get_save_id (
884 etta
->priv
->source_model
,
885 e_tree_table_adapter_node_at_row (etta
, row
));
889 tree_table_adapter_row_count (ETableModel
*etm
)
891 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
893 return etta
->priv
->n_map
;
897 tree_table_adapter_value_at (ETableModel
*etm
,
901 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
907 return e_tree_table_adapter_node_at_row (etta
, row
);
909 return etta
->priv
->source_model
;
913 return e_tree_model_value_at (
914 etta
->priv
->source_model
,
915 e_tree_table_adapter_node_at_row (etta
, row
), col
);
920 tree_table_adapter_set_value_at (ETableModel
*etm
,
925 g_warn_if_reached ();
929 tree_table_adapter_is_cell_editable (ETableModel
*etm
,
937 tree_table_adapter_append_row (ETableModel
*etm
,
944 tree_table_adapter_duplicate_value (ETableModel
*etm
,
948 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
950 return e_tree_model_duplicate_value (etta
->priv
->source_model
, col
, value
);
954 tree_table_adapter_free_value (ETableModel
*etm
,
958 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
960 e_tree_model_free_value (etta
->priv
->source_model
, col
, value
);
964 tree_table_adapter_initialize_value (ETableModel
*etm
,
967 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
969 return e_tree_model_initialize_value (etta
->priv
->source_model
, col
);
973 tree_table_adapter_value_is_empty (ETableModel
*etm
,
977 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
979 return e_tree_model_value_is_empty (etta
->priv
->source_model
, col
, value
);
983 tree_table_adapter_value_to_string (ETableModel
*etm
,
987 ETreeTableAdapter
*etta
= (ETreeTableAdapter
*) etm
;
989 return e_tree_model_value_to_string (etta
->priv
->source_model
, col
, value
);
993 e_tree_table_adapter_class_init (ETreeTableAdapterClass
*class)
995 GObjectClass
*object_class
;
997 g_type_class_add_private (class, sizeof (ETreeTableAdapterPrivate
));
999 object_class
= G_OBJECT_CLASS (class);
1000 object_class
->set_property
= tree_table_adapter_set_property
;
1001 object_class
->get_property
= tree_table_adapter_get_property
;
1002 object_class
->dispose
= tree_table_adapter_dispose
;
1003 object_class
->finalize
= tree_table_adapter_finalize
;
1004 object_class
->constructed
= tree_table_adapter_constructed
;
1006 g_object_class_install_property (
1009 g_param_spec_object (
1013 E_TYPE_TABLE_HEADER
,
1015 G_PARAM_CONSTRUCT_ONLY
|
1016 G_PARAM_STATIC_STRINGS
));
1018 g_object_class_install_property (
1021 g_param_spec_object (
1025 E_TYPE_TABLE_SORT_INFO
,
1028 G_PARAM_STATIC_STRINGS
));
1030 g_object_class_install_property (
1033 g_param_spec_object (
1039 G_PARAM_CONSTRUCT_ONLY
|
1040 G_PARAM_STATIC_STRINGS
));
1042 signals
[SORTING_CHANGED
] = g_signal_new (
1044 G_OBJECT_CLASS_TYPE (object_class
),
1046 G_STRUCT_OFFSET (ETreeTableAdapterClass
, sorting_changed
),
1048 e_marshal_BOOLEAN__NONE
,
1054 e_tree_table_adapter_table_model_init (ETableModelInterface
*iface
)
1056 iface
->column_count
= tree_table_adapter_column_count
;
1057 iface
->row_count
= tree_table_adapter_row_count
;
1058 iface
->append_row
= tree_table_adapter_append_row
;
1060 iface
->value_at
= tree_table_adapter_value_at
;
1061 iface
->set_value_at
= tree_table_adapter_set_value_at
;
1062 iface
->is_cell_editable
= tree_table_adapter_is_cell_editable
;
1064 iface
->has_save_id
= tree_table_adapter_has_save_id
;
1065 iface
->get_save_id
= tree_table_adapter_get_save_id
;
1067 iface
->duplicate_value
= tree_table_adapter_duplicate_value
;
1068 iface
->free_value
= tree_table_adapter_free_value
;
1069 iface
->initialize_value
= tree_table_adapter_initialize_value
;
1070 iface
->value_is_empty
= tree_table_adapter_value_is_empty
;
1071 iface
->value_to_string
= tree_table_adapter_value_to_string
;
1075 e_tree_table_adapter_init (ETreeTableAdapter
*etta
)
1077 etta
->priv
= E_TREE_TABLE_ADAPTER_GET_PRIVATE (etta
);
1079 etta
->priv
->nodes
= g_hash_table_new (NULL
, NULL
);
1081 etta
->priv
->root_visible
= TRUE
;
1082 etta
->priv
->remap_needed
= TRUE
;
1086 e_tree_table_adapter_new (ETreeModel
*source_model
,
1087 ETableSortInfo
*sort_info
,
1088 ETableHeader
*header
)
1090 g_return_val_if_fail (E_IS_TREE_MODEL (source_model
), NULL
);
1092 if (sort_info
!= NULL
)
1093 g_return_val_if_fail (E_IS_TABLE_SORT_INFO (sort_info
), NULL
);
1096 g_return_val_if_fail (E_IS_TABLE_HEADER (header
), NULL
);
1098 return g_object_new (
1099 E_TYPE_TREE_TABLE_ADAPTER
,
1100 "source-model", source_model
,
1101 "sort-info", sort_info
,
1107 e_tree_table_adapter_get_header (ETreeTableAdapter
*etta
)
1109 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1111 return etta
->priv
->header
;
1115 e_tree_table_adapter_get_sort_info (ETreeTableAdapter
*etta
)
1117 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1119 return etta
->priv
->sort_info
;
1123 e_tree_table_adapter_set_sort_info (ETreeTableAdapter
*etta
,
1124 ETableSortInfo
*sort_info
)
1126 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1128 if (sort_info
!= NULL
) {
1129 g_return_if_fail (E_IS_TABLE_SORT_INFO (sort_info
));
1130 g_object_ref (sort_info
);
1133 if (etta
->priv
->sort_info
!= NULL
) {
1134 g_signal_handler_disconnect (
1135 etta
->priv
->sort_info
,
1136 etta
->priv
->sort_info_changed_handler_id
);
1137 etta
->priv
->sort_info_changed_handler_id
= 0;
1139 g_clear_object (&etta
->priv
->sort_info
);
1142 etta
->priv
->sort_info
= sort_info
;
1144 if (etta
->priv
->sort_info
!= NULL
) {
1147 handler_id
= g_signal_connect (
1148 etta
->priv
->sort_info
, "sort_info_changed",
1149 G_CALLBACK (tree_table_adapter_sort_info_changed_cb
),
1151 etta
->priv
->sort_info_changed_handler_id
= handler_id
;
1154 g_object_notify (G_OBJECT (etta
), "sort-info");
1156 if (etta
->priv
->root
== NULL
)
1159 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1160 resort_node (etta
, etta
->priv
->root
, TRUE
);
1161 fill_map (etta
, 0, etta
->priv
->root
);
1162 e_table_model_changed (E_TABLE_MODEL (etta
));
1166 e_tree_table_adapter_get_source_model (ETreeTableAdapter
*etta
)
1168 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1170 return etta
->priv
->source_model
;
1175 gboolean expanded_default
;
1180 save_expanded_state_func (gpointer keyp
,
1184 ETreePath path
= keyp
;
1185 node_t
*node
= ((GNode
*) value
)->data
;
1186 TreeAndRoot
*tar
= data
;
1189 if (node
->expanded
!= tar
->expanded_default
) {
1190 gchar
*save_id
= e_tree_model_get_save_id (tar
->model
, path
);
1191 xmlnode
= xmlNewChild (tar
->root
, NULL
, (const guchar
*)"node", NULL
);
1192 e_xml_set_string_prop_by_name (xmlnode
, (const guchar
*)"id", save_id
);
1198 e_tree_table_adapter_save_expanded_state_xml (ETreeTableAdapter
*etta
)
1204 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1206 doc
= xmlNewDoc ((const guchar
*)"1.0");
1207 root
= xmlNewDocNode (doc
, NULL
, (const guchar
*)"expanded_state", NULL
);
1208 xmlDocSetRootElement (doc
, root
);
1210 tar
.model
= etta
->priv
->source_model
;
1212 tar
.expanded_default
= e_tree_model_get_expanded_default (etta
->priv
->source_model
);
1214 e_xml_set_integer_prop_by_name (root
, (const guchar
*)"vers", 2);
1215 e_xml_set_bool_prop_by_name (root
, (const guchar
*)"default", tar
.expanded_default
);
1217 g_hash_table_foreach (etta
->priv
->nodes
, save_expanded_state_func
, &tar
);
1223 e_tree_table_adapter_save_expanded_state (ETreeTableAdapter
*etta
,
1224 const gchar
*filename
)
1228 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1230 doc
= e_tree_table_adapter_save_expanded_state_xml (etta
);
1232 e_xml_save_file (filename
, doc
);
1238 open_file (ETreeTableAdapter
*etta
,
1239 const gchar
*filename
)
1244 gboolean model_default
, saved_default
;
1246 if (!g_file_test (filename
, G_FILE_TEST_EXISTS
))
1251 gchar
*locale_filename
= g_win32_locale_filename_from_utf8 (filename
);
1252 doc
= xmlParseFile (locale_filename
);
1253 g_free (locale_filename
);
1256 doc
= xmlParseFile (filename
);
1262 root
= xmlDocGetRootElement (doc
);
1263 if (root
== NULL
|| strcmp ((gchar
*) root
->name
, "expanded_state")) {
1268 vers
= e_xml_get_integer_prop_by_name_with_default (root
, (const guchar
*)"vers", 0);
1273 model_default
= e_tree_model_get_expanded_default (etta
->priv
->source_model
);
1274 saved_default
= e_xml_get_bool_prop_by_name_with_default (root
, (const guchar
*)"default", !model_default
);
1275 if (saved_default
!= model_default
) {
1283 /* state: <0 ... collapse; 0 ... use default; >0 ... expand */
1285 e_tree_table_adapter_force_expanded_state (ETreeTableAdapter
*etta
,
1288 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1290 etta
->priv
->force_expanded_state
= state
;
1294 e_tree_table_adapter_load_expanded_state_xml (ETreeTableAdapter
*etta
,
1297 xmlNode
*root
, *child
;
1298 gboolean model_default
;
1299 gboolean file_default
= FALSE
;
1301 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1302 g_return_if_fail (doc
!= NULL
);
1304 root
= xmlDocGetRootElement (doc
);
1306 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1308 model_default
= e_tree_model_get_expanded_default (etta
->priv
->source_model
);
1310 if (!strcmp ((gchar
*) root
->name
, "expanded_state")) {
1313 state
= e_xml_get_string_prop_by_name_with_default (root
, (const guchar
*)"default", "");
1315 if (state
[0] == 't')
1316 file_default
= TRUE
;
1318 file_default
= FALSE
; /* Even unspecified we'll consider as false */
1323 /* Incase the default is changed, lets forget the changes and stick to default */
1325 if (file_default
!= model_default
) {
1330 for (child
= root
->xmlChildrenNode
; child
; child
= child
->next
) {
1334 if (strcmp ((gchar
*) child
->name
, "node")) {
1335 d (g_warning ("unknown node '%s' in %s", child
->name
, filename
));
1339 id
= e_xml_get_string_prop_by_name_with_default (child
, (const guchar
*)"id", "");
1341 if (!strcmp (id
, "")) {
1346 path
= e_tree_model_get_node_by_id (etta
->priv
->source_model
, id
);
1348 e_tree_table_adapter_node_set_expanded (etta
, path
, !model_default
);
1353 e_table_model_changed (E_TABLE_MODEL (etta
));
1357 e_tree_table_adapter_load_expanded_state (ETreeTableAdapter
*etta
,
1358 const gchar
*filename
)
1362 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1364 doc
= open_file (etta
, filename
);
1368 e_tree_table_adapter_load_expanded_state_xml (etta
, doc
);
1374 e_tree_table_adapter_root_node_set_visible (ETreeTableAdapter
*etta
,
1379 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1381 if (etta
->priv
->root_visible
== visible
)
1384 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1386 etta
->priv
->root_visible
= visible
;
1388 ETreePath root
= e_tree_model_get_root (etta
->priv
->source_model
);
1390 e_tree_table_adapter_node_set_expanded (etta
, root
, TRUE
);
1392 size
= (visible
? 1 : 0) + (etta
->priv
->root
? ((node_t
*) etta
->priv
->root
->data
)->num_visible_children
: 0);
1393 resize_map (etta
, size
);
1394 if (etta
->priv
->root
)
1395 fill_map (etta
, 0, etta
->priv
->root
);
1396 e_table_model_changed (E_TABLE_MODEL (etta
));
1400 e_tree_table_adapter_node_set_expanded (ETreeTableAdapter
*etta
,
1408 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1410 gnode
= lookup_gnode (etta
, path
);
1412 if (!expanded
&& (!gnode
|| (e_tree_model_node_is_root (etta
->priv
->source_model
, path
) && !etta
->priv
->root_visible
)))
1415 if (!gnode
&& expanded
) {
1416 ETreePath parent
= e_tree_model_node_get_parent (etta
->priv
->source_model
, path
);
1417 g_return_if_fail (parent
!= NULL
);
1418 e_tree_table_adapter_node_set_expanded (etta
, parent
, expanded
);
1419 gnode
= lookup_gnode (etta
, path
);
1421 g_return_if_fail (gnode
!= NULL
);
1423 node
= (node_t
*) gnode
->data
;
1425 if (expanded
== node
->expanded
)
1428 node
->expanded
= expanded
;
1430 row
= e_tree_table_adapter_row_of_node (etta
, path
);
1434 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1435 e_table_model_pre_change (E_TABLE_MODEL (etta
));
1436 e_table_model_row_changed (E_TABLE_MODEL (etta
), row
);
1439 gint num_children
= insert_children (etta
, gnode
);
1440 update_child_counts (gnode
, num_children
);
1441 if (etta
->priv
->sort_info
&& e_table_sort_info_sorting_get_count (etta
->priv
->sort_info
) > 0)
1442 resort_node (etta
, gnode
, TRUE
);
1443 resize_map (etta
, etta
->priv
->n_map
+ num_children
);
1444 move_map_elements (etta
, row
+ 1 + num_children
, row
+ 1, etta
->priv
->n_map
- row
- 1 - num_children
);
1445 fill_map (etta
, row
, gnode
);
1446 if (num_children
!= 0) {
1447 e_table_model_rows_inserted (E_TABLE_MODEL (etta
), row
+ 1, num_children
);
1449 e_table_model_no_change (E_TABLE_MODEL (etta
));
1451 gint num_children
= delete_children (etta
, gnode
);
1452 if (num_children
== 0) {
1453 e_table_model_no_change (E_TABLE_MODEL (etta
));
1456 move_map_elements (etta
, row
+ 1, row
+ 1 + num_children
, etta
->priv
->n_map
- row
- 1 - num_children
);
1457 update_child_counts (gnode
, - num_children
);
1458 resize_map (etta
, etta
->priv
->n_map
- num_children
);
1459 e_table_model_rows_deleted (E_TABLE_MODEL (etta
), row
+ 1, num_children
);
1464 e_tree_table_adapter_node_set_expanded_recurse (ETreeTableAdapter
*etta
,
1470 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1472 e_tree_table_adapter_node_set_expanded (etta
, path
, expanded
);
1474 for (children
= e_tree_model_node_get_first_child (etta
->priv
->source_model
, path
);
1476 children
= e_tree_model_node_get_next (etta
->priv
->source_model
, children
)) {
1477 e_tree_table_adapter_node_set_expanded_recurse (etta
, children
, expanded
);
1482 e_tree_table_adapter_node_at_row (ETreeTableAdapter
*etta
,
1485 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1487 if (row
== -1 && etta
->priv
->n_map
> 0)
1488 row
= etta
->priv
->n_map
- 1;
1489 else if (row
< 0 || row
>= etta
->priv
->n_map
)
1492 return etta
->priv
->map_table
[row
]->path
;
1496 e_tree_table_adapter_row_of_node (ETreeTableAdapter
*etta
,
1501 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), -1);
1503 node
= get_node (etta
, path
);
1507 if (etta
->priv
->remap_needed
)
1508 remap_indices (etta
);
1514 e_tree_table_adapter_root_node_is_visible (ETreeTableAdapter
*etta
)
1516 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), FALSE
);
1518 return etta
->priv
->root_visible
;
1522 e_tree_table_adapter_show_node (ETreeTableAdapter
*etta
,
1527 g_return_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
));
1529 parent
= e_tree_model_node_get_parent (etta
->priv
->source_model
, path
);
1532 e_tree_table_adapter_node_set_expanded (etta
, parent
, TRUE
);
1533 parent
= e_tree_model_node_get_parent (etta
->priv
->source_model
, parent
);
1538 e_tree_table_adapter_node_is_expanded (ETreeTableAdapter
*etta
,
1543 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), FALSE
);
1545 node
= get_node (etta
, path
);
1546 if (!e_tree_model_node_is_expandable (etta
->priv
->source_model
, path
) || !node
)
1549 return node
->expanded
;
1553 e_tree_table_adapter_node_get_next (ETreeTableAdapter
*etta
,
1558 g_return_val_if_fail (E_IS_TREE_TABLE_ADAPTER (etta
), NULL
);
1560 node
= lookup_gnode (etta
, path
);
1562 if (node
&& node
->next
)
1563 return ((node_t
*) node
->next
->data
)->path
;