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 gtk_clist_unselect_all (GTK_CLIST (sctree));
254 node = gtk_ctree_node_nth (GTK_CTREE(sctree), row);
256 /*No need to manage overlapped list*/
258 if (row_is_selected(sctree, row))
259 gtk_clist_unselect_row (GTK_CLIST (sctree), row, col);
261 g_signal_emit_by_name
263 "tree_select_row", node, col);
265 g_signal_emit_by_name
267 "tree_select_row", node, col);
269 sctree->anchor_row = node;
271 select_range (sctree, row);
273 gtk_clist_thaw (GTK_CLIST (sctree));
276 /* Our handler for button_press events. We override all of GtkCList's broken
280 gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
289 g_return_val_if_fail (widget != NULL, FALSE);
290 g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
291 g_return_val_if_fail (event != NULL, FALSE);
293 sctree = GTK_SCTREE (widget);
294 clist = GTK_CLIST (widget);
297 if (event->window != clist->clist_window)
298 return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
300 on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
302 if (on_row && !GTK_WIDGET_HAS_FOCUS(widget))
303 gtk_widget_grab_focus (widget);
305 if (gtk_ctree_is_hot_spot (GTK_CTREE(sctree), event->x, event->y)) {
306 gtk_ctree_toggle_expansion
308 gtk_ctree_node_nth(GTK_CTREE(sctree), row));
312 switch (event->type) {
313 case GDK_BUTTON_PRESS:
314 if (event->button == 1 || event->button == 2) {
315 if (event->button == 2)
316 event->state &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK);
318 /* Save the mouse info for DnD */
319 sctree->dnd_press_button = event->button;
320 sctree->dnd_press_x = event->x;
321 sctree->dnd_press_y = event->y;
323 /* Handle selection */
324 if ((row_is_selected (sctree, row)
325 && !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
326 || ((event->state & GDK_CONTROL_MASK)
327 && !(event->state & GDK_SHIFT_MASK))) {
328 sctree->dnd_select_pending = TRUE;
329 sctree->dnd_select_pending_state = event->state;
330 sctree->dnd_select_pending_row = row;
332 select_row (sctree, row, col, event->state);
334 gtk_clist_unselect_all (clist);
337 } else if (event->button == 3) {
338 /* Emit *_popup_menu signal*/
340 if (!row_is_selected(sctree,row))
341 select_row (sctree, row, col, 0);
342 g_signal_emit (G_OBJECT (sctree),
343 sctree_signals[ROW_POPUP_MENU],
346 gtk_clist_unselect_all(clist);
347 g_signal_emit (G_OBJECT (sctree),
348 sctree_signals[EMPTY_POPUP_MENU],
356 case GDK_2BUTTON_PRESS:
357 if (event->button != 1)
360 sctree->dnd_select_pending = FALSE;
361 sctree->dnd_select_pending_state = 0;
364 g_signal_emit (G_OBJECT (sctree),
365 sctree_signals[OPEN_ROW], 0);
377 /* Our handler for button_release events. We override all of GtkCList's broken
381 gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event)
389 g_return_val_if_fail (widget != NULL, FALSE);
390 g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
391 g_return_val_if_fail (event != NULL, FALSE);
393 sctree = GTK_SCTREE (widget);
394 clist = GTK_CLIST (widget);
397 if (event->window != clist->clist_window)
398 return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
400 on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
402 if (!(event->button == 1 || event->button == 2))
405 sctree->dnd_press_button = 0;
406 sctree->dnd_press_x = 0;
407 sctree->dnd_press_y = 0;
410 if (sctree->dnd_select_pending) {
411 select_row (sctree, row, col, sctree->dnd_select_pending_state);
412 sctree->dnd_select_pending = FALSE;
413 sctree->dnd_select_pending_state = 0;
422 /* Our handler for motion_notify events. We override all of GtkCList's broken
426 gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event)
431 g_return_val_if_fail (widget != NULL, FALSE);
432 g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
433 g_return_val_if_fail (event != NULL, FALSE);
435 sctree = GTK_SCTREE (widget);
436 clist = GTK_CLIST (widget);
438 if (event->window != clist->clist_window)
439 return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
441 if (!((sctree->dnd_press_button == 1 && (event->state & GDK_BUTTON1_MASK))
442 || (sctree->dnd_press_button == 2 && (event->state & GDK_BUTTON2_MASK))))
445 /* This is the same threshold value that is used in gtkdnd.c */
447 if (MAX (ABS (sctree->dnd_press_x - event->x),
448 ABS (sctree->dnd_press_y - event->y)) <= 3)
451 /* Handle any pending selections */
453 if (sctree->dnd_select_pending) {
454 if (!row_is_selected(sctree,sctree->dnd_select_pending_row))
456 sctree->dnd_select_pending_row,
458 sctree->dnd_select_pending_state);
460 sctree->dnd_select_pending = FALSE;
461 sctree->dnd_select_pending_state = 0;
464 g_signal_emit (G_OBJECT (sctree),
465 sctree_signals[START_DRAG],
467 sctree->dnd_press_button,
472 /* We override the drag_begin signal to do nothing */
474 gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context)
479 /* We override the drag_end signal to do nothing */
481 gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context)
486 /* We override the drag_data_get signal to do nothing */
488 gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
489 GtkSelectionData *data, guint info, guint time)
494 /* We override the drag_leave signal to do nothing */
496 gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time)
501 /* We override the drag_motion signal to do nothing */
503 gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
504 gint x, gint y, guint time)
509 /* We override the drag_drop signal to do nothing */
511 gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
512 gint x, gint y, guint time)
517 /* We override the drag_data_received signal to do nothing */
519 gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
520 gint x, gint y, GtkSelectionData *data,
521 guint info, guint time)
526 /* Our handler for the clear signal of the clist. We have to reset the anchor
530 gtk_sctree_clear (GtkCList *clist)
534 g_return_if_fail (clist != NULL);
535 g_return_if_fail (GTK_IS_SCTREE (clist));
537 sctree = GTK_SCTREE (clist);
538 sctree->anchor_row = NULL;
540 if (((GtkCListClass *)parent_class)->clear)
541 (* ((GtkCListClass *)parent_class)->clear) (clist);
544 /* Our handler for the change_focus_row_expansion signal of the ctree.
545 We have to set the anchor to parent visible node.
548 gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node)
550 g_return_if_fail (ctree != NULL);
551 g_return_if_fail (GTK_IS_SCTREE (ctree));
553 (* parent_class->tree_collapse) (ctree, node);
554 GTK_SCTREE(ctree)->anchor_row =
555 gtk_ctree_node_nth(ctree, GTK_CLIST(ctree)->focus_row);
558 GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column,
564 sctree = gtk_type_new (gtk_sctree_get_type ());
565 gtk_ctree_construct (GTK_CTREE (sctree), columns, tree_column, titles);
567 gtk_clist_set_selection_mode(GTK_CLIST(sctree), GTK_SELECTION_EXTENDED);
569 return GTK_WIDGET (sctree);
573 g_return_val_if_fail (columns > 0, NULL);
574 g_return_val_if_fail (tree_column >= 0, NULL);
576 widget = gtk_widget_new (TYPE_GTK_SCTREE,
577 "n_columns", columns,
578 "tree_column", tree_column,
581 GtkCList *clist = GTK_CLIST (widget);
584 for (i = 0; i < columns; i++)
585 gtk_clist_set_column_title (clist, i, titles[i]);
586 gtk_clist_column_titles_show (clist);
593 void gtk_sctree_select (GtkSCTree *sctree, GtkCTreeNode *node)
596 g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
600 void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCTreeNode *node, int state)
603 g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
607 void gtk_sctree_unselect_all (GtkSCTree *sctree)
609 gtk_clist_unselect_all(GTK_CLIST(sctree));
610 sctree->anchor_row = NULL;
613 void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCTreeNode *node)
615 sctree->anchor_row = node;
618 /***********************************************************
619 * Tree sorting functions *
620 ***********************************************************/
622 static void sink(GtkCList *clist, GPtrArray *numbers, gint root, gint bottom)
630 /* find the maximum element of numbers[root],
631 numbers[2*root] and numbers[2*root+1] */
633 if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, root)),
634 GTK_CTREE_ROW(g_ptr_array_index( numbers, j))) >= 0)
637 if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, k)),
638 GTK_CTREE_ROW (g_ptr_array_index( numbers, j))) > 0)
640 /* if numbers[root] wasn't the maximum element then
643 temp = g_ptr_array_index( numbers,root);
644 g_ptr_array_index( numbers, root) = g_ptr_array_index( numbers, j);
645 g_ptr_array_index( numbers, j) = temp;
646 sink( clist, numbers, j, bottom);
651 static void heap_sort(GtkCList *clist, GPtrArray *numbers, gint array_size)
657 for (i = (array_size / 2); i >= 1; i--)
658 sink( clist, numbers, i, array_size);
659 /* output the Heap */
660 for (i = array_size; i >= 2; i--) {
661 temp = g_ptr_array_index( numbers, 1);
662 g_ptr_array_index( numbers, 1) = g_ptr_array_index( numbers, i);
663 g_ptr_array_index( numbers, i) = temp;
664 sink( clist, numbers, 1, i-1);
669 tree_sort (GtkCTree *ctree,
673 GtkCTreeNode *list_start, *work, *next;
674 GPtrArray *row_array, *viewable_array;
679 clist = GTK_CLIST (ctree);
682 work = GTK_CTREE_ROW (node)->children;
684 work = GTK_CTREE_NODE (clist->row_list);
686 row_array = g_ptr_array_new();
687 viewable_array = g_ptr_array_new();
690 g_ptr_array_add( row_array, NULL);
692 /* add all rows to row_array */
693 g_ptr_array_add( row_array, work);
694 if (GTK_CTREE_ROW (work)->parent && gtk_ctree_is_viewable( ctree, work))
695 g_ptr_array_add( viewable_array, GTK_CTREE_ROW (work)->parent);
696 next = GTK_CTREE_ROW (work)->sibling;
697 gtk_ctree_unlink( ctree, work, FALSE);
701 heap_sort( clist, row_array, (row_array->len)-1);
704 list_start = GTK_CTREE_ROW (node)->children;
706 list_start = GTK_CTREE_NODE (clist->row_list);
708 if (clist->sort_type == GTK_SORT_ASCENDING) {
709 for (i=(row_array->len)-1; i>=1; i--) {
710 work = g_ptr_array_index( row_array, i);
711 gtk_ctree_link( ctree, work, node, list_start, FALSE);
713 /* insert work at the beginning of the list */
716 for (i=1; i<row_array->len; i++) {
717 work = g_ptr_array_index( row_array, i);
718 gtk_ctree_link( ctree, work, node, list_start, FALSE);
720 /* insert work at the beginning of the list */
724 for (i=0; i<viewable_array->len; i++) {
725 gtk_ctree_expand( ctree, g_ptr_array_index( viewable_array, i));
730 g_ptr_array_free( row_array, TRUE);
731 g_ptr_array_free( viewable_array, TRUE);
735 gtk_sctree_sort_recursive (GtkCTree *ctree,
739 GtkCTreeNode *focus_node = NULL;
741 g_return_if_fail (ctree != NULL);
742 g_return_if_fail (GTK_IS_CTREE (ctree));
744 clist = GTK_CLIST (ctree);
746 gtk_clist_freeze (clist);
748 if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
749 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
751 g_list_free (clist->undo_selection);
752 g_list_free (clist->undo_unselection);
753 clist->undo_selection = NULL;
754 clist->undo_unselection = NULL;
757 if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
758 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
760 gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_sort), NULL);
763 tree_sort (ctree, NULL, NULL);
766 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
767 clist->undo_anchor = clist->focus_row;
770 gtk_clist_thaw (clist);
774 gtk_sctree_sort_node (GtkCTree *ctree,
778 GtkCTreeNode *focus_node = NULL;
780 g_return_if_fail (ctree != NULL);
781 g_return_if_fail (GTK_IS_CTREE (ctree));
783 clist = GTK_CLIST (ctree);
785 gtk_clist_freeze (clist);
787 if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
788 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
790 g_list_free (clist->undo_selection);
791 g_list_free (clist->undo_unselection);
792 clist->undo_selection = NULL;
793 clist->undo_unselection = NULL;
796 if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
797 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
799 tree_sort (ctree, node, NULL);
802 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
803 clist->undo_anchor = clist->focus_row;
806 gtk_clist_thaw (clist);
809 /************************************************************************/
812 gtk_ctree_unlink (GtkCTree *ctree,
814 gboolean update_focus_row)
821 GtkCTreeNode *parent;
824 g_return_if_fail (ctree != NULL);
825 g_return_if_fail (GTK_IS_CTREE (ctree));
826 g_return_if_fail (node != NULL);
828 clist = GTK_CLIST (ctree);
830 if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
831 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
833 g_list_free (clist->undo_selection);
834 g_list_free (clist->undo_unselection);
835 clist->undo_selection = NULL;
836 clist->undo_unselection = NULL;
839 visible = gtk_ctree_is_viewable (ctree, node);
841 /* clist->row_list_end unlinked ? */
842 if (visible && (GTK_CTREE_NODE_NEXT (node) == NULL ||
843 (GTK_CTREE_ROW (node)->children && gtk_ctree_is_ancestor (ctree, node,
844 GTK_CTREE_NODE (clist->row_list_end)))))
845 clist->row_list_end = (GList *) (GTK_CTREE_NODE_PREV (node));
849 level = GTK_CTREE_ROW (node)->level;
850 work = GTK_CTREE_NODE_NEXT (node);
851 while (work && GTK_CTREE_ROW (work)->level > level) {
852 work = GTK_CTREE_NODE_NEXT (work);
857 clist->rows -= (rows + 1);
859 if (update_focus_row) {
862 pos = g_list_position (clist->row_list, (GList *)node);
863 if (pos + rows < clist->focus_row)
864 clist->focus_row -= (rows + 1);
865 else if (pos <= clist->focus_row) {
866 if (!GTK_CTREE_ROW (node)->sibling)
867 clist->focus_row = MAX (pos - 1, 0);
869 clist->focus_row = pos;
871 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
873 clist->undo_anchor = clist->focus_row;
878 list = (GList *)GTK_CTREE_NODE_PREV (work);
880 list = (GList *)work;
881 list->prev = (GList *)GTK_CTREE_NODE_PREV (node);
884 if (GTK_CTREE_NODE_PREV (node) &&
885 GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (node)) == node) {
886 list = (GList *)GTK_CTREE_NODE_PREV (node);
887 list->next = (GList *)work;
891 parent = GTK_CTREE_ROW (node)->parent;
893 if (GTK_CTREE_ROW (parent)->children == node) {
894 GTK_CTREE_ROW (parent)->children = GTK_CTREE_ROW (node)->sibling;
895 if (!GTK_CTREE_ROW (parent)->children)
896 gtk_ctree_collapse (ctree, parent);
899 GtkCTreeNode *sibling;
901 sibling = GTK_CTREE_ROW (parent)->children;
902 while (GTK_CTREE_ROW (sibling)->sibling != node)
903 sibling = GTK_CTREE_ROW (sibling)->sibling;
904 GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
908 if (clist->row_list == (GList *)node)
909 clist->row_list = (GList *) (GTK_CTREE_ROW (node)->sibling);
911 GtkCTreeNode *sibling;
913 sibling = GTK_CTREE_NODE (clist->row_list);
914 while (GTK_CTREE_ROW (sibling)->sibling != node)
915 sibling = GTK_CTREE_ROW (sibling)->sibling;
916 GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
922 gtk_ctree_link (GtkCTree *ctree,
924 GtkCTreeNode *parent,
925 GtkCTreeNode *sibling,
926 gboolean update_focus_row)
932 gboolean visible = FALSE;
936 g_return_if_fail (GTK_CTREE_ROW (sibling)->parent == parent);
937 g_return_if_fail (node != NULL);
938 g_return_if_fail (node != sibling);
939 g_return_if_fail (node != parent);
941 clist = GTK_CLIST (ctree);
943 if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
944 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
946 g_list_free (clist->undo_selection);
947 g_list_free (clist->undo_unselection);
948 clist->undo_selection = NULL;
949 clist->undo_unselection = NULL;
952 for (rows = 1, list_end = (GList *)node; list_end->next;
953 list_end = list_end->next)
956 GTK_CTREE_ROW (node)->parent = parent;
957 GTK_CTREE_ROW (node)->sibling = sibling;
959 if (!parent || (parent && (gtk_ctree_is_viewable (ctree, parent) &&
960 GTK_CTREE_ROW (parent)->expanded))) {
966 work = (GList *)(GTK_CTREE_ROW (parent)->children);
968 work = clist->row_list;
971 if (work != (GList *)sibling) {
972 while (GTK_CTREE_ROW (work)->sibling != sibling)
973 work = (GList *)(GTK_CTREE_ROW (work)->sibling);
974 GTK_CTREE_ROW (work)->sibling = node;
977 if (sibling == GTK_CTREE_NODE (clist->row_list))
978 clist->row_list = (GList *) node;
979 if (GTK_CTREE_NODE_PREV (sibling) &&
980 GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (sibling)) == sibling) {
981 list = (GList *)GTK_CTREE_NODE_PREV (sibling);
982 list->next = (GList *)node;
985 list = (GList *)node;
986 list->prev = (GList *)GTK_CTREE_NODE_PREV (sibling);
987 list_end->next = (GList *)sibling;
988 list = (GList *)sibling;
989 list->prev = list_end;
990 if (parent && GTK_CTREE_ROW (parent)->children == sibling)
991 GTK_CTREE_ROW (parent)->children = node;
996 while (GTK_CTREE_ROW (work)->sibling)
997 work = (GList *)(GTK_CTREE_ROW (work)->sibling);
998 GTK_CTREE_ROW (work)->sibling = node;
1000 /* find last visible child of sibling */
1001 work = (GList *) gtk_ctree_last_visible (ctree,
1002 GTK_CTREE_NODE (work));
1004 list_end->next = work->next;
1006 list = work->next->prev = list_end;
1007 work->next = (GList *)node;
1008 list = (GList *)node;
1013 GTK_CTREE_ROW (parent)->children = node;
1014 list = (GList *)node;
1015 list->prev = (GList *)parent;
1016 if (GTK_CTREE_ROW (parent)->expanded) {
1017 list_end->next = (GList *)GTK_CTREE_NODE_NEXT (parent);
1018 if (GTK_CTREE_NODE_NEXT(parent)) {
1019 list = (GList *)GTK_CTREE_NODE_NEXT (parent);
1020 list->prev = list_end;
1022 list = (GList *)parent;
1023 list->next = (GList *)node;
1026 list_end->next = NULL;
1029 clist->row_list = (GList *)node;
1030 list = (GList *)node;
1032 list_end->next = NULL;
1037 gtk_ctree_pre_recursive (ctree, node, tree_update_level, NULL);
1039 if (clist->row_list_end == NULL ||
1040 clist->row_list_end->next == (GList *)node)
1041 clist->row_list_end = list_end;
1043 if (visible && update_focus_row) {
1046 pos = g_list_position (clist->row_list, (GList *)node);
1048 if (pos <= clist->focus_row) {
1049 clist->focus_row += rows;
1050 clist->undo_anchor = clist->focus_row;
1056 tree_update_level (GtkCTree *ctree,
1063 if (GTK_CTREE_ROW (node)->parent)
1064 GTK_CTREE_ROW (node)->level =
1065 GTK_CTREE_ROW (GTK_CTREE_ROW (node)->parent)->level + 1;
1067 GTK_CTREE_ROW (node)->level = 1;
1070 static GtkCTreeNode *
1071 gtk_ctree_last_visible (GtkCTree *ctree,
1079 work = GTK_CTREE_ROW (node)->children;
1081 if (!work || !GTK_CTREE_ROW (node)->expanded)
1084 while (GTK_CTREE_ROW (work)->sibling)
1085 work = GTK_CTREE_ROW (work)->sibling;
1087 return gtk_ctree_last_visible (ctree, work);
1090 /* this wrapper simply replaces NULL pixmaps
1091 * with a transparent, 1x1 pixmap. This works
1092 * around a memory problem deep inside gtk,
1093 * revealed by valgrind.
1095 GtkCTreeNode* gtk_sctree_insert_node (GtkCTree *ctree,
1096 GtkCTreeNode *parent,
1097 GtkCTreeNode *sibling,
1100 GdkPixmap *pixmap_closed,
1101 GdkBitmap *mask_closed,
1102 GdkPixmap *pixmap_opened,
1103 GdkBitmap *mask_opened,
1108 stock_pixmap_gdk(ctree, STOCK_PIXMAP_EMPTY,
1109 &emptyxpm, &emptyxpmmask);
1111 if (!pixmap_closed) {
1112 pixmap_closed = emptyxpm;
1113 mask_closed = emptyxpmmask;
1115 if (!pixmap_opened) {
1116 pixmap_opened = emptyxpm;
1117 mask_opened = emptyxpmmask;
1119 return gtk_ctree_insert_node(ctree, parent, sibling, text,spacing,
1120 pixmap_closed, mask_closed, pixmap_opened, mask_opened,
1124 /* this wrapper simply replaces NULL pixmaps
1125 * with a transparent, 1x1 pixmap. This works
1126 * around a memory problem deep inside gtk,
1127 * revealed by valgrind.
1129 void gtk_sctree_set_node_info (GtkCTree *ctree,
1133 GdkPixmap *pixmap_closed,
1134 GdkBitmap *mask_closed,
1135 GdkPixmap *pixmap_opened,
1136 GdkBitmap *mask_opened,
1141 stock_pixmap_gdk(ctree, STOCK_PIXMAP_EMPTY,
1142 &emptyxpm, &emptyxpmmask);
1144 if (!pixmap_closed) {
1145 pixmap_closed = emptyxpm;
1146 mask_closed = emptyxpmmask;
1148 if (!pixmap_opened) {
1149 pixmap_opened = emptyxpm;
1150 mask_opened = emptyxpmmask;
1152 gtk_ctree_set_node_info(ctree, node, text, spacing,
1153 pixmap_closed, mask_closed, pixmap_opened, mask_opened,