0.8.6claws57
[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
9
10 enum {
11         ROW_POPUP_MENU,
12         EMPTY_POPUP_MENU,
13         OPEN_ROW,
14         START_DRAG,
15         LAST_SIGNAL
16 };
17
18
19 static void gtk_sctree_class_init (GtkSCTreeClass *class);
20 static void gtk_sctree_init (GtkSCTree *sctree);
21
22 static gint gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event);
23 static gint gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event);
24 static gint gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event);
25 static void gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context);
26 static void gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context);
27 static void gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
28                                      GtkSelectionData *data, guint info, guint time);
29 static void gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time);
30 static gboolean gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
31                                        gint x, gint y, guint time);
32 static gboolean gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
33                                      gint x, gint y, guint time);
34 static void gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
35                                           gint x, gint y, GtkSelectionData *data,
36                                           guint info, guint time);
37
38 static void gtk_sctree_clear (GtkCList *clist);
39 static void gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node);
40        
41 static void tree_sort (GtkCTree *ctree, GtkCTreeNode  *node, gpointer data);
42 void gtk_sctree_sort_node (GtkCTree *ctree, GtkCTreeNode *node);
43 void gtk_sctree_sort_recursive (GtkCTree *ctree, GtkCTreeNode *node);
44
45 static void gtk_ctree_link (GtkCTree *ctree,
46                         GtkCTreeNode  *node,
47                         GtkCTreeNode  *parent,
48                         GtkCTreeNode  *sibling,
49                         gboolean       update_focus_row);
50
51 static void gtk_ctree_unlink (GtkCTree      *ctree, 
52                         GtkCTreeNode  *node,
53                         gboolean       update_focus_row);
54
55 static void tree_update_level (GtkCTree      *ctree, 
56                         GtkCTreeNode  *node, 
57                         gpointer       data);
58
59 static GtkCTreeNode * gtk_ctree_last_visible (GtkCTree     *ctree,
60                                               GtkCTreeNode *node);
61
62 static GtkCTreeClass *parent_class;
63
64 static guint sctree_signals[LAST_SIGNAL];
65
66
67 #define GTK_CLIST_CLASS_FW(_widget_) GTK_CLIST_CLASS (((GtkObject*) (_widget_))->klass)
68
69 /**
70  * gtk_sctree_get_type:
71  * @void: 
72  * 
73  * Creates the GtkSCTree class and its type information
74  * 
75  * Return value: The type ID for GtkSCTreeClass
76  **/
77 GtkType
78 gtk_sctree_get_type (void)
79 {
80         static GtkType sctree_type = 0;
81
82         if (!sctree_type) {
83                 GtkTypeInfo sctree_info = {
84                         "GtkSCTree",
85                         sizeof (GtkSCTree),
86                         sizeof (GtkSCTreeClass),
87                         (GtkClassInitFunc) gtk_sctree_class_init,
88                         (GtkObjectInitFunc) gtk_sctree_init,
89                         NULL, /* reserved_1 */
90                         NULL, /* reserved_2 */
91                         (GtkClassInitFunc) NULL
92                 };
93
94                 sctree_type = gtk_type_unique (gtk_ctree_get_type (), &sctree_info);
95         }
96
97         return sctree_type;
98 }
99
100 /* Standard class initialization function */
101 static void
102 gtk_sctree_class_init (GtkSCTreeClass *klass)
103 {
104         GtkObjectClass *object_class;
105         GtkWidgetClass *widget_class;
106         GtkCListClass *clist_class;
107         GtkCTreeClass *ctree_class;
108
109         object_class = (GtkObjectClass *) klass;
110         widget_class = (GtkWidgetClass *) klass;
111         clist_class = (GtkCListClass *) klass;
112         ctree_class = (GtkCTreeClass *) klass;
113
114         parent_class = gtk_type_class (gtk_ctree_get_type ());
115
116         sctree_signals[ROW_POPUP_MENU] =
117                 gtk_signal_new ("row_popup_menu",
118                                 GTK_RUN_FIRST,
119                                 object_class->type,
120                                 GTK_SIGNAL_OFFSET (GtkSCTreeClass, row_popup_menu),
121                                 gtk_marshal_NONE__POINTER,
122                                 GTK_TYPE_NONE, 1,
123                                 GTK_TYPE_GDK_EVENT);
124         sctree_signals[EMPTY_POPUP_MENU] =
125                 gtk_signal_new ("empty_popup_menu",
126                                 GTK_RUN_FIRST,
127                                 object_class->type,
128                                 GTK_SIGNAL_OFFSET (GtkSCTreeClass, empty_popup_menu),
129                                 gtk_marshal_NONE__POINTER,
130                                 GTK_TYPE_NONE, 1,
131                                 GTK_TYPE_GDK_EVENT);
132         sctree_signals[OPEN_ROW] =
133                 gtk_signal_new ("open_row",
134                                 GTK_RUN_FIRST,
135                                 object_class->type,
136                                 GTK_SIGNAL_OFFSET (GtkSCTreeClass, open_row),
137                                 gtk_marshal_NONE__NONE,
138                                 GTK_TYPE_NONE, 0);
139         sctree_signals[START_DRAG] =
140                 gtk_signal_new ("start_drag",
141                                 GTK_RUN_FIRST,
142                                 object_class->type,
143                                 GTK_SIGNAL_OFFSET (GtkSCTreeClass, start_drag),
144                                 gtk_marshal_NONE__INT_POINTER,
145                                 GTK_TYPE_NONE, 2,
146                                 GTK_TYPE_INT,
147                                 GTK_TYPE_GDK_EVENT);
148
149         gtk_object_class_add_signals (object_class, sctree_signals, LAST_SIGNAL);
150
151         clist_class->clear = gtk_sctree_clear;
152         ctree_class->tree_collapse = gtk_sctree_collapse;
153         
154         widget_class->button_press_event = gtk_sctree_button_press;
155         widget_class->button_release_event = gtk_sctree_button_release;
156         widget_class->motion_notify_event = gtk_sctree_motion;
157         widget_class->drag_begin = gtk_sctree_drag_begin;
158         widget_class->drag_end = gtk_sctree_drag_end;
159         widget_class->drag_data_get = gtk_sctree_drag_data_get;
160         widget_class->drag_leave = gtk_sctree_drag_leave;
161         widget_class->drag_motion = gtk_sctree_drag_motion;
162         widget_class->drag_drop = gtk_sctree_drag_drop;
163         widget_class->drag_data_received = gtk_sctree_drag_data_received;
164 }
165
166 /* Standard object initialization function */
167 static void
168 gtk_sctree_init (GtkSCTree *sctree)
169 {
170         sctree->anchor_row = NULL;
171
172         /* GtkCTree does not specify pointer motion by default */
173         gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
174         gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
175 }
176
177 /* Get information the specified row is selected. */
178
179 static gboolean
180 row_is_selected(GtkSCTree *sctree, gint row)
181 {
182         GtkCListRow *clist_row;
183         clist_row =  g_list_nth (GTK_CLIST(sctree)->row_list, row)->data;
184         return clist_row ? clist_row->state == GTK_STATE_SELECTED : FALSE;
185 }
186
187 /* Selects the rows between the anchor to the specified row, inclusive.  */
188 static void
189 select_range (GtkSCTree *sctree, gint row)
190 {
191         gint prev_row;
192         gint min, max;
193         gint i;
194
195         if (sctree->anchor_row == NULL) {
196                 prev_row = row;
197                 sctree->anchor_row = gtk_ctree_node_nth(GTK_CTREE(sctree), row);
198         } else
199                 prev_row = g_list_position(GTK_CLIST(sctree)->row_list,
200                                            (GList *)sctree->anchor_row);
201
202         if (row < prev_row) {
203                 min = row;
204                 max = prev_row;
205                 GTK_CLIST(sctree)->focus_row = max;
206         } else {
207                 min = prev_row;
208                 max = row;
209         }
210         for (i = min; i <= max; i++)
211                 gtk_clist_select_row (GTK_CLIST (sctree), i, -1);
212 }
213
214 /* Handles row selection according to the specified modifier state */
215 static void
216 select_row (GtkSCTree *sctree, gint row, gint col, guint state)
217 {
218         gboolean range, additive;
219         g_return_if_fail (sctree != NULL);
220         g_return_if_fail (GTK_IS_SCTREE (sctree));
221     
222         range = ((state & GDK_SHIFT_MASK) != 0) &&
223                 (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
224                 (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
225         additive = ((state & GDK_CONTROL_MASK) != 0) &&
226                    (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
227                    (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
228
229         gtk_clist_freeze (GTK_CLIST (sctree));
230         GTK_CLIST(sctree)->focus_row = row;
231         GTK_CLIST_CLASS(GTK_OBJECT(sctree)->klass)->refresh(GTK_CLIST(sctree));
232         if (!additive)
233                 gtk_clist_unselect_all (GTK_CLIST (sctree));
234
235         if (!range) {
236                 GtkCTreeNode *node;
237
238                 node = gtk_ctree_node_nth (GTK_CTREE(sctree), row);
239
240                 /*No need to manage overlapped list*/
241                 if (additive) {
242                         if (row_is_selected(sctree, row))
243                                 gtk_clist_unselect_row (GTK_CLIST (sctree), row, col);
244                         else
245                                 gtk_signal_emit_by_name
246                                         (GTK_OBJECT (sctree),
247                                          "tree_select_row", node, col);
248                 } else {
249                         gtk_signal_emit_by_name
250                                 (GTK_OBJECT (sctree),
251                                  "tree_select_row", node, col);
252                 }
253                 sctree->anchor_row = node;
254         } else
255                 select_range (sctree, row);
256         gtk_clist_thaw (GTK_CLIST (sctree));
257 }
258
259 /* Our handler for button_press events.  We override all of GtkCList's broken
260  * behavior.
261  */
262 static gint
263 gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
264 {
265         GtkSCTree *sctree;
266         GtkCList *clist;
267         gboolean on_row;
268         gint row;
269         gint col;
270         gint retval;
271
272         g_return_val_if_fail (widget != NULL, FALSE);
273         g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
274         g_return_val_if_fail (event != NULL, FALSE);
275
276         sctree = GTK_SCTREE (widget);
277         clist = GTK_CLIST (widget);
278         retval = FALSE;
279
280         if (event->window != clist->clist_window)
281                 return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
282
283         on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
284
285         if (on_row && !GTK_WIDGET_HAS_FOCUS(widget))
286                 gtk_widget_grab_focus (widget);
287
288         if (gtk_ctree_is_hot_spot (GTK_CTREE(sctree), event->x, event->y)) {
289                 gtk_ctree_toggle_expansion
290                         (GTK_CTREE(sctree), 
291                          gtk_ctree_node_nth(GTK_CTREE(sctree), row));
292                 return TRUE;
293         }
294
295         switch (event->type) {
296         case GDK_BUTTON_PRESS:
297                 if (event->button == 1 || event->button == 2) {
298                         if (event->button == 2)
299                                 event->state &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK);
300                         if (on_row) {
301                                 /* Save the mouse info for DnD */
302                                 sctree->dnd_press_button = event->button;
303                                 sctree->dnd_press_x = event->x;
304                                 sctree->dnd_press_y = event->y;
305
306                                 /* Handle selection */
307                                 if ((row_is_selected (sctree, row)
308                                      && !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
309                                     || ((event->state & GDK_CONTROL_MASK)
310                                         && !(event->state & GDK_SHIFT_MASK))) {
311                                         sctree->dnd_select_pending = TRUE;
312                                         sctree->dnd_select_pending_state = event->state;
313                                         sctree->dnd_select_pending_row = row;
314                                 } else
315                                         select_row (sctree, row, col, event->state);
316                         } else
317                                 gtk_clist_unselect_all (clist);
318
319                         retval = TRUE;
320                 } else if (event->button == 3) {
321                         /* Emit *_popup_menu signal*/
322                         if (on_row) {
323                                 if (!row_is_selected(sctree,row))
324                                         select_row (sctree, row, col, 0);
325                                 gtk_signal_emit (GTK_OBJECT (sctree),
326                                                  sctree_signals[ROW_POPUP_MENU],
327                                                  event);
328                         } else {
329                                 gtk_clist_unselect_all(clist);
330                                 gtk_signal_emit (GTK_OBJECT (sctree),
331                                                  sctree_signals[EMPTY_POPUP_MENU],
332                                                  event);
333                         }
334                         retval = TRUE;
335                 }
336
337                 break;
338
339         case GDK_2BUTTON_PRESS:
340                 if (event->button != 1)
341                         break;
342
343                 sctree->dnd_select_pending = FALSE;
344                 sctree->dnd_select_pending_state = 0;
345
346                 if (on_row)
347                         gtk_signal_emit (GTK_OBJECT (sctree),
348                                          sctree_signals[OPEN_ROW]);
349
350                 retval = TRUE;
351                 break;
352
353         default:
354                 break;
355         }
356
357         return retval;
358 }
359
360 /* Our handler for button_release events.  We override all of GtkCList's broken
361  * behavior.
362  */
363 static gint
364 gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event)
365 {
366         GtkSCTree *sctree;
367         GtkCList *clist;
368         gint on_row;
369         gint row, col;
370         gint retval;
371
372         g_return_val_if_fail (widget != NULL, FALSE);
373         g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
374         g_return_val_if_fail (event != NULL, FALSE);
375
376         sctree = GTK_SCTREE (widget);
377         clist = GTK_CLIST (widget);
378         retval = FALSE;
379
380         if (event->window != clist->clist_window)
381                 return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
382
383         on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col);
384
385         if (!(event->button == 1 || event->button == 2))
386                 return FALSE;
387
388         sctree->dnd_press_button = 0;
389         sctree->dnd_press_x = 0;
390         sctree->dnd_press_y = 0;
391
392         if (on_row) {
393                 if (sctree->dnd_select_pending) {
394                         select_row (sctree, row, col, sctree->dnd_select_pending_state);
395                         sctree->dnd_select_pending = FALSE;
396                         sctree->dnd_select_pending_state = 0;
397                 }
398
399                 retval = TRUE;
400         }
401
402         return retval;
403 }
404
405 /* Our handler for motion_notify events.  We override all of GtkCList's broken
406  * behavior.
407  */
408 static gint
409 gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event)
410 {
411         GtkSCTree *sctree;
412         GtkCList *clist;
413
414         g_return_val_if_fail (widget != NULL, FALSE);
415         g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
416         g_return_val_if_fail (event != NULL, FALSE);
417
418         sctree = GTK_SCTREE (widget);
419         clist = GTK_CLIST (widget);
420
421         if (event->window != clist->clist_window)
422                 return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
423
424         if (!((sctree->dnd_press_button == 1 && (event->state & GDK_BUTTON1_MASK))
425               || (sctree->dnd_press_button == 2 && (event->state & GDK_BUTTON2_MASK))))
426                 return FALSE;
427
428         /* This is the same threshold value that is used in gtkdnd.c */
429
430         if (MAX (ABS (sctree->dnd_press_x - event->x),
431                  ABS (sctree->dnd_press_y - event->y)) <= 3)
432                 return FALSE;
433
434         /* Handle any pending selections */
435
436         if (sctree->dnd_select_pending) {
437                 if (!row_is_selected(sctree,sctree->dnd_select_pending_row))
438                         select_row (sctree,
439                                     sctree->dnd_select_pending_row,
440                                     -1,
441                                     sctree->dnd_select_pending_state);
442
443                 sctree->dnd_select_pending = FALSE;
444                 sctree->dnd_select_pending_state = 0;
445         }
446
447         gtk_signal_emit (GTK_OBJECT (sctree),
448                          sctree_signals[START_DRAG],
449                          sctree->dnd_press_button,
450                          event);
451         return TRUE;
452 }
453
454 /* We override the drag_begin signal to do nothing */
455 static void
456 gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context)
457 {
458         /* nothing */
459 }
460
461 /* We override the drag_end signal to do nothing */
462 static void
463 gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context)
464 {
465         /* nothing */
466 }
467
468 /* We override the drag_data_get signal to do nothing */
469 static void
470 gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
471                                      GtkSelectionData *data, guint info, guint time)
472 {
473         /* nothing */
474 }
475
476 /* We override the drag_leave signal to do nothing */
477 static void
478 gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time)
479 {
480         /* nothing */
481 }
482
483 /* We override the drag_motion signal to do nothing */
484 static gboolean
485 gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
486                                    gint x, gint y, guint time)
487 {
488         return FALSE;
489 }
490
491 /* We override the drag_drop signal to do nothing */
492 static gboolean
493 gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
494                                  gint x, gint y, guint time)
495 {
496         return FALSE;
497 }
498
499 /* We override the drag_data_received signal to do nothing */
500 static void
501 gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
502                                           gint x, gint y, GtkSelectionData *data,
503                                           guint info, guint time)
504 {
505         /* nothing */
506 }
507
508 /* Our handler for the clear signal of the clist.  We have to reset the anchor
509  * to null.
510  */
511 static void
512 gtk_sctree_clear (GtkCList *clist)
513 {
514         GtkSCTree *sctree;
515
516         g_return_if_fail (clist != NULL);
517         g_return_if_fail (GTK_IS_SCTREE (clist));
518
519         sctree = GTK_SCTREE (clist);
520         sctree->anchor_row = NULL;
521
522         if (((GtkCListClass *)parent_class)->clear)
523                 (* ((GtkCListClass *)parent_class)->clear) (clist);
524 }
525
526 /* Our handler for the change_focus_row_expansion signal of the ctree.  
527  We have to set the anchor to parent visible node.
528  */
529 static void 
530 gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node)
531 {
532         g_return_if_fail (ctree != NULL);
533         g_return_if_fail (GTK_IS_SCTREE (ctree));
534
535         (* parent_class->tree_collapse) (ctree, node);
536         GTK_SCTREE(ctree)->anchor_row =
537                 gtk_ctree_node_nth(ctree, GTK_CLIST(ctree)->focus_row);
538 }
539
540 GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column, 
541                                        gchar *titles[])
542 {
543         GtkSCTree* sctree;
544
545         sctree = gtk_type_new (gtk_sctree_get_type ());
546         gtk_ctree_construct (GTK_CTREE (sctree), columns, tree_column, titles);
547         gtk_clist_set_selection_mode(GTK_CLIST(sctree), GTK_SELECTION_EXTENDED);
548
549         return GTK_WIDGET (sctree);
550 }
551
552 void gtk_sctree_select (GtkSCTree *sctree, GtkCTreeNode *node)
553 {
554         select_row(sctree, 
555                    g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node),
556                    -1, 0);
557 }
558
559 void gtk_sctree_unselect_all (GtkSCTree *sctree)
560 {
561         gtk_clist_unselect_all(GTK_CLIST(sctree));
562         sctree->anchor_row = NULL;
563 }
564
565 void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCTreeNode *node)
566 {
567         sctree->anchor_row = node;
568 }
569
570 /***********************************************************
571  *             Tree sorting functions                      *
572  ***********************************************************/
573
574 static void sink(GtkCList *clist, GPtrArray *numbers, gint root, gint bottom)
575 {
576         gint j, k ;
577         GtkCTreeNode *temp;
578
579         j = 2 * root;
580         k = j + 1;
581
582         /* find the maximum element of numbers[root],
583            numbers[2*root] and numbers[2*root+1] */
584         if (j <= bottom) {
585                 if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, root)),
586                                     GTK_CTREE_ROW(g_ptr_array_index( numbers, j))) >= 0)
587                         j = root;
588                 if (k <= bottom)
589                         if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, k)),
590                                             GTK_CTREE_ROW (g_ptr_array_index( numbers, j))) > 0)
591                                 j = k;
592                 /* if numbers[root] wasn't the maximum element then
593                    sink again */
594                 if (root != j) {
595                         temp = g_ptr_array_index( numbers,root);
596                         g_ptr_array_index( numbers, root) = g_ptr_array_index( numbers, j);
597                         g_ptr_array_index( numbers, j) = temp;
598                         sink( clist, numbers, j, bottom);
599                 }
600         }
601 }
602
603 static void heap_sort(GtkCList *clist, GPtrArray *numbers, gint array_size)
604 {
605         gint i;
606         GtkCTreeNode *temp;
607         
608         /* build the Heap */
609         for (i = (array_size / 2); i >= 1; i--)
610                 sink( clist, numbers, i, array_size);
611         /* output the Heap */
612         for (i = array_size; i >= 2; i--) {
613                 temp = g_ptr_array_index( numbers, 1);
614                 g_ptr_array_index( numbers, 1) = g_ptr_array_index( numbers, i);
615                 g_ptr_array_index( numbers, i) = temp;
616                 sink( clist, numbers, 1, i-1);
617         }
618 }
619
620 static void
621 tree_sort (GtkCTree    *ctree,
622            GtkCTreeNode *node,
623            gpointer      data)
624 {
625         GtkCTreeNode *list_start, *work, *next;
626         GPtrArray *row_array, *viewable_array;
627         GtkCList *clist;
628         gint i;
629
630
631         clist = GTK_CLIST (ctree);
632
633         if (node)
634                 work = GTK_CTREE_ROW (node)->children;
635         else
636                 work = GTK_CTREE_NODE (clist->row_list);
637
638         row_array = g_ptr_array_new();
639         viewable_array = g_ptr_array_new();
640
641         if (work) {
642                 g_ptr_array_add( row_array, NULL);
643                 while (work) {
644                         /* add all rows to row_array */
645                         g_ptr_array_add( row_array, work);
646                         if (GTK_CTREE_ROW (work)->parent && gtk_ctree_is_viewable( ctree, work))
647                                 g_ptr_array_add( viewable_array, GTK_CTREE_ROW (work)->parent);
648                         next = GTK_CTREE_ROW (work)->sibling;
649                         gtk_ctree_unlink( ctree, work, FALSE);
650                         work = next;
651                 }
652
653                 heap_sort( clist, row_array, (row_array->len)-1);
654
655                 if (node)
656                         list_start = GTK_CTREE_ROW (node)->children;
657                 else
658                         list_start = GTK_CTREE_NODE (clist->row_list);
659
660                 if (clist->sort_type == GTK_SORT_ASCENDING) {
661                         for (i=(row_array->len)-1; i>=1; i--) {
662                                 work = g_ptr_array_index( row_array, i);
663                                 gtk_ctree_link( ctree, work, node, list_start, FALSE);
664                                 list_start = work;
665                                 /* insert work at the beginning of the list */
666                         }
667                 } else {
668                         for (i=1; i<row_array->len; i++) {
669                                 work = g_ptr_array_index( row_array, i);
670                                 gtk_ctree_link( ctree, work, node, list_start, FALSE);
671                                 list_start = work;
672                                 /* insert work at the beginning of the list */
673                         }
674                 }
675
676                 for (i=0; i<viewable_array->len; i++) {
677                         gtk_ctree_expand( ctree, g_ptr_array_index( viewable_array, i));
678                 }
679                 
680         }
681
682         g_ptr_array_free( row_array, TRUE);
683         g_ptr_array_free( viewable_array, TRUE);
684 }
685
686 void
687 gtk_sctree_sort_recursive (GtkCTree     *ctree, 
688                           GtkCTreeNode *node)
689 {
690         GtkCList *clist;
691         GtkCTreeNode *focus_node = NULL;
692
693         g_return_if_fail (ctree != NULL);
694         g_return_if_fail (GTK_IS_CTREE (ctree));
695
696         clist = GTK_CLIST (ctree);
697
698         gtk_clist_freeze (clist);
699
700         if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
701                 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
702       
703                 g_list_free (clist->undo_selection);
704                 g_list_free (clist->undo_unselection);
705                 clist->undo_selection = NULL;
706                 clist->undo_unselection = NULL;
707         }
708
709         if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
710                 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
711       
712         gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_sort), NULL);
713
714         if (!node)
715                 tree_sort (ctree, NULL, NULL);
716
717         if (focus_node) {
718                 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
719                 clist->undo_anchor = clist->focus_row;
720         }
721
722         gtk_clist_thaw (clist);
723 }
724
725 void
726 gtk_sctree_sort_node (GtkCTree     *ctree, 
727                      GtkCTreeNode *node)
728 {
729         GtkCList *clist;
730         GtkCTreeNode *focus_node = NULL;
731
732         g_return_if_fail (ctree != NULL);
733         g_return_if_fail (GTK_IS_CTREE (ctree));
734
735         clist = GTK_CLIST (ctree);
736
737         gtk_clist_freeze (clist);
738
739         if (clist->selection_mode == GTK_SELECTION_EXTENDED) {
740                 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
741
742                 g_list_free (clist->undo_selection);
743                 g_list_free (clist->undo_unselection);
744                 clist->undo_selection = NULL;
745                 clist->undo_unselection = NULL;
746         }
747
748         if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
749                 focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
750
751         tree_sort (ctree, node, NULL);
752
753         if (focus_node) {
754                 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
755                 clist->undo_anchor = clist->focus_row;
756         }
757
758         gtk_clist_thaw (clist);
759 }
760
761 /************************************************************************/
762
763 static void
764 gtk_ctree_unlink (GtkCTree     *ctree, 
765                   GtkCTreeNode *node,
766                   gboolean      update_focus_row)
767 {
768         GtkCList *clist;
769         gint rows;
770         gint level;
771         gint visible;
772         GtkCTreeNode *work;
773         GtkCTreeNode *parent;
774         GList *list;
775
776         g_return_if_fail (ctree != NULL);
777         g_return_if_fail (GTK_IS_CTREE (ctree));
778         g_return_if_fail (node != NULL);
779
780         clist = GTK_CLIST (ctree);
781   
782         if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
783                 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
784
785                 g_list_free (clist->undo_selection);
786                 g_list_free (clist->undo_unselection);
787                 clist->undo_selection = NULL;
788                 clist->undo_unselection = NULL;
789         }
790
791         visible = gtk_ctree_is_viewable (ctree, node);
792
793         /* clist->row_list_end unlinked ? */
794         if (visible && (GTK_CTREE_NODE_NEXT (node) == NULL ||
795            (GTK_CTREE_ROW (node)->children && gtk_ctree_is_ancestor (ctree, node,
796             GTK_CTREE_NODE (clist->row_list_end)))))
797                 clist->row_list_end = (GList *) (GTK_CTREE_NODE_PREV (node));
798
799         /* update list */
800         rows = 0;
801         level = GTK_CTREE_ROW (node)->level;
802         work = GTK_CTREE_NODE_NEXT (node);
803         while (work && GTK_CTREE_ROW (work)->level > level) {
804                 work = GTK_CTREE_NODE_NEXT (work);
805                 rows++;
806         }
807
808         if (visible) {
809                 clist->rows -= (rows + 1);
810
811                 if (update_focus_row) {
812                         gint pos;
813
814                         pos = g_list_position (clist->row_list, (GList *)node);
815                         if (pos + rows < clist->focus_row)
816                                 clist->focus_row -= (rows + 1);
817                         else if (pos <= clist->focus_row) {
818                                 if (!GTK_CTREE_ROW (node)->sibling)
819                                         clist->focus_row = MAX (pos - 1, 0);
820                                 else
821                                         clist->focus_row = pos;
822               
823                                 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
824                         }
825                         clist->undo_anchor = clist->focus_row;
826                 }
827         }
828
829         if (work) {
830                 list = (GList *)GTK_CTREE_NODE_PREV (work);
831                 list->next = NULL;
832                 list = (GList *)work;
833                 list->prev = (GList *)GTK_CTREE_NODE_PREV (node);
834         }
835
836         if (GTK_CTREE_NODE_PREV (node) &&
837             GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (node)) == node) {
838                 list = (GList *)GTK_CTREE_NODE_PREV (node);
839                 list->next = (GList *)work;
840         }
841
842         /* update tree */
843         parent = GTK_CTREE_ROW (node)->parent;
844         if (parent) {
845                 if (GTK_CTREE_ROW (parent)->children == node) {
846                         GTK_CTREE_ROW (parent)->children = GTK_CTREE_ROW (node)->sibling;
847                         if (!GTK_CTREE_ROW (parent)->children)
848                                 gtk_ctree_collapse (ctree, parent);
849                 }
850                 else {
851                         GtkCTreeNode *sibling;
852
853                         sibling = GTK_CTREE_ROW (parent)->children;
854                         while (GTK_CTREE_ROW (sibling)->sibling != node)
855                                 sibling = GTK_CTREE_ROW (sibling)->sibling;
856                         GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
857                 }
858         }
859         else {
860                 if (clist->row_list == (GList *)node)
861                         clist->row_list = (GList *) (GTK_CTREE_ROW (node)->sibling);
862                 else {
863                         GtkCTreeNode *sibling;
864
865                         sibling = GTK_CTREE_NODE (clist->row_list);
866                         while (GTK_CTREE_ROW (sibling)->sibling != node)
867                                 sibling = GTK_CTREE_ROW (sibling)->sibling;
868                         GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
869                 }
870         }
871 }
872
873 static void
874 gtk_ctree_link (GtkCTree     *ctree,
875                 GtkCTreeNode *node,
876                 GtkCTreeNode *parent,
877                 GtkCTreeNode *sibling,
878                 gboolean      update_focus_row)
879 {
880         GtkCList *clist;
881         GList *list_end;
882         GList *list;
883         GList *work;
884         gboolean visible = FALSE;
885         gint rows = 0;
886   
887         if (sibling)
888                 g_return_if_fail (GTK_CTREE_ROW (sibling)->parent == parent);
889         g_return_if_fail (node != NULL);
890         g_return_if_fail (node != sibling);
891         g_return_if_fail (node != parent);
892
893         clist = GTK_CLIST (ctree);
894
895         if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) {
896                 GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL);
897
898                 g_list_free (clist->undo_selection);
899                 g_list_free (clist->undo_unselection);
900                 clist->undo_selection = NULL;
901                 clist->undo_unselection = NULL;
902         }
903
904         for (rows = 1, list_end = (GList *)node; list_end->next;
905              list_end = list_end->next)
906                 rows++;
907
908         GTK_CTREE_ROW (node)->parent = parent;
909         GTK_CTREE_ROW (node)->sibling = sibling;
910
911         if (!parent || (parent && (gtk_ctree_is_viewable (ctree, parent) &&
912             GTK_CTREE_ROW (parent)->expanded))) {
913                 visible = TRUE;
914                 clist->rows += rows;
915         }
916
917         if (parent)
918                 work = (GList *)(GTK_CTREE_ROW (parent)->children);
919         else
920                 work = clist->row_list;
921
922         if (sibling) {
923                 if (work != (GList *)sibling) {
924                         while (GTK_CTREE_ROW (work)->sibling != sibling)
925                                 work = (GList *)(GTK_CTREE_ROW (work)->sibling);
926                         GTK_CTREE_ROW (work)->sibling = node;
927                 }
928
929                 if (sibling == GTK_CTREE_NODE (clist->row_list))
930                 clist->row_list = (GList *) node;
931                 if (GTK_CTREE_NODE_PREV (sibling) &&
932                     GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (sibling)) == sibling) {
933                         list = (GList *)GTK_CTREE_NODE_PREV (sibling);
934                         list->next = (GList *)node;
935                 }
936
937                 list = (GList *)node;
938                 list->prev = (GList *)GTK_CTREE_NODE_PREV (sibling);
939                 list_end->next = (GList *)sibling;
940                 list = (GList *)sibling;
941                 list->prev = list_end;
942                 if (parent && GTK_CTREE_ROW (parent)->children == sibling)
943                         GTK_CTREE_ROW (parent)->children = node;
944         }
945         else {
946                 if (work) {
947                         /* find sibling */
948                         while (GTK_CTREE_ROW (work)->sibling)
949                         work = (GList *)(GTK_CTREE_ROW (work)->sibling);
950                         GTK_CTREE_ROW (work)->sibling = node;
951
952                         /* find last visible child of sibling */
953                         work = (GList *) gtk_ctree_last_visible (ctree,
954                                GTK_CTREE_NODE (work));
955
956                         list_end->next = work->next;
957                         if (work->next)
958                                 list = work->next->prev = list_end;
959                         work->next = (GList *)node;
960                         list = (GList *)node;
961                         list->prev = work;
962                 }
963                 else {
964                         if (parent) {
965                                 GTK_CTREE_ROW (parent)->children = node;
966                                 list = (GList *)node;
967                                 list->prev = (GList *)parent;
968                                 if (GTK_CTREE_ROW (parent)->expanded) {
969                                         list_end->next = (GList *)GTK_CTREE_NODE_NEXT (parent);
970                                         if (GTK_CTREE_NODE_NEXT(parent)) {
971                                                 list = (GList *)GTK_CTREE_NODE_NEXT (parent);
972                                                 list->prev = list_end;
973                                         }
974                                         list = (GList *)parent;
975                                         list->next = (GList *)node;
976                                 }
977                                 else
978                                         list_end->next = NULL;
979                         }
980                         else {
981                                 clist->row_list = (GList *)node;
982                                 list = (GList *)node;
983                                 list->prev = NULL;
984                                 list_end->next = NULL;
985                         }
986                 }
987         }
988
989         gtk_ctree_pre_recursive (ctree, node, tree_update_level, NULL); 
990
991         if (clist->row_list_end == NULL ||
992             clist->row_list_end->next == (GList *)node)
993                 clist->row_list_end = list_end;
994
995         if (visible && update_focus_row) {
996                 gint pos;
997           
998                 pos = g_list_position (clist->row_list, (GList *)node);
999   
1000                 if (pos <= clist->focus_row) {
1001                         clist->focus_row += rows;
1002                         clist->undo_anchor = clist->focus_row;
1003                 }
1004         }
1005 }
1006
1007 static void
1008 tree_update_level (GtkCTree     *ctree, 
1009                    GtkCTreeNode *node, 
1010                    gpointer      data)
1011 {
1012         if (!node)
1013                 return;
1014
1015         if (GTK_CTREE_ROW (node)->parent)
1016                 GTK_CTREE_ROW (node)->level = 
1017                 GTK_CTREE_ROW (GTK_CTREE_ROW (node)->parent)->level + 1;
1018         else
1019                 GTK_CTREE_ROW (node)->level = 1;
1020 }
1021
1022 static GtkCTreeNode *
1023 gtk_ctree_last_visible (GtkCTree     *ctree,
1024                         GtkCTreeNode *node)
1025 {
1026         GtkCTreeNode *work;
1027   
1028         if (!node)
1029                 return NULL;
1030
1031         work = GTK_CTREE_ROW (node)->children;
1032
1033         if (!work || !GTK_CTREE_ROW (node)->expanded)
1034                 return node;
1035
1036         while (GTK_CTREE_ROW (work)->sibling)
1037                 work = GTK_CTREE_ROW (work)->sibling;
1038
1039         return gtk_ctree_last_visible (ctree, work);
1040 }