Improve some sieve-related translations
[claws.git] / src / gtk / gtksctree.c
blob027300d34b96bc36584dace9bfdc6e8a9ea7bf78
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
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>
10 * Parts of this file from gtkflist.c:
11 * Copyright (C) 1999 The Free Software Foundation
12 * Author: Federico Mena <federico@nuclecu.unam.mx>
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.
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.
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/>.
29 #include "config.h"
31 #include <stdlib.h>
33 #include "gtksctree.h"
34 #include "claws-marshal.h"
35 #include "prefs_common.h"
36 #include "utils.h"
37 #include "gtkutils.h"
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)
58 enum {
59 ROW_POPUP_MENU,
60 EMPTY_POPUP_MENU,
61 OPEN_ROW,
62 START_DRAG,
63 LAST_SIGNAL
66 static void gtk_sctree_class_init (GtkSCTreeClass *class);
67 static void gtk_sctree_init (GtkSCTree *sctree);
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);
85 static void gtk_sctree_clear (GtkCMCList *clist);
86 static void gtk_sctree_real_unselect_all (GtkCMCList *clist);
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);
92 static void gtk_sctree_link (GtkCMCTree *ctree,
93 GtkCMCTreeNode *node,
94 GtkCMCTreeNode *parent,
95 GtkCMCTreeNode *sibling,
96 gboolean update_focus_row);
98 static void gtk_sctree_unlink (GtkCMCTree *ctree,
99 GtkCMCTreeNode *node,
100 gboolean update_focus_row);
102 static void stree_update_level (GtkCMCTree *ctree,
103 GtkCMCTreeNode *node,
104 gpointer data);
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);
118 static GtkCMCTreeClass *parent_class;
120 static guint sctree_signals[LAST_SIGNAL];
123 * gtk_sctree_get_type:
124 * @void:
126 * Creates the GtkSCTree class and its type information
128 * Return value: The type ID for GtkSCTreeClass
130 GType
131 gtk_sctree_get_type (void)
133 static GType sctree_type = 0;
135 if (!sctree_type) {
136 GTypeInfo sctree_info = {
137 sizeof (GtkSCTreeClass),
139 (GBaseInitFunc) NULL,
140 (GBaseFinalizeFunc) NULL,
142 (GClassInitFunc) gtk_sctree_class_init,
143 (GClassFinalizeFunc) NULL,
144 NULL, /* class_data */
146 sizeof (GtkSCTree),
147 0, /* n_preallocs */
148 (GInstanceInitFunc) gtk_sctree_init,
150 (const GTypeValueTable *) NULL /* value table */
153 sctree_type = g_type_register_static (GTK_TYPE_CMCTREE, "GtkSCTree", &sctree_info, (GTypeFlags)0);
156 return sctree_type;
159 static void
160 gtk_sctree_change_focus_row_expansion (GtkCMCTree *ctree,
161 GtkCMCTreeExpansionType action)
163 GtkCMCList *clist;
164 GtkCMCTreeNode *node;
166 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
168 clist = GTK_CMCLIST (ctree);
170 if (gtkut_pointer_is_grabbed (GTK_WIDGET (ctree)) &&
171 gtk_widget_has_grab (GTK_WIDGET(ctree)))
172 return;
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;
179 switch (action)
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);
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;
209 static void gtk_sctree_finalize(GObject *object)
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);
217 /* Standard class initialization function */
218 static void
219 gtk_sctree_class_init (GtkSCTreeClass *klass)
221 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
222 GtkWidgetClass *widget_class;
223 GtkCMCListClass *clist_class;
224 GtkCMCTreeClass *ctree_class;
226 widget_class = (GtkWidgetClass *) klass;
227 clist_class = (GtkCMCListClass *) klass;
228 ctree_class = (GtkCMCTreeClass *) klass;
230 parent_class = g_type_class_peek (gtk_cmctree_get_type ());
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);
269 /* gtk_object_class_add_signals (object_class, sctree_signals, LAST_SIGNAL); */
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;
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;
289 gobject_class->finalize = gtk_sctree_finalize;
292 /* Standard object initialization function */
293 static void
294 gtk_sctree_init (GtkSCTree *sctree)
296 sctree->anchor_row = NULL;
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);
303 /* Get information the specified row is selected. */
305 static gboolean
306 row_is_selected(GtkSCTree *sctree, gint row)
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;
313 /* Selects the rows between the anchor to the specified row, inclusive. */
314 static void
315 select_range (GtkSCTree *sctree, gint row)
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);
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;
336 sctree->selecting_range++;
338 if (max < min) {
339 int t = min;
340 min = max;
341 max = t;
344 if (max - min > 10)
345 gtk_cmclist_freeze(GTK_CMCLIST(sctree));
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);
353 node = node->next;
355 if (max - min > 10)
356 gtk_cmclist_thaw(GTK_CMCLIST(sctree));
359 sctree->selecting_range--;
360 gtk_cmclist_select_row (GTK_CMCLIST (sctree), max, -1);
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)
370 gboolean range, additive;
371 cm_return_if_fail (sctree != NULL);
372 cm_return_if_fail (GTK_IS_SCTREE (sctree));
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);
381 if (!range && !additive && sctree->force_additive_sel)
382 additive = TRUE;
384 GTK_CMCLIST(sctree)->focus_row = row;
386 if (!additive) {
387 gtk_cmclist_unselect_all (GTK_CMCLIST (sctree));
390 if (!range) {
391 GtkCMCTreeNode *node;
393 node = _node ? _node : gtk_cmctree_node_nth (GTK_CMCTREE(sctree), row);
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);
408 sctree->anchor_row = node;
409 } else
410 select_range (sctree, row);
413 static gboolean
414 sctree_is_hot_spot (GtkSCTree *sctree,
415 GtkCMCTreeNode *node,
416 gint row,
417 gint x,
418 gint y)
420 GtkCMCTreeRow *tree_row;
421 GtkCMCList *clist;
422 GtkCMCTree *ctree;
423 gint xl, xmax;
424 gint yu;
425 gint hotspot_size;
427 cm_return_val_if_fail (GTK_IS_SCTREE (sctree), FALSE);
428 cm_return_val_if_fail (node != NULL, FALSE);
430 clist = GTK_CMCLIST (sctree);
431 ctree = GTK_CMCTREE (sctree);
433 if (!clist->column[ctree->tree_column].visible ||
434 ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
435 return FALSE;
437 tree_row = GTK_CMCTREE_ROW (node);
438 if (!tree_row->children)
439 return FALSE;
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;
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);
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;
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;
478 #endif
479 return (x >= xl && x <= xmax && y >= yu && y <= yu + hotspot_size);
482 gboolean
483 gtk_sctree_is_hot_spot (GtkSCTree *ctree,
484 gint x,
485 gint y)
487 GtkCMCTreeNode *node;
488 gint column;
489 gint row;
491 cm_return_val_if_fail (GTK_IS_SCTREE (ctree), FALSE);
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);
497 return FALSE;
500 /* Our handler for button_press events. We override all of GtkCMCList's broken
501 * behavior.
503 static gint
504 gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
506 GtkSCTree *sctree;
507 GtkCMCList *clist;
508 gboolean on_row;
509 gint row;
510 gint col;
511 gint retval;
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);
517 sctree = GTK_SCTREE (widget);
518 clist = GTK_CMCLIST (widget);
519 retval = FALSE;
521 if (event->window != clist->clist_window)
522 return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
524 on_row = gtk_cmclist_get_selection_info (clist, event->x, event->y, &row, &col);
526 if (on_row && !gtk_widget_has_focus(widget))
527 gtk_widget_grab_focus (widget);
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;
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;
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);
562 } else {
563 gtk_cmclist_unselect_all (clist);
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);
581 retval = TRUE;
584 break;
586 case GDK_2BUTTON_PRESS:
587 if (event->button != 1)
588 break;
590 sctree->dnd_select_pending = FALSE;
591 sctree->dnd_select_pending_state = 0;
593 if (on_row)
594 g_signal_emit (G_OBJECT (sctree),
595 sctree_signals[OPEN_ROW], 0);
597 retval = TRUE;
598 break;
600 default:
601 break;
604 return retval;
607 /* Our handler for button_release events. We override all of GtkCMCList's broken
608 * behavior.
610 static gint
611 gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event)
613 GtkSCTree *sctree;
614 GtkCMCList *clist;
615 gint on_row;
616 gint row, col;
617 gint retval;
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);
623 sctree = GTK_SCTREE (widget);
624 clist = GTK_CMCLIST (widget);
625 retval = FALSE;
627 if (event->window != clist->clist_window)
628 return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
630 on_row = gtk_cmclist_get_selection_info (clist, event->x, event->y, &row, &col);
632 if (!(event->button == 1 || event->button == 2))
633 return FALSE;
635 sctree->dnd_press_button = 0;
636 sctree->dnd_press_x = 0;
637 sctree->dnd_press_y = 0;
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;
646 retval = TRUE;
649 return retval;
652 /* Our handler for motion_notify events. We override all of GtkCMCList's broken
653 * behavior.
655 static gint
656 gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event)
658 GtkSCTree *sctree;
659 GtkCMCList *clist;
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);
665 sctree = GTK_SCTREE (widget);
666 clist = GTK_CMCLIST (widget);
668 if (event->window != clist->clist_window)
669 return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
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;
675 /* This is the same threshold value that is used in gtkdnd.c */
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;
686 /* Handle any pending selections */
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,
693 sctree->dnd_select_pending_state,
694 NULL);
696 sctree->dnd_select_pending = FALSE;
697 sctree->dnd_select_pending_state = 0;
700 g_signal_emit (G_OBJECT (sctree),
701 sctree_signals[START_DRAG],
703 sctree->dnd_press_button,
704 event);
705 return TRUE;
708 /* We override the drag_begin signal to do nothing */
709 static void
710 gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context)
712 /* nothing */
715 /* We override the drag_end signal to do nothing */
716 static void
717 gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context)
719 /* nothing */
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)
727 /* nothing */
730 /* We override the drag_leave signal to do nothing */
731 static void
732 gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time)
734 /* nothing */
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)
742 return FALSE;
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)
750 return FALSE;
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)
759 /* nothing */
762 /* Our handler for the clear signal of the clist. We have to reset the anchor
763 * to null.
765 static void
766 gtk_sctree_clear (GtkCMCList *clist)
768 GtkSCTree *sctree;
770 cm_return_if_fail (clist != NULL);
771 cm_return_if_fail (GTK_IS_SCTREE (clist));
773 sctree = GTK_SCTREE (clist);
774 sctree->anchor_row = NULL;
776 if (((GtkCMCListClass *)parent_class)->clear)
777 (* ((GtkCMCListClass *)parent_class)->clear) (clist);
780 static void
781 gtk_sctree_real_unselect_all (GtkCMCList *clist)
783 GtkSCTree *sctree;
784 gboolean should_freeze = FALSE;
786 cm_return_if_fail (clist != NULL);
787 cm_return_if_fail (GTK_IS_SCTREE (clist));
789 sctree = GTK_SCTREE (clist);
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));
797 if (((GtkCMCListClass *)parent_class)->unselect_all)
798 (* ((GtkCMCListClass *)parent_class)->unselect_all) (clist);
800 if (should_freeze) {
801 gtk_cmclist_thaw (GTK_CMCLIST (sctree));
802 sctree->selecting_range--;
806 static void
807 gtk_sctree_column_auto_resize (GtkCMCList *clist,
808 GtkCMCListRow *clist_row,
809 gint column,
810 gint old_width)
812 /* resize column if needed for auto_resize */
813 GtkRequisition requisition;
815 if (!clist->column[column].auto_resize ||
816 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
817 return;
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;
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)
830 GList *list;
831 GtkRequisition button_req;
832 gint new_width;
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)
838 gtk_widget_get_requisition (clist->column[column].button, &button_req);
839 new_width = (button_req.width -
840 (CELL_SPACING + (2 * COLUMN_INSET)));
842 else
843 new_width = 0;
845 for (list = clist->row_list; list; list = list->next)
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;
853 if (new_width < clist->column[column].width)
854 gtk_cmclist_set_column_width (clist, column, new_width);
858 static void
859 gtk_sctree_auto_resize_columns (GtkCMCList *clist)
861 gint i;
863 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
864 return;
866 for (i = 0; i < clist->columns; i++)
867 gtk_sctree_column_auto_resize (clist, NULL, i, clist->column[i].width);
870 static void
871 gtk_sctree_real_tree_collapse (GtkCMCTree *ctree,
872 GtkCMCTreeNode *node)
874 GtkCMCList *clist;
875 GtkCMCTreeNode *work;
876 GtkRequisition requisition;
877 gboolean visible;
878 gint level;
880 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
882 if (!node || !GTK_CMCTREE_ROW (node)->expanded ||
883 GTK_CMCTREE_ROW (node)->is_leaf)
884 return;
886 clist = GTK_CMCLIST (ctree);
888 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
890 GTK_CMCTREE_ROW (node)->expanded = FALSE;
891 level = GTK_CMCTREE_ROW (node)->level;
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);
900 /* unref/unset opened pixbuf */
901 if (GTK_CMCELL_PIXTEXT
902 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
904 g_object_unref
905 (GTK_CMCELL_PIXTEXT
906 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
908 GTK_CMCELL_PIXTEXT
909 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
912 /* set/ref closed pixbuf */
913 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
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);
920 work = GTK_CMCTREE_ROW (node)->children;
921 if (work)
923 gint tmp = 0;
924 gint row;
925 GList *list;
927 while (work && GTK_CMCTREE_ROW (work)->level > level)
929 work = GTK_CMCTREE_NODE_NEXT (work);
930 tmp++;
933 if (work)
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;
942 else
944 list = (GList *)node;
945 list->next = NULL;
946 clist->row_list_end = (GList *)node;
949 if (visible)
951 /* resize auto_resize columns if needed */
952 gtk_sctree_auto_resize_columns (clist);
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;
959 clist->rows -= tmp;
960 CLIST_REFRESH (clist);
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);
972 GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column,
973 gchar *titles[])
975 GtkWidget *widget;
977 cm_return_val_if_fail (columns > 0, NULL);
978 cm_return_val_if_fail (tree_column >= 0, NULL);
980 if (tree_column >= columns) {
981 g_warning("wrong tree column");
982 tree_column = 0;
983 print_backtrace();
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;
994 for (i = 0; i < columns; i++)
995 gtk_cmclist_set_column_title (clist, i, titles[i]);
996 gtk_cmclist_column_titles_show (clist);
999 GTK_SCTREE(widget)->show_stripes = TRUE;
1000 GTK_SCTREE(widget)->always_expand_recursively = TRUE;
1001 GTK_SCTREE(widget)->force_additive_sel = FALSE;
1003 GTK_SCTREE(widget)->use_markup = g_new0(gboolean, columns);
1005 return widget;
1008 void gtk_sctree_set_use_markup (GtkSCTree *sctree,
1009 int column,
1010 gboolean markup)
1012 gint columns = 0;
1013 GValue value = { 0 };
1015 cm_return_if_fail(GTK_IS_SCTREE(sctree));
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);
1022 cm_return_if_fail(column < columns);
1024 sctree->use_markup[column] = markup;
1027 void gtk_sctree_select (GtkSCTree *sctree, GtkCMCTreeNode *node)
1029 select_row(sctree,
1030 g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)node),
1031 -1, 0, node);
1034 void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCMCTreeNode *node, int state)
1036 select_row(sctree,
1037 g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)node),
1038 -1, state, node);
1041 void gtk_sctree_unselect_all (GtkSCTree *sctree)
1043 gtk_cmclist_unselect_all(GTK_CMCLIST(sctree));
1044 sctree->anchor_row = NULL;
1047 void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCMCTreeNode *node)
1049 sctree->anchor_row = node;
1052 void gtk_sctree_remove_node (GtkSCTree *sctree, GtkCMCTreeNode *node)
1054 if (sctree->anchor_row == node)
1055 sctree->anchor_row = NULL;
1056 gtk_cmctree_remove_node(GTK_CMCTREE(sctree), node);
1059 void gtk_sctree_set_stripes(GtkSCTree *sctree, gboolean show_stripes)
1061 sctree->show_stripes = show_stripes;
1064 void gtk_sctree_set_recursive_expand(GtkSCTree *sctree, gboolean rec_exp)
1066 sctree->always_expand_recursively = rec_exp;
1069 /***********************************************************
1070 * Tree sorting functions *
1071 ***********************************************************/
1073 static void sink(GtkCMCList *clist, GPtrArray *numbers, gint root, gint bottom)
1075 gint j, k ;
1076 GtkCMCTreeNode *temp;
1078 j = 2 * root;
1079 k = j + 1;
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);
1102 static void heap_sort(GtkCMCList *clist, GPtrArray *numbers, gint array_size)
1104 gint i;
1105 GtkCMCTreeNode *temp;
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);
1119 static void
1120 stree_sort (GtkCMCTree *ctree,
1121 GtkCMCTreeNode *node,
1122 gpointer data)
1124 GtkCMCTreeNode *list_start, *work, *next;
1125 GPtrArray *row_array, *viewable_array;
1126 GtkCMCList *clist;
1127 gint i;
1129 clist = GTK_CMCLIST (ctree);
1131 if (node)
1132 work = GTK_CMCTREE_ROW (node)->children;
1133 else
1134 work = GTK_CMCTREE_NODE (clist->row_list);
1136 row_array = g_ptr_array_new();
1137 viewable_array = g_ptr_array_new();
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;
1151 heap_sort( clist, row_array, (row_array->len)-1);
1153 if (node)
1154 list_start = GTK_CMCTREE_ROW (node)->children;
1155 else
1156 list_start = GTK_CMCTREE_NODE (clist->row_list);
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 */
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 */
1174 for (i=0; i<viewable_array->len; i++) {
1175 gtk_cmctree_expand( ctree, g_ptr_array_index( viewable_array, i));
1179 g_ptr_array_free( row_array, TRUE);
1180 g_ptr_array_free( viewable_array, TRUE);
1183 void
1184 gtk_sctree_sort_recursive (GtkCMCTree *ctree,
1185 GtkCMCTreeNode *node)
1187 GtkCMCList *clist;
1188 GtkCMCTreeNode *focus_node = NULL;
1190 cm_return_if_fail (ctree != NULL);
1191 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1193 clist = GTK_CMCLIST (ctree);
1195 gtk_cmclist_freeze (clist);
1197 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1198 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1200 g_list_free (clist->undo_selection);
1201 g_list_free (clist->undo_unselection);
1202 clist->undo_selection = NULL;
1203 clist->undo_unselection = NULL;
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));
1209 GTK_SCTREE(ctree)->sorting = TRUE;
1211 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (stree_sort), NULL);
1213 if (!node)
1214 stree_sort (ctree, NULL, NULL);
1216 GTK_SCTREE(ctree)->sorting = FALSE;
1218 if (focus_node) {
1219 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
1220 clist->undo_anchor = clist->focus_row;
1223 gtk_cmclist_thaw (clist);
1226 void
1227 gtk_sctree_sort_node (GtkCMCTree *ctree,
1228 GtkCMCTreeNode *node)
1230 GtkCMCList *clist;
1231 GtkCMCTreeNode *focus_node = NULL;
1233 cm_return_if_fail (ctree != NULL);
1234 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1236 clist = GTK_CMCLIST (ctree);
1238 gtk_cmclist_freeze (clist);
1240 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1241 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1243 g_list_free (clist->undo_selection);
1244 g_list_free (clist->undo_unselection);
1245 clist->undo_selection = NULL;
1246 clist->undo_unselection = NULL;
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));
1252 GTK_SCTREE(ctree)->sorting = TRUE;
1254 stree_sort (ctree, node, NULL);
1256 GTK_SCTREE(ctree)->sorting = FALSE;
1258 if (focus_node) {
1259 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
1260 clist->undo_anchor = clist->focus_row;
1263 gtk_cmclist_thaw (clist);
1266 /************************************************************************/
1268 static void
1269 gtk_sctree_unlink (GtkCMCTree *ctree,
1270 GtkCMCTreeNode *node,
1271 gboolean update_focus_row)
1273 GtkCMCList *clist;
1274 gint rows;
1275 gint level;
1276 gint visible;
1277 GtkCMCTreeNode *work;
1278 GtkCMCTreeNode *parent;
1279 GList *list;
1281 cm_return_if_fail (ctree != NULL);
1282 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1283 cm_return_if_fail (node != NULL);
1285 clist = GTK_CMCLIST (ctree);
1287 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1288 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1290 g_list_free (clist->undo_selection);
1291 g_list_free (clist->undo_unselection);
1292 clist->undo_selection = NULL;
1293 clist->undo_unselection = NULL;
1296 visible = gtk_cmctree_is_viewable (ctree, node);
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));
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++;
1313 if (visible) {
1314 clist->rows -= (rows + 1);
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;
1327 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
1329 clist->undo_anchor = clist->focus_row;
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);
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;
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;
1352 else {
1353 GtkCMCTreeNode *sibling;
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;
1361 else {
1362 if (clist->row_list == (GList *)node)
1363 clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling);
1364 else {
1365 GtkCMCTreeNode *sibling;
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;
1375 static void
1376 gtk_sctree_link (GtkCMCTree *ctree,
1377 GtkCMCTreeNode *node,
1378 GtkCMCTreeNode *parent,
1379 GtkCMCTreeNode *sibling,
1380 gboolean update_focus_row)
1382 GtkCMCList *clist;
1383 GList *list_end;
1384 GList *list;
1385 GList *work;
1386 gboolean visible = FALSE;
1387 gint rows = 0;
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);
1395 clist = GTK_CMCLIST (ctree);
1397 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1398 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1400 g_list_free (clist->undo_selection);
1401 g_list_free (clist->undo_unselection);
1402 clist->undo_selection = NULL;
1403 clist->undo_unselection = NULL;
1406 for (rows = 1, list_end = (GList *)node; list_end->next;
1407 list_end = list_end->next)
1408 rows++;
1410 GTK_CMCTREE_ROW (node)->parent = parent;
1411 GTK_CMCTREE_ROW (node)->sibling = sibling;
1413 if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) &&
1414 GTK_CMCTREE_ROW (parent)->expanded))) {
1415 visible = TRUE;
1416 clist->rows += rows;
1419 if (parent)
1420 work = (GList *)(GTK_CMCTREE_ROW (parent)->children);
1421 else
1422 work = clist->row_list;
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;
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;
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;
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;
1454 /* find last visible child of sibling */
1455 work = (GList *) gtk_sctree_last_visible (ctree,
1456 GTK_CMCTREE_NODE (work));
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;
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;
1476 list = (GList *)parent;
1477 list->next = (GList *)node;
1479 else
1480 list_end->next = NULL;
1482 else {
1483 clist->row_list = (GList *)node;
1484 list = (GList *)node;
1485 list->prev = NULL;
1486 list_end->next = NULL;
1491 gtk_cmctree_pre_recursive (ctree, node, stree_update_level, NULL);
1493 if (clist->row_list_end == NULL ||
1494 clist->row_list_end->next == (GList *)node)
1495 clist->row_list_end = list_end;
1497 if (visible && update_focus_row) {
1498 gint pos;
1499 pos = g_list_position (clist->row_list, (GList *)node);
1501 if (pos <= clist->focus_row) {
1502 clist->focus_row += rows;
1503 clist->undo_anchor = clist->focus_row;
1508 static void
1509 stree_update_level (GtkCMCTree *ctree,
1510 GtkCMCTreeNode *node,
1511 gpointer data)
1513 if (!node)
1514 return;
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;
1523 static GtkCMCTreeNode *
1524 gtk_sctree_last_visible (GtkCMCTree *ctree,
1525 GtkCMCTreeNode *node)
1527 GtkCMCTreeNode *work;
1529 if (!node)
1530 return NULL;
1532 work = GTK_CMCTREE_ROW (node)->children;
1534 if (!work || !GTK_CMCTREE_ROW (node)->expanded)
1535 return node;
1537 while (GTK_CMCTREE_ROW (work)->sibling)
1538 work = GTK_CMCTREE_ROW (work)->sibling;
1540 return gtk_sctree_last_visible (ctree, work);
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)
1553 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
1555 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
1557 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
1559 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
1562 GTK_CMCTREE_ROW (node)->pixbuf_opened = NULL;
1563 GTK_CMCTREE_ROW (node)->pixbuf_closed = NULL;
1565 if (pixbuf_closed)
1567 GTK_CMCTREE_ROW (node)->pixbuf_closed = g_object_ref (pixbuf_closed);
1569 if (pixbuf_opened)
1571 GTK_CMCTREE_ROW (node)->pixbuf_opened = g_object_ref (pixbuf_opened);
1574 GTK_CMCTREE_ROW (node)->is_leaf = is_leaf;
1575 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
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);
1585 static GtkCMCTreeRow *
1586 srow_new (GtkCMCTree *ctree)
1588 GtkCMCList *clist;
1589 GtkCMCTreeRow *ctree_row;
1590 int i;
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++)
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;
1603 GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
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;
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;
1621 return ctree_row;
1624 static void
1625 srow_delete (GtkCMCTree *ctree,
1626 GtkCMCTreeRow *ctree_row)
1628 GtkCMCList *clist;
1629 gint i;
1631 clist = GTK_CMCLIST (ctree);
1633 for (i = 0; i < clist->columns; i++)
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)
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);
1645 if (ctree_row->row.style)
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);
1652 if (ctree_row->pixbuf_closed)
1654 g_object_unref (ctree_row->pixbuf_closed);
1657 if (ctree_row->pixbuf_opened)
1659 g_object_unref (ctree_row->pixbuf_opened);
1662 if (ctree_row->row.destroy)
1664 GDestroyNotify dnotify = ctree_row->row.destroy;
1665 gpointer ddata = ctree_row->row.data;
1667 ctree_row->row.destroy = NULL;
1668 ctree_row->row.data = NULL;
1670 dnotify (ddata);
1673 g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell);
1674 g_slice_free (GtkCMCTreeRow, ctree_row);
1677 static void
1678 stree_delete_row (GtkCMCTree *ctree,
1679 GtkCMCTreeNode *node,
1680 gpointer data)
1682 srow_delete (ctree, GTK_CMCTREE_ROW (node));
1683 g_list_free_1 ((GList *)node);
1686 static void
1687 gtk_sctree_real_tree_expand (GtkCMCTree *ctree,
1688 GtkCMCTreeNode *node)
1690 GtkCMCList *clist;
1691 GtkCMCTreeNode *work;
1692 GtkRequisition requisition;
1693 gboolean visible;
1695 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1697 if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf)
1698 return;
1700 clist = GTK_CMCLIST (ctree);
1702 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1704 GTK_CMCTREE_ROW (node)->expanded = TRUE;
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);
1713 /* unref/unset closed pixbuf */
1714 if (GTK_CMCELL_PIXTEXT
1715 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
1717 g_object_unref
1718 (GTK_CMCELL_PIXTEXT
1719 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
1721 GTK_CMCELL_PIXTEXT
1722 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
1725 /* set/ref opened pixbuf */
1726 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
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);
1734 work = GTK_CMCTREE_ROW (node)->children;
1735 if (work)
1737 GList *list = (GList *)work;
1738 gint *cell_width = NULL;
1739 gint tmp = 0;
1740 gint row;
1741 gint i;
1743 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
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;
1749 while (work)
1751 /* search maximum cell widths of auto_resize columns */
1752 for (i = 0; i < clist->columns; i++)
1753 if (clist->column[i].auto_resize)
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]);
1760 list = (GList *)work;
1761 work = GTK_CMCTREE_NODE_NEXT (work);
1762 tmp++;
1765 else
1766 while (work)
1768 list = (GList *)work;
1769 work = GTK_CMCTREE_NODE_NEXT (work);
1770 tmp++;
1773 list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node);
1775 if (GTK_CMCTREE_NODE_NEXT (node))
1777 GList *tmp_list;
1779 if (clist->row_list_end == list)
1780 clist->row_list_end = g_list_last(list);
1782 tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node);
1783 tmp_list->prev = list;
1785 else
1786 clist->row_list_end = list;
1788 list = (GList *)node;
1789 list->next = (GList *)(GTK_CMCTREE_ROW (node)->children);
1791 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
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);
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;
1806 clist->rows += tmp;
1807 CLIST_REFRESH (clist);
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);
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)
1828 GtkCMCList *clist;
1829 GtkCMCTreeRow *new_row;
1830 GtkCMCTreeNode *node;
1831 GList *list;
1832 gint i;
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);
1838 if (parent && GTK_CMCTREE_ROW (parent)->is_leaf)
1839 return NULL;
1841 clist = GTK_CMCLIST (ctree);
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);
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);
1855 sset_node_info (ctree, node, text ?
1856 text[ctree->tree_column] : NULL, spacing, pixbuf_closed,
1857 pixbuf_opened, is_leaf, expanded);
1859 /* sorted insertion */
1860 if (GTK_CMCLIST_AUTO_SORT (clist))
1862 if (parent)
1863 sibling = GTK_CMCTREE_ROW (parent)->children;
1864 else
1865 sibling = GTK_CMCTREE_NODE (clist->row_list);
1867 while (sibling && clist->compare
1868 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0)
1869 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1872 gtk_sctree_link (ctree, node, parent, sibling, FALSE);
1874 if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
1875 gtk_cmctree_is_viewable (ctree, node))
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);
1882 if (clist->rows == 1)
1884 clist->focus_row = 0;
1885 if (clist->selection_mode == GTK_SELECTION_BROWSE)
1886 gtk_sctree_select (GTK_SCTREE(ctree), node);
1890 CLIST_REFRESH (clist);
1892 return node;
1895 GtkCMCTreeNode *
1896 gtk_sctree_insert_gnode (GtkCMCTree *ctree,
1897 GtkCMCTreeNode *parent,
1898 GtkCMCTreeNode *sibling,
1899 GNode *gnode,
1900 GtkCMCTreeGNodeFunc func,
1901 gpointer data)
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;
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);
1917 clist = GTK_CMCLIST (ctree);
1919 if (parent)
1920 depth = GTK_CMCTREE_ROW (parent)->level + 1;
1922 list = g_list_alloc ();
1923 list->data = srow_new (ctree);
1924 cnode = GTK_CMCTREE_NODE (list);
1926 gtk_cmclist_freeze (clist);
1928 sset_node_info (ctree, cnode, "", 0, NULL, NULL, TRUE, FALSE);
1930 if (!func (ctree, depth, gnode, cnode, data))
1932 stree_delete_row (ctree, cnode, NULL);
1933 gtk_cmclist_thaw (clist);
1934 return NULL;
1937 if (GTK_CMCLIST_AUTO_SORT (clist))
1939 if (parent)
1940 sibling = GTK_CMCTREE_ROW (parent)->children;
1941 else
1942 sibling = GTK_CMCTREE_NODE (clist->row_list);
1944 while (sibling && clist->compare
1945 (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0)
1946 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1949 gtk_sctree_link (ctree, cnode, parent, sibling, FALSE);
1951 for (work = g_node_last_child (gnode); work; work = work->prev)
1953 new_child = gtk_sctree_insert_gnode (ctree, cnode, child,
1954 work, func, data);
1955 if (new_child)
1956 child = new_child;
1959 gtk_cmclist_thaw (clist);
1961 return cnode;
1964 static void
1965 sreal_tree_move (GtkCMCTree *ctree,
1966 GtkCMCTreeNode *node,
1967 GtkCMCTreeNode *new_parent,
1968 GtkCMCTreeNode *new_sibling)
1970 GtkCMCList *clist;
1971 GtkCMCTreeNode *work;
1972 gboolean visible = FALSE;
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);
1979 if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf)
1980 return;
1982 /* new_parent != child of child */
1983 for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent)
1984 if (work == node)
1985 return;
1987 clist = GTK_CMCLIST (ctree);
1989 visible = gtk_cmctree_is_viewable (ctree, node);
1991 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
1993 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1995 g_list_free (clist->undo_selection);
1996 g_list_free (clist->undo_unselection);
1997 clist->undo_selection = NULL;
1998 clist->undo_unselection = NULL;
2001 if (GTK_CMCLIST_AUTO_SORT (clist))
2003 if (new_parent == GTK_CMCTREE_ROW (node)->parent)
2004 return;
2006 if (new_parent)
2007 new_sibling = GTK_CMCTREE_ROW (new_parent)->children;
2008 else
2009 new_sibling = GTK_CMCTREE_NODE (clist->row_list);
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;
2016 if (new_parent == GTK_CMCTREE_ROW (node)->parent &&
2017 new_sibling == GTK_CMCTREE_ROW (node)->sibling)
2018 return;
2020 gtk_cmclist_freeze (clist);
2022 work = NULL;
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));
2027 gtk_sctree_unlink (ctree, node, FALSE);
2028 gtk_sctree_link (ctree, node, new_parent, new_sibling, FALSE);
2030 if (!GTK_SCTREE(ctree)->sorting && work)
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;
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));
2045 gtk_cmclist_thaw (clist);
2048 void gtk_sctree_set_column_tooltip (GtkSCTree *sctree,
2049 int column,
2050 const gchar *tip)
2052 CLAWS_SET_TIP(GTK_CMCLIST(sctree)->column[column].button,
2053 tip);