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