2 * This program is based on gtkflist.c
8 #include "sylpheed-marshal.h"
9 #include "stock_pixmap.h"
19 static GdkPixmap *emptyxpm = NULL;
20 static GdkBitmap *emptyxpmmask = NULL;
22 static void gtk_sctree_class_init (GtkSCTreeClass *class);
23 static void gtk_sctree_init (GtkSCTree *sctree);
25 static gint gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event);
26 static gint gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event);
27 static gint gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event);
28 static void gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context);
29 static void gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context);
30 static void gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
31 GtkSelectionData *data, guint info, guint time);
32 static void gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time);
33 static gboolean gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
34 gint x, gint y, guint time);
35 static gboolean gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
36 gint x, gint y, guint time);
37 static void gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
38 gint x, gint y, GtkSelectionData *data,
39 guint info, guint time);
41 static void gtk_sctree_clear (GtkCList *clist);
42 static void gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node);
44 static void tree_sort (GtkCTree *ctree, GtkCTreeNode *node, gpointer data);
45 void gtk_sctree_sort_node (GtkCTree *ctree, GtkCTreeNode *node);
46 void gtk_sctree_sort_recursive (GtkCTree *ctree, GtkCTreeNode *node);
48 static void gtk_ctree_link (GtkCTree *ctree,
51 GtkCTreeNode *sibling,
52 gboolean update_focus_row);
54 static void gtk_ctree_unlink (GtkCTree *ctree,
56 gboolean update_focus_row);
58 static void tree_update_level (GtkCTree *ctree,
62 static GtkCTreeNode * gtk_ctree_last_visible (GtkCTree *ctree,
65 static GtkCTreeClass *parent_class;
67 static guint sctree_signals[LAST_SIGNAL];
71 * gtk_sctree_get_type:
74 * Creates the GtkSCTree class and its type information
76 * Return value: The type ID for GtkSCTreeClass
79 gtk_sctree_get_type (void)
81 static GType sctree_type = 0;
84 GTypeInfo sctree_info = {
85 sizeof (GtkSCTreeClass),
88 (GBaseFinalizeFunc) NULL,
90 (GClassInitFunc) gtk_sctree_class_init,
91 (GClassFinalizeFunc) NULL,
92 NULL, /* class_data */
96 (GInstanceInitFunc) gtk_sctree_init,
99 sctree_type = g_type_register_static (GTK_TYPE_CTREE, "GtkSCTree", &sctree_info, (GTypeFlags)0);
105 /* Standard class initialization function */
107 gtk_sctree_class_init (GtkSCTreeClass *klass)
109 GtkObjectClass *object_class;
110 GtkWidgetClass *widget_class;
111 GtkCListClass *clist_class;
112 GtkCTreeClass *ctree_class;
114 object_class = (GtkObjectClass *) klass;
115 widget_class = (GtkWidgetClass *) klass;
116 clist_class = (GtkCListClass *) klass;
117 ctree_class = (GtkCTreeClass *) klass;
119 parent_class = gtk_type_class (gtk_ctree_get_type ());
121 sctree_signals[ROW_POPUP_MENU] =
122 g_signal_new ("row_popup_menu",
123 G_TYPE_FROM_CLASS (klass),
125 G_STRUCT_OFFSET (GtkSCTreeClass, row_popup_menu),
127 sylpheed_marshal_VOID__POINTER,
130 sctree_signals[EMPTY_POPUP_MENU] =
131 g_signal_new ("empty_popup_menu",
132 G_TYPE_FROM_CLASS (klass),
134 G_STRUCT_OFFSET (GtkSCTreeClass, empty_popup_menu),
136 sylpheed_marshal_VOID__POINTER,
139 sctree_signals[OPEN_ROW] =
140 g_signal_new ("open_row",
141 G_TYPE_FROM_CLASS (klass),
143 G_STRUCT_OFFSET (GtkSCTreeClass, open_row),
145 g_cclosure_marshal_VOID__VOID,
147 sctree_signals[START_DRAG] =
148 g_signal_new ("start_drag",
149 G_TYPE_FROM_CLASS (klass),
151 G_STRUCT_OFFSET (GtkSCTreeClass, start_drag),
153 sylpheed_marshal_VOID__INT_POINTER,
158 /* gtk_object_class_add_signals (object_class, sctree_signals, LAST_SIGNAL); */
160 clist_class->clear = gtk_sctree_clear;
161 ctree_class->tree_collapse = gtk_sctree_collapse;
163 widget_class->button_press_event = gtk_sctree_button_press;
164 widget_class->button_release_event = gtk_sctree_button_release;
165 widget_class->motion_notify_event = gtk_sctree_motion;
166 widget_class->drag_begin = gtk_sctree_drag_begin;
167 widget_class->drag_end = gtk_sctree_drag_end;
168 widget_class->drag_data_get = gtk_sctree_drag_data_get;
169 widget_class->drag_leave = gtk_sctree_drag_leave;
170 widget_class->drag_motion = gtk_sctree_drag_motion;
171 widget_class->drag_drop = gtk_sctree_drag_drop;
172 widget_class->drag_data_received = gtk_sctree_drag_data_received;
175 /* Standard object initialization function */
177 gtk_sctree_init (GtkSCTree *sctree)
179 sctree->anchor_row = NULL;
181 /* GtkCTree does not specify pointer motion by default */
182 gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
183 gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
186 /* Get information the specified row is selected. */
189 row_is_selected(GtkSCTree *sctree, gint row)
191 GtkCListRow *clist_row;
192 clist_row = g_list_nth (GTK_CLIST(sctree)->row_list, row)->data;
193 return clist_row ? clist_row->state == GTK_STATE_SELECTED : FALSE;
196 /* Selects the rows between the anchor to the specified row, inclusive. */
198 select_range (GtkSCTree *sctree, gint row)
204 if (sctree->anchor_row == NULL) {
206 sctree->anchor_row = gtk_ctree_node_nth(GTK_CTREE(sctree), row);
208 prev_row = g_list_position(GTK_CLIST(sctree)->row_list,
209 (GList *)sctree->anchor_row);
211 if (row < prev_row) {
214 GTK_CLIST(sctree)->focus_row = max;
219 sctree->selecting_range = TRUE;
220 for (i = min; i < max; i++)
221 gtk_clist_select_row (GTK_CLIST (sctree), i, -1);
223 sctree->selecting_range = FALSE;
224 gtk_clist_select_row (GTK_CLIST (sctree), max, -1);
227 /* Handles row selection according to the specified modifier state */
229 select_row (GtkSCTree *sctree, gint row, gint col, guint state)
231 gboolean range, additive;
232 g_return_if_fail (sctree != NULL);
233 g_return_if_fail (GTK_IS_SCTREE (sctree));
235 range = ((state & GDK_SHIFT_MASK) != 0) &&
236 (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
237 (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
238 additive = ((state & GDK_CONTROL_MASK) != 0) &&
239 (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
240 (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
242 gtk_clist_freeze (GTK_CLIST (sctree));
244 GTK_CLIST(sctree)->focus_row = row;
247 sctree->selecting_range = TRUE;
248 gtk_clist_unselect_all (GTK_CLIST (sctree));
249 sctree->selecting_range = FALSE;
255 node = gtk_ctree_node_nth (GTK_CTREE(sctree), row);
257 /*No need to manage overlapped list*/
259 if (row_is_selected(sctree, row))
260 gtk_clist_unselect_row (GTK_CLIST (sctree), row, col);
262 g_signal_emit_by_name
264 "tree_select_row", node, col);
266 g_signal_emit_by_name
268 "tree_select_row", node, col);
270 sctree->anchor_row = node;
272 select_range (sctree, row);
274 gtk_clist_thaw (GTK_CLIST (sctree));
277 /* Our handler for button_press events. We override all of GtkCList's broken
281 gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
290 g_return_val_if_fail (widget != NULL, FALSE);
291 g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
292 g_return_val_if_fail (event != NULL, FALSE);
294 sctree = GTK_SCTREE (widget);
295 clist = GTK_CLIST (widget);
298 if (event->window != clist->clist_window)
299 return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
301 on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
303 if (on_row && !GTK_WIDGET_HAS_FOCUS(widget))
304 gtk_widget_grab_focus (widget);
306 if (gtk_ctree_is_hot_spot (GTK_CTREE(sctree), event->x, event->y)) {
307 gtk_ctree_toggle_expansion
309 gtk_ctree_node_nth(GTK_CTREE(sctree), row));
313 switch (event->type) {
314 case GDK_BUTTON_PRESS:
315 if (event->button == 1 || event->button == 2) {
316 if (event->button == 2)
317 event->state &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK);
319 /* Save the mouse info for DnD */
320 sctree->dnd_press_button = event->button;
321 sctree->dnd_press_x = event->x;
322 sctree->dnd_press_y = event->y;
324 /* Handle selection */
325 if ((row_is_selected (sctree, row)
326 && !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
327 || ((event->state & GDK_CONTROL_MASK)
328 && !(event->state & GDK_SHIFT_MASK))) {
329 sctree->dnd_select_pending = TRUE;
330 sctree->dnd_select_pending_state = event->state;
331 sctree->dnd_select_pending_row = row;
333 select_row (sctree, row, col, event->state);
335 sctree->selecting_range = TRUE;
336 gtk_clist_unselect_all (clist);
337 sctree->selecting_range = FALSE;
341 } else if (event->button == 3) {
342 /* Emit *_popup_menu signal*/
344 if (!row_is_selected(sctree,row))
345 select_row (sctree, row, col, 0);
346 g_signal_emit (G_OBJECT (sctree),
347 sctree_signals[ROW_POPUP_MENU],
350 sctree->selecting_range = TRUE;
351 gtk_clist_unselect_all(clist);
352 sctree->selecting_range = FALSE;
353 g_signal_emit (G_OBJECT (sctree),
354 sctree_signals[EMPTY_POPUP_MENU],
362 case GDK_2BUTTON_PRESS:
363 if (event->button != 1)
366 sctree->dnd_select_pending = FALSE;
367 sctree->dnd_select_pending_state = 0;
370 g_signal_emit (G_OBJECT (sctree),
371 sctree_signals[OPEN_ROW], 0);
383 /* Our handler for button_release events. We override all of GtkCList's broken
387 gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event)
395 g_return_val_if_fail (widget != NULL, FALSE);
396 g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
397 g_return_val_if_fail (event != NULL, FALSE);
399 sctree = GTK_SCTREE (widget);
400 clist = GTK_CLIST (widget);
403 if (event->window != clist->clist_window)
404 return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
406 on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
408 if (!(event->button == 1 || event->button == 2))
411 sctree->dnd_press_button = 0;
412 sctree->dnd_press_x = 0;
413 sctree->dnd_press_y = 0;
416 if (sctree->dnd_select_pending) {
417 select_row (sctree, row, col, sctree->dnd_select_pending_state);
418 sctree->dnd_select_pending = FALSE;
419 sctree->dnd_select_pending_state = 0;
428 /* Our handler for motion_notify events. We override all of GtkCList's broken
432 gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event)
437 g_return_val_if_fail (widget != NULL, FALSE);
438 g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
439 g_return_val_if_fail (event != NULL, FALSE);
441 sctree = GTK_SCTREE (widget);
442 clist = GTK_CLIST (widget);
444 if (event->window != clist->clist_window)
445 return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
447 if (!((sctree->dnd_press_button == 1 && (event->state & GDK_BUTTON1_MASK))
448 || (sctree->dnd_press_button == 2 && (event->state & GDK_BUTTON2_MASK))))
451 /* This is the same threshold value that is used in gtkdnd.c */
453 if (MAX (ABS (sctree->dnd_press_x - event->x),
454 ABS (sctree->dnd_press_y - event->y)) <= 3)
457 /* Handle any pending selections */
459 if (sctree->dnd_select_pending) {
460 if (!row_is_selected(sctree,sctree->dnd_select_pending_row))
462 sctree->dnd_select_pending_row,
464 sctree->dnd_select_pending_state);
466 sctree->dnd_select_pending = FALSE;
467 sctree->dnd_select_pending_state = 0;
470 g_signal_emit (G_OBJECT (sctree),
471 sctree_signals[START_DRAG],
473 sctree->dnd_press_button,
478 /* We override the drag_begin signal to do nothing */
480 gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context)
485 /* We override the drag_end signal to do nothing */
487 gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context)
492 /* We override the drag_data_get signal to do nothing */
494 gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
495 GtkSelectionData *data, guint info, guint time)
500 /* We override the drag_leave signal to do nothing */
502 gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time)
507 /* We override the drag_motion signal to do nothing */
509 gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
510 gint x, gint y, guint time)
515 /* We override the drag_drop signal to do nothing */
517 gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
518 gint x, gint y, guint time)
523 /* We override the drag_data_received signal to do nothing */
525 gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
526 gint x, gint y, GtkSelectionData *data,
527 guint info, guint time)
532 /* Our handler for the clear signal of the clist. We have to reset the anchor
536 gtk_sctree_clear (GtkCList *clist)
540 g_return_if_fail (clist != NULL);
541 g_return_if_fail (GTK_IS_SCTREE (clist));
543 sctree = GTK_SCTREE (clist);
544 sctree->anchor_row = NULL;
546 if (((GtkCListClass *)parent_class)->clear)
547 (* ((GtkCListClass *)parent_class)->clear) (clist);
550 /* Our handler for the change_focus_row_expansion signal of the ctree.
551 We have to set the anchor to parent visible node.
554 gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node)
556 g_return_if_fail (ctree != NULL);
557 g_return_if_fail (GTK_IS_SCTREE (ctree));
559 (* parent_class->tree_collapse) (ctree, node);
560 GTK_SCTREE(ctree)->anchor_row =
561 gtk_ctree_node_nth(ctree, GTK_CLIST(ctree)->focus_row);
564 GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column,
569 g_return_val_if_fail (columns > 0, NULL);
570 g_return_val_if_fail (tree_column >= 0, NULL);
572 widget = gtk_widget_new (TYPE_GTK_SCTREE,
573 "n_columns", columns,
574 "tree_column", tree_column,
577 GtkCList *clist = GTK_CLIST (widget);
580 for (i = 0; i < columns; i++)
581 gtk_clist_set_column_title (clist, i, titles[i]);
582 gtk_clist_column_titles_show (clist);
588 void gtk_sctree_select (GtkSCTree *sctree, GtkCTreeNode *node)
591 g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
595 void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCTreeNode *node, int state)
598 g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
602 void gtk_sctree_unselect_all (GtkSCTree *sctree)
604 sctree->selecting_range = TRUE;
605 gtk_clist_unselect_all(GTK_CLIST(sctree));
606 sctree->selecting_range = FALSE;
607 sctree->anchor_row = NULL;
610 void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCTreeNode *node)
612 sctree->anchor_row = node;
615 void gtk_sctree_remove_node (GtkSCTree *sctree, GtkCTreeNode *node)
617 if (sctree->anchor_row == node)
618 sctree->anchor_row = NULL;
619 gtk_ctree_remove_node(GTK_CTREE(sctree), node);
622 /***********************************************************
623 * Tree sorting functions *
624 ***********************************************************/
626 static void sink(GtkCList *clist, GPtrArray *numbers, gint root, gint bottom)
634 /* find the maximum element of numbers[root],
635 numbers[2*root] and numbers[2*root+1] */
637 if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, root)),
638 GTK_CTREE_ROW(g_ptr_array_index( numbers, j))) >= 0)
641 if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, k)),
642 GTK_CTREE_ROW (g_ptr_array_index( numbers, j))) > 0)
644 /* if numbers[root] wasn't the maximum element then
647 temp = g_ptr_array_index( numbers,root);
648 g_ptr_array_index( numbers, root) = g_ptr_array_index( numbers, j);
649 g_ptr_array_index( numbers, j) = temp;
650 sink( clist, numbers, j, bottom);
655 static void heap_sort(GtkCList *clist, GPtrArray *numbers, gint array_size)
661 for (i = (array_size / 2); i >= 1; i--)
662 sink( clist, numbers, i, array_size);
663 /* output the Heap */
664 for (i = array_size; i >= 2; i--) {
665 temp = g_ptr_array_index( numbers, 1);
666 g_ptr_array_index( numbers, 1) = g_ptr_array_index( numbers, i);
667 g_ptr_array_index( numbers, i) = temp;
668 sink( clist, numbers, 1, i-1);
673 tree_sort (GtkCTree *ctree,
677 GtkCTreeNode *list_start, *work, *next;
678 GPtrArray *row_array, *viewable_array;
683 clist = GTK_CLIST (ctree);
686 work = GTK_CTREE_ROW (node)->children;
688 work = GTK_CTREE_NODE (clist->row_list);
690 row_array = g_ptr_array_new();
691 viewable_array = g_ptr_array_new();
694 g_ptr_array_add( row_array, NULL);
696 /* add all rows to row_array */
697 g_ptr_array_add( row_array, work);
698 if (GTK_CTREE_ROW (work)->parent && gtk_ctree_is_viewable( ctree, work))
699 g_ptr_array_add( viewable_array, GTK_CTREE_ROW (work)->parent);
700 next = GTK_CTREE_ROW (work)->sibling;
701 gtk_ctree_unlink( ctree, work, FALSE);
705 heap_sort( clist, row_array, (row_array->len)-1);
708 list_start = GTK_CTREE_ROW (node)->children;
710 list_start = GTK_CTREE_NODE (clist->row_list);
712 if (clist->sort_type == GTK_SORT_ASCENDING) {
713 for (i=(row_array->len)-1; i>=1; i--) {
714 work = g_ptr_array_index( row_array, i);
715 gtk_ctree_link( ctree, work, node, list_start, FALSE);
717 /* insert work at the beginning of the list */
720 for (i=1; i<row_array->len; i++) {
721 work = g_ptr_array_index( row_array, i);
722 gtk_ctree_link( ctree, work, node, list_start, FALSE);
724 /* insert work at the beginning of the list */
728 for (i=0; i<viewable_array->len; i++) {
729 gtk_ctree_expand( ctree, g_ptr_array_index( viewable_array, i));
734 g_ptr_array_free( row_array, TRUE);
735 g_ptr_array_free( viewable_array, TRUE);
739 gtk_sctree_sort_recursive (GtkCTree *ctree,
743 GtkCTreeNode *focus_node = NULL;
745 g_return_if_fail (ctree != NULL);
746 g_return_if_fail (GTK_IS_CTREE (ctree));
748 clist = GTK_CLIST (ctree);
750 gtk_clist_freeze (clist);
752 if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
753 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
755 g_list_free (clist->undo_selection);
756 g_list_free (clist->undo_unselection);
757 clist->undo_selection = NULL;
758 clist->undo_unselection = NULL;
761 if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
762 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
764 gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_sort), NULL);
767 tree_sort (ctree, NULL, NULL);
770 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
771 clist->undo_anchor = clist->focus_row;
774 gtk_clist_thaw (clist);
778 gtk_sctree_sort_node (GtkCTree *ctree,
782 GtkCTreeNode *focus_node = NULL;
784 g_return_if_fail (ctree != NULL);
785 g_return_if_fail (GTK_IS_CTREE (ctree));
787 clist = GTK_CLIST (ctree);
789 gtk_clist_freeze (clist);
791 if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
792 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
794 g_list_free (clist->undo_selection);
795 g_list_free (clist->undo_unselection);
796 clist->undo_selection = NULL;
797 clist->undo_unselection = NULL;
800 if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
801 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
803 tree_sort (ctree, node, NULL);
806 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
807 clist->undo_anchor = clist->focus_row;
810 gtk_clist_thaw (clist);
813 /************************************************************************/
816 gtk_ctree_unlink (GtkCTree *ctree,
818 gboolean update_focus_row)
825 GtkCTreeNode *parent;
828 g_return_if_fail (ctree != NULL);
829 g_return_if_fail (GTK_IS_CTREE (ctree));
830 g_return_if_fail (node != NULL);
832 clist = GTK_CLIST (ctree);
834 if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
835 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
837 g_list_free (clist->undo_selection);
838 g_list_free (clist->undo_unselection);
839 clist->undo_selection = NULL;
840 clist->undo_unselection = NULL;
843 visible = gtk_ctree_is_viewable (ctree, node);
845 /* clist->row_list_end unlinked ? */
846 if (visible && (GTK_CTREE_NODE_NEXT (node) == NULL ||
847 (GTK_CTREE_ROW (node)->children && gtk_ctree_is_ancestor (ctree, node,
848 GTK_CTREE_NODE (clist->row_list_end)))))
849 clist->row_list_end = (GList *) (GTK_CTREE_NODE_PREV (node));
853 level = GTK_CTREE_ROW (node)->level;
854 work = GTK_CTREE_NODE_NEXT (node);
855 while (work && GTK_CTREE_ROW (work)->level > level) {
856 work = GTK_CTREE_NODE_NEXT (work);
861 clist->rows -= (rows + 1);
863 if (update_focus_row) {
866 pos = g_list_position (clist->row_list, (GList *)node);
867 if (pos + rows < clist->focus_row)
868 clist->focus_row -= (rows + 1);
869 else if (pos <= clist->focus_row) {
870 if (!GTK_CTREE_ROW (node)->sibling)
871 clist->focus_row = MAX (pos - 1, 0);
873 clist->focus_row = pos;
875 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
877 clist->undo_anchor = clist->focus_row;
882 list = (GList *)GTK_CTREE_NODE_PREV (work);
884 list = (GList *)work;
885 list->prev = (GList *)GTK_CTREE_NODE_PREV (node);
888 if (GTK_CTREE_NODE_PREV (node) &&
889 GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (node)) == node) {
890 list = (GList *)GTK_CTREE_NODE_PREV (node);
891 list->next = (GList *)work;
895 parent = GTK_CTREE_ROW (node)->parent;
897 if (GTK_CTREE_ROW (parent)->children == node) {
898 GTK_CTREE_ROW (parent)->children = GTK_CTREE_ROW (node)->sibling;
899 if (!GTK_CTREE_ROW (parent)->children)
900 gtk_ctree_collapse (ctree, parent);
903 GtkCTreeNode *sibling;
905 sibling = GTK_CTREE_ROW (parent)->children;
906 while (GTK_CTREE_ROW (sibling)->sibling != node)
907 sibling = GTK_CTREE_ROW (sibling)->sibling;
908 GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
912 if (clist->row_list == (GList *)node)
913 clist->row_list = (GList *) (GTK_CTREE_ROW (node)->sibling);
915 GtkCTreeNode *sibling;
917 sibling = GTK_CTREE_NODE (clist->row_list);
918 while (GTK_CTREE_ROW (sibling)->sibling != node)
919 sibling = GTK_CTREE_ROW (sibling)->sibling;
920 GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
926 gtk_ctree_link (GtkCTree *ctree,
928 GtkCTreeNode *parent,
929 GtkCTreeNode *sibling,
930 gboolean update_focus_row)
936 gboolean visible = FALSE;
940 g_return_if_fail (GTK_CTREE_ROW (sibling)->parent == parent);
941 g_return_if_fail (node != NULL);
942 g_return_if_fail (node != sibling);
943 g_return_if_fail (node != parent);
945 clist = GTK_CLIST (ctree);
947 if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
948 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
950 g_list_free (clist->undo_selection);
951 g_list_free (clist->undo_unselection);
952 clist->undo_selection = NULL;
953 clist->undo_unselection = NULL;
956 for (rows = 1, list_end = (GList *)node; list_end->next;
957 list_end = list_end->next)
960 GTK_CTREE_ROW (node)->parent = parent;
961 GTK_CTREE_ROW (node)->sibling = sibling;
963 if (!parent || (parent && (gtk_ctree_is_viewable (ctree, parent) &&
964 GTK_CTREE_ROW (parent)->expanded))) {
970 work = (GList *)(GTK_CTREE_ROW (parent)->children);
972 work = clist->row_list;
975 if (work != (GList *)sibling) {
976 while (GTK_CTREE_ROW (work)->sibling != sibling)
977 work = (GList *)(GTK_CTREE_ROW (work)->sibling);
978 GTK_CTREE_ROW (work)->sibling = node;
981 if (sibling == GTK_CTREE_NODE (clist->row_list))
982 clist->row_list = (GList *) node;
983 if (GTK_CTREE_NODE_PREV (sibling) &&
984 GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (sibling)) == sibling) {
985 list = (GList *)GTK_CTREE_NODE_PREV (sibling);
986 list->next = (GList *)node;
989 list = (GList *)node;
990 list->prev = (GList *)GTK_CTREE_NODE_PREV (sibling);
991 list_end->next = (GList *)sibling;
992 list = (GList *)sibling;
993 list->prev = list_end;
994 if (parent && GTK_CTREE_ROW (parent)->children == sibling)
995 GTK_CTREE_ROW (parent)->children = node;
1000 while (GTK_CTREE_ROW (work)->sibling)
1001 work = (GList *)(GTK_CTREE_ROW (work)->sibling);
1002 GTK_CTREE_ROW (work)->sibling = node;
1004 /* find last visible child of sibling */
1005 work = (GList *) gtk_ctree_last_visible (ctree,
1006 GTK_CTREE_NODE (work));
1008 list_end->next = work->next;
1010 list = work->next->prev = list_end;
1011 work->next = (GList *)node;
1012 list = (GList *)node;
1017 GTK_CTREE_ROW (parent)->children = node;
1018 list = (GList *)node;
1019 list->prev = (GList *)parent;
1020 if (GTK_CTREE_ROW (parent)->expanded) {
1021 list_end->next = (GList *)GTK_CTREE_NODE_NEXT (parent);
1022 if (GTK_CTREE_NODE_NEXT(parent)) {
1023 list = (GList *)GTK_CTREE_NODE_NEXT (parent);
1024 list->prev = list_end;
1026 list = (GList *)parent;
1027 list->next = (GList *)node;
1030 list_end->next = NULL;
1033 clist->row_list = (GList *)node;
1034 list = (GList *)node;
1036 list_end->next = NULL;
1041 gtk_ctree_pre_recursive (ctree, node, tree_update_level, NULL);
1043 if (clist->row_list_end == NULL ||
1044 clist->row_list_end->next == (GList *)node)
1045 clist->row_list_end = list_end;
1047 if (visible && update_focus_row) {
1050 pos = g_list_position (clist->row_list, (GList *)node);
1052 if (pos <= clist->focus_row) {
1053 clist->focus_row += rows;
1054 clist->undo_anchor = clist->focus_row;
1060 tree_update_level (GtkCTree *ctree,
1067 if (GTK_CTREE_ROW (node)->parent)
1068 GTK_CTREE_ROW (node)->level =
1069 GTK_CTREE_ROW (GTK_CTREE_ROW (node)->parent)->level + 1;
1071 GTK_CTREE_ROW (node)->level = 1;
1074 static GtkCTreeNode *
1075 gtk_ctree_last_visible (GtkCTree *ctree,
1083 work = GTK_CTREE_ROW (node)->children;
1085 if (!work || !GTK_CTREE_ROW (node)->expanded)
1088 while (GTK_CTREE_ROW (work)->sibling)
1089 work = GTK_CTREE_ROW (work)->sibling;
1091 return gtk_ctree_last_visible (ctree, work);
1094 /* this wrapper simply replaces NULL pixmaps
1095 * with a transparent, 1x1 pixmap. This works
1096 * around a memory problem deep inside gtk,
1097 * revealed by valgrind.
1099 GtkCTreeNode* gtk_sctree_insert_node (GtkCTree *ctree,
1100 GtkCTreeNode *parent,
1101 GtkCTreeNode *sibling,
1104 GdkPixmap *pixmap_closed,
1105 GdkBitmap *mask_closed,
1106 GdkPixmap *pixmap_opened,
1107 GdkBitmap *mask_opened,
1112 stock_pixmap_gdk(GTK_WIDGET(ctree), STOCK_PIXMAP_EMPTY,
1113 &emptyxpm, &emptyxpmmask);
1115 if (!pixmap_closed) {
1116 pixmap_closed = emptyxpm;
1117 mask_closed = emptyxpmmask;
1119 if (!pixmap_opened) {
1120 pixmap_opened = emptyxpm;
1121 mask_opened = emptyxpmmask;
1123 return gtk_ctree_insert_node(ctree, parent, sibling, text,spacing,
1124 pixmap_closed, mask_closed, pixmap_opened, mask_opened,
1128 /* this wrapper simply replaces NULL pixmaps
1129 * with a transparent, 1x1 pixmap. This works
1130 * around a memory problem deep inside gtk,
1131 * revealed by valgrind.
1133 void gtk_sctree_set_node_info (GtkCTree *ctree,
1137 GdkPixmap *pixmap_closed,
1138 GdkBitmap *mask_closed,
1139 GdkPixmap *pixmap_opened,
1140 GdkBitmap *mask_opened,
1145 stock_pixmap_gdk(GTK_WIDGET(ctree), STOCK_PIXMAP_EMPTY,
1146 &emptyxpm, &emptyxpmmask);
1148 if (!pixmap_closed) {
1149 pixmap_closed = emptyxpm;
1150 mask_closed = emptyxpmmask;
1152 if (!pixmap_opened) {
1153 pixmap_opened = emptyxpm;
1154 mask_opened = emptyxpmmask;
1156 gtk_ctree_set_node_info(ctree, node, text, spacing,
1157 pixmap_closed, mask_closed, pixmap_opened, mask_opened,