2006-05-26 [colin] 2.2.0cvs57
[claws.git] / src / gtk / gtksctree.c
1 /*
2  * This program is based on gtkflist.c
3  */
4
5 #include <stdlib.h>
6
7 #include "gtksctree.h"
8 #include "sylpheed-marshal.h"
9 #include "stock_pixmap.h"
10
11 #define CLIST_UNFROZEN(clist)     (((GtkCList*) (clist))->freeze_count == 0)
12 #define CLIST_REFRESH(clist)    G_STMT_START { \
13   if (CLIST_UNFROZEN (clist)) \
14     GTK_CLIST_GET_CLASS (clist)->refresh ((GtkCList*) (clist)); \
15 } G_STMT_END
16 #define CELL_SPACING               1
17 #define CLIST_OPTIMUM_SIZE         64
18 #define COLUMN_INSET               3
19
20 enum {
21         ROW_POPUP_MENU,
22         EMPTY_POPUP_MENU,
23         OPEN_ROW,
24         START_DRAG,
25         LAST_SIGNAL
26 };
27
28 static GdkPixmap *emptyxpm = NULL;
29 static GdkBitmap *emptyxpmmask = NULL;
30
31 static void gtk_sctree_class_init (GtkSCTreeClass *class);
32 static void gtk_sctree_init (GtkSCTree *sctree);
33
34 static gint gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event);
35 static gint gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event);
36 static gint gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event);
37 static void gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context);
38 static void gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context);
39 static void gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
40                                      GtkSelectionData *data, guint info, guint time);
41 static void gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time);
42 static gboolean gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
43                                        gint x, gint y, guint time);
44 static gboolean gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
45                                      gint x, gint y, guint time);
46 static void gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
47                                           gint x, gint y, GtkSelectionData *data,
48                                           guint info, guint time);
49
50 static void gtk_sctree_clear (GtkCList *clist);
51 static void gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node);
52        
53 static void stree_sort (GtkCTree *ctree, GtkCTreeNode  *node, gpointer data);
54 void gtk_sctree_sort_node (GtkCTree *ctree, GtkCTreeNode *node);
55 void gtk_sctree_sort_recursive (GtkCTree *ctree, GtkCTreeNode *node);
56
57 static void gtk_sctree_link (GtkCTree *ctree,
58                         GtkCTreeNode  *node,
59                         GtkCTreeNode  *parent,
60                         GtkCTreeNode  *sibling,
61                         gboolean       update_focus_row);
62
63 static void gtk_sctree_unlink (GtkCTree      *ctree, 
64                         GtkCTreeNode  *node,
65                         gboolean       update_focus_row);
66
67 static void stree_update_level (GtkCTree      *ctree, 
68                         GtkCTreeNode  *node, 
69                         gpointer       data);
70
71 static GtkCTreeNode * gtk_sctree_last_visible (GtkCTree     *ctree,
72                                               GtkCTreeNode *node);
73 static void gtk_sctree_real_tree_expand            (GtkCTree      *ctree,
74                                                  GtkCTreeNode  *node);
75 static void
76 sreal_tree_move (GtkCTree     *ctree,
77                 GtkCTreeNode *node,
78                 GtkCTreeNode *new_parent, 
79                 GtkCTreeNode *new_sibling);
80
81 static GtkCTreeClass *parent_class;
82
83 static guint sctree_signals[LAST_SIGNAL];
84
85
86 /**
87  * gtk_sctree_get_type:
88  * @void: 
89  * 
90  * Creates the GtkSCTree class and its type information
91  * 
92  * Return value: The type ID for GtkSCTreeClass
93  **/
94 GType
95 gtk_sctree_get_type (void)
96 {
97         static GType sctree_type = 0;
98
99         if (!sctree_type) {
100                 GTypeInfo sctree_info = {
101                         sizeof (GtkSCTreeClass),
102
103                         (GBaseInitFunc) NULL,
104                         (GBaseFinalizeFunc) NULL,
105
106                         (GClassInitFunc) gtk_sctree_class_init,
107                         (GClassFinalizeFunc) NULL,
108                         NULL,   /* class_data */
109
110                         sizeof (GtkSCTree),
111                         0,      /* n_preallocs */
112                         (GInstanceInitFunc) gtk_sctree_init,
113                 };
114
115                 sctree_type = g_type_register_static (GTK_TYPE_CTREE, "GtkSCTree", &sctree_info, (GTypeFlags)0);
116         }
117
118         return sctree_type;
119 }
120
121 /* Standard class initialization function */
122 static void
123 gtk_sctree_class_init (GtkSCTreeClass *klass)
124 {
125         GtkObjectClass *object_class;
126         GtkWidgetClass *widget_class;
127         GtkCListClass *clist_class;
128         GtkCTreeClass *ctree_class;
129
130         object_class = (GtkObjectClass *) klass;
131         widget_class = (GtkWidgetClass *) klass;
132         clist_class = (GtkCListClass *) klass;
133         ctree_class = (GtkCTreeClass *) klass;
134
135         parent_class = gtk_type_class (gtk_ctree_get_type ());
136
137         sctree_signals[ROW_POPUP_MENU] =
138                 g_signal_new ("row_popup_menu",
139                               G_TYPE_FROM_CLASS (klass),
140                               G_SIGNAL_RUN_FIRST,
141                               G_STRUCT_OFFSET (GtkSCTreeClass, row_popup_menu),
142                               NULL, NULL,
143                               sylpheed_marshal_VOID__POINTER,
144                               G_TYPE_NONE, 1,
145                               GDK_TYPE_EVENT);
146         sctree_signals[EMPTY_POPUP_MENU] =
147                 g_signal_new ("empty_popup_menu",
148                               G_TYPE_FROM_CLASS (klass),
149                               G_SIGNAL_RUN_FIRST,
150                               G_STRUCT_OFFSET (GtkSCTreeClass, empty_popup_menu),
151                               NULL, NULL,
152                               sylpheed_marshal_VOID__POINTER,
153                               G_TYPE_NONE, 1,
154                               GDK_TYPE_EVENT);
155         sctree_signals[OPEN_ROW] =
156                 g_signal_new ("open_row",
157                               G_TYPE_FROM_CLASS (klass),
158                               G_SIGNAL_RUN_FIRST,
159                               G_STRUCT_OFFSET (GtkSCTreeClass, open_row),
160                               NULL, NULL,
161                               g_cclosure_marshal_VOID__VOID,
162                               G_TYPE_NONE, 0);
163         sctree_signals[START_DRAG] =
164                 g_signal_new ("start_drag",
165                               G_TYPE_FROM_CLASS (klass),
166                               G_SIGNAL_RUN_FIRST,
167                               G_STRUCT_OFFSET (GtkSCTreeClass, start_drag),
168                               NULL, NULL,
169                               sylpheed_marshal_VOID__INT_POINTER,
170                               G_TYPE_NONE, 2,
171                               G_TYPE_INT,
172                               GDK_TYPE_EVENT);
173
174         /* gtk_object_class_add_signals (object_class, sctree_signals, LAST_SIGNAL); */
175
176         clist_class->clear = gtk_sctree_clear;
177         ctree_class->tree_collapse = gtk_sctree_collapse;
178         ctree_class->tree_expand = gtk_sctree_real_tree_expand;
179         ctree_class->tree_move = sreal_tree_move;
180         
181         widget_class->button_press_event = gtk_sctree_button_press;
182         widget_class->button_release_event = gtk_sctree_button_release;
183         widget_class->motion_notify_event = gtk_sctree_motion;
184         widget_class->drag_begin = gtk_sctree_drag_begin;
185         widget_class->drag_end = gtk_sctree_drag_end;
186         widget_class->drag_data_get = gtk_sctree_drag_data_get;
187         widget_class->drag_leave = gtk_sctree_drag_leave;
188         widget_class->drag_motion = gtk_sctree_drag_motion;
189         widget_class->drag_drop = gtk_sctree_drag_drop;
190         widget_class->drag_data_received = gtk_sctree_drag_data_received;
191 }
192
193 /* Standard object initialization function */
194 static void
195 gtk_sctree_init (GtkSCTree *sctree)
196 {
197         sctree->anchor_row = NULL;
198
199         /* GtkCTree does not specify pointer motion by default */
200         gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
201         gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
202 }
203
204 /* Get information the specified row is selected. */
205
206 static gboolean
207 row_is_selected(GtkSCTree *sctree, gint row)
208 {
209         GtkCListRow *clist_row;
210         clist_row =  g_list_nth (GTK_CLIST(sctree)->row_list, row)->data;
211         return clist_row ? clist_row->state == GTK_STATE_SELECTED : FALSE;
212 }
213
214 /* Selects the rows between the anchor to the specified row, inclusive.  */
215 static void
216 select_range (GtkSCTree *sctree, gint row)
217 {
218         gint prev_row;
219         gint min, max;
220         gint i;
221         GList *node;
222         if (sctree->anchor_row == NULL) {
223                 prev_row = row;
224                 sctree->anchor_row = gtk_ctree_node_nth(GTK_CTREE(sctree), row);
225         } else
226                 prev_row = g_list_position(GTK_CLIST(sctree)->row_list,
227                                            (GList *)sctree->anchor_row);
228
229         if (row < prev_row) {
230                 min = row;
231                 max = prev_row;
232                 GTK_CLIST(sctree)->focus_row = max;
233         } else {
234                 min = prev_row;
235                 max = row;
236         }
237         sctree->selecting_range = TRUE;
238         
239         if (max < min) {
240                 int t = min;
241                 min = max;
242                 max = t;
243         }
244         node = g_list_nth((GTK_CLIST(sctree))->row_list, min);
245         for (i = min; i < max; i++) {
246                 if (node && GTK_CTREE_ROW (node)->row.selectable) {
247                         g_signal_emit_by_name(G_OBJECT(sctree), "tree_select_row",
248                                 node, -1);
249                 }
250                 node = node->next;
251         }
252
253         sctree->selecting_range = FALSE;
254         gtk_clist_select_row (GTK_CLIST (sctree), max, -1);
255 }
256
257 /* Handles row selection according to the specified modifier state */
258 static void
259 select_row (GtkSCTree *sctree, gint row, gint col, guint state)
260 {
261         gboolean range, additive;
262         g_return_if_fail (sctree != NULL);
263         g_return_if_fail (GTK_IS_SCTREE (sctree));
264     
265         range = ((state & GDK_SHIFT_MASK) != 0) &&
266                 (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
267                 (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
268         additive = ((state & GDK_CONTROL_MASK) != 0) &&
269                    (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
270                    (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
271
272         gtk_clist_freeze (GTK_CLIST (sctree));
273
274         GTK_CLIST(sctree)->focus_row = row;
275
276         if (!additive) {
277                 sctree->selecting_range = TRUE;
278                 gtk_clist_unselect_all (GTK_CLIST (sctree));
279                 sctree->selecting_range = FALSE;
280         }
281
282         if (!range) {
283                 GtkCTreeNode *node;
284
285                 node = gtk_ctree_node_nth (GTK_CTREE(sctree), row);
286
287                 /*No need to manage overlapped list*/
288                 if (additive) {
289                         if (row_is_selected(sctree, row))
290                                 gtk_clist_unselect_row (GTK_CLIST (sctree), row, col);
291                         else
292                                 g_signal_emit_by_name
293                                         (G_OBJECT (sctree),
294                                          "tree_select_row", node, col);
295                 } else {
296                         g_signal_emit_by_name
297                                 (G_OBJECT (sctree),
298                                  "tree_select_row", node, col);
299                 }
300                 sctree->anchor_row = node;
301         } else
302                 select_range (sctree, row);
303         
304         gtk_clist_thaw (GTK_CLIST (sctree));
305 }
306
307 /* Our handler for button_press events.  We override all of GtkCList's broken
308  * behavior.
309  */
310 static gint
311 gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
312 {
313         GtkSCTree *sctree;
314         GtkCList *clist;
315         gboolean on_row;
316         gint row;
317         gint col;
318         gint retval;
319
320         g_return_val_if_fail (widget != NULL, FALSE);
321         g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
322         g_return_val_if_fail (event != NULL, FALSE);
323
324         sctree = GTK_SCTREE (widget);
325         clist = GTK_CLIST (widget);
326         retval = FALSE;
327
328         if (event->window != clist->clist_window)
329                 return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
330
331         on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
332
333         if (on_row && !GTK_WIDGET_HAS_FOCUS(widget))
334                 gtk_widget_grab_focus (widget);
335
336         if (gtk_ctree_is_hot_spot (GTK_CTREE(sctree), event->x, event->y)) {
337                 gtk_ctree_toggle_expansion
338                         (GTK_CTREE(sctree), 
339                          gtk_ctree_node_nth(GTK_CTREE(sctree), row));
340                 return TRUE;
341         }
342
343         switch (event->type) {
344         case GDK_BUTTON_PRESS:
345                 if (event->button == 1 || event->button == 2) {
346                         if (event->button == 2)
347                                 event->state &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK);
348                         if (on_row) {
349                                 /* Save the mouse info for DnD */
350                                 sctree->dnd_press_button = event->button;
351                                 sctree->dnd_press_x = event->x;
352                                 sctree->dnd_press_y = event->y;
353
354                                 /* Handle selection */
355                                 if ((row_is_selected (sctree, row)
356                                      && !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
357                                     || ((event->state & GDK_CONTROL_MASK)
358                                         && !(event->state & GDK_SHIFT_MASK))) {
359                                         sctree->dnd_select_pending = TRUE;
360                                         sctree->dnd_select_pending_state = event->state;
361                                         sctree->dnd_select_pending_row = row;
362                                 } else {
363                                         select_row (sctree, row, col, event->state);
364                                 }
365                         } else {
366                                 sctree->selecting_range = TRUE;
367                                 gtk_clist_unselect_all (clist);
368                                 sctree->selecting_range = FALSE;
369                         }
370
371                         retval = TRUE;
372                 } else if (event->button == 3) {
373                         /* Emit *_popup_menu signal*/
374                         if (on_row) {
375                                 if (!row_is_selected(sctree,row))
376                                         select_row (sctree, row, col, 0);
377                                 g_signal_emit (G_OBJECT (sctree),
378                                                  sctree_signals[ROW_POPUP_MENU],
379                                                  0, event);
380                         } else {
381                                 sctree->selecting_range = TRUE;
382                                 gtk_clist_unselect_all(clist);
383                                 sctree->selecting_range = FALSE;
384                                 g_signal_emit (G_OBJECT (sctree),
385                                                  sctree_signals[EMPTY_POPUP_MENU],
386                                                  0, event);
387                         }
388                         retval = TRUE;
389                 }
390
391                 break;
392
393         case GDK_2BUTTON_PRESS:
394                 if (event->button != 1)
395                         break;
396
397                 sctree->dnd_select_pending = FALSE;
398                 sctree->dnd_select_pending_state = 0;
399
400                 if (on_row)
401                         g_signal_emit (G_OBJECT (sctree),
402                                        sctree_signals[OPEN_ROW], 0);
403
404                 retval = TRUE;
405                 break;
406
407         default:
408                 break;
409         }
410
411         return retval;
412 }
413
414 /* Our handler for button_release events.  We override all of GtkCList's broken
415  * behavior.
416  */
417 static gint
418 gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event)
419 {
420         GtkSCTree *sctree;
421         GtkCList *clist;
422         gint on_row;
423         gint row, col;
424         gint retval;
425
426         g_return_val_if_fail (widget != NULL, FALSE);
427         g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
428         g_return_val_if_fail (event != NULL, FALSE);
429
430         sctree = GTK_SCTREE (widget);
431         clist = GTK_CLIST (widget);
432         retval = FALSE;
433
434         if (event->window != clist->clist_window)
435                 return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
436
437         on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
438
439         if (!(event->button == 1 || event->button == 2))
440                 return FALSE;
441
442         sctree->dnd_press_button = 0;
443         sctree->dnd_press_x = 0;
444         sctree->dnd_press_y = 0;
445
446         if (on_row) {
447                 if (sctree->dnd_select_pending) {
448                         select_row (sctree, row, col, sctree->dnd_select_pending_state);
449                         sctree->dnd_select_pending = FALSE;
450                         sctree->dnd_select_pending_state = 0;
451                 }
452
453                 retval = TRUE;
454         }
455
456         return retval;
457 }
458
459 /* Our handler for motion_notify events.  We override all of GtkCList's broken
460  * behavior.
461  */
462 static gint
463 gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event)
464 {
465         GtkSCTree *sctree;
466         GtkCList *clist;
467
468         g_return_val_if_fail (widget != NULL, FALSE);
469         g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
470         g_return_val_if_fail (event != NULL, FALSE);
471
472         sctree = GTK_SCTREE (widget);
473         clist = GTK_CLIST (widget);
474
475         if (event->window != clist->clist_window)
476                 return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
477
478         if (!((sctree->dnd_press_button == 1 && (event->state & GDK_BUTTON1_MASK))
479               || (sctree->dnd_press_button == 2 && (event->state & GDK_BUTTON2_MASK))))
480                 return FALSE;
481
482         /* This is the same threshold value that is used in gtkdnd.c */
483
484         if (MAX (ABS (sctree->dnd_press_x - event->x),
485                  ABS (sctree->dnd_press_y - event->y)) <= 3)
486                 return FALSE;
487
488         /* Handle any pending selections */
489
490         if (sctree->dnd_select_pending) {
491                 if (!row_is_selected(sctree,sctree->dnd_select_pending_row))
492                         select_row (sctree,
493                                     sctree->dnd_select_pending_row,
494                                     -1,
495                                     sctree->dnd_select_pending_state);
496
497                 sctree->dnd_select_pending = FALSE;
498                 sctree->dnd_select_pending_state = 0;
499         }
500
501         g_signal_emit (G_OBJECT (sctree),
502                        sctree_signals[START_DRAG],
503                        0,
504                        sctree->dnd_press_button,
505                        event);
506         return TRUE;
507 }
508
509 /* We override the drag_begin signal to do nothing */
510 static void
511 gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context)
512 {
513         /* nothing */
514 }
515
516 /* We override the drag_end signal to do nothing */
517 static void
518 gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context)
519 {
520         /* nothing */
521 }
522
523 /* We override the drag_data_get signal to do nothing */
524 static void
525 gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
526                                      GtkSelectionData *data, guint info, guint time)
527 {
528         /* nothing */
529 }
530
531 /* We override the drag_leave signal to do nothing */
532 static void
533 gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time)
534 {
535         /* nothing */
536 }
537
538 /* We override the drag_motion signal to do nothing */
539 static gboolean
540 gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
541                                    gint x, gint y, guint time)
542 {
543         return FALSE;
544 }
545
546 /* We override the drag_drop signal to do nothing */
547 static gboolean
548 gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
549                                  gint x, gint y, guint time)
550 {
551         return FALSE;
552 }
553
554 /* We override the drag_data_received signal to do nothing */
555 static void
556 gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
557                                           gint x, gint y, GtkSelectionData *data,
558                                           guint info, guint time)
559 {
560         /* nothing */
561 }
562
563 /* Our handler for the clear signal of the clist.  We have to reset the anchor
564  * to null.
565  */
566 static void
567 gtk_sctree_clear (GtkCList *clist)
568 {
569         GtkSCTree *sctree;
570
571         g_return_if_fail (clist != NULL);
572         g_return_if_fail (GTK_IS_SCTREE (clist));
573
574         sctree = GTK_SCTREE (clist);
575         sctree->anchor_row = NULL;
576
577         if (((GtkCListClass *)parent_class)->clear)
578                 (* ((GtkCListClass *)parent_class)->clear) (clist);
579 }
580
581 /* Our handler for the change_focus_row_expansion signal of the ctree.  
582  We have to set the anchor to parent visible node.
583  */
584 static void 
585 gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node)
586 {
587         g_return_if_fail (ctree != NULL);
588         g_return_if_fail (GTK_IS_SCTREE (ctree));
589
590         (* parent_class->tree_collapse) (ctree, node);
591         GTK_SCTREE(ctree)->anchor_row =
592                 gtk_ctree_node_nth(ctree, GTK_CLIST(ctree)->focus_row);
593 }
594
595 GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column, 
596                                        gchar *titles[])
597 {
598         GtkWidget *widget;
599                                                                                                             
600         g_return_val_if_fail (columns > 0, NULL);
601         g_return_val_if_fail (tree_column >= 0, NULL);
602                                                                                                             
603         widget = gtk_widget_new (TYPE_GTK_SCTREE,
604                                  "n_columns", columns,
605                                  "tree_column", tree_column,
606                                  NULL);
607         if (titles) {
608                 GtkCList *clist = GTK_CLIST (widget);
609                 guint i;
610
611                 for (i = 0; i < columns; i++)
612                         gtk_clist_set_column_title (clist, i, titles[i]);
613                 gtk_clist_column_titles_show (clist);
614         }
615
616         return widget;
617 }
618
619 void gtk_sctree_select (GtkSCTree *sctree, GtkCTreeNode *node)
620 {
621         select_row(sctree, 
622                    g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
623                    -1, 0);
624 }
625
626 void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCTreeNode *node, int state)
627 {
628         select_row(sctree, 
629                    g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
630                    -1, state);
631 }
632
633 void gtk_sctree_unselect_all (GtkSCTree *sctree)
634 {
635         sctree->selecting_range = TRUE;
636         gtk_clist_unselect_all(GTK_CLIST(sctree));
637         sctree->selecting_range = FALSE;
638         sctree->anchor_row = NULL;
639 }
640
641 void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCTreeNode *node)
642 {
643         sctree->anchor_row = node;
644 }
645
646 void gtk_sctree_remove_node (GtkSCTree *sctree, GtkCTreeNode *node)
647 {
648         if (sctree->anchor_row == node)
649                 sctree->anchor_row = NULL;
650         gtk_ctree_remove_node(GTK_CTREE(sctree), node);
651 }
652
653 /***********************************************************
654  *             Tree sorting functions                      *
655  ***********************************************************/
656
657 static void sink(GtkCList *clist, GPtrArray *numbers, gint root, gint bottom)
658 {
659         gint j, k ;
660         GtkCTreeNode *temp;
661
662         j = 2 * root;
663         k = j + 1;
664
665         /* find the maximum element of numbers[root],
666            numbers[2*root] and numbers[2*root+1] */
667         if (j <= bottom) {
668                 if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, root)),
669                                     GTK_CTREE_ROW(g_ptr_array_index( numbers, j))) >= 0)
670                         j = root;
671                 if (k <= bottom)
672                         if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, k)),
673                                             GTK_CTREE_ROW (g_ptr_array_index( numbers, j))) > 0)
674                                 j = k;
675                 /* if numbers[root] wasn't the maximum element then
676                    sink again */
677                 if (root != j) {
678                         temp = g_ptr_array_index( numbers,root);
679                         g_ptr_array_index( numbers, root) = g_ptr_array_index( numbers, j);
680                         g_ptr_array_index( numbers, j) = temp;
681                         sink( clist, numbers, j, bottom);
682                 }
683         }
684 }
685
686 static void heap_sort(GtkCList *clist, GPtrArray *numbers, gint array_size)
687 {
688         gint i;
689         GtkCTreeNode *temp;
690         
691         /* build the Heap */
692         for (i = (array_size / 2); i >= 1; i--)
693                 sink( clist, numbers, i, array_size);
694         /* output the Heap */
695         for (i = array_size; i >= 2; i--) {
696                 temp = g_ptr_array_index( numbers, 1);
697                 g_ptr_array_index( numbers, 1) = g_ptr_array_index( numbers, i);
698                 g_ptr_array_index( numbers, i) = temp;
699                 sink( clist, numbers, 1, i-1);
700         }
701 }
702
703 static void
704 stree_sort (GtkCTree    *ctree,
705            GtkCTreeNode *node,
706            gpointer      data)
707 {
708         GtkCTreeNode *list_start, *work, *next;
709         GPtrArray *row_array, *viewable_array;
710         GtkCList *clist;
711         gint i;
712
713         clist = GTK_CLIST (ctree);
714
715         if (node)
716                 work = GTK_CTREE_ROW (node)->children;
717         else
718                 work = GTK_CTREE_NODE (clist->row_list);
719
720         row_array = g_ptr_array_new();
721         viewable_array = g_ptr_array_new();
722
723         if (work) {
724                 g_ptr_array_add( row_array, NULL);
725                 while (work) {
726                         /* add all rows to row_array */
727                         g_ptr_array_add( row_array, work);
728                         if (GTK_CTREE_ROW (work)->parent && gtk_ctree_is_viewable( ctree, work))
729                                 g_ptr_array_add( viewable_array, GTK_CTREE_ROW (work)->parent);
730                         next = GTK_CTREE_ROW (work)->sibling;
731                         gtk_sctree_unlink( ctree, work, FALSE);
732                         work = next;
733                 }
734
735                 heap_sort( clist, row_array, (row_array->len)-1);
736
737                 if (node)
738                         list_start = GTK_CTREE_ROW (node)->children;
739                 else
740                         list_start = GTK_CTREE_NODE (clist->row_list);
741
742                 if (clist->sort_type == GTK_SORT_ASCENDING) {
743                         for (i=(row_array->len)-1; i>=1; i--) {
744                                 work = g_ptr_array_index( row_array, i);
745                                 gtk_sctree_link( ctree, work, node, list_start, FALSE);
746                                 list_start = work;
747                                 /* insert work at the beginning of the list */
748                         }
749                 } else {
750                         for (i=1; i<row_array->len; i++) {
751                                 work = g_ptr_array_index( row_array, i);
752                                 gtk_sctree_link( ctree, work, node, list_start, FALSE);
753                                 list_start = work;
754                                 /* insert work at the beginning of the list */
755                         }
756                 }
757
758                 for (i=0; i<viewable_array->len; i++) {
759                         gtk_ctree_expand( ctree, g_ptr_array_index( viewable_array, i));
760                 }
761                 
762         }
763         g_ptr_array_free( row_array, TRUE);
764         g_ptr_array_free( viewable_array, TRUE);
765 }
766
767 void
768 gtk_sctree_sort_recursive (GtkCTree     *ctree, 
769                           GtkCTreeNode *node)
770 {
771         GtkCList *clist;
772         GtkCTreeNode *focus_node = NULL;
773
774         g_return_if_fail (ctree != NULL);
775         g_return_if_fail (GTK_IS_CTREE (ctree));
776
777         clist = GTK_CLIST (ctree);
778
779         gtk_clist_freeze (clist);
780
781         if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
782                 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
783       
784                 g_list_free (clist->undo_selection);
785                 g_list_free (clist->undo_unselection);
786                 clist->undo_selection = NULL;
787                 clist->undo_unselection = NULL;
788         }
789
790         if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
791                 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
792       
793         GTK_SCTREE(ctree)->sorting = TRUE;
794
795         gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (stree_sort), NULL);
796
797         if (!node)
798                 stree_sort (ctree, NULL, NULL);
799
800         GTK_SCTREE(ctree)->sorting = FALSE;
801
802         if (focus_node) {
803                 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
804                 clist->undo_anchor = clist->focus_row;
805         }
806
807         gtk_clist_thaw (clist);
808 }
809
810 void
811 gtk_sctree_sort_node (GtkCTree     *ctree, 
812                      GtkCTreeNode *node)
813 {
814         GtkCList *clist;
815         GtkCTreeNode *focus_node = NULL;
816
817         g_return_if_fail (ctree != NULL);
818         g_return_if_fail (GTK_IS_CTREE (ctree));
819
820         clist = GTK_CLIST (ctree);
821
822         gtk_clist_freeze (clist);
823
824         if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
825                 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
826
827                 g_list_free (clist->undo_selection);
828                 g_list_free (clist->undo_unselection);
829                 clist->undo_selection = NULL;
830                 clist->undo_unselection = NULL;
831         }
832
833         if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
834                 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
835
836         GTK_SCTREE(ctree)->sorting = TRUE;
837
838         stree_sort (ctree, node, NULL);
839
840         GTK_SCTREE(ctree)->sorting = FALSE;
841
842         if (focus_node) {
843                 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
844                 clist->undo_anchor = clist->focus_row;
845         }
846
847         gtk_clist_thaw (clist);
848 }
849
850 /************************************************************************/
851
852 static void
853 gtk_sctree_unlink (GtkCTree     *ctree, 
854                   GtkCTreeNode *node,
855                   gboolean      update_focus_row)
856 {
857         GtkCList *clist;
858         gint rows;
859         gint level;
860         gint visible;
861         GtkCTreeNode *work;
862         GtkCTreeNode *parent;
863         GList *list;
864
865         g_return_if_fail (ctree != NULL);
866         g_return_if_fail (GTK_IS_CTREE (ctree));
867         g_return_if_fail (node != NULL);
868
869         clist = GTK_CLIST (ctree);
870   
871         if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
872                 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
873
874                 g_list_free (clist->undo_selection);
875                 g_list_free (clist->undo_unselection);
876                 clist->undo_selection = NULL;
877                 clist->undo_unselection = NULL;
878         }
879
880         visible = gtk_ctree_is_viewable (ctree, node);
881
882         /* clist->row_list_end unlinked ? */
883         if (visible && (GTK_CTREE_NODE_NEXT (node) == NULL ||
884            (GTK_CTREE_ROW (node)->children && gtk_ctree_is_ancestor (ctree, node,
885             GTK_CTREE_NODE (clist->row_list_end)))))
886                 clist->row_list_end = (GList *) (GTK_CTREE_NODE_PREV (node));
887
888         /* update list */
889         rows = 0;
890         level = GTK_CTREE_ROW (node)->level;
891         work = GTK_CTREE_NODE_NEXT (node);
892         while (work && GTK_CTREE_ROW (work)->level > level) {
893                 work = GTK_CTREE_NODE_NEXT (work);
894                 rows++;
895         }
896
897         if (visible) {
898                 clist->rows -= (rows + 1);
899
900                 if (update_focus_row) {
901                         gint pos;
902                         pos = g_list_position (clist->row_list, (GList *)node);
903                         if (pos + rows < clist->focus_row)
904                                 clist->focus_row -= (rows + 1);
905                         else if (pos <= clist->focus_row) {
906                                 if (!GTK_CTREE_ROW (node)->sibling)
907                                         clist->focus_row = MAX (pos - 1, 0);
908                                 else
909                                         clist->focus_row = pos;
910               
911                                 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
912                         }
913                         clist->undo_anchor = clist->focus_row;
914                 }
915         }
916
917         if (work) {
918                 list = (GList *)GTK_CTREE_NODE_PREV (work);
919                 list->next = NULL;
920                 list = (GList *)work;
921                 list->prev = (GList *)GTK_CTREE_NODE_PREV (node);
922         }
923
924         if (GTK_CTREE_NODE_PREV (node) &&
925             GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (node)) == node) {
926                 list = (GList *)GTK_CTREE_NODE_PREV (node);
927                 list->next = (GList *)work;
928         }
929
930         /* update tree */
931         parent = GTK_CTREE_ROW (node)->parent;
932         if (parent) {
933                 if (GTK_CTREE_ROW (parent)->children == node) {
934                         GTK_CTREE_ROW (parent)->children = GTK_CTREE_ROW (node)->sibling;
935                         if (!GTK_CTREE_ROW (parent)->children)
936                                 gtk_ctree_collapse (ctree, parent);
937                 }
938                 else {
939                         GtkCTreeNode *sibling;
940
941                         sibling = GTK_CTREE_ROW (parent)->children;
942                         while (GTK_CTREE_ROW (sibling)->sibling != node)
943                                 sibling = GTK_CTREE_ROW (sibling)->sibling;
944                         GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
945                 }
946         }
947         else {
948                 if (clist->row_list == (GList *)node)
949                         clist->row_list = (GList *) (GTK_CTREE_ROW (node)->sibling);
950                 else {
951                         GtkCTreeNode *sibling;
952
953                         sibling = GTK_CTREE_NODE (clist->row_list);
954                         while (GTK_CTREE_ROW (sibling)->sibling != node)
955                                 sibling = GTK_CTREE_ROW (sibling)->sibling;
956                         GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
957                 }
958         }
959 }
960
961 static void
962 gtk_sctree_link (GtkCTree     *ctree,
963                 GtkCTreeNode *node,
964                 GtkCTreeNode *parent,
965                 GtkCTreeNode *sibling,
966                 gboolean      update_focus_row)
967 {
968         GtkCList *clist;
969         GList *list_end;
970         GList *list;
971         GList *work;
972         gboolean visible = FALSE;
973         gint rows = 0;
974   
975         if (sibling)
976                 g_return_if_fail (GTK_CTREE_ROW (sibling)->parent == parent);
977         g_return_if_fail (node != NULL);
978         g_return_if_fail (node != sibling);
979         g_return_if_fail (node != parent);
980
981         clist = GTK_CLIST (ctree);
982
983         if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
984                 GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
985
986                 g_list_free (clist->undo_selection);
987                 g_list_free (clist->undo_unselection);
988                 clist->undo_selection = NULL;
989                 clist->undo_unselection = NULL;
990         }
991
992         for (rows = 1, list_end = (GList *)node; list_end->next;
993              list_end = list_end->next)
994                 rows++;
995
996         GTK_CTREE_ROW (node)->parent = parent;
997         GTK_CTREE_ROW (node)->sibling = sibling;
998
999         if (!parent || (parent && (gtk_ctree_is_viewable (ctree, parent) &&
1000             GTK_CTREE_ROW (parent)->expanded))) {
1001                 visible = TRUE;
1002                 clist->rows += rows;
1003         }
1004
1005         if (parent)
1006                 work = (GList *)(GTK_CTREE_ROW (parent)->children);
1007         else
1008                 work = clist->row_list;
1009
1010         if (sibling) {
1011                 if (work != (GList *)sibling) {
1012                         while (GTK_CTREE_ROW (work)->sibling != sibling)
1013                                 work = (GList *)(GTK_CTREE_ROW (work)->sibling);
1014                         GTK_CTREE_ROW (work)->sibling = node;
1015                 }
1016
1017                 if (sibling == GTK_CTREE_NODE (clist->row_list))
1018                 clist->row_list = (GList *) node;
1019                 if (GTK_CTREE_NODE_PREV (sibling) &&
1020                     GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (sibling)) == sibling) {
1021                         list = (GList *)GTK_CTREE_NODE_PREV (sibling);
1022                         list->next = (GList *)node;
1023                 }
1024
1025                 list = (GList *)node;
1026                 list->prev = (GList *)GTK_CTREE_NODE_PREV (sibling);
1027                 list_end->next = (GList *)sibling;
1028                 list = (GList *)sibling;
1029                 list->prev = list_end;
1030                 if (parent && GTK_CTREE_ROW (parent)->children == sibling)
1031                         GTK_CTREE_ROW (parent)->children = node;
1032         }
1033         else {
1034                 if (work) {
1035                         /* find sibling */
1036                         while (GTK_CTREE_ROW (work)->sibling)
1037                         work = (GList *)(GTK_CTREE_ROW (work)->sibling);
1038                         GTK_CTREE_ROW (work)->sibling = node;
1039
1040                         /* find last visible child of sibling */
1041                         work = (GList *) gtk_sctree_last_visible (ctree,
1042                                GTK_CTREE_NODE (work));
1043
1044                         list_end->next = work->next;
1045                         if (work->next)
1046                                 list = work->next->prev = list_end;
1047                         work->next = (GList *)node;
1048                         list = (GList *)node;
1049                         list->prev = work;
1050                 }
1051                 else {
1052                         if (parent) {
1053                                 GTK_CTREE_ROW (parent)->children = node;
1054                                 list = (GList *)node;
1055                                 list->prev = (GList *)parent;
1056                                 if (GTK_CTREE_ROW (parent)->expanded) {
1057                                         list_end->next = (GList *)GTK_CTREE_NODE_NEXT (parent);
1058                                         if (GTK_CTREE_NODE_NEXT(parent)) {
1059                                                 list = (GList *)GTK_CTREE_NODE_NEXT (parent);
1060                                                 list->prev = list_end;
1061                                         }
1062                                         list = (GList *)parent;
1063                                         list->next = (GList *)node;
1064                                 }
1065                                 else
1066                                         list_end->next = NULL;
1067                         }
1068                         else {
1069                                 clist->row_list = (GList *)node;
1070                                 list = (GList *)node;
1071                                 list->prev = NULL;
1072                                 list_end->next = NULL;
1073                         }
1074                 }
1075         }
1076
1077         gtk_ctree_pre_recursive (ctree, node, stree_update_level, NULL); 
1078
1079         if (clist->row_list_end == NULL ||
1080             clist->row_list_end->next == (GList *)node)
1081                 clist->row_list_end = list_end;
1082
1083         if (visible && update_focus_row) {
1084                 gint pos;
1085                 pos = g_list_position (clist->row_list, (GList *)node);
1086   
1087                 if (pos <= clist->focus_row) {
1088                         clist->focus_row += rows;
1089                         clist->undo_anchor = clist->focus_row;
1090                 }
1091         }
1092 }
1093
1094 static void
1095 stree_update_level (GtkCTree     *ctree, 
1096                    GtkCTreeNode *node, 
1097                    gpointer      data)
1098 {
1099         if (!node)
1100                 return;
1101
1102         if (GTK_CTREE_ROW (node)->parent)
1103                 GTK_CTREE_ROW (node)->level = 
1104                 GTK_CTREE_ROW (GTK_CTREE_ROW (node)->parent)->level + 1;
1105         else
1106                 GTK_CTREE_ROW (node)->level = 1;
1107 }
1108
1109 static GtkCTreeNode *
1110 gtk_sctree_last_visible (GtkCTree     *ctree,
1111                         GtkCTreeNode *node)
1112 {
1113         GtkCTreeNode *work;
1114   
1115         if (!node)
1116                 return NULL;
1117
1118         work = GTK_CTREE_ROW (node)->children;
1119
1120         if (!work || !GTK_CTREE_ROW (node)->expanded)
1121                 return node;
1122
1123         while (GTK_CTREE_ROW (work)->sibling)
1124                 work = GTK_CTREE_ROW (work)->sibling;
1125
1126         return gtk_sctree_last_visible (ctree, work);
1127 }
1128
1129 /* this wrapper simply replaces NULL pixmaps 
1130  * with a transparent, 1x1 pixmap. This works
1131  * around a memory problem deep inside gtk, 
1132  * revealed by valgrind. 
1133  */
1134 /*GtkCTreeNode* gtk_sctree_insert_node        (GtkCTree *ctree,
1135                                              GtkCTreeNode *parent,
1136                                              GtkCTreeNode *sibling,
1137                                              gchar *text[],
1138                                              guint8 spacing,
1139                                              GdkPixmap *pixmap_closed,
1140                                              GdkBitmap *mask_closed,
1141                                              GdkPixmap *pixmap_opened,
1142                                              GdkBitmap *mask_opened,
1143                                              gboolean is_leaf,
1144                                              gboolean expanded)
1145 {
1146         if (!emptyxpm) {
1147                 stock_pixmap_gdk(GTK_WIDGET(ctree), STOCK_PIXMAP_EMPTY,
1148                          &emptyxpm, &emptyxpmmask);
1149         }
1150         if (!pixmap_closed) {
1151                 pixmap_closed = emptyxpm;
1152                 mask_closed = emptyxpmmask;
1153         }
1154         if (!pixmap_opened) {
1155                 pixmap_opened = emptyxpm;
1156                 mask_opened = emptyxpmmask;
1157         }
1158         return gtk_ctree_insert_node(ctree, parent, sibling, text,spacing,
1159                 pixmap_closed, mask_closed, pixmap_opened, mask_opened,
1160                 is_leaf, expanded);
1161 }*/
1162
1163 static void 
1164 sset_node_info (GtkCTree     *ctree,
1165                GtkCTreeNode *node,
1166                const gchar  *text,
1167                guint8        spacing,
1168                GdkPixmap    *pixmap_closed,
1169                GdkBitmap    *mask_closed,
1170                GdkPixmap    *pixmap_opened,
1171                GdkBitmap    *mask_opened,
1172                gboolean      is_leaf,
1173                gboolean      expanded)
1174 {
1175   if (GTK_CTREE_ROW (node)->pixmap_opened)
1176     {
1177       gdk_pixmap_unref (GTK_CTREE_ROW (node)->pixmap_opened);
1178       if (GTK_CTREE_ROW (node)->mask_opened) 
1179         gdk_bitmap_unref (GTK_CTREE_ROW (node)->mask_opened);
1180     }
1181   if (GTK_CTREE_ROW (node)->pixmap_closed)
1182     {
1183       gdk_pixmap_unref (GTK_CTREE_ROW (node)->pixmap_closed);
1184       if (GTK_CTREE_ROW (node)->mask_closed) 
1185         gdk_bitmap_unref (GTK_CTREE_ROW (node)->mask_closed);
1186     }
1187
1188   GTK_CTREE_ROW (node)->pixmap_opened = NULL;
1189   GTK_CTREE_ROW (node)->mask_opened   = NULL;
1190   GTK_CTREE_ROW (node)->pixmap_closed = NULL;
1191   GTK_CTREE_ROW (node)->mask_closed   = NULL;
1192
1193   if (pixmap_closed)
1194     {
1195       GTK_CTREE_ROW (node)->pixmap_closed = gdk_pixmap_ref (pixmap_closed);
1196       if (mask_closed) 
1197         GTK_CTREE_ROW (node)->mask_closed = gdk_bitmap_ref (mask_closed);
1198     }
1199   if (pixmap_opened)
1200     {
1201       GTK_CTREE_ROW (node)->pixmap_opened = gdk_pixmap_ref (pixmap_opened);
1202       if (mask_opened) 
1203         GTK_CTREE_ROW (node)->mask_opened = gdk_bitmap_ref (mask_opened);
1204     }
1205
1206   GTK_CTREE_ROW (node)->is_leaf  = is_leaf;
1207   GTK_CTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
1208
1209   if (GTK_CTREE_ROW (node)->expanded)
1210     gtk_ctree_node_set_pixtext (ctree, node, ctree->tree_column,
1211                                 text, spacing, pixmap_opened, mask_opened);
1212   else 
1213     gtk_ctree_node_set_pixtext (ctree, node, ctree->tree_column,
1214                                 text, spacing, pixmap_closed, mask_closed);
1215 }
1216
1217 static void
1218 stree_draw_node (GtkCTree     *ctree, 
1219                 GtkCTreeNode *node)
1220 {
1221   GtkCList *clist;
1222   
1223   clist = GTK_CLIST (ctree);
1224
1225   if (CLIST_UNFROZEN (clist) && gtk_ctree_is_viewable (ctree, node))
1226     {
1227       GtkCTreeNode *work;
1228       gint num = 0;
1229       
1230       work = GTK_CTREE_NODE (clist->row_list);
1231       while (work && work != node)
1232         {
1233           work = GTK_CTREE_NODE_NEXT (work);
1234           num++;
1235         }
1236       if (work && gtk_clist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE)
1237         GTK_CLIST_GET_CLASS (clist)->draw_row
1238           (clist, NULL, num, GTK_CLIST_ROW ((GList *) node));
1239     }
1240 }
1241
1242 /* this wrapper simply replaces NULL pixmaps 
1243  * with a transparent, 1x1 pixmap. This works
1244  * around a memory problem deep inside gtk, 
1245  * revealed by valgrind. 
1246  */
1247 void        gtk_sctree_set_node_info        (GtkCTree *ctree,
1248                                              GtkCTreeNode *node,
1249                                              const gchar *text,
1250                                              guint8 spacing,
1251                                              GdkPixmap *pixmap_closed,
1252                                              GdkBitmap *mask_closed,
1253                                              GdkPixmap *pixmap_opened,
1254                                              GdkBitmap *mask_opened,
1255                                              gboolean is_leaf,
1256                                              gboolean expanded)
1257 {
1258   gboolean old_leaf;
1259   gboolean old_expanded;
1260   GtkCTreeNode *work;
1261  
1262   if (!emptyxpm) {
1263           stock_pixmap_gdk(GTK_WIDGET(ctree), STOCK_PIXMAP_EMPTY,
1264                    &emptyxpm, &emptyxpmmask);
1265   }
1266   if (!pixmap_closed) {
1267           pixmap_closed = emptyxpm;
1268           mask_closed = emptyxpmmask;
1269   }
1270   if (!pixmap_opened) {
1271           pixmap_opened = emptyxpm;
1272           mask_opened = emptyxpmmask;
1273   }
1274
1275   if (!GTK_IS_CTREE (ctree) || !node) return;
1276
1277   old_leaf = GTK_CTREE_ROW (node)->is_leaf;
1278   old_expanded = GTK_CTREE_ROW (node)->expanded;
1279
1280   if (is_leaf && (work = GTK_CTREE_ROW (node)->children) != NULL)
1281     {
1282       GtkCTreeNode *ptr;
1283       
1284       while (work)
1285         {
1286           ptr = work;
1287           work = GTK_CTREE_ROW (work)->sibling;
1288           gtk_ctree_remove_node (ctree, ptr);
1289         }
1290     }
1291
1292   sset_node_info (ctree, node, text, spacing, pixmap_closed, mask_closed,
1293                  pixmap_opened, mask_opened, is_leaf, expanded);
1294
1295   if (!is_leaf && !old_leaf)
1296     {
1297       GTK_CTREE_ROW (node)->expanded = old_expanded;
1298       if (expanded && !old_expanded)
1299         gtk_ctree_expand (ctree, node);
1300       else if (!expanded && old_expanded)
1301         gtk_ctree_collapse (ctree, node);
1302     }
1303
1304   GTK_CTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
1305   
1306   stree_draw_node (ctree, node);
1307 }
1308
1309 static GtkCTreeRow *
1310 srow_new (GtkCTree *ctree)
1311 {
1312   GtkCList *clist;
1313   GtkCTreeRow *ctree_row;
1314   int i;
1315
1316   clist = GTK_CLIST (ctree);
1317 #if GTK_CHECK_VERSION(2,9,0)
1318   ctree_row = g_slice_new (GtkCTreeRow);
1319   ctree_row->row.cell = g_slice_alloc (sizeof (GtkCell) * clist->columns);
1320 #else
1321   ctree_row = g_chunk_new (GtkCTreeRow, (GMemChunk *)clist->row_mem_chunk);
1322   ctree_row->row.cell = g_chunk_new (GtkCell, (GMemChunk *)clist->cell_mem_chunk);
1323 #endif
1324   for (i = 0; i < clist->columns; i++)
1325     {
1326       ctree_row->row.cell[i].type = GTK_CELL_EMPTY;
1327       ctree_row->row.cell[i].vertical = 0;
1328       ctree_row->row.cell[i].horizontal = 0;
1329       ctree_row->row.cell[i].style = NULL;
1330     }
1331
1332   GTK_CELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
1333
1334   ctree_row->row.fg_set     = FALSE;
1335   ctree_row->row.bg_set     = FALSE;
1336   ctree_row->row.style      = NULL;
1337   ctree_row->row.selectable = TRUE;
1338   ctree_row->row.state      = GTK_STATE_NORMAL;
1339   ctree_row->row.data       = NULL;
1340   ctree_row->row.destroy    = NULL;
1341
1342   ctree_row->level         = 0;
1343   ctree_row->expanded      = FALSE;
1344   ctree_row->parent        = NULL;
1345   ctree_row->sibling       = NULL;
1346   ctree_row->children      = NULL;
1347   ctree_row->pixmap_closed = NULL;
1348   ctree_row->mask_closed   = NULL;
1349   ctree_row->pixmap_opened = NULL;
1350   ctree_row->mask_opened   = NULL;
1351   
1352   return ctree_row;
1353 }
1354
1355 static void
1356 srow_delete (GtkCTree    *ctree,
1357             GtkCTreeRow *ctree_row)
1358 {
1359   GtkCList *clist;
1360   gint i;
1361
1362   clist = GTK_CLIST (ctree);
1363
1364   for (i = 0; i < clist->columns; i++)
1365     {
1366       GTK_CLIST_GET_CLASS (clist)->set_cell_contents
1367         (clist, &(ctree_row->row), i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
1368       if (ctree_row->row.cell[i].style)
1369         {
1370           if (GTK_WIDGET_REALIZED (ctree))
1371             gtk_style_detach (ctree_row->row.cell[i].style);
1372           g_object_unref (ctree_row->row.cell[i].style);
1373         }
1374     }
1375
1376   if (ctree_row->row.style)
1377     {
1378       if (GTK_WIDGET_REALIZED (ctree))
1379         gtk_style_detach (ctree_row->row.style);
1380       g_object_unref (ctree_row->row.style);
1381     }
1382
1383   if (ctree_row->pixmap_closed)
1384     {
1385       gdk_pixmap_unref (ctree_row->pixmap_closed);
1386       if (ctree_row->mask_closed)
1387         gdk_bitmap_unref (ctree_row->mask_closed);
1388     }
1389
1390   if (ctree_row->pixmap_opened)
1391     {
1392       gdk_pixmap_unref (ctree_row->pixmap_opened);
1393       if (ctree_row->mask_opened)
1394         gdk_bitmap_unref (ctree_row->mask_opened);
1395     }
1396
1397   if (ctree_row->row.destroy)
1398     {
1399       GtkDestroyNotify dnotify = ctree_row->row.destroy;
1400       gpointer ddata = ctree_row->row.data;
1401
1402       ctree_row->row.destroy = NULL;
1403       ctree_row->row.data = NULL;
1404
1405       dnotify (ddata);
1406     }
1407
1408 #if GTK_CHECK_VERSION(2,9,0)  
1409   g_slice_free1 (sizeof (GtkCell) * clist->columns, ctree_row->row.cell);
1410   g_slice_free (GtkCTreeRow, ctree_row);
1411 #else
1412   g_mem_chunk_free ((GMemChunk *)clist->cell_mem_chunk, ctree_row->row.cell);
1413   g_mem_chunk_free ((GMemChunk *)clist->row_mem_chunk, ctree_row);
1414 #endif
1415 }
1416
1417 static void
1418 stree_delete_row (GtkCTree     *ctree, 
1419                  GtkCTreeNode *node, 
1420                  gpointer      data)
1421 {
1422   srow_delete (ctree, GTK_CTREE_ROW (node));
1423   g_list_free_1 ((GList *)node);
1424 }
1425
1426 static void
1427 gtk_sctree_column_auto_resize (GtkCList    *clist,
1428                     GtkCListRow *clist_row,
1429                     gint         column,
1430                     gint         old_width)
1431 {
1432   /* resize column if needed for auto_resize */
1433   GtkRequisition requisition;
1434
1435   if (!clist->column[column].auto_resize ||
1436       GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
1437     return;
1438
1439   if (clist_row)
1440     GTK_CLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
1441                                                    column, &requisition);
1442   else
1443     requisition.width = 0;
1444
1445   if (requisition.width > clist->column[column].width)
1446     gtk_clist_set_column_width (clist, column, requisition.width);
1447   else if (requisition.width < old_width &&
1448            old_width == clist->column[column].width)
1449     {
1450       GList *list;
1451       gint new_width;
1452
1453       /* run a "gtk_clist_optimal_column_width" but break, if
1454        * the column doesn't shrink */
1455       if (GTK_CLIST_SHOW_TITLES (clist) && clist->column[column].button)
1456         new_width = (clist->column[column].button->requisition.width -
1457                      (CELL_SPACING + (2 * COLUMN_INSET)));
1458       else
1459         new_width = 0;
1460
1461       for (list = clist->row_list; list; list = list->next)
1462         {
1463           GTK_CLIST_GET_CLASS (clist)->cell_size_request
1464             (clist, GTK_CLIST_ROW (list), column, &requisition);
1465           new_width = MAX (new_width, requisition.width);
1466           if (new_width == clist->column[column].width)
1467             break;
1468         }
1469       if (new_width < clist->column[column].width)
1470         gtk_clist_set_column_width (clist, column, new_width);
1471     }
1472 }
1473
1474
1475 static void 
1476 gtk_sctree_real_tree_expand (GtkCTree     *ctree,
1477                   GtkCTreeNode *node)
1478 {
1479   GtkCList *clist;
1480   GtkCTreeNode *work;
1481   GtkRequisition requisition;
1482   gboolean visible;
1483   gint level;
1484
1485   g_return_if_fail (GTK_IS_CTREE (ctree));
1486
1487   if (!node || GTK_CTREE_ROW (node)->expanded || GTK_CTREE_ROW (node)->is_leaf)
1488     return;
1489
1490   clist = GTK_CLIST (ctree);
1491   
1492   GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1493
1494   GTK_CTREE_ROW (node)->expanded = TRUE;
1495   level = GTK_CTREE_ROW (node)->level;
1496
1497   visible = gtk_ctree_is_viewable (ctree, node);
1498   /* get cell width if tree_column is auto resized */
1499   if (visible && clist->column[ctree->tree_column].auto_resize &&
1500       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
1501     GTK_CLIST_GET_CLASS (clist)->cell_size_request
1502       (clist, &GTK_CTREE_ROW (node)->row, ctree->tree_column, &requisition);
1503
1504   /* unref/unset closed pixmap */
1505   if (GTK_CELL_PIXTEXT 
1506       (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap)
1507     {
1508       gdk_pixmap_unref
1509         (GTK_CELL_PIXTEXT
1510          (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap);
1511       
1512       GTK_CELL_PIXTEXT
1513         (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = NULL;
1514       
1515       if (GTK_CELL_PIXTEXT 
1516           (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask)
1517         {
1518           gdk_pixmap_unref
1519             (GTK_CELL_PIXTEXT 
1520              (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask);
1521           GTK_CELL_PIXTEXT 
1522             (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask = NULL;
1523         }
1524     }
1525
1526   /* set/ref opened pixmap */
1527   if (GTK_CTREE_ROW (node)->pixmap_opened)
1528     {
1529       GTK_CELL_PIXTEXT 
1530         (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = 
1531         gdk_pixmap_ref (GTK_CTREE_ROW (node)->pixmap_opened);
1532
1533       if (GTK_CTREE_ROW (node)->mask_opened) 
1534         GTK_CELL_PIXTEXT 
1535           (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask = 
1536           gdk_pixmap_ref (GTK_CTREE_ROW (node)->mask_opened);
1537     }
1538
1539
1540   work = GTK_CTREE_ROW (node)->children;
1541   if (work)
1542     {
1543       GList *list = (GList *)work;
1544       gint *cell_width = NULL;
1545       gint tmp = 0;
1546       gint row;
1547       gint i;
1548       
1549       if (visible && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
1550         {
1551           cell_width = g_new0 (gint, clist->columns);
1552           if (clist->column[ctree->tree_column].auto_resize)
1553               cell_width[ctree->tree_column] = requisition.width;
1554
1555           while (work)
1556             {
1557               /* search maximum cell widths of auto_resize columns */
1558               for (i = 0; i < clist->columns; i++)
1559                 if (clist->column[i].auto_resize)
1560                   {
1561                     GTK_CLIST_GET_CLASS (clist)->cell_size_request
1562                       (clist, &GTK_CTREE_ROW (work)->row, i, &requisition);
1563                     cell_width[i] = MAX (requisition.width, cell_width[i]);
1564                   }
1565
1566               list = (GList *)work;
1567               work = GTK_CTREE_NODE_NEXT (work);
1568               tmp++;
1569             }
1570         }
1571       else
1572         while (work)
1573           {
1574             list = (GList *)work;
1575             work = GTK_CTREE_NODE_NEXT (work);
1576             tmp++;
1577           }
1578
1579       list->next = (GList *)GTK_CTREE_NODE_NEXT (node);
1580
1581       if (GTK_CTREE_NODE_NEXT (node))
1582         {
1583           GList *tmp_list;
1584
1585           tmp_list = (GList *)GTK_CTREE_NODE_NEXT (node);
1586           tmp_list->prev = list;
1587         }
1588       else
1589         clist->row_list_end = list;
1590
1591       list = (GList *)node;
1592       list->next = (GList *)(GTK_CTREE_ROW (node)->children);
1593
1594       if (visible)
1595         {
1596           /* resize auto_resize columns if needed */
1597           for (i = 0; i < clist->columns; i++)
1598             if (clist->column[i].auto_resize &&
1599                 cell_width[i] > clist->column[i].width)
1600               gtk_clist_set_column_width (clist, i, cell_width[i]);
1601           g_free (cell_width);
1602         
1603           if (!GTK_SCTREE(ctree)->sorting) {
1604                   /* update focus_row position */
1605                   row = g_list_position (clist->row_list, (GList *)node);
1606                   if (row < clist->focus_row)
1607                     clist->focus_row += tmp;
1608           }
1609           clist->rows += tmp;
1610           CLIST_REFRESH (clist);
1611         }
1612     }
1613   else if (visible && clist->column[ctree->tree_column].auto_resize)
1614     /* resize tree_column if needed */
1615     gtk_sctree_column_auto_resize (clist, &GTK_CTREE_ROW (node)->row, ctree->tree_column,
1616                         requisition.width);
1617 }
1618
1619 GtkCTreeNode * 
1620 gtk_sctree_insert_node (GtkCTree     *ctree,
1621                        GtkCTreeNode *parent, 
1622                        GtkCTreeNode *sibling,
1623                        gchar        *text[],
1624                        guint8        spacing,
1625                        GdkPixmap    *pixmap_closed,
1626                        GdkBitmap    *mask_closed,
1627                        GdkPixmap    *pixmap_opened,
1628                        GdkBitmap    *mask_opened,
1629                        gboolean      is_leaf,
1630                        gboolean      expanded)
1631 {
1632   GtkCList *clist;
1633   GtkCTreeRow *new_row;
1634   GtkCTreeNode *node;
1635   GList *list;
1636   gint i;
1637
1638   if (!emptyxpm) {
1639           stock_pixmap_gdk(GTK_WIDGET(ctree), STOCK_PIXMAP_EMPTY,
1640                    &emptyxpm, &emptyxpmmask);
1641   }
1642   if (!pixmap_closed) {
1643           pixmap_closed = emptyxpm;
1644           mask_closed = emptyxpmmask;
1645   }
1646   if (!pixmap_opened) {
1647           pixmap_opened = emptyxpm;
1648           mask_opened = emptyxpmmask;
1649   }
1650   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
1651   if (sibling)
1652     g_return_val_if_fail (GTK_CTREE_ROW (sibling)->parent == parent, NULL);
1653
1654   if (parent && GTK_CTREE_ROW (parent)->is_leaf)
1655     return NULL;
1656
1657   clist = GTK_CLIST (ctree);
1658
1659   /* create the row */
1660   new_row = srow_new (ctree);
1661   list = g_list_alloc ();
1662   list->data = new_row;
1663   node = GTK_CTREE_NODE (list);
1664
1665   if (text)
1666     for (i = 0; i < clist->columns; i++)
1667       if (text[i] && i != ctree->tree_column)
1668         GTK_CLIST_GET_CLASS (clist)->set_cell_contents
1669           (clist, &(new_row->row), i, GTK_CELL_TEXT, text[i], 0, NULL, NULL);
1670
1671   sset_node_info (ctree, node, text ?
1672                  text[ctree->tree_column] : NULL, spacing, pixmap_closed,
1673                  mask_closed, pixmap_opened, mask_opened, is_leaf, expanded);
1674
1675   /* sorted insertion */
1676   if (GTK_CLIST_AUTO_SORT (clist))
1677     {
1678       if (parent)
1679         sibling = GTK_CTREE_ROW (parent)->children;
1680       else
1681         sibling = GTK_CTREE_NODE (clist->row_list);
1682
1683       while (sibling && clist->compare
1684              (clist, GTK_CTREE_ROW (node), GTK_CTREE_ROW (sibling)) > 0)
1685         sibling = GTK_CTREE_ROW (sibling)->sibling;
1686     }
1687
1688   gtk_sctree_link (ctree, node, parent, sibling, FALSE);
1689
1690   if (text && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist) &&
1691       gtk_ctree_is_viewable (ctree, node))
1692     {
1693       for (i = 0; i < clist->columns; i++)
1694         if (clist->column[i].auto_resize)
1695           gtk_sctree_column_auto_resize (clist, &(new_row->row), i, 0);
1696     }
1697
1698   if (clist->rows == 1)
1699     {
1700       clist->focus_row = 0;
1701       if (clist->selection_mode == GTK_SELECTION_BROWSE)
1702         gtk_sctree_select (GTK_SCTREE(ctree), node);
1703     }
1704
1705
1706   CLIST_REFRESH (clist);
1707
1708   return node;
1709 }
1710
1711 GtkCTreeNode *
1712 gtk_sctree_insert_gnode (GtkCTree          *ctree,
1713                         GtkCTreeNode      *parent,
1714                         GtkCTreeNode      *sibling,
1715                         GNode             *gnode,
1716                         GtkCTreeGNodeFunc  func,
1717                         gpointer           data)
1718 {
1719   GtkCList *clist;
1720   GtkCTreeNode *cnode = NULL;
1721   GtkCTreeNode *child = NULL;
1722   GtkCTreeNode *new_child;
1723   GList *list;
1724   GNode *work;
1725   guint depth = 1;
1726
1727   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
1728   g_return_val_if_fail (gnode != NULL, NULL);
1729   g_return_val_if_fail (func != NULL, NULL);
1730   if (sibling)
1731     g_return_val_if_fail (GTK_CTREE_ROW (sibling)->parent == parent, NULL);
1732   
1733   clist = GTK_CLIST (ctree);
1734
1735   if (parent)
1736     depth = GTK_CTREE_ROW (parent)->level + 1;
1737
1738   list = g_list_alloc ();
1739   list->data = srow_new (ctree);
1740   cnode = GTK_CTREE_NODE (list);
1741
1742   gtk_clist_freeze (clist);
1743
1744   sset_node_info (ctree, cnode, "", 0, NULL, NULL, NULL, NULL, TRUE, FALSE);
1745
1746   if (!func (ctree, depth, gnode, cnode, data))
1747     {
1748       stree_delete_row (ctree, cnode, NULL);
1749       gtk_clist_thaw (clist);
1750       return NULL;
1751     }
1752
1753   if (GTK_CLIST_AUTO_SORT (clist))
1754     {
1755       if (parent)
1756         sibling = GTK_CTREE_ROW (parent)->children;
1757       else
1758         sibling = GTK_CTREE_NODE (clist->row_list);
1759
1760       while (sibling && clist->compare
1761              (clist, GTK_CTREE_ROW (cnode), GTK_CTREE_ROW (sibling)) > 0)
1762         sibling = GTK_CTREE_ROW (sibling)->sibling;
1763     }
1764
1765   gtk_sctree_link (ctree, cnode, parent, sibling, FALSE);
1766
1767   for (work = g_node_last_child (gnode); work; work = work->prev)
1768     {
1769       new_child = gtk_sctree_insert_gnode (ctree, cnode, child,
1770                                           work, func, data);
1771       if (new_child)
1772         child = new_child;
1773     }   
1774   
1775   gtk_clist_thaw (clist);
1776
1777   return cnode;
1778 }
1779
1780 static void
1781 sreal_tree_move (GtkCTree     *ctree,
1782                 GtkCTreeNode *node,
1783                 GtkCTreeNode *new_parent, 
1784                 GtkCTreeNode *new_sibling)
1785 {
1786   GtkCList *clist;
1787   GtkCTreeNode *work;
1788   gboolean visible = FALSE;
1789
1790   g_return_if_fail (ctree != NULL);
1791   g_return_if_fail (node != NULL);
1792   g_return_if_fail (!new_sibling || 
1793                     GTK_CTREE_ROW (new_sibling)->parent == new_parent);
1794
1795   if (new_parent && GTK_CTREE_ROW (new_parent)->is_leaf)
1796     return;
1797
1798   /* new_parent != child of child */
1799   for (work = new_parent; work; work = GTK_CTREE_ROW (work)->parent)
1800     if (work == node)
1801       return;
1802
1803   clist = GTK_CLIST (ctree);
1804
1805   visible = gtk_ctree_is_viewable (ctree, node);
1806
1807   if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
1808     {
1809       GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1810       
1811       g_list_free (clist->undo_selection);
1812       g_list_free (clist->undo_unselection);
1813       clist->undo_selection = NULL;
1814       clist->undo_unselection = NULL;
1815     }
1816
1817   if (GTK_CLIST_AUTO_SORT (clist))
1818     {
1819       if (new_parent == GTK_CTREE_ROW (node)->parent)
1820         return;
1821       
1822       if (new_parent)
1823         new_sibling = GTK_CTREE_ROW (new_parent)->children;
1824       else
1825         new_sibling = GTK_CTREE_NODE (clist->row_list);
1826
1827       while (new_sibling && clist->compare
1828              (clist, GTK_CTREE_ROW (node), GTK_CTREE_ROW (new_sibling)) > 0)
1829         new_sibling = GTK_CTREE_ROW (new_sibling)->sibling;
1830     }
1831
1832   if (new_parent == GTK_CTREE_ROW (node)->parent && 
1833       new_sibling == GTK_CTREE_ROW (node)->sibling)
1834     return;
1835
1836   gtk_clist_freeze (clist);
1837
1838   work = NULL;
1839
1840   if (!GTK_SCTREE(ctree)->sorting && gtk_ctree_is_viewable (ctree, node))
1841     work = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
1842       
1843   gtk_sctree_unlink (ctree, node, FALSE);
1844   gtk_sctree_link (ctree, node, new_parent, new_sibling, FALSE);
1845   
1846   if (!GTK_SCTREE(ctree)->sorting && work)
1847     {
1848       while (work &&  !gtk_ctree_is_viewable (ctree, work))
1849         work = GTK_CTREE_ROW (work)->parent;
1850       clist->focus_row = g_list_position (clist->row_list, (GList *)work);
1851       clist->undo_anchor = clist->focus_row;
1852     }
1853
1854   if (clist->column[ctree->tree_column].auto_resize &&
1855       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist) &&
1856       (visible || gtk_ctree_is_viewable (ctree, node)))
1857     gtk_clist_set_column_width
1858       (clist, ctree->tree_column,
1859        gtk_clist_optimal_column_width (clist, ctree->tree_column));
1860
1861   gtk_clist_thaw (clist);
1862 }
1863