No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-tree-selection-model.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-tree-selection-model.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
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 * Mike Kestner <mkestner@ximian.com>
19 *
20 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include "table/e-tree-table-adapter.h"
29 #include <glib/gi18n.h>
30 #include "e-util/e-util.h"
31
32 #include "e-tree-selection-model.h"
33
34 #define E_TREE_SELECTION_MODEL_GET_PRIVATE(obj) \
35 (G_TYPE_INSTANCE_GET_PRIVATE \
36 ((obj), E_TYPE_TREE_SELECTION_MODEL, ETreeSelectionModelPrivate))
37
38 G_DEFINE_TYPE (
39 ETreeSelectionModel, e_tree_selection_model, E_TYPE_SELECTION_MODEL)
40
41 enum {
42 PROP_0,
43 PROP_CURSOR_ROW,
44 PROP_CURSOR_COL,
45 PROP_MODEL,
46 PROP_ETTA
47 };
48
49 struct _ETreeSelectionModelPrivate {
50 ETreeTableAdapter *etta;
51 ETreeModel *model;
52
53 GHashTable *paths;
54 ETreePath cursor_path;
55 ETreePath start_path;
56 gint cursor_col;
57 gchar *cursor_save_id;
58
59 gint tree_model_pre_change_id;
60 gint tree_model_no_change_id;
61 gint tree_model_node_changed_id;
62 gint tree_model_node_data_changed_id;
63 gint tree_model_node_col_changed_id;
64 gint tree_model_node_inserted_id;
65 gint tree_model_node_removed_id;
66 gint tree_model_node_deleted_id;
67 };
68
69 static gint
70 get_cursor_row (ETreeSelectionModel *etsm)
71 {
72 if (etsm->priv->cursor_path)
73 return e_tree_table_adapter_row_of_node (
74 etsm->priv->etta, etsm->priv->cursor_path);
75
76 return -1;
77 }
78
79 static void
80 clear_selection (ETreeSelectionModel *etsm)
81 {
82 g_hash_table_destroy (etsm->priv->paths);
83 etsm->priv->paths = g_hash_table_new (NULL, NULL);
84 }
85
86 static void
87 change_one_path (ETreeSelectionModel *etsm,
88 ETreePath path,
89 gboolean grow)
90 {
91 if (!path)
92 return;
93
94 if (grow)
95 g_hash_table_insert (etsm->priv->paths, path, path);
96 else if (g_hash_table_lookup (etsm->priv->paths, path))
97 g_hash_table_remove (etsm->priv->paths, path);
98 }
99
100 static void
101 select_single_path (ETreeSelectionModel *etsm,
102 ETreePath path)
103 {
104 clear_selection (etsm);
105 change_one_path (etsm, path, TRUE);
106 etsm->priv->cursor_path = path;
107 etsm->priv->start_path = NULL;
108 }
109
110 static void
111 select_range (ETreeSelectionModel *etsm,
112 gint start,
113 gint end)
114 {
115 gint i;
116
117 if (start > end) {
118 i = start;
119 start = end;
120 end = i;
121 }
122
123 for (i = start; i <= end; i++) {
124 ETreePath path = e_tree_table_adapter_node_at_row (etsm->priv->etta, i);
125 if (path)
126 g_hash_table_insert (etsm->priv->paths, path, path);
127 }
128 }
129
130 static void
131 free_id (ETreeSelectionModel *etsm)
132 {
133 g_free (etsm->priv->cursor_save_id);
134 etsm->priv->cursor_save_id = NULL;
135 }
136
137 static void
138 restore_cursor (ETreeSelectionModel *etsm,
139 ETreeModel *etm)
140 {
141 clear_selection (etsm);
142 etsm->priv->cursor_path = NULL;
143
144 if (etsm->priv->cursor_save_id) {
145 etsm->priv->cursor_path = e_tree_model_get_node_by_id (
146 etm, etsm->priv->cursor_save_id);
147 if (etsm->priv->cursor_path != NULL && etsm->priv->cursor_col == -1)
148 etsm->priv->cursor_col = 0;
149
150 select_single_path (etsm, etsm->priv->cursor_path);
151 }
152
153 e_selection_model_selection_changed (E_SELECTION_MODEL (etsm));
154
155 if (etsm->priv->cursor_path) {
156 gint cursor_row = get_cursor_row (etsm);
157 e_selection_model_cursor_changed (
158 E_SELECTION_MODEL (etsm),
159 cursor_row, etsm->priv->cursor_col);
160 } else {
161 e_selection_model_cursor_changed (
162 E_SELECTION_MODEL (etsm), -1, -1);
163 e_selection_model_cursor_activated (
164 E_SELECTION_MODEL (etsm), -1, -1);
165
166 }
167
168 free_id (etsm);
169 }
170
171 static void
172 etsm_pre_change (ETreeModel *etm,
173 ETreeSelectionModel *etsm)
174 {
175 g_free (etsm->priv->cursor_save_id);
176 etsm->priv->cursor_save_id = NULL;
177
178 if (e_tree_model_has_get_node_by_id (etm) &&
179 e_tree_model_has_save_id (etm) &&
180 etsm->priv->cursor_path) {
181 etsm->priv->cursor_save_id = e_tree_model_get_save_id (
182 etm, etsm->priv->cursor_path);
183 }
184 }
185
186 static void
187 etsm_no_change (ETreeModel *etm,
188 ETreeSelectionModel *etsm)
189 {
190 free_id (etsm);
191 }
192
193 static void
194 etsm_node_changed (ETreeModel *etm,
195 ETreePath node,
196 ETreeSelectionModel *etsm)
197 {
198 restore_cursor (etsm, etm);
199 }
200
201 static void
202 etsm_node_data_changed (ETreeModel *etm,
203 ETreePath node,
204 ETreeSelectionModel *etsm)
205 {
206 free_id (etsm);
207 }
208
209 static void
210 etsm_node_col_changed (ETreeModel *etm,
211 ETreePath node,
212 gint col,
213 ETreeSelectionModel *etsm)
214 {
215 free_id (etsm);
216 }
217
218 static void
219 etsm_node_inserted (ETreeModel *etm,
220 ETreePath parent,
221 ETreePath child,
222 ETreeSelectionModel *etsm)
223 {
224 restore_cursor (etsm, etm);
225 }
226
227 static void
228 etsm_node_removed (ETreeModel *etm,
229 ETreePath parent,
230 ETreePath child,
231 gint old_position,
232 ETreeSelectionModel *etsm)
233 {
234 restore_cursor (etsm, etm);
235 }
236
237 static void
238 etsm_node_deleted (ETreeModel *etm,
239 ETreePath child,
240 ETreeSelectionModel *etsm)
241 {
242 restore_cursor (etsm, etm);
243 }
244
245 static void
246 add_model (ETreeSelectionModel *etsm,
247 ETreeModel *model)
248 {
249 ETreeSelectionModelPrivate *priv = etsm->priv;
250
251 priv->model = model;
252
253 if (!priv->model)
254 return;
255
256 g_object_ref (priv->model);
257
258 priv->tree_model_pre_change_id = g_signal_connect_after (
259 priv->model, "pre_change",
260 G_CALLBACK (etsm_pre_change), etsm);
261
262 priv->tree_model_no_change_id = g_signal_connect_after (
263 priv->model, "no_change",
264 G_CALLBACK (etsm_no_change), etsm);
265
266 priv->tree_model_node_changed_id = g_signal_connect_after (
267 priv->model, "node_changed",
268 G_CALLBACK (etsm_node_changed), etsm);
269
270 priv->tree_model_node_data_changed_id = g_signal_connect_after (
271 priv->model, "node_data_changed",
272 G_CALLBACK (etsm_node_data_changed), etsm);
273
274 priv->tree_model_node_col_changed_id = g_signal_connect_after (
275 priv->model, "node_col_changed",
276 G_CALLBACK (etsm_node_col_changed), etsm);
277
278 priv->tree_model_node_inserted_id = g_signal_connect_after (
279 priv->model, "node_inserted",
280 G_CALLBACK (etsm_node_inserted), etsm);
281
282 priv->tree_model_node_removed_id = g_signal_connect_after (
283 priv->model, "node_removed",
284 G_CALLBACK (etsm_node_removed), etsm);
285
286 priv->tree_model_node_deleted_id = g_signal_connect_after (
287 priv->model, "node_deleted",
288 G_CALLBACK (etsm_node_deleted), etsm);
289 }
290
291 static void
292 drop_model (ETreeSelectionModel *etsm)
293 {
294 ETreeSelectionModelPrivate *priv = etsm->priv;
295
296 if (!priv->model)
297 return;
298
299 g_signal_handler_disconnect (
300 priv->model, priv->tree_model_pre_change_id);
301 g_signal_handler_disconnect (
302 priv->model, priv->tree_model_no_change_id);
303 g_signal_handler_disconnect (
304 priv->model, priv->tree_model_node_changed_id);
305 g_signal_handler_disconnect (
306 priv->model, priv->tree_model_node_data_changed_id);
307 g_signal_handler_disconnect (
308 priv->model, priv->tree_model_node_col_changed_id);
309 g_signal_handler_disconnect (
310 priv->model, priv->tree_model_node_inserted_id);
311 g_signal_handler_disconnect (
312 priv->model, priv->tree_model_node_removed_id);
313 g_signal_handler_disconnect (
314 priv->model, priv->tree_model_node_deleted_id);
315
316 g_object_unref (priv->model);
317 priv->model = NULL;
318
319 priv->tree_model_pre_change_id = 0;
320 priv->tree_model_no_change_id = 0;
321 priv->tree_model_node_changed_id = 0;
322 priv->tree_model_node_data_changed_id = 0;
323 priv->tree_model_node_col_changed_id = 0;
324 priv->tree_model_node_inserted_id = 0;
325 priv->tree_model_node_removed_id = 0;
326 priv->tree_model_node_deleted_id = 0;
327 }
328
329 static void
330 etsm_dispose (GObject *object)
331 {
332 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (object);
333
334 drop_model (etsm);
335
336 /* Chain up to parent's dispose() method. */
337 G_OBJECT_CLASS (e_tree_selection_model_parent_class)->dispose (object);
338 }
339
340 static void
341 etsm_finalize (GObject *object)
342 {
343 ETreeSelectionModelPrivate *priv;
344
345 priv = E_TREE_SELECTION_MODEL_GET_PRIVATE (object);
346
347 clear_selection (E_TREE_SELECTION_MODEL (object));
348 g_hash_table_destroy (priv->paths);
349
350 /* Chain up to parent's finalize() method. */
351 G_OBJECT_CLASS (e_tree_selection_model_parent_class)->finalize (object);
352 }
353
354 static void
355 etsm_get_property (GObject *object,
356 guint property_id,
357 GValue *value,
358 GParamSpec *pspec)
359 {
360 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (object);
361
362 switch (property_id) {
363 case PROP_CURSOR_ROW:
364 g_value_set_int (value, get_cursor_row (etsm));
365 break;
366
367 case PROP_CURSOR_COL:
368 g_value_set_int (value, etsm->priv->cursor_col);
369 break;
370
371 case PROP_MODEL:
372 g_value_set_object (value, etsm->priv->model);
373 break;
374
375 case PROP_ETTA:
376 g_value_set_object (value, etsm->priv->etta);
377 break;
378 }
379 }
380
381 static void
382 etsm_set_property (GObject *object,
383 guint property_id,
384 const GValue *value,
385 GParamSpec *pspec)
386 {
387 ESelectionModel *esm = E_SELECTION_MODEL (object);
388 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (object);
389
390 switch (property_id) {
391 case PROP_CURSOR_ROW:
392 e_selection_model_do_something (
393 esm, g_value_get_int (value),
394 etsm->priv->cursor_col, 0);
395 break;
396
397 case PROP_CURSOR_COL:
398 e_selection_model_do_something (
399 esm, get_cursor_row (etsm),
400 g_value_get_int (value), 0);
401 break;
402
403 case PROP_MODEL:
404 drop_model (etsm);
405 add_model (etsm, E_TREE_MODEL (g_value_get_object (value)));
406 break;
407
408 case PROP_ETTA:
409 etsm->priv->etta =
410 E_TREE_TABLE_ADAPTER (g_value_get_object (value));
411 break;
412 }
413 }
414
415 static gboolean
416 etsm_is_path_selected (ETreeSelectionModel *etsm,
417 ETreePath path)
418 {
419 if (path && g_hash_table_lookup (etsm->priv->paths, path))
420 return TRUE;
421
422 return FALSE;
423 }
424
425 /**
426 * e_selection_model_is_row_selected
427 * @selection: #ESelectionModel to check
428 * @n: The row to check
429 *
430 * This routine calculates whether the given row is selected.
431 *
432 * Returns: %TRUE if the given row is selected
433 */
434 static gboolean
435 etsm_is_row_selected (ESelectionModel *selection,
436 gint row)
437 {
438 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
439 ETreePath path;
440
441 g_return_val_if_fail (
442 row < e_table_model_row_count (
443 E_TABLE_MODEL (etsm->priv->etta)), FALSE);
444 g_return_val_if_fail (row >= 0, FALSE);
445 g_return_val_if_fail (etsm != NULL, FALSE);
446
447 path = e_tree_table_adapter_node_at_row (etsm->priv->etta, row);
448 return etsm_is_path_selected (etsm, path);
449 }
450
451 typedef struct {
452 ETreeSelectionModel *etsm;
453 EForeachFunc callback;
454 gpointer closure;
455 } ModelAndCallback;
456
457 static void
458 etsm_row_foreach_cb (gpointer key,
459 gpointer value,
460 gpointer user_data)
461 {
462 ETreePath path = key;
463 ModelAndCallback *mac = user_data;
464 gint row = e_tree_table_adapter_row_of_node (
465 mac->etsm->priv->etta, path);
466 if (row >= 0)
467 mac->callback (row, mac->closure);
468 }
469
470 /**
471 * e_selection_model_foreach
472 * @selection: #ESelectionModel to traverse
473 * @callback: The callback function to call back.
474 * @closure: The closure
475 *
476 * This routine calls the given callback function once for each
477 * selected row, passing closure as the closure.
478 */
479 static void
480 etsm_foreach (ESelectionModel *selection,
481 EForeachFunc callback,
482 gpointer closure)
483 {
484 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
485 ModelAndCallback mac;
486
487 mac.etsm = etsm;
488 mac.callback = callback;
489 mac.closure = closure;
490
491 g_hash_table_foreach (etsm->priv->paths, etsm_row_foreach_cb, &mac);
492 }
493
494 /**
495 * e_selection_model_clear
496 * @selection: #ESelectionModel to clear
497 *
498 * This routine clears the selection to no rows selected.
499 */
500 static void
501 etsm_clear (ESelectionModel *selection)
502 {
503 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
504
505 clear_selection (etsm);
506
507 etsm->priv->cursor_path = NULL;
508 e_selection_model_selection_changed (E_SELECTION_MODEL (etsm));
509 e_selection_model_cursor_changed (E_SELECTION_MODEL (etsm), -1, -1);
510 }
511
512 /**
513 * e_selection_model_selected_count
514 * @selection: #ESelectionModel to count
515 *
516 * This routine calculates the number of rows selected.
517 *
518 * Returns: The number of rows selected in the given model.
519 */
520 static gint
521 etsm_selected_count (ESelectionModel *selection)
522 {
523 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
524
525 return g_hash_table_size (etsm->priv->paths);
526 }
527
528 static gint
529 etsm_row_count (ESelectionModel *selection)
530 {
531 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
532 return e_table_model_row_count (E_TABLE_MODEL (etsm->priv->etta));
533 }
534
535 /**
536 * e_selection_model_select_all
537 * @selection: #ESelectionModel to select all
538 *
539 * This routine selects all the rows in the given
540 * #ESelectionModel.
541 */
542 static void
543 etsm_select_all (ESelectionModel *selection)
544 {
545 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
546 ETreePath root;
547
548 root = e_tree_model_get_root (etsm->priv->model);
549 if (root == NULL)
550 return;
551
552 clear_selection (etsm);
553 select_range (etsm, 0, etsm_row_count (selection) - 1);
554
555 if (etsm->priv->cursor_path == NULL)
556 etsm->priv->cursor_path = e_tree_table_adapter_node_at_row (
557 etsm->priv->etta, 0);
558
559 e_selection_model_selection_changed (E_SELECTION_MODEL (etsm));
560
561 e_selection_model_cursor_changed (
562 E_SELECTION_MODEL (etsm),
563 get_cursor_row (etsm), etsm->priv->cursor_col);
564 }
565
566 /**
567 * e_selection_model_invert_selection
568 * @selection: #ESelectionModel to invert
569 *
570 * This routine inverts all the rows in the given
571 * #ESelectionModel.
572 */
573 static void
574 etsm_invert_selection (ESelectionModel *selection)
575 {
576 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
577 gint count = etsm_row_count (selection);
578 gint i;
579
580 for (i = 0; i < count; i++) {
581 ETreePath path;
582
583 path = e_tree_table_adapter_node_at_row (etsm->priv->etta, i);
584 if (!path)
585 continue;
586 if (g_hash_table_lookup (etsm->priv->paths, path))
587 g_hash_table_remove (etsm->priv->paths, path);
588 else
589 g_hash_table_insert (etsm->priv->paths, path, path);
590 }
591
592 etsm->priv->cursor_col = -1;
593 etsm->priv->cursor_path = NULL;
594 etsm->priv->start_path = NULL;
595 e_selection_model_selection_changed (E_SELECTION_MODEL (etsm));
596 e_selection_model_cursor_changed (E_SELECTION_MODEL (etsm), -1, -1);
597 }
598
599 static void
600 etsm_change_one_row (ESelectionModel *selection,
601 gint row,
602 gboolean grow)
603 {
604 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
605 ETreePath path;
606
607 g_return_if_fail (
608 row < e_table_model_row_count (
609 E_TABLE_MODEL (etsm->priv->etta)));
610 g_return_if_fail (row >= 0);
611 g_return_if_fail (selection != NULL);
612
613 path = e_tree_table_adapter_node_at_row (etsm->priv->etta, row);
614
615 if (!path)
616 return;
617
618 change_one_path (etsm, path, grow);
619 }
620
621 static void
622 etsm_change_cursor (ESelectionModel *selection,
623 gint row,
624 gint col)
625 {
626 ETreeSelectionModel *etsm;
627
628 g_return_if_fail (selection != NULL);
629 g_return_if_fail (E_IS_SELECTION_MODEL (selection));
630
631 etsm = E_TREE_SELECTION_MODEL (selection);
632
633 if (row == -1) {
634 etsm->priv->cursor_path = NULL;
635 } else {
636 etsm->priv->cursor_path =
637 e_tree_table_adapter_node_at_row (
638 etsm->priv->etta, row);
639 }
640 etsm->priv->cursor_col = col;
641 }
642
643 static gint
644 etsm_cursor_row (ESelectionModel *selection)
645 {
646 return get_cursor_row (E_TREE_SELECTION_MODEL (selection));
647 }
648
649 static gint
650 etsm_cursor_col (ESelectionModel *selection)
651 {
652 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
653 return etsm->priv->cursor_col;
654 }
655
656 static void
657 etsm_get_rows (gint row,
658 gpointer d)
659 {
660 gint **rowp = d;
661
662 **rowp = row;
663 (*rowp)++;
664 }
665
666 static void
667 etsm_select_single_row (ESelectionModel *selection,
668 gint row)
669 {
670 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
671 ETreePath path;
672 gint rows[5], *rowp = NULL, size;
673
674 path = e_tree_table_adapter_node_at_row (etsm->priv->etta, row);
675 g_return_if_fail (path != NULL);
676
677 /* we really only care about the size=1 case (cursor changed),
678 * but this doesn't cost much */
679 size = g_hash_table_size (etsm->priv->paths);
680 if (size > 0 && size <= 5) {
681 rowp = rows;
682 etsm_foreach (selection, etsm_get_rows, &rowp);
683 }
684
685 select_single_path (etsm, path);
686
687 if (size > 5) {
688 e_selection_model_selection_changed (E_SELECTION_MODEL (etsm));
689 } else {
690 if (rowp) {
691 gint *p = rows;
692
693 while (p < rowp)
694 e_selection_model_selection_row_changed (
695 (ESelectionModel *) etsm, *p++);
696 }
697 e_selection_model_selection_row_changed (
698 (ESelectionModel *) etsm, row);
699 }
700 }
701
702 static void
703 etsm_toggle_single_row (ESelectionModel *selection,
704 gint row)
705 {
706 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
707 ETreePath path;
708
709 path = e_tree_table_adapter_node_at_row (etsm->priv->etta, row);
710 g_return_if_fail (path);
711
712 if (g_hash_table_lookup (etsm->priv->paths, path))
713 g_hash_table_remove (etsm->priv->paths, path);
714 else
715 g_hash_table_insert (etsm->priv->paths, path, path);
716
717 etsm->priv->start_path = NULL;
718
719 e_selection_model_selection_row_changed ((ESelectionModel *) etsm, row);
720 }
721
722 static void
723 etsm_real_move_selection_end (ETreeSelectionModel *etsm,
724 gint row)
725 {
726 ETreePath end_path;
727 gint start;
728
729 end_path = e_tree_table_adapter_node_at_row (etsm->priv->etta, row);
730 g_return_if_fail (end_path);
731
732 start = e_tree_table_adapter_row_of_node (
733 etsm->priv->etta, etsm->priv->start_path);
734 clear_selection (etsm);
735 select_range (etsm, start, row);
736 }
737
738 static void
739 etsm_move_selection_end (ESelectionModel *selection,
740 gint row)
741 {
742 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
743
744 g_return_if_fail (etsm->priv->cursor_path);
745
746 etsm_real_move_selection_end (etsm, row);
747 e_selection_model_selection_changed (E_SELECTION_MODEL (selection));
748 }
749
750 static void
751 etsm_set_selection_end (ESelectionModel *selection,
752 gint row)
753 {
754 ETreeSelectionModel *etsm = E_TREE_SELECTION_MODEL (selection);
755
756 g_return_if_fail (etsm->priv->cursor_path);
757
758 if (!etsm->priv->start_path)
759 etsm->priv->start_path = etsm->priv->cursor_path;
760 etsm_real_move_selection_end (etsm, row);
761 e_selection_model_selection_changed (E_SELECTION_MODEL (etsm));
762 }
763
764 struct foreach_path_t {
765 ETreeForeachFunc callback;
766 gpointer closure;
767 };
768
769 static void
770 foreach_path (gpointer key,
771 gpointer value,
772 gpointer data)
773 {
774 ETreePath path = key;
775 struct foreach_path_t *c = data;
776 c->callback (path, c->closure);
777 }
778
779 void
780 e_tree_selection_model_foreach (ETreeSelectionModel *etsm,
781 ETreeForeachFunc callback,
782 gpointer closure)
783 {
784 if (etsm->priv->paths) {
785 struct foreach_path_t c;
786 c.callback = callback;
787 c.closure = closure;
788 g_hash_table_foreach (etsm->priv->paths, foreach_path, &c);
789 return;
790 }
791 }
792
793 void
794 e_tree_selection_model_select_single_path (ETreeSelectionModel *etsm,
795 ETreePath path)
796 {
797 select_single_path (etsm, path);
798
799 e_selection_model_selection_changed (E_SELECTION_MODEL (etsm));
800 }
801
802 void
803 e_tree_selection_model_select_paths (ETreeSelectionModel *etsm,
804 GPtrArray *paths)
805 {
806 ETreePath path;
807 gint i;
808
809 for (i = 0; i < paths->len; i++) {
810 path = paths->pdata[i];
811 change_one_path (etsm, path, TRUE);
812 }
813
814 e_selection_model_selection_changed (E_SELECTION_MODEL (etsm));
815 }
816
817 void
818 e_tree_selection_model_add_to_selection (ETreeSelectionModel *etsm,
819 ETreePath path)
820 {
821 change_one_path (etsm, path, TRUE);
822
823 e_selection_model_selection_changed (E_SELECTION_MODEL (etsm));
824 }
825
826 void
827 e_tree_selection_model_change_cursor (ETreeSelectionModel *etsm,
828 ETreePath path)
829 {
830 gint row;
831
832 etsm->priv->cursor_path = path;
833
834 row = get_cursor_row (etsm);
835
836 E_SELECTION_MODEL (etsm)->old_selection = -1;
837
838 e_selection_model_cursor_changed (
839 E_SELECTION_MODEL (etsm), row, etsm->priv->cursor_col);
840 e_selection_model_cursor_activated (
841 E_SELECTION_MODEL (etsm), row, etsm->priv->cursor_col);
842 }
843
844 ETreePath
845 e_tree_selection_model_get_cursor (ETreeSelectionModel *etsm)
846 {
847 return etsm->priv->cursor_path;
848 }
849
850 static void
851 e_tree_selection_model_init (ETreeSelectionModel *etsm)
852 {
853 etsm->priv = E_TREE_SELECTION_MODEL_GET_PRIVATE (etsm);
854
855 etsm->priv->paths = g_hash_table_new (NULL, NULL);
856 etsm->priv->cursor_col = -1;
857 }
858
859 static void
860 e_tree_selection_model_class_init (ETreeSelectionModelClass *class)
861 {
862 GObjectClass *object_class;
863 ESelectionModelClass *esm_class;
864
865 g_type_class_add_private (class, sizeof (ETreeSelectionModelPrivate));
866
867 object_class = G_OBJECT_CLASS (class);
868 object_class->dispose = etsm_dispose;
869 object_class->finalize = etsm_finalize;
870 object_class->get_property = etsm_get_property;
871 object_class->set_property = etsm_set_property;
872
873 esm_class = E_SELECTION_MODEL_CLASS (class);
874 esm_class->is_row_selected = etsm_is_row_selected;
875 esm_class->foreach = etsm_foreach;
876 esm_class->clear = etsm_clear;
877 esm_class->selected_count = etsm_selected_count;
878 esm_class->select_all = etsm_select_all;
879 esm_class->invert_selection = etsm_invert_selection;
880 esm_class->row_count = etsm_row_count;
881
882 esm_class->change_one_row = etsm_change_one_row;
883 esm_class->change_cursor = etsm_change_cursor;
884 esm_class->cursor_row = etsm_cursor_row;
885 esm_class->cursor_col = etsm_cursor_col;
886
887 esm_class->select_single_row = etsm_select_single_row;
888 esm_class->toggle_single_row = etsm_toggle_single_row;
889 esm_class->move_selection_end = etsm_move_selection_end;
890 esm_class->set_selection_end = etsm_set_selection_end;
891
892 g_object_class_install_property (
893 object_class,
894 PROP_CURSOR_ROW,
895 g_param_spec_int (
896 "cursor_row",
897 "Cursor Row",
898 NULL,
899 0, G_MAXINT, 0,
900 G_PARAM_READWRITE));
901
902 g_object_class_install_property (
903 object_class,
904 PROP_CURSOR_COL,
905 g_param_spec_int (
906 "cursor_col",
907 "Cursor Column",
908 NULL,
909 0, G_MAXINT, 0,
910 G_PARAM_READWRITE));
911
912 g_object_class_install_property (
913 object_class,
914 PROP_MODEL,
915 g_param_spec_object (
916 "model",
917 "Model",
918 NULL,
919 E_TYPE_TREE_MODEL,
920 G_PARAM_READWRITE));
921
922 g_object_class_install_property (
923 object_class,
924 PROP_ETTA,
925 g_param_spec_object (
926 "etta",
927 "ETTA",
928 NULL,
929 E_TYPE_TREE_TABLE_ADAPTER,
930 G_PARAM_READWRITE));
931
932 }
933
934 ESelectionModel *
935 e_tree_selection_model_new (void)
936 {
937 return g_object_new (E_TYPE_TREE_SELECTION_MODEL, NULL);
938 }