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