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