No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Chris Lahey <clahey@ximian.com>
18 * Chris Toshok <toshok@ximian.com>
19 *
20 * Adapted from the gtree code and ETableModel.
21 *
22 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
23 *
24 */
25
26 /* FIXME: Overall e-tree-sorted.c needs to be made more efficient. */
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #include <stdio.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <string.h>
38
39 #include <libxml/parser.h>
40 #include <libxml/xmlmemory.h>
41
42 #include "e-util/e-util.h"
43 #include "libevolution-utils/e-xml-utils.h"
44
45 #include "e-table-sorting-utils.h"
46 #include "e-tree-sorted.h"
47
48 /* maximum insertions between an idle event that we will do without scheduling an idle sort */
49 #define ETS_INSERT_MAX (4)
50
51 #define d(x)
52
53 #define E_TREE_SORTED_GET_PRIVATE(obj) \
54 (G_TYPE_INSTANCE_GET_PRIVATE \
55 ((obj), E_TYPE_TREE_SORTED, ETreeSortedPrivate))
56
57 G_DEFINE_TYPE (ETreeSorted, e_tree_sorted, E_TYPE_TREE_MODEL)
58
59 enum {
60 NODE_RESORTED,
61 LAST_SIGNAL
62 };
63
64 static guint signals[LAST_SIGNAL] = {0, };
65
66 typedef struct ETreeSortedPath ETreeSortedPath;
67
68 struct ETreeSortedPath {
69 ETreePath corresponding;
70
71 /* parent/child/sibling pointers */
72 ETreeSortedPath *parent;
73 gint num_children;
74 ETreeSortedPath **children;
75 gint position;
76 gint orig_position;
77
78 guint needs_resort : 1;
79 guint child_needs_resort : 1;
80 guint resort_all_children : 1;
81 guint needs_regen_to_sort : 1;
82 };
83
84 struct _ETreeSortedPrivate {
85 ETreeModel *source;
86 ETreeSortedPath *root;
87
88 ETableSortInfo *sort_info;
89 ETableHeader *full_header;
90
91 ETreeSortedPath *last_access;
92
93 gint tree_model_pre_change_id;
94 gint tree_model_no_change_id;
95 gint tree_model_node_changed_id;
96 gint tree_model_node_data_changed_id;
97 gint tree_model_node_col_changed_id;
98 gint tree_model_node_inserted_id;
99 gint tree_model_node_removed_id;
100 gint tree_model_node_deleted_id;
101 gint tree_model_node_request_collapse_id;
102
103 gint sort_info_changed_id;
104 gint sort_idle_id;
105 gint insert_idle_id;
106 gint insert_count;
107
108 guint in_resort_idle : 1;
109 guint nested_resort_idle : 1;
110 };
111
112 enum {
113 ARG_0,
114
115 ARG_SORT_INFO
116 };
117
118 static void ets_sort_info_changed (ETableSortInfo *sort_info, ETreeSorted *ets);
119 static void resort_node (ETreeSorted *ets, ETreeSortedPath *path, gboolean resort_all_children, gboolean needs_regen, gboolean send_signals);
120 static void mark_path_needs_resort (ETreeSorted *ets, ETreeSortedPath *path, gboolean needs_rebuild, gboolean resort_all_children);
121 static void schedule_resort (ETreeSorted *ets, ETreeSortedPath *path, gboolean needs_regen, gboolean resort_all_children);
122 static void free_path (ETreeSortedPath *path);
123 static void generate_children (ETreeSorted *ets, ETreeSortedPath *path);
124 static void regenerate_children (ETreeSorted *ets, ETreeSortedPath *path);
125
126 /* idle callbacks */
127
128 static gboolean
129 ets_sort_idle (gpointer user_data)
130 {
131 ETreeSorted *ets = user_data;
132 if (ets->priv->in_resort_idle) {
133 ets->priv->nested_resort_idle = TRUE;
134 return FALSE;
135 }
136 ets->priv->in_resort_idle = TRUE;
137 if (ets->priv->root) {
138 do {
139 ets->priv->nested_resort_idle = FALSE;
140 resort_node (ets, ets->priv->root, FALSE, FALSE, TRUE);
141 } while (ets->priv->nested_resort_idle);
142 }
143 ets->priv->in_resort_idle = FALSE;
144 ets->priv->sort_idle_id = 0;
145 return FALSE;
146 }
147
148 #define ETS_SORT_IDLE_ACTIVATED(ets) ((ets)->priv->sort_idle_id != 0)
149
150 inline static void
151 ets_stop_sort_idle (ETreeSorted *ets)
152 {
153 if (ets->priv->sort_idle_id) {
154 g_source_remove (ets->priv->sort_idle_id);
155 ets->priv->sort_idle_id = 0;
156 }
157 }
158
159 static gboolean
160 ets_insert_idle (ETreeSorted *ets)
161 {
162 ets->priv->insert_count = 0;
163 ets->priv->insert_idle_id = 0;
164 return FALSE;
165 }
166
167 /* Helper functions */
168
169 #define CHECK_AROUND_LAST_ACCESS
170
171 static inline ETreeSortedPath *
172 check_last_access (ETreeSorted *ets,
173 ETreePath corresponding)
174 {
175 #ifdef CHECK_AROUND_LAST_ACCESS
176 ETreeSortedPath *parent;
177 #endif
178
179 if (ets->priv->last_access == NULL)
180 return NULL;
181
182 if (ets->priv->last_access == corresponding) {
183 d (g_print ("Found last access %p at %p.", ets->priv->last_access, ets->priv->last_access));
184 return ets->priv->last_access;
185 }
186
187 #ifdef CHECK_AROUND_LAST_ACCESS
188 parent = ets->priv->last_access->parent;
189 if (parent && parent->children) {
190 gint position = ets->priv->last_access->position;
191 gint end = MIN (parent->num_children, position + 10);
192 gint start = MAX (0, position - 10);
193 gint initial = MAX (MIN (position, end), start);
194 gint i;
195
196 for (i = initial; i < end; i++) {
197 if (parent->children[i] && parent->children[i]->corresponding == corresponding) {
198 d (g_print ("Found last access %p at %p.", ets->priv->last_access, parent->children[i]));
199 return parent->children[i];
200 }
201 }
202
203 for (i = initial - 1; i >= start; i--) {
204 if (parent->children[i] && parent->children[i]->corresponding == corresponding) {
205 d (g_print ("Found last access %p at %p.", ets->priv->last_access, parent->children[i]));
206 return parent->children[i];
207 }
208 }
209 }
210 #endif
211 return NULL;
212 }
213
214 static ETreeSortedPath *
215 find_path (ETreeSorted *ets,
216 ETreePath corresponding)
217 {
218 gint depth;
219 ETreePath *sequence;
220 gint i;
221 ETreeSortedPath *path;
222 ETreeSortedPath *check_last;
223
224 if (corresponding == NULL)
225 return NULL;
226
227 check_last = check_last_access (ets, corresponding);
228 if (check_last) {
229 d (g_print (" (find_path)\n"));
230 return check_last;
231 }
232
233 depth = e_tree_model_node_depth (ets->priv->source, corresponding);
234
235 sequence = g_new (ETreePath, depth + 1);
236
237 sequence[0] = corresponding;
238
239 for (i = 0; i < depth; i++)
240 sequence[i + 1] = e_tree_model_node_get_parent (ets->priv->source, sequence[i]);
241
242 path = ets->priv->root;
243
244 for (i = depth - 1; i >= 0 && path != NULL; i--) {
245 gint j;
246
247 if (path->num_children == -1) {
248 path = NULL;
249 break;
250 }
251
252 for (j = 0; j < path->num_children; j++) {
253 if (path->children[j]->corresponding == sequence[i]) {
254 break;
255 }
256 }
257
258 if (j < path->num_children) {
259 path = path->children[j];
260 } else {
261 path = NULL;
262 }
263 }
264 g_free (sequence);
265
266 d (g_print ("Didn't find last access %p. Setting to %p. (find_path)\n", ets->priv->last_access, path));
267 ets->priv->last_access = path;
268
269 return path;
270 }
271
272 static ETreeSortedPath *
273 find_child_path (ETreeSorted *ets,
274 ETreeSortedPath *parent,
275 ETreePath corresponding)
276 {
277 gint i;
278
279 if (corresponding == NULL)
280 return NULL;
281
282 if (parent->num_children == -1) {
283 return NULL;
284 }
285
286 for (i = 0; i < parent->num_children; i++)
287 if (parent->children[i]->corresponding == corresponding)
288 return parent->children[i];
289
290 return NULL;
291 }
292
293 static ETreeSortedPath *
294 find_or_create_path (ETreeSorted *ets,
295 ETreePath corresponding)
296 {
297 gint depth;
298 ETreePath *sequence;
299 gint i;
300 ETreeSortedPath *path;
301 ETreeSortedPath *check_last;
302
303 if (corresponding == NULL)
304 return NULL;
305
306 check_last = check_last_access (ets, corresponding);
307 if (check_last) {
308 d (g_print (" (find_or_create_path)\n"));
309 return check_last;
310 }
311
312 depth = e_tree_model_node_depth (ets->priv->source, corresponding);
313
314 sequence = g_new (ETreePath, depth + 1);
315
316 sequence[0] = corresponding;
317
318 for (i = 0; i < depth; i++)
319 sequence[i + 1] = e_tree_model_node_get_parent (ets->priv->source, sequence[i]);
320
321 path = ets->priv->root;
322
323 for (i = depth - 1; i >= 0 && path != NULL; i--) {
324 gint j;
325
326 if (path->num_children == -1) {
327 generate_children (ets, path);
328 }
329
330 for (j = 0; j < path->num_children; j++) {
331 if (path->children[j]->corresponding == sequence[i]) {
332 break;
333 }
334 }
335
336 if (j < path->num_children) {
337 path = path->children[j];
338 } else {
339 path = NULL;
340 }
341 }
342 g_free (sequence);
343
344 d (g_print ("Didn't find last access %p. Setting to %p. (find_or_create_path)\n", ets->priv->last_access, path));
345 ets->priv->last_access = path;
346
347 return path;
348 }
349
350 static void
351 free_children (ETreeSortedPath *path)
352 {
353 gint i;
354
355 if (path == NULL)
356 return;
357
358 for (i = 0; i < path->num_children; i++) {
359 free_path (path->children[i]);
360 }
361
362 g_free (path->children);
363 path->children = NULL;
364 path->num_children = -1;
365 }
366
367 static void
368 free_path (ETreeSortedPath *path)
369 {
370 free_children (path);
371 g_slice_free (ETreeSortedPath, path);
372 }
373
374 static ETreeSortedPath *
375 new_path (ETreeSortedPath *parent,
376 ETreePath corresponding)
377 {
378 ETreeSortedPath *path;
379
380 path = g_slice_new0 (ETreeSortedPath);
381
382 path->corresponding = corresponding;
383 path->parent = parent;
384 path->num_children = -1;
385 path->children = NULL;
386 path->position = -1;
387 path->orig_position = -1;
388 path->child_needs_resort = 0;
389 path->resort_all_children = 0;
390 path->needs_resort = 0;
391 path->needs_regen_to_sort = 0;
392
393 return path;
394 }
395
396 static gboolean
397 reposition_path (ETreeSorted *ets,
398 ETreeSortedPath *path)
399 {
400 gint new_index;
401 gint old_index = path->position;
402 ETreeSortedPath *parent = path->parent;
403 gboolean changed = FALSE;
404 if (parent) {
405 if (ets->priv->sort_idle_id == 0) {
406 if (ets->priv->insert_count > ETS_INSERT_MAX) {
407 /* schedule a sort, and append instead */
408 schedule_resort (ets, parent, TRUE, FALSE);
409 } else {
410 /* make sure we have an idle handler to reset the count every now and then */
411 if (ets->priv->insert_idle_id == 0) {
412 ets->priv->insert_idle_id = g_idle_add_full (40, (GSourceFunc) ets_insert_idle, ets, NULL);
413 }
414
415 new_index = e_table_sorting_utils_tree_check_position
416 (E_TREE_MODEL (ets),
417 ets->priv->sort_info,
418 ets->priv->full_header,
419 (ETreePath *) parent->children,
420 parent->num_children,
421 old_index);
422
423 if (new_index > old_index) {
424 gint i;
425 ets->priv->insert_count++;
426 memmove (parent->children + old_index, parent->children + old_index + 1, sizeof (ETreePath) * (new_index - old_index));
427 parent->children[new_index] = path;
428 for (i = old_index; i <= new_index; i++)
429 parent->children[i]->position = i;
430 changed = TRUE;
431 e_tree_model_node_changed (E_TREE_MODEL (ets), parent);
432 e_tree_sorted_node_resorted (ets, parent);
433 } else if (new_index < old_index) {
434 gint i;
435 ets->priv->insert_count++;
436 memmove (parent->children + new_index + 1, parent->children + new_index, sizeof (ETreePath) * (old_index - new_index));
437 parent->children[new_index] = path;
438 for (i = new_index; i <= old_index; i++)
439 parent->children[i]->position = i;
440 changed = TRUE;
441 e_tree_model_node_changed (E_TREE_MODEL (ets), parent);
442 e_tree_sorted_node_resorted (ets, parent);
443 }
444 }
445 } else
446 mark_path_needs_resort (ets, parent, TRUE, FALSE);
447 }
448 return changed;
449 }
450
451 static void
452 regenerate_children (ETreeSorted *ets,
453 ETreeSortedPath *path)
454 {
455 ETreeSortedPath **children;
456 gint i;
457
458 children = g_new (ETreeSortedPath *, path->num_children);
459 for (i = 0; i < path->num_children; i++)
460 children[path->children[i]->orig_position] = path->children[i];
461 g_free (path->children);
462 path->children = children;
463 }
464
465 static void
466 generate_children (ETreeSorted *ets,
467 ETreeSortedPath *path)
468 {
469 ETreePath child;
470 gint i;
471 gint count;
472
473 free_children (path);
474
475 count = 0;
476 for (child = e_tree_model_node_get_first_child (ets->priv->source, path->corresponding);
477 child;
478 child = e_tree_model_node_get_next (ets->priv->source, child)) {
479 count++;
480 }
481
482 path->num_children = count;
483 path->children = g_new (ETreeSortedPath *, count);
484 for (child = e_tree_model_node_get_first_child (ets->priv->source, path->corresponding), i = 0;
485 child;
486 child = e_tree_model_node_get_next (ets->priv->source, child), i++) {
487 path->children[i] = new_path (path, child);
488 path->children[i]->position = i;
489 path->children[i]->orig_position = i;
490 }
491 if (path->num_children > 0)
492 schedule_resort (ets, path, FALSE, TRUE);
493 }
494
495 static void
496 resort_node (ETreeSorted *ets,
497 ETreeSortedPath *path,
498 gboolean resort_all_children,
499 gboolean needs_regen,
500 gboolean send_signals)
501 {
502 gboolean needs_resort;
503 if (path) {
504 needs_resort = path->needs_resort || resort_all_children;
505 needs_regen = path->needs_regen_to_sort || needs_regen;
506 if (path->num_children > 0) {
507 if (needs_resort && send_signals)
508 e_tree_model_pre_change (E_TREE_MODEL (ets));
509 if (needs_resort) {
510 gint i;
511 d (g_print ("Start sort of node %p\n", path));
512 if (needs_regen)
513 regenerate_children (ets, path);
514 d (g_print ("Regened sort of node %p\n", path));
515 e_table_sorting_utils_tree_sort (
516 E_TREE_MODEL (ets),
517 ets->priv->sort_info,
518 ets->priv->full_header,
519 (ETreePath *) path->children,
520 path->num_children);
521 d (g_print ("Renumbering sort of node %p\n", path));
522 for (i = 0; i < path->num_children; i++) {
523 path->children[i]->position = i;
524 }
525 d (g_print ("End sort of node %p\n", path));
526 }
527 if (path->resort_all_children)
528 resort_all_children = TRUE;
529 if ((resort_all_children || path->child_needs_resort) && path->num_children >= 0) {
530 gint i;
531 for (i = 0; i < path->num_children; i++) {
532 resort_node (ets, path->children[i], resort_all_children, needs_regen, send_signals && !needs_resort);
533 }
534 path->child_needs_resort = 0;
535 }
536 }
537 path->needs_resort = 0;
538 path->child_needs_resort = 0;
539 path->needs_regen_to_sort = 0;
540 path->resort_all_children = 0;
541 if (needs_resort && send_signals && path->num_children > 0) {
542 e_tree_model_node_changed (E_TREE_MODEL (ets), path);
543 e_tree_sorted_node_resorted (ets, path);
544 }
545 }
546 }
547
548 static void
549 mark_path_child_needs_resort (ETreeSorted *ets,
550 ETreeSortedPath *path)
551 {
552 if (path == NULL)
553 return;
554 if (!path->child_needs_resort) {
555 path->child_needs_resort = 1;
556 mark_path_child_needs_resort (ets, path->parent);
557 }
558 }
559
560 static void
561 mark_path_needs_resort (ETreeSorted *ets,
562 ETreeSortedPath *path,
563 gboolean needs_regen,
564 gboolean resort_all_children)
565 {
566 if (path == NULL)
567 return;
568 if (path->num_children == 0)
569 return;
570 path->needs_resort = 1;
571 path->needs_regen_to_sort = needs_regen;
572 path->resort_all_children = resort_all_children;
573 mark_path_child_needs_resort (ets, path->parent);
574 }
575
576 static void
577 schedule_resort (ETreeSorted *ets,
578 ETreeSortedPath *path,
579 gboolean needs_regen,
580 gboolean resort_all_children)
581 {
582 ets->priv->insert_count = 0;
583 if (ets->priv->insert_idle_id != 0) {
584 g_source_remove (ets->priv->insert_idle_id);
585 ets->priv->insert_idle_id = 0;
586 }
587
588 if (path == NULL)
589 return;
590 if (path->num_children == 0)
591 return;
592
593 mark_path_needs_resort (ets, path, needs_regen, resort_all_children);
594 if (ets->priv->sort_idle_id == 0) {
595 ets->priv->sort_idle_id = g_idle_add_full (50, (GSourceFunc) ets_sort_idle, ets, NULL);
596 } else if (ets->priv->in_resort_idle) {
597 ets->priv->nested_resort_idle = TRUE;
598 }
599 }
600
601 /* virtual methods */
602
603 static void
604 ets_dispose (GObject *object)
605 {
606 ETreeSortedPrivate *priv;
607
608 priv = E_TREE_SORTED_GET_PRIVATE (object);
609
610 if (priv->source) {
611 g_signal_handler_disconnect (
612 priv->source, priv->tree_model_pre_change_id);
613 g_signal_handler_disconnect (
614 priv->source, priv->tree_model_no_change_id);
615 g_signal_handler_disconnect (
616 priv->source, priv->tree_model_node_changed_id);
617 g_signal_handler_disconnect (
618 priv->source, priv->tree_model_node_data_changed_id);
619 g_signal_handler_disconnect (
620 priv->source, priv->tree_model_node_col_changed_id);
621 g_signal_handler_disconnect (
622 priv->source, priv->tree_model_node_inserted_id);
623 g_signal_handler_disconnect (
624 priv->source, priv->tree_model_node_removed_id);
625 g_signal_handler_disconnect (
626 priv->source, priv->tree_model_node_deleted_id);
627 g_signal_handler_disconnect (
628 priv->source, priv->tree_model_node_request_collapse_id);
629
630 g_object_unref (priv->source);
631 priv->source = NULL;
632
633 priv->tree_model_pre_change_id = 0;
634 priv->tree_model_no_change_id = 0;
635 priv->tree_model_node_changed_id = 0;
636 priv->tree_model_node_data_changed_id = 0;
637 priv->tree_model_node_col_changed_id = 0;
638 priv->tree_model_node_inserted_id = 0;
639 priv->tree_model_node_removed_id = 0;
640 priv->tree_model_node_deleted_id = 0;
641 priv->tree_model_node_request_collapse_id = 0;
642 }
643
644 if (priv->sort_info) {
645 g_signal_handler_disconnect (
646 priv->sort_info, priv->sort_info_changed_id);
647 priv->sort_info_changed_id = 0;
648
649 g_object_unref (priv->sort_info);
650 priv->sort_info = NULL;
651 }
652
653 ets_stop_sort_idle (E_TREE_SORTED (object));
654
655 if (priv->insert_idle_id) {
656 g_source_remove (priv->insert_idle_id);
657 priv->insert_idle_id = 0;
658 }
659
660 if (priv->full_header) {
661 g_object_unref (priv->full_header);
662 priv->full_header = NULL;
663 }
664
665 /* Chain up to parent's dispose() method. */
666 G_OBJECT_CLASS (e_tree_sorted_parent_class)->dispose (object);
667 }
668
669 static void
670 ets_finalize (GObject *object)
671 {
672 ETreeSortedPrivate *priv;
673
674 priv = E_TREE_SORTED_GET_PRIVATE (object);
675
676 if (priv->root)
677 free_path (priv->root);
678
679 /* Chain up to parent's finalize() method. */
680 G_OBJECT_CLASS (e_tree_sorted_parent_class)->finalize (object);
681 }
682
683 static ETreePath
684 ets_get_root (ETreeModel *etm)
685 {
686 ETreeSortedPrivate *priv = E_TREE_SORTED (etm)->priv;
687 if (priv->root == NULL) {
688 ETreeSorted *ets = E_TREE_SORTED (etm);
689 ETreePath corresponding = e_tree_model_get_root (ets->priv->source);
690
691 if (corresponding) {
692 priv->root = new_path (NULL, corresponding);
693 }
694 }
695 if (priv->root && priv->root->num_children == -1) {
696 generate_children (E_TREE_SORTED (etm), priv->root);
697 }
698
699 return priv->root;
700 }
701
702 static ETreePath
703 ets_get_parent (ETreeModel *etm,
704 ETreePath node)
705 {
706 ETreeSortedPath *path = node;
707 return path->parent;
708 }
709
710 static ETreePath
711 ets_get_first_child (ETreeModel *etm,
712 ETreePath node)
713 {
714 ETreeSortedPath *path = node;
715 ETreeSorted *ets = E_TREE_SORTED (etm);
716
717 if (path->num_children == -1)
718 generate_children (ets, path);
719
720 if (path->num_children > 0)
721 return path->children[0];
722 else
723 return NULL;
724 }
725
726 static ETreePath
727 ets_get_last_child (ETreeModel *etm,
728 ETreePath node)
729 {
730 ETreeSortedPath *path = node;
731 ETreeSorted *ets = E_TREE_SORTED (etm);
732
733 if (path->num_children == -1)
734 generate_children (ets, path);
735
736 if (path->num_children > 0)
737 return path->children[path->num_children - 1];
738 else
739 return NULL;
740 }
741
742 static ETreePath
743 ets_get_next (ETreeModel *etm,
744 ETreePath node)
745 {
746 ETreeSortedPath *path = node;
747 ETreeSortedPath *parent = path->parent;
748 if (parent) {
749 if (parent->num_children > path->position + 1)
750 return parent->children[path->position + 1];
751 else
752 return NULL;
753 } else
754 return NULL;
755 }
756
757 static ETreePath
758 ets_get_prev (ETreeModel *etm,
759 ETreePath node)
760 {
761 ETreeSortedPath *path = node;
762 ETreeSortedPath *parent = path->parent;
763 if (parent) {
764 if (path->position - 1 >= 0)
765 return parent->children[path->position - 1];
766 else
767 return NULL;
768 } else
769 return NULL;
770 }
771
772 static gboolean
773 ets_is_root (ETreeModel *etm,
774 ETreePath node)
775 {
776 ETreeSortedPath *path = node;
777 ETreeSorted *ets = E_TREE_SORTED (etm);
778
779 return e_tree_model_node_is_root (ets->priv->source, path->corresponding);
780 }
781
782 static gboolean
783 ets_is_expandable (ETreeModel *etm,
784 ETreePath node)
785 {
786 ETreeSortedPath *path = node;
787 ETreeSorted *ets = E_TREE_SORTED (etm);
788 gboolean expandable = e_tree_model_node_is_expandable (ets->priv->source, path->corresponding);
789
790 if (path->num_children == -1) {
791 generate_children (ets, node);
792 }
793
794 return expandable;
795 }
796
797 static guint
798 ets_get_children (ETreeModel *etm,
799 ETreePath node,
800 ETreePath **nodes)
801 {
802 ETreeSortedPath *path = node;
803 guint n_children;
804
805 if (path->num_children == -1) {
806 generate_children (E_TREE_SORTED (etm), node);
807 }
808
809 n_children = path->num_children;
810
811 if (nodes) {
812 gint i;
813
814 (*nodes) = g_malloc (sizeof (ETreePath) * n_children);
815 for (i = 0; i < n_children; i++) {
816 (*nodes)[i] = path->children[i];
817 }
818 }
819
820 return n_children;
821 }
822
823 static guint
824 ets_depth (ETreeModel *etm,
825 ETreePath node)
826 {
827 ETreeSortedPath *path = node;
828 ETreeSorted *ets = E_TREE_SORTED (etm);
829
830 return e_tree_model_node_depth (ets->priv->source, path->corresponding);
831 }
832
833 static GdkPixbuf *
834 ets_icon_at (ETreeModel *etm,
835 ETreePath node)
836 {
837 ETreeSortedPath *path = node;
838 ETreeSorted *ets = E_TREE_SORTED (etm);
839
840 return e_tree_model_icon_at (ets->priv->source, path->corresponding);
841 }
842
843 static gboolean
844 ets_get_expanded_default (ETreeModel *etm)
845 {
846 ETreeSorted *ets = E_TREE_SORTED (etm);
847
848 return e_tree_model_get_expanded_default (ets->priv->source);
849 }
850
851 static gint
852 ets_column_count (ETreeModel *etm)
853 {
854 ETreeSorted *ets = E_TREE_SORTED (etm);
855
856 return e_tree_model_column_count (ets->priv->source);
857 }
858
859 static gboolean
860 ets_has_save_id (ETreeModel *etm)
861 {
862 return TRUE;
863 }
864
865 static gchar *
866 ets_get_save_id (ETreeModel *etm,
867 ETreePath node)
868 {
869 ETreeSorted *ets = E_TREE_SORTED (etm);
870 ETreeSortedPath *path = node;
871
872 if (e_tree_model_has_save_id (ets->priv->source))
873 return e_tree_model_get_save_id (ets->priv->source, path->corresponding);
874 else
875 return g_strdup_printf ("%p", path->corresponding);
876 }
877
878 static gboolean
879 ets_has_get_node_by_id (ETreeModel *etm)
880 {
881 ETreeSorted *ets = E_TREE_SORTED (etm);
882 return e_tree_model_has_get_node_by_id (ets->priv->source);
883 }
884
885 static ETreePath
886 ets_get_node_by_id (ETreeModel *etm,
887 const gchar *save_id)
888 {
889 ETreeSorted *ets = E_TREE_SORTED (etm);
890 ETreePath node;
891
892 node = e_tree_model_get_node_by_id (ets->priv->source, save_id);
893
894 return find_path (ets, node);
895 }
896
897 static gboolean
898 ets_has_change_pending (ETreeModel *etm)
899 {
900 ETreeSorted *ets = E_TREE_SORTED (etm);
901
902 return ets->priv->sort_idle_id != 0;
903 }
904
905 static gpointer
906 ets_value_at (ETreeModel *etm,
907 ETreePath node,
908 gint col)
909 {
910 ETreeSorted *ets = E_TREE_SORTED (etm);
911 ETreeSortedPath *path = node;
912
913 return e_tree_model_value_at (ets->priv->source, path->corresponding, col);
914 }
915
916 static void
917 ets_set_value_at (ETreeModel *etm,
918 ETreePath node,
919 gint col,
920 gconstpointer val)
921 {
922 ETreeSorted *ets = E_TREE_SORTED (etm);
923 ETreeSortedPath *path = node;
924
925 e_tree_model_set_value_at (ets->priv->source, path->corresponding, col, val);
926 }
927
928 static gboolean
929 ets_is_editable (ETreeModel *etm,
930 ETreePath node,
931 gint col)
932 {
933 ETreeSorted *ets = E_TREE_SORTED (etm);
934 ETreeSortedPath *path = node;
935
936 return e_tree_model_node_is_editable (ets->priv->source, path->corresponding, col);
937 }
938
939 /* The default for ets_duplicate_value is to return the raw value. */
940 static gpointer
941 ets_duplicate_value (ETreeModel *etm,
942 gint col,
943 gconstpointer value)
944 {
945 ETreeSorted *ets = E_TREE_SORTED (etm);
946
947 return e_tree_model_duplicate_value (ets->priv->source, col, value);
948 }
949
950 static void
951 ets_free_value (ETreeModel *etm,
952 gint col,
953 gpointer value)
954 {
955 ETreeSorted *ets = E_TREE_SORTED (etm);
956
957 e_tree_model_free_value (ets->priv->source, col, value);
958 }
959
960 static gpointer
961 ets_initialize_value (ETreeModel *etm,
962 gint col)
963 {
964 ETreeSorted *ets = E_TREE_SORTED (etm);
965
966 return e_tree_model_initialize_value (ets->priv->source, col);
967 }
968
969 static gboolean
970 ets_value_is_empty (ETreeModel *etm,
971 gint col,
972 gconstpointer value)
973 {
974 ETreeSorted *ets = E_TREE_SORTED (etm);
975
976 return e_tree_model_value_is_empty (ets->priv->source, col, value);
977 }
978
979 static gchar *
980 ets_value_to_string (ETreeModel *etm,
981 gint col,
982 gconstpointer value)
983 {
984 ETreeSorted *ets = E_TREE_SORTED (etm);
985
986 return e_tree_model_value_to_string (ets->priv->source, col, value);
987 }
988
989 /* Proxy functions */
990
991 static void
992 ets_proxy_pre_change (ETreeModel *etm,
993 ETreeSorted *ets)
994 {
995 e_tree_model_pre_change (E_TREE_MODEL (ets));
996 }
997
998 static void
999 ets_proxy_no_change (ETreeModel *etm,
1000 ETreeSorted *ets)
1001 {
1002 e_tree_model_no_change (E_TREE_MODEL (ets));
1003 }
1004
1005 static void
1006 ets_proxy_node_changed (ETreeModel *etm,
1007 ETreePath node,
1008 ETreeSorted *ets)
1009 {
1010 ets->priv->last_access = NULL;
1011 d (g_print ("Setting last access %p. (ets_proxy_node_changed)\n", ets->priv->last_access));
1012
1013 if (e_tree_model_node_is_root (ets->priv->source, node)) {
1014 ets_stop_sort_idle (ets);
1015
1016 if (ets->priv->root) {
1017 free_path (ets->priv->root);
1018 }
1019 ets->priv->root = new_path (NULL, node);
1020 e_tree_model_node_changed (E_TREE_MODEL (ets), ets->priv->root);
1021 return;
1022 } else {
1023 ETreeSortedPath *path = find_path (ets, node);
1024
1025 if (path) {
1026 free_children (path);
1027 if (!reposition_path (ets, path)) {
1028 e_tree_model_node_changed (E_TREE_MODEL (ets), path);
1029 } else {
1030 e_tree_model_no_change (E_TREE_MODEL (ets));
1031 }
1032 } else {
1033 e_tree_model_no_change (E_TREE_MODEL (ets));
1034 }
1035 }
1036 }
1037
1038 static void
1039 ets_proxy_node_data_changed (ETreeModel *etm,
1040 ETreePath node,
1041 ETreeSorted *ets)
1042 {
1043 ETreeSortedPath *path = find_path (ets, node);
1044
1045 if (path) {
1046 if (!reposition_path (ets, path))
1047 e_tree_model_node_data_changed (E_TREE_MODEL (ets), path);
1048 else
1049 e_tree_model_no_change (E_TREE_MODEL (ets));
1050 } else
1051 e_tree_model_no_change (E_TREE_MODEL (ets));
1052 }
1053
1054 static void
1055 ets_proxy_node_col_changed (ETreeModel *etm,
1056 ETreePath node,
1057 gint col,
1058 ETreeSorted *ets)
1059 {
1060 ETreeSortedPath *path = find_path (ets, node);
1061
1062 if (path) {
1063 gboolean changed = FALSE;
1064 if (e_table_sorting_utils_affects_sort (ets->priv->sort_info, ets->priv->full_header, col))
1065 changed = reposition_path (ets, path);
1066 if (!changed)
1067 e_tree_model_node_col_changed (E_TREE_MODEL (ets), path, col);
1068 else
1069 e_tree_model_no_change (E_TREE_MODEL (ets));
1070 } else
1071 e_tree_model_no_change (E_TREE_MODEL (ets));
1072 }
1073
1074 static void
1075 ets_proxy_node_inserted (ETreeModel *etm,
1076 ETreePath parent,
1077 ETreePath child,
1078 ETreeSorted *ets)
1079 {
1080 ETreeSortedPath *parent_path = find_path (ets, parent);
1081
1082 if (parent_path && parent_path->num_children != -1) {
1083 gint i;
1084 gint j;
1085 ETreeSortedPath *path;
1086 gint position = parent_path->num_children;
1087 ETreePath counter;
1088
1089 for (counter = e_tree_model_node_get_next (etm, child);
1090 counter;
1091 counter = e_tree_model_node_get_next (etm, counter))
1092 position--;
1093
1094 if (position != parent_path->num_children) {
1095 for (i = 0; i < parent_path->num_children; i++) {
1096 if (parent_path->children[i]->orig_position >= position)
1097 parent_path->children[i]->orig_position++;
1098 }
1099 }
1100
1101 i = parent_path->num_children;
1102 path = new_path (parent_path, child);
1103 path->orig_position = position;
1104 if (!ETS_SORT_IDLE_ACTIVATED (ets)) {
1105 ets->priv->insert_count++;
1106 if (ets->priv->insert_count > ETS_INSERT_MAX) {
1107 /* schedule a sort, and append instead */
1108 schedule_resort (ets, parent_path, TRUE, FALSE);
1109 } else {
1110 /* make sure we have an idle handler to reset the count every now and then */
1111 if (ets->priv->insert_idle_id == 0) {
1112 ets->priv->insert_idle_id = g_idle_add_full (40, (GSourceFunc) ets_insert_idle, ets, NULL);
1113 }
1114 i = e_table_sorting_utils_tree_insert
1115 (ets->priv->source,
1116 ets->priv->sort_info,
1117 ets->priv->full_header,
1118 (ETreePath *) parent_path->children,
1119 parent_path->num_children,
1120 path);
1121 }
1122 } else {
1123 mark_path_needs_resort (ets, parent_path, TRUE, FALSE);
1124 }
1125 parent_path->num_children++;
1126 parent_path->children = g_renew (ETreeSortedPath *, parent_path->children, parent_path->num_children);
1127 memmove (parent_path->children + i + 1, parent_path->children + i, (parent_path->num_children - 1 - i) * sizeof (gint));
1128 parent_path->children[i] = path;
1129 for (j = i; j < parent_path->num_children; j++) {
1130 parent_path->children[j]->position = j;
1131 }
1132 e_tree_model_node_inserted (E_TREE_MODEL (ets), parent_path, parent_path->children[i]);
1133 } else if (ets->priv->root == NULL && parent == NULL) {
1134 if (child) {
1135 ets->priv->root = new_path (NULL, child);
1136 e_tree_model_node_inserted (E_TREE_MODEL (ets), NULL, ets->priv->root);
1137 } else {
1138 e_tree_model_no_change (E_TREE_MODEL (ets));
1139 }
1140 } else {
1141 e_tree_model_no_change (E_TREE_MODEL (ets));
1142 }
1143 }
1144
1145 static void
1146 ets_proxy_node_removed (ETreeModel *etm,
1147 ETreePath parent,
1148 ETreePath child,
1149 gint old_position,
1150 ETreeSorted *ets)
1151 {
1152 ETreeSortedPath *parent_path = find_path (ets, parent);
1153 ETreeSortedPath *path;
1154
1155 if (parent_path)
1156 path = find_child_path (ets, parent_path, child);
1157 else
1158 path = find_path (ets, child);
1159
1160 d (g_print ("Setting last access %p. (ets_proxy_node_removed)\n ", ets->priv->last_access));
1161 ets->priv->last_access = NULL;
1162
1163 if (path && parent_path && parent_path->num_children != -1) {
1164 gint i;
1165 for (i = 0; i < parent_path->num_children; i++) {
1166 if (parent_path->children[i]->orig_position > old_position)
1167 parent_path->children[i]->orig_position--;
1168 }
1169
1170 i = path->position;
1171
1172 parent_path->num_children--;
1173 memmove (parent_path->children + i, parent_path->children + i + 1, sizeof (ETreeSortedPath *) * (parent_path->num_children - i));
1174 for (; i < parent_path->num_children; i++) {
1175 parent_path->children[i]->position = i;
1176 }
1177 e_tree_model_node_removed (E_TREE_MODEL (ets), parent_path, path, path->position);
1178 free_path (path);
1179 } else if (path && path == ets->priv->root) {
1180 ets->priv->root = NULL;
1181 e_tree_model_node_removed (E_TREE_MODEL (ets), NULL, path, -1);
1182 free_path (path);
1183 }
1184 }
1185
1186 static void
1187 ets_proxy_node_deleted (ETreeModel *etm,
1188 ETreePath child,
1189 ETreeSorted *ets)
1190 {
1191 e_tree_model_node_deleted (E_TREE_MODEL (ets), NULL);
1192 }
1193
1194 static void
1195 ets_proxy_node_request_collapse (ETreeModel *etm,
1196 ETreePath node,
1197 ETreeSorted *ets)
1198 {
1199 ETreeSortedPath *path = find_path (ets, node);
1200 if (path) {
1201 e_tree_model_node_request_collapse (E_TREE_MODEL (ets), path);
1202 }
1203 }
1204
1205 static void
1206 ets_sort_info_changed (ETableSortInfo *sort_info,
1207 ETreeSorted *ets)
1208 {
1209 schedule_resort (ets, ets->priv->root, TRUE, TRUE);
1210 }
1211
1212 /* Initialization and creation */
1213
1214 static void
1215 e_tree_sorted_class_init (ETreeSortedClass *class)
1216 {
1217 GObjectClass *object_class;
1218 ETreeModelClass *tree_model_class;
1219
1220 g_type_class_add_private (class, sizeof (ETreeSortedPrivate));
1221
1222 object_class = G_OBJECT_CLASS (class);
1223 object_class->dispose = ets_dispose;
1224 object_class->finalize = ets_finalize;
1225
1226 tree_model_class = E_TREE_MODEL_CLASS (class);
1227 tree_model_class->get_root = ets_get_root;
1228 tree_model_class->get_parent = ets_get_parent;
1229 tree_model_class->get_first_child = ets_get_first_child;
1230 tree_model_class->get_last_child = ets_get_last_child;
1231 tree_model_class->get_prev = ets_get_prev;
1232 tree_model_class->get_next = ets_get_next;
1233
1234 tree_model_class->is_root = ets_is_root;
1235 tree_model_class->is_expandable = ets_is_expandable;
1236 tree_model_class->get_children = ets_get_children;
1237 tree_model_class->depth = ets_depth;
1238
1239 tree_model_class->icon_at = ets_icon_at;
1240
1241 tree_model_class->get_expanded_default = ets_get_expanded_default;
1242 tree_model_class->column_count = ets_column_count;
1243
1244 tree_model_class->has_save_id = ets_has_save_id;
1245 tree_model_class->get_save_id = ets_get_save_id;
1246
1247 tree_model_class->has_get_node_by_id = ets_has_get_node_by_id;
1248 tree_model_class->get_node_by_id = ets_get_node_by_id;
1249
1250 tree_model_class->has_change_pending = ets_has_change_pending;
1251
1252 tree_model_class->value_at = ets_value_at;
1253 tree_model_class->set_value_at = ets_set_value_at;
1254 tree_model_class->is_editable = ets_is_editable;
1255
1256 tree_model_class->duplicate_value = ets_duplicate_value;
1257 tree_model_class->free_value = ets_free_value;
1258 tree_model_class->initialize_value = ets_initialize_value;
1259 tree_model_class->value_is_empty = ets_value_is_empty;
1260 tree_model_class->value_to_string = ets_value_to_string;
1261
1262 signals[NODE_RESORTED] = g_signal_new (
1263 "node_resorted",
1264 G_TYPE_FROM_CLASS (object_class),
1265 G_SIGNAL_RUN_LAST,
1266 G_STRUCT_OFFSET (ETreeSortedClass, node_resorted),
1267 (GSignalAccumulator) NULL, NULL,
1268 g_cclosure_marshal_VOID__POINTER,
1269 G_TYPE_NONE, 1,
1270 G_TYPE_POINTER);
1271 }
1272
1273 static void
1274 e_tree_sorted_init (ETreeSorted *ets)
1275 {
1276 ets->priv = E_TREE_SORTED_GET_PRIVATE (ets);
1277 }
1278
1279 /**
1280 * e_tree_sorted_construct:
1281 * @etree:
1282 *
1283 *
1284 **/
1285 void
1286 e_tree_sorted_construct (ETreeSorted *ets,
1287 ETreeModel *source,
1288 ETableHeader *full_header,
1289 ETableSortInfo *sort_info)
1290 {
1291 ets->priv->source = source;
1292 if (source)
1293 g_object_ref (source);
1294
1295 ets->priv->full_header = full_header;
1296 if (full_header)
1297 g_object_ref (full_header);
1298
1299 e_tree_sorted_set_sort_info (ets, sort_info);
1300
1301 ets->priv->tree_model_pre_change_id = g_signal_connect (
1302 source, "pre_change",
1303 G_CALLBACK (ets_proxy_pre_change), ets);
1304 ets->priv->tree_model_no_change_id = g_signal_connect (
1305 source, "no_change",
1306 G_CALLBACK (ets_proxy_no_change), ets);
1307 ets->priv->tree_model_node_changed_id = g_signal_connect (
1308 source, "node_changed",
1309 G_CALLBACK (ets_proxy_node_changed), ets);
1310 ets->priv->tree_model_node_data_changed_id = g_signal_connect (
1311 source, "node_data_changed",
1312 G_CALLBACK (ets_proxy_node_data_changed), ets);
1313 ets->priv->tree_model_node_col_changed_id = g_signal_connect (
1314 source, "node_col_changed",
1315 G_CALLBACK (ets_proxy_node_col_changed), ets);
1316 ets->priv->tree_model_node_inserted_id = g_signal_connect (
1317 source, "node_inserted",
1318 G_CALLBACK (ets_proxy_node_inserted), ets);
1319 ets->priv->tree_model_node_removed_id = g_signal_connect (
1320 source, "node_removed",
1321 G_CALLBACK (ets_proxy_node_removed), ets);
1322 ets->priv->tree_model_node_deleted_id = g_signal_connect (
1323 source, "node_deleted",
1324 G_CALLBACK (ets_proxy_node_deleted), ets);
1325 ets->priv->tree_model_node_request_collapse_id = g_signal_connect (
1326 source, "node_request_collapse",
1327 G_CALLBACK (ets_proxy_node_request_collapse), ets);
1328
1329 }
1330
1331 /**
1332 * e_tree_sorted_new
1333 *
1334 * FIXME docs here.
1335 *
1336 * return values: a newly constructed ETreeSorted.
1337 */
1338 ETreeSorted *
1339 e_tree_sorted_new (ETreeModel *source,
1340 ETableHeader *full_header,
1341 ETableSortInfo *sort_info)
1342 {
1343 ETreeSorted *ets = g_object_new (E_TYPE_TREE_SORTED, NULL);
1344
1345 e_tree_sorted_construct (ets, source, full_header, sort_info);
1346
1347 return ets;
1348 }
1349
1350 ETreePath
1351 e_tree_sorted_view_to_model_path (ETreeSorted *ets,
1352 ETreePath view_path)
1353 {
1354 ETreeSortedPath *path = view_path;
1355 if (path) {
1356 ets->priv->last_access = path;
1357 d (g_print ("Setting last access %p. (e_tree_sorted_view_to_model_path)\n", ets->priv->last_access));
1358 return path->corresponding;
1359 } else
1360 return NULL;
1361 }
1362
1363 ETreePath
1364 e_tree_sorted_model_to_view_path (ETreeSorted *ets,
1365 ETreePath model_path)
1366 {
1367 return find_or_create_path (ets, model_path);
1368 }
1369
1370 gint
1371 e_tree_sorted_orig_position (ETreeSorted *ets,
1372 ETreePath path)
1373 {
1374 ETreeSortedPath *sorted_path = path;
1375 return sorted_path->orig_position;
1376 }
1377
1378 gint
1379 e_tree_sorted_node_num_children (ETreeSorted *ets,
1380 ETreePath path)
1381 {
1382 ETreeSortedPath *sorted_path = path;
1383
1384 if (sorted_path->num_children == -1) {
1385 generate_children (ets, sorted_path);
1386 }
1387
1388 return sorted_path->num_children;
1389 }
1390
1391 void
1392 e_tree_sorted_node_resorted (ETreeSorted *sorted,
1393 ETreePath node)
1394 {
1395 g_return_if_fail (sorted != NULL);
1396 g_return_if_fail (E_IS_TREE_SORTED (sorted));
1397
1398 g_signal_emit (sorted, signals[NODE_RESORTED], 0, node);
1399 }
1400
1401 void
1402 e_tree_sorted_set_sort_info (ETreeSorted *ets,
1403 ETableSortInfo *sort_info)
1404 {
1405
1406 g_return_if_fail (ets != NULL);
1407
1408 if (ets->priv->sort_info) {
1409 if (ets->priv->sort_info_changed_id != 0)
1410 g_signal_handler_disconnect (
1411 ets->priv->sort_info,
1412 ets->priv->sort_info_changed_id);
1413 ets->priv->sort_info_changed_id = 0;
1414 g_object_unref (ets->priv->sort_info);
1415 }
1416
1417 ets->priv->sort_info = sort_info;
1418 if (sort_info) {
1419 g_object_ref (sort_info);
1420 ets->priv->sort_info_changed_id = g_signal_connect (
1421 ets->priv->sort_info, "sort_info_changed",
1422 G_CALLBACK (ets_sort_info_changed), ets);
1423 }
1424
1425 if (ets->priv->root)
1426 schedule_resort (ets, ets->priv->root, TRUE, TRUE);
1427 }
1428
1429 ETableSortInfo *
1430 e_tree_sorted_get_sort_info (ETreeSorted *ets)
1431 {
1432 return ets->priv->sort_info;
1433 }