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;
246 GTK_CLIST_GET_CLASS(sctree)->refresh(GTK_CLIST(sctree));
249 sctree->selecting_range = TRUE;
250 gtk_clist_unselect_all (GTK_CLIST (sctree));
251 sctree->selecting_range = FALSE;
257 node = gtk_ctree_node_nth (GTK_CTREE(sctree), row);
259 /*No need to manage overlapped list*/
261 if (row_is_selected(sctree, row))
262 gtk_clist_unselect_row (GTK_CLIST (sctree), row, col);
264 g_signal_emit_by_name
266 "tree_select_row", node, col);
268 g_signal_emit_by_name
270 "tree_select_row", node, col);
272 sctree->anchor_row = node;
274 select_range (sctree, row);
276 gtk_clist_thaw (GTK_CLIST (sctree));
279 /* Our handler for button_press events. We override all of GtkCList's broken
283 gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
292 g_return_val_if_fail (widget != NULL, FALSE);
293 g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
294 g_return_val_if_fail (event != NULL, FALSE);
296 sctree = GTK_SCTREE (widget);
297 clist = GTK_CLIST (widget);
300 if (event->window != clist->clist_window)
301 return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
303 on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
305 if (on_row && !GTK_WIDGET_HAS_FOCUS(widget))
306 gtk_widget_grab_focus (widget);
308 if (gtk_ctree_is_hot_spot (GTK_CTREE(sctree), event->x, event->y)) {
309 gtk_ctree_toggle_expansion
311 gtk_ctree_node_nth(GTK_CTREE(sctree), row));
315 switch (event->type) {
316 case GDK_BUTTON_PRESS:
317 if (event->button == 1 || event->button == 2) {
318 if (event->button == 2)
319 event->state &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK);
321 /* Save the mouse info for DnD */
322 sctree->dnd_press_button = event->button;
323 sctree->dnd_press_x = event->x;
324 sctree->dnd_press_y = event->y;
326 /* Handle selection */
327 if ((row_is_selected (sctree, row)
328 && !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
329 || ((event->state & GDK_CONTROL_MASK)
330 && !(event->state & GDK_SHIFT_MASK))) {
331 sctree->dnd_select_pending = TRUE;
332 sctree->dnd_select_pending_state = event->state;
333 sctree->dnd_select_pending_row = row;
335 select_row (sctree, row, col, event->state);
337 sctree->selecting_range = TRUE;
338 gtk_clist_unselect_all (clist);
339 sctree->selecting_range = FALSE;
343 } else if (event->button == 3) {
344 /* Emit *_popup_menu signal*/
346 if (!row_is_selected(sctree,row))
347 select_row (sctree, row, col, 0);
348 g_signal_emit (G_OBJECT (sctree),
349 sctree_signals[ROW_POPUP_MENU],
352 sctree->selecting_range = TRUE;
353 gtk_clist_unselect_all(clist);
354 sctree->selecting_range = FALSE;
355 g_signal_emit (G_OBJECT (sctree),
356 sctree_signals[EMPTY_POPUP_MENU],
364 case GDK_2BUTTON_PRESS:
365 if (event->button != 1)
368 sctree->dnd_select_pending = FALSE;
369 sctree->dnd_select_pending_state = 0;
372 g_signal_emit (G_OBJECT (sctree),
373 sctree_signals[OPEN_ROW], 0);
385 /* Our handler for button_release events. We override all of GtkCList's broken
389 gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event)
397 g_return_val_if_fail (widget != NULL, FALSE);
398 g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
399 g_return_val_if_fail (event != NULL, FALSE);
401 sctree = GTK_SCTREE (widget);
402 clist = GTK_CLIST (widget);
405 if (event->window != clist->clist_window)
406 return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
408 on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
410 if (!(event->button == 1 || event->button == 2))
413 sctree->dnd_press_button = 0;
414 sctree->dnd_press_x = 0;
415 sctree->dnd_press_y = 0;
418 if (sctree->dnd_select_pending) {
419 select_row (sctree, row, col, sctree->dnd_select_pending_state);
420 sctree->dnd_select_pending = FALSE;
421 sctree->dnd_select_pending_state = 0;
430 /* Our handler for motion_notify events. We override all of GtkCList's broken
434 gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event)
439 g_return_val_if_fail (widget != NULL, FALSE);
440 g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
441 g_return_val_if_fail (event != NULL, FALSE);
443 sctree = GTK_SCTREE (widget);
444 clist = GTK_CLIST (widget);
446 if (event->window != clist->clist_window)
447 return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
449 if (!((sctree->dnd_press_button == 1 && (event->state & GDK_BUTTON1_MASK))
450 || (sctree->dnd_press_button == 2 && (event->state & GDK_BUTTON2_MASK))))
453 /* This is the same threshold value that is used in gtkdnd.c */
455 if (MAX (ABS (sctree->dnd_press_x - event->x),
456 ABS (sctree->dnd_press_y - event->y)) <= 3)
459 /* Handle any pending selections */
461 if (sctree->dnd_select_pending) {
462 if (!row_is_selected(sctree,sctree->dnd_select_pending_row))
464 sctree->dnd_select_pending_row,
466 sctree->dnd_select_pending_state);
468 sctree->dnd_select_pending = FALSE;
469 sctree->dnd_select_pending_state = 0;
472 g_signal_emit (G_OBJECT (sctree),
473 sctree_signals[START_DRAG],
475 sctree->dnd_press_button,
480 /* We override the drag_begin signal to do nothing */
482 gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context)
487 /* We override the drag_end signal to do nothing */
489 gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context)
494 /* We override the drag_data_get signal to do nothing */
496 gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
497 GtkSelectionData *data, guint info, guint time)
502 /* We override the drag_leave signal to do nothing */
504 gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time)
509 /* We override the drag_motion signal to do nothing */
511 gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
512 gint x, gint y, guint time)
517 /* We override the drag_drop signal to do nothing */
519 gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
520 gint x, gint y, guint time)
525 /* We override the drag_data_received signal to do nothing */
527 gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
528 gint x, gint y, GtkSelectionData *data,
529 guint info, guint time)
534 /* Our handler for the clear signal of the clist. We have to reset the anchor
538 gtk_sctree_clear (GtkCList *clist)
542 g_return_if_fail (clist != NULL);
543 g_return_if_fail (GTK_IS_SCTREE (clist));
545 sctree = GTK_SCTREE (clist);
546 sctree->anchor_row = NULL;
548 if (((GtkCListClass *)parent_class)->clear)
549 (* ((GtkCListClass *)parent_class)->clear) (clist);
552 /* Our handler for the change_focus_row_expansion signal of the ctree.
553 We have to set the anchor to parent visible node.
556 gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node)
558 g_return_if_fail (ctree != NULL);
559 g_return_if_fail (GTK_IS_SCTREE (ctree));
561 (* parent_class->tree_collapse) (ctree, node);
562 GTK_SCTREE(ctree)->anchor_row =
563 gtk_ctree_node_nth(ctree, GTK_CLIST(ctree)->focus_row);
566 GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column,
572 sctree = gtk_type_new (gtk_sctree_get_type ());
573 gtk_ctree_construct (GTK_CTREE (sctree), columns, tree_column, titles);
575 gtk_clist_set_selection_mode(GTK_CLIST(sctree), GTK_SELECTION_EXTENDED);
577 return GTK_WIDGET (sctree);
581 g_return_val_if_fail (columns > 0, NULL);
582 g_return_val_if_fail (tree_column >= 0, NULL);
584 widget = gtk_widget_new (TYPE_GTK_SCTREE,
585 "n_columns", columns,
586 "tree_column", tree_column,
589 GtkCList *clist = GTK_CLIST (widget);
592 for (i = 0; i < columns; i++)
593 gtk_clist_set_column_title (clist, i, titles[i]);
594 gtk_clist_column_titles_show (clist);
601 void gtk_sctree_select (GtkSCTree *sctree, GtkCTreeNode *node)
604 g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
608 void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCTreeNode *node, int state)
611 g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
615 void gtk_sctree_unselect_all (GtkSCTree *sctree)
617 sctree->selecting_range = TRUE;
618 gtk_clist_unselect_all(GTK_CLIST(sctree));
619 sctree->selecting_range = FALSE;
620 sctree->anchor_row = NULL;
623 void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCTreeNode *node)
625 sctree->anchor_row = node;
628 /***********************************************************
629 * Tree sorting functions *
630 ***********************************************************/
632 static void sink(GtkCList *clist, GPtrArray *numbers, gint root, gint bottom)
640 /* find the maximum element of numbers[root],
641 numbers[2*root] and numbers[2*root+1] */
643 if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, root)),
644 GTK_CTREE_ROW(g_ptr_array_index( numbers, j))) >= 0)
647 if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, k)),
648 GTK_CTREE_ROW (g_ptr_array_index( numbers, j))) > 0)
650 /* if numbers[root] wasn't the maximum element then
653 temp = g_ptr_array_index( numbers,root);
654 g_ptr_array_index( numbers, root) = g_ptr_array_index( numbers, j);
655 g_ptr_array_index( numbers, j) = temp;
656 sink( clist, numbers, j, bottom);
661 static void heap_sort(GtkCList *clist, GPtrArray *numbers, gint array_size)
667 for (i = (array_size / 2); i >= 1; i--)
668 sink( clist, numbers, i, array_size);
669 /* output the Heap */
670 for (i = array_size; i >= 2; i--) {
671 temp = g_ptr_array_index( numbers, 1);
672 g_ptr_array_index( numbers, 1) = g_ptr_array_index( numbers, i);
673 g_ptr_array_index( numbers, i) = temp;
674 sink( clist, numbers, 1, i-1);
679 tree_sort (GtkCTree *ctree,
683 GtkCTreeNode *list_start, *work, *next;
684 GPtrArray *row_array, *viewable_array;
689 clist = GTK_CLIST (ctree);
692 work = GTK_CTREE_ROW (node)->children;
694 work = GTK_CTREE_NODE (clist->row_list);
696 row_array = g_ptr_array_new();
697 viewable_array = g_ptr_array_new();
700 g_ptr_array_add( row_array, NULL);
702 /* add all rows to row_array */
703 g_ptr_array_add( row_array, work);
704 if (GTK_CTREE_ROW (work)->parent && gtk_ctree_is_viewable( ctree, work))
705 g_ptr_array_add( viewable_array, GTK_CTREE_ROW (work)->parent);
706 next = GTK_CTREE_ROW (work)->sibling;
707 gtk_ctree_unlink( ctree, work, FALSE);
711 heap_sort( clist, row_array, (row_array->len)-1);
714 list_start = GTK_CTREE_ROW (node)->children;
716 list_start = GTK_CTREE_NODE (clist->row_list);
718 if (clist->sort_type == GTK_SORT_ASCENDING) {
719 for (i=(row_array->len)-1; i>=1; i--) {
720 work = g_ptr_array_index( row_array, i);
721 gtk_ctree_link( ctree, work, node, list_start, FALSE);
723 /* insert work at the beginning of the list */
726 for (i=1; i<row_array->len; i++) {
727 work = g_ptr_array_index( row_array, i);
728 gtk_ctree_link( ctree, work, node, list_start, FALSE);
730 /* insert work at the beginning of the list */
734 for (i=0; i<viewable_array->len; i++) {
735 gtk_ctree_expand( ctree, g_ptr_array_index( viewable_array, i));
740 g_ptr_array_free( row_array, TRUE);
741 g_ptr_array_free( viewable_array, TRUE);
745 gtk_sctree_sort_recursive (GtkCTree *ctree,
749 GtkCTreeNode *focus_node = NULL;
751 g_return_if_fail (ctree != NULL);
752 g_return_if_fail (GTK_IS_CTREE (ctree));
754 clist = GTK_CLIST (ctree);
756 gtk_clist_freeze (clist);
758 if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
759 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
761 g_list_free (clist->undo_selection);
762 g_list_free (clist->undo_unselection);
763 clist->undo_selection = NULL;
764 clist->undo_unselection = NULL;
767 if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
768 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
770 gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_sort), NULL);
773 tree_sort (ctree, NULL, NULL);
776 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
777 clist->undo_anchor = clist->focus_row;
780 gtk_clist_thaw (clist);
784 gtk_sctree_sort_node (GtkCTree *ctree,
788 GtkCTreeNode *focus_node = NULL;
790 g_return_if_fail (ctree != NULL);
791 g_return_if_fail (GTK_IS_CTREE (ctree));
793 clist = GTK_CLIST (ctree);
795 gtk_clist_freeze (clist);
797 if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
798 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
800 g_list_free (clist->undo_selection);
801 g_list_free (clist->undo_unselection);
802 clist->undo_selection = NULL;
803 clist->undo_unselection = NULL;
806 if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
807 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
809 tree_sort (ctree, node, NULL);
812 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
813 clist->undo_anchor = clist->focus_row;
816 gtk_clist_thaw (clist);
819 /************************************************************************/
822 gtk_ctree_unlink (GtkCTree *ctree,
824 gboolean update_focus_row)
831 GtkCTreeNode *parent;
834 g_return_if_fail (ctree != NULL);
835 g_return_if_fail (GTK_IS_CTREE (ctree));
836 g_return_if_fail (node != NULL);
838 clist = GTK_CLIST (ctree);
840 if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
841 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
843 g_list_free (clist->undo_selection);
844 g_list_free (clist->undo_unselection);
845 clist->undo_selection = NULL;
846 clist->undo_unselection = NULL;
849 visible = gtk_ctree_is_viewable (ctree, node);
851 /* clist->row_list_end unlinked ? */
852 if (visible && (GTK_CTREE_NODE_NEXT (node) == NULL ||
853 (GTK_CTREE_ROW (node)->children && gtk_ctree_is_ancestor (ctree, node,
854 GTK_CTREE_NODE (clist->row_list_end)))))
855 clist->row_list_end = (GList *) (GTK_CTREE_NODE_PREV (node));
859 level = GTK_CTREE_ROW (node)->level;
860 work = GTK_CTREE_NODE_NEXT (node);
861 while (work && GTK_CTREE_ROW (work)->level > level) {
862 work = GTK_CTREE_NODE_NEXT (work);
867 clist->rows -= (rows + 1);
869 if (update_focus_row) {
872 pos = g_list_position (clist->row_list, (GList *)node);
873 if (pos + rows < clist->focus_row)
874 clist->focus_row -= (rows + 1);
875 else if (pos <= clist->focus_row) {
876 if (!GTK_CTREE_ROW (node)->sibling)
877 clist->focus_row = MAX (pos - 1, 0);
879 clist->focus_row = pos;
881 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
883 clist->undo_anchor = clist->focus_row;
888 list = (GList *)GTK_CTREE_NODE_PREV (work);
890 list = (GList *)work;
891 list->prev = (GList *)GTK_CTREE_NODE_PREV (node);
894 if (GTK_CTREE_NODE_PREV (node) &&
895 GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (node)) == node) {
896 list = (GList *)GTK_CTREE_NODE_PREV (node);
897 list->next = (GList *)work;
901 parent = GTK_CTREE_ROW (node)->parent;
903 if (GTK_CTREE_ROW (parent)->children == node) {
904 GTK_CTREE_ROW (parent)->children = GTK_CTREE_ROW (node)->sibling;
905 if (!GTK_CTREE_ROW (parent)->children)
906 gtk_ctree_collapse (ctree, parent);
909 GtkCTreeNode *sibling;
911 sibling = GTK_CTREE_ROW (parent)->children;
912 while (GTK_CTREE_ROW (sibling)->sibling != node)
913 sibling = GTK_CTREE_ROW (sibling)->sibling;
914 GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
918 if (clist->row_list == (GList *)node)
919 clist->row_list = (GList *) (GTK_CTREE_ROW (node)->sibling);
921 GtkCTreeNode *sibling;
923 sibling = GTK_CTREE_NODE (clist->row_list);
924 while (GTK_CTREE_ROW (sibling)->sibling != node)
925 sibling = GTK_CTREE_ROW (sibling)->sibling;
926 GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
932 gtk_ctree_link (GtkCTree *ctree,
934 GtkCTreeNode *parent,
935 GtkCTreeNode *sibling,
936 gboolean update_focus_row)
942 gboolean visible = FALSE;
946 g_return_if_fail (GTK_CTREE_ROW (sibling)->parent == parent);
947 g_return_if_fail (node != NULL);
948 g_return_if_fail (node != sibling);
949 g_return_if_fail (node != parent);
951 clist = GTK_CLIST (ctree);
953 if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
954 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
956 g_list_free (clist->undo_selection);
957 g_list_free (clist->undo_unselection);
958 clist->undo_selection = NULL;
959 clist->undo_unselection = NULL;
962 for (rows = 1, list_end = (GList *)node; list_end->next;
963 list_end = list_end->next)
966 GTK_CTREE_ROW (node)->parent = parent;
967 GTK_CTREE_ROW (node)->sibling = sibling;
969 if (!parent || (parent && (gtk_ctree_is_viewable (ctree, parent) &&
970 GTK_CTREE_ROW (parent)->expanded))) {
976 work = (GList *)(GTK_CTREE_ROW (parent)->children);
978 work = clist->row_list;
981 if (work != (GList *)sibling) {
982 while (GTK_CTREE_ROW (work)->sibling != sibling)
983 work = (GList *)(GTK_CTREE_ROW (work)->sibling);
984 GTK_CTREE_ROW (work)->sibling = node;
987 if (sibling == GTK_CTREE_NODE (clist->row_list))
988 clist->row_list = (GList *) node;
989 if (GTK_CTREE_NODE_PREV (sibling) &&
990 GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (sibling)) == sibling) {
991 list = (GList *)GTK_CTREE_NODE_PREV (sibling);
992 list->next = (GList *)node;
995 list = (GList *)node;
996 list->prev = (GList *)GTK_CTREE_NODE_PREV (sibling);
997 list_end->next = (GList *)sibling;
998 list = (GList *)sibling;
999 list->prev = list_end;
1000 if (parent && GTK_CTREE_ROW (parent)->children == sibling)
1001 GTK_CTREE_ROW (parent)->children = node;
1006 while (GTK_CTREE_ROW (work)->sibling)
1007 work = (GList *)(GTK_CTREE_ROW (work)->sibling);
1008 GTK_CTREE_ROW (work)->sibling = node;
1010 /* find last visible child of sibling */
1011 work = (GList *) gtk_ctree_last_visible (ctree,
1012 GTK_CTREE_NODE (work));
1014 list_end->next = work->next;
1016 list = work->next->prev = list_end;
1017 work->next = (GList *)node;
1018 list = (GList *)node;
1023 GTK_CTREE_ROW (parent)->children = node;
1024 list = (GList *)node;
1025 list->prev = (GList *)parent;
1026 if (GTK_CTREE_ROW (parent)->expanded) {
1027 list_end->next = (GList *)GTK_CTREE_NODE_NEXT (parent);
1028 if (GTK_CTREE_NODE_NEXT(parent)) {
1029 list = (GList *)GTK_CTREE_NODE_NEXT (parent);
1030 list->prev = list_end;
1032 list = (GList *)parent;
1033 list->next = (GList *)node;
1036 list_end->next = NULL;
1039 clist->row_list = (GList *)node;
1040 list = (GList *)node;
1042 list_end->next = NULL;
1047 gtk_ctree_pre_recursive (ctree, node, tree_update_level, NULL);
1049 if (clist->row_list_end == NULL ||
1050 clist->row_list_end->next == (GList *)node)
1051 clist->row_list_end = list_end;
1053 if (visible && update_focus_row) {
1056 pos = g_list_position (clist->row_list, (GList *)node);
1058 if (pos <= clist->focus_row) {
1059 clist->focus_row += rows;
1060 clist->undo_anchor = clist->focus_row;
1066 tree_update_level (GtkCTree *ctree,
1073 if (GTK_CTREE_ROW (node)->parent)
1074 GTK_CTREE_ROW (node)->level =
1075 GTK_CTREE_ROW (GTK_CTREE_ROW (node)->parent)->level + 1;
1077 GTK_CTREE_ROW (node)->level = 1;
1080 static GtkCTreeNode *
1081 gtk_ctree_last_visible (GtkCTree *ctree,
1089 work = GTK_CTREE_ROW (node)->children;
1091 if (!work || !GTK_CTREE_ROW (node)->expanded)
1094 while (GTK_CTREE_ROW (work)->sibling)
1095 work = GTK_CTREE_ROW (work)->sibling;
1097 return gtk_ctree_last_visible (ctree, work);
1100 /* this wrapper simply replaces NULL pixmaps
1101 * with a transparent, 1x1 pixmap. This works
1102 * around a memory problem deep inside gtk,
1103 * revealed by valgrind.
1105 GtkCTreeNode* gtk_sctree_insert_node (GtkCTree *ctree,
1106 GtkCTreeNode *parent,
1107 GtkCTreeNode *sibling,
1110 GdkPixmap *pixmap_closed,
1111 GdkBitmap *mask_closed,
1112 GdkPixmap *pixmap_opened,
1113 GdkBitmap *mask_opened,
1118 stock_pixmap_gdk((GtkWidget*)ctree, STOCK_PIXMAP_EMPTY,
1119 &emptyxpm, &emptyxpmmask);
1121 if (!pixmap_closed) {
1122 pixmap_closed = emptyxpm;
1123 mask_closed = emptyxpmmask;
1125 if (!pixmap_opened) {
1126 pixmap_opened = emptyxpm;
1127 mask_opened = emptyxpmmask;
1129 return gtk_ctree_insert_node(ctree, parent, sibling, text,spacing,
1130 pixmap_closed, mask_closed, pixmap_opened, mask_opened,
1134 /* this wrapper simply replaces NULL pixmaps
1135 * with a transparent, 1x1 pixmap. This works
1136 * around a memory problem deep inside gtk,
1137 * revealed by valgrind.
1139 void gtk_sctree_set_node_info (GtkCTree *ctree,
1143 GdkPixmap *pixmap_closed,
1144 GdkBitmap *mask_closed,
1145 GdkPixmap *pixmap_opened,
1146 GdkBitmap *mask_opened,
1151 stock_pixmap_gdk((GtkWidget*)ctree, STOCK_PIXMAP_EMPTY,
1152 &emptyxpm, &emptyxpmmask);
1154 if (!pixmap_closed) {
1155 pixmap_closed = emptyxpm;
1156 mask_closed = emptyxpmmask;
1158 if (!pixmap_opened) {
1159 pixmap_opened = emptyxpm;
1160 mask_opened = emptyxpmmask;
1162 gtk_ctree_set_node_info(ctree, node, text, spacing,
1163 pixmap_closed, mask_closed, pixmap_opened, mask_opened,