2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
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/>.
31 #include "gtksctree.h"
32 #include "claws-marshal.h"
33 #include "prefs_common.h"
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)); \
42 #define CELL_SPACING 1
43 #define CLIST_OPTIMUM_SIZE 64
44 #define COLUMN_INSET 3
46 #define TAB_SIZE (PM_SIZE + 6)
47 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
48 (((row) + 1) * CELL_SPACING) + \
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 \
54 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
64 static void gtk_sctree_class_init (GtkSCTreeClass *class);
65 static void gtk_sctree_init (GtkSCTree *sctree);
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);
83 static void gtk_sctree_clear (GtkCMCList *clist);
84 static void gtk_sctree_real_unselect_all (GtkCMCList *clist);
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);
90 static void gtk_sctree_link (GtkCMCTree *ctree,
92 GtkCMCTreeNode *parent,
93 GtkCMCTreeNode *sibling,
94 gboolean update_focus_row);
96 static void gtk_sctree_unlink (GtkCMCTree *ctree,
98 gboolean update_focus_row);
100 static void stree_update_level (GtkCMCTree *ctree,
101 GtkCMCTreeNode *node,
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);
111 sreal_tree_move (GtkCMCTree *ctree,
112 GtkCMCTreeNode *node,
113 GtkCMCTreeNode *new_parent,
114 GtkCMCTreeNode *new_sibling);
116 static GtkCMCTreeClass *parent_class;
118 static guint sctree_signals[LAST_SIGNAL];
121 * gtk_sctree_get_type:
124 * Creates the GtkSCTree class and its type information
126 * Return value: The type ID for GtkSCTreeClass
129 gtk_sctree_get_type (void)
131 static GType sctree_type = 0;
134 GTypeInfo sctree_info = {
135 sizeof (GtkSCTreeClass),
137 (GBaseInitFunc) NULL,
138 (GBaseFinalizeFunc) NULL,
140 (GClassInitFunc) gtk_sctree_class_init,
141 (GClassFinalizeFunc) NULL,
142 NULL, /* class_data */
146 (GInstanceInitFunc) gtk_sctree_init,
148 (const GTypeValueTable *) NULL /* value table */
151 sctree_type = g_type_register_static (GTK_TYPE_CMCTREE, "GtkSCTree", &sctree_info, (GTypeFlags)0);
158 gtk_sctree_change_focus_row_expansion (GtkCMCTree *ctree,
159 GtkCMCTreeExpansionType action)
162 GtkCMCTreeNode *node;
164 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
166 clist = GTK_CMCLIST (ctree);
168 if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (ctree))) &&
169 gtk_widget_has_grab (GTK_WIDGET(ctree)))
173 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) ||
174 GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children))
179 case GTK_CMCTREE_EXPANSION_EXPAND:
180 if (GTK_SCTREE(ctree)->always_expand_recursively)
181 gtk_cmctree_expand_recursive (ctree, node);
183 gtk_cmctree_expand (ctree, node);
186 case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE:
187 gtk_cmctree_expand_recursive (ctree, node);
189 case GTK_CMCTREE_EXPANSION_COLLAPSE:
190 gtk_cmctree_collapse (ctree, node);
192 case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE:
193 gtk_cmctree_collapse_recursive (ctree, node);
195 case GTK_CMCTREE_EXPANSION_TOGGLE:
196 if (GTK_SCTREE(ctree)->always_expand_recursively)
197 gtk_cmctree_toggle_expansion_recursive (ctree, node);
199 gtk_cmctree_toggle_expansion (ctree, node);
201 case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE:
202 gtk_cmctree_toggle_expansion_recursive (ctree, node);
207 static void gtk_sctree_finalize(GObject *object)
209 GtkSCTree *sctree = GTK_SCTREE(object);
210 g_free(sctree->use_markup);
211 sctree->use_markup = NULL;
212 G_OBJECT_CLASS (parent_class)->finalize (object);
215 /* Standard class initialization function */
217 gtk_sctree_class_init (GtkSCTreeClass *klass)
219 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
220 GtkWidgetClass *widget_class;
221 GtkCMCListClass *clist_class;
222 GtkCMCTreeClass *ctree_class;
224 widget_class = (GtkWidgetClass *) klass;
225 clist_class = (GtkCMCListClass *) klass;
226 ctree_class = (GtkCMCTreeClass *) klass;
228 parent_class = g_type_class_peek (gtk_cmctree_get_type ());
230 sctree_signals[ROW_POPUP_MENU] =
231 g_signal_new ("row_popup_menu",
232 G_TYPE_FROM_CLASS (klass),
234 G_STRUCT_OFFSET (GtkSCTreeClass, row_popup_menu),
236 claws_marshal_VOID__POINTER,
239 sctree_signals[EMPTY_POPUP_MENU] =
240 g_signal_new ("empty_popup_menu",
241 G_TYPE_FROM_CLASS (klass),
243 G_STRUCT_OFFSET (GtkSCTreeClass, empty_popup_menu),
245 claws_marshal_VOID__POINTER,
248 sctree_signals[OPEN_ROW] =
249 g_signal_new ("open_row",
250 G_TYPE_FROM_CLASS (klass),
252 G_STRUCT_OFFSET (GtkSCTreeClass, open_row),
254 g_cclosure_marshal_VOID__VOID,
256 sctree_signals[START_DRAG] =
257 g_signal_new ("start_drag",
258 G_TYPE_FROM_CLASS (klass),
260 G_STRUCT_OFFSET (GtkSCTreeClass, start_drag),
262 claws_marshal_VOID__INT_POINTER,
267 /* gtk_object_class_add_signals (object_class, sctree_signals, LAST_SIGNAL); */
269 clist_class->clear = gtk_sctree_clear;
270 clist_class->unselect_all = gtk_sctree_real_unselect_all;
271 ctree_class->tree_collapse = gtk_sctree_real_tree_collapse;
272 ctree_class->tree_expand = gtk_sctree_real_tree_expand;
273 ctree_class->tree_move = sreal_tree_move;
274 ctree_class->change_focus_row_expansion = gtk_sctree_change_focus_row_expansion;
276 widget_class->button_press_event = gtk_sctree_button_press;
277 widget_class->button_release_event = gtk_sctree_button_release;
278 widget_class->motion_notify_event = gtk_sctree_motion;
279 widget_class->drag_begin = gtk_sctree_drag_begin;
280 widget_class->drag_end = gtk_sctree_drag_end;
281 widget_class->drag_data_get = gtk_sctree_drag_data_get;
282 widget_class->drag_leave = gtk_sctree_drag_leave;
283 widget_class->drag_motion = gtk_sctree_drag_motion;
284 widget_class->drag_drop = gtk_sctree_drag_drop;
285 widget_class->drag_data_received = gtk_sctree_drag_data_received;
287 gobject_class->finalize = gtk_sctree_finalize;
290 /* Standard object initialization function */
292 gtk_sctree_init (GtkSCTree *sctree)
294 sctree->anchor_row = NULL;
296 /* GtkCMCTree does not specify pointer motion by default */
297 gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
298 gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK);
301 /* Get information the specified row is selected. */
304 row_is_selected(GtkSCTree *sctree, gint row)
306 GtkCMCListRow *clist_row;
307 clist_row = g_list_nth (GTK_CMCLIST(sctree)->row_list, row)->data;
308 return clist_row ? clist_row->state == GTK_STATE_SELECTED : FALSE;
311 /* Selects the rows between the anchor to the specified row, inclusive. */
313 select_range (GtkSCTree *sctree, gint row)
319 if (sctree->anchor_row == NULL) {
321 sctree->anchor_row = gtk_cmctree_node_nth(GTK_CMCTREE(sctree), row);
323 prev_row = g_list_position(GTK_CMCLIST(sctree)->row_list,
324 (GList *)sctree->anchor_row);
326 if (row < prev_row) {
329 GTK_CMCLIST(sctree)->focus_row = min;
334 sctree->selecting_range++;
343 gtk_cmclist_freeze(GTK_CMCLIST(sctree));
345 node = g_list_nth((GTK_CMCLIST(sctree))->row_list, min);
346 for (i = min; i < max; i++) {
347 if (node && GTK_CMCTREE_ROW (node)->row.selectable) {
348 g_signal_emit_by_name(G_OBJECT(sctree), "tree_select_row",
354 gtk_cmclist_thaw(GTK_CMCLIST(sctree));
357 sctree->selecting_range--;
358 gtk_cmclist_select_row (GTK_CMCLIST (sctree), max, -1);
361 /* Handles row selection according to the specified modifier state */
362 /* in certain cases, we arrive here from a function knowing the GtkCMCTreeNode, and having
363 * already slowly found row using g_list_position. In which case, _node will be non-NULL
364 * to avoid this function having to slowly find it with g_list_nth. */
366 select_row (GtkSCTree *sctree, gint row, gint col, guint state, GtkCMCTreeNode *_node)
368 gboolean range, additive;
369 cm_return_if_fail (sctree != NULL);
370 cm_return_if_fail (GTK_IS_SCTREE (sctree));
372 range = ((state & GDK_SHIFT_MASK) != 0) &&
373 (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
374 (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
375 additive = ((state & GDK_CONTROL_MASK) != 0) &&
376 (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
377 (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
379 if (!range && !additive && sctree->force_additive_sel)
382 GTK_CMCLIST(sctree)->focus_row = row;
385 gtk_cmclist_unselect_all (GTK_CMCLIST (sctree));
389 GtkCMCTreeNode *node;
391 node = _node ? _node : gtk_cmctree_node_nth (GTK_CMCTREE(sctree), row);
393 /*No need to manage overlapped list*/
395 if (row_is_selected(sctree, row))
396 gtk_cmclist_unselect_row (GTK_CMCLIST (sctree), row, col);
398 g_signal_emit_by_name
400 "tree_select_row", node, col);
402 g_signal_emit_by_name
404 "tree_select_row", node, col);
406 sctree->anchor_row = node;
408 select_range (sctree, row);
412 sctree_is_hot_spot (GtkSCTree *sctree,
413 GtkCMCTreeNode *node,
418 GtkCMCTreeRow *tree_row;
425 cm_return_val_if_fail (GTK_IS_SCTREE (sctree), FALSE);
426 cm_return_val_if_fail (node != NULL, FALSE);
428 clist = GTK_CMCLIST (sctree);
429 ctree = GTK_CMCTREE (sctree);
431 if (!clist->column[ctree->tree_column].visible ||
432 ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE)
435 tree_row = GTK_CMCTREE_ROW (node);
436 if (!tree_row->children)
439 hotspot_size = clist->row_height-2;
440 if (hotspot_size > clist->column[ctree->tree_column].area.width - 2)
441 hotspot_size = clist->column[ctree->tree_column].area.width - 2;
443 if (!GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist)))
444 yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - hotspot_size) / 2 -
445 (clist->row_height - 1) % 2);
447 yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height/2 - hotspot_size) / 2 -
448 (clist->row_height/2 - 1) % 2);
451 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
452 xl = clist->column[ctree->tree_column].area.x +
453 clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
454 (tree_row->level - 1) * ctree->tree_indent - hotspot_size;
456 xl = clist->column[ctree->tree_column].area.x + clist->hoffset +
457 (tree_row->level - 1) * ctree->tree_indent;
459 xmax = xl + hotspot_size;
461 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT) {
462 xl = clist->column[ctree->tree_column].area.x +
463 clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
464 (tree_row->level - 1) * ctree->tree_indent - hotspot_size;
465 xmax = xl + hotspot_size;
466 } else if (ctree->tree_column == 0) {
467 xl = clist->column[ctree->tree_column].area.x + clist->hoffset;
468 xmax = clist->column[ctree->tree_column].area.x + clist->hoffset +
469 (tree_row->level - 1) * ctree->tree_indent +
472 xl = clist->column[ctree->tree_column].area.x + clist->hoffset +
473 (tree_row->level - 1) * ctree->tree_indent;
474 xmax = xl + hotspot_size;
477 return (x >= xl && x <= xmax && y >= yu && y <= yu + hotspot_size);
481 gtk_sctree_is_hot_spot (GtkSCTree *ctree,
485 GtkCMCTreeNode *node;
489 cm_return_val_if_fail (GTK_IS_SCTREE (ctree), FALSE);
491 if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column))
492 if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row))))
493 return sctree_is_hot_spot (ctree, node, row, x, y);
498 /* Our handler for button_press events. We override all of GtkCMCList's broken
502 gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event)
511 cm_return_val_if_fail (widget != NULL, FALSE);
512 cm_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
513 cm_return_val_if_fail (event != NULL, FALSE);
515 sctree = GTK_SCTREE (widget);
516 clist = GTK_CMCLIST (widget);
519 if (event->window != clist->clist_window)
520 return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
522 on_row = gtk_cmclist_get_selection_info (clist, event->x, event->y, &row, &col);
524 if (on_row && !gtk_widget_has_focus(widget))
525 gtk_widget_grab_focus (widget);
527 if (gtk_sctree_is_hot_spot (GTK_SCTREE(sctree), event->x, event->y)) {
528 GtkCMCTreeNode *node = gtk_cmctree_node_nth(GTK_CMCTREE(sctree), row);
529 if (GTK_CMCTREE_ROW (node)->expanded)
530 gtk_cmctree_collapse(GTK_CMCTREE(sctree), node);
531 else if (GTK_SCTREE(sctree)->always_expand_recursively)
532 gtk_cmctree_expand_recursive (GTK_CMCTREE(sctree), node);
534 gtk_cmctree_expand(GTK_CMCTREE(sctree), node);
538 switch (event->type) {
539 case GDK_BUTTON_PRESS:
540 if (event->button == 1 || event->button == 2) {
541 if (event->button == 2)
542 event->state &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK);
544 /* Save the mouse info for DnD */
545 sctree->dnd_press_button = event->button;
546 sctree->dnd_press_x = event->x;
547 sctree->dnd_press_y = event->y;
549 /* Handle selection */
550 if ((row_is_selected (sctree, row)
551 && !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
552 || ((event->state & GDK_CONTROL_MASK)
553 && !(event->state & GDK_SHIFT_MASK))) {
554 sctree->dnd_select_pending = TRUE;
555 sctree->dnd_select_pending_state = event->state;
556 sctree->dnd_select_pending_row = row;
558 select_row (sctree, row, col, event->state, NULL);
561 gtk_cmclist_unselect_all (clist);
565 } else if (event->button == 3) {
566 /* Emit *_popup_menu signal*/
568 if (!row_is_selected(sctree,row))
569 select_row (sctree, row, col, 0, NULL);
570 g_signal_emit (G_OBJECT (sctree),
571 sctree_signals[ROW_POPUP_MENU],
574 gtk_cmclist_unselect_all(clist);
575 g_signal_emit (G_OBJECT (sctree),
576 sctree_signals[EMPTY_POPUP_MENU],
584 case GDK_2BUTTON_PRESS:
585 if (event->button != 1)
588 sctree->dnd_select_pending = FALSE;
589 sctree->dnd_select_pending_state = 0;
592 g_signal_emit (G_OBJECT (sctree),
593 sctree_signals[OPEN_ROW], 0);
605 /* Our handler for button_release events. We override all of GtkCMCList's broken
609 gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event)
617 cm_return_val_if_fail (widget != NULL, FALSE);
618 cm_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
619 cm_return_val_if_fail (event != NULL, FALSE);
621 sctree = GTK_SCTREE (widget);
622 clist = GTK_CMCLIST (widget);
625 if (event->window != clist->clist_window)
626 return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
628 on_row = gtk_cmclist_get_selection_info (clist, event->x, event->y, &row, &col);
630 if (!(event->button == 1 || event->button == 2))
633 sctree->dnd_press_button = 0;
634 sctree->dnd_press_x = 0;
635 sctree->dnd_press_y = 0;
638 if (sctree->dnd_select_pending) {
639 select_row (sctree, row, col, sctree->dnd_select_pending_state, NULL);
640 sctree->dnd_select_pending = FALSE;
641 sctree->dnd_select_pending_state = 0;
650 /* Our handler for motion_notify events. We override all of GtkCMCList's broken
654 gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event)
659 cm_return_val_if_fail (widget != NULL, FALSE);
660 cm_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE);
661 cm_return_val_if_fail (event != NULL, FALSE);
663 sctree = GTK_SCTREE (widget);
664 clist = GTK_CMCLIST (widget);
666 if (event->window != clist->clist_window)
667 return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
669 if (!((sctree->dnd_press_button == 1 && (event->state & GDK_BUTTON1_MASK))
670 || (sctree->dnd_press_button == 2 && (event->state & GDK_BUTTON2_MASK))))
673 /* This is the same threshold value that is used in gtkdnd.c */
680 if (MAX (ABS (sctree->dnd_press_x - event->x),
681 ABS (sctree->dnd_press_y - event->y)) <= THRESHOLD)
684 /* Handle any pending selections */
686 if (sctree->dnd_select_pending) {
687 if (!row_is_selected(sctree,sctree->dnd_select_pending_row))
689 sctree->dnd_select_pending_row,
691 sctree->dnd_select_pending_state,
694 sctree->dnd_select_pending = FALSE;
695 sctree->dnd_select_pending_state = 0;
698 g_signal_emit (G_OBJECT (sctree),
699 sctree_signals[START_DRAG],
701 sctree->dnd_press_button,
706 /* We override the drag_begin signal to do nothing */
708 gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context)
713 /* We override the drag_end signal to do nothing */
715 gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context)
720 /* We override the drag_data_get signal to do nothing */
722 gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context,
723 GtkSelectionData *data, guint info, guint time)
728 /* We override the drag_leave signal to do nothing */
730 gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time)
735 /* We override the drag_motion signal to do nothing */
737 gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context,
738 gint x, gint y, guint time)
743 /* We override the drag_drop signal to do nothing */
745 gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context,
746 gint x, gint y, guint time)
751 /* We override the drag_data_received signal to do nothing */
753 gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context,
754 gint x, gint y, GtkSelectionData *data,
755 guint info, guint time)
760 /* Our handler for the clear signal of the clist. We have to reset the anchor
764 gtk_sctree_clear (GtkCMCList *clist)
768 cm_return_if_fail (clist != NULL);
769 cm_return_if_fail (GTK_IS_SCTREE (clist));
771 sctree = GTK_SCTREE (clist);
772 sctree->anchor_row = NULL;
774 if (((GtkCMCListClass *)parent_class)->clear)
775 (* ((GtkCMCListClass *)parent_class)->clear) (clist);
779 gtk_sctree_real_unselect_all (GtkCMCList *clist)
782 gboolean should_freeze = FALSE;
784 cm_return_if_fail (clist != NULL);
785 cm_return_if_fail (GTK_IS_SCTREE (clist));
787 sctree = GTK_SCTREE (clist);
789 if (sc_g_list_bigger(GTK_CMCLIST(sctree)->selection, 10)) {
790 should_freeze = TRUE;
791 sctree->selecting_range++;
792 gtk_cmclist_freeze (GTK_CMCLIST (sctree));
795 if (((GtkCMCListClass *)parent_class)->unselect_all)
796 (* ((GtkCMCListClass *)parent_class)->unselect_all) (clist);
799 gtk_cmclist_thaw (GTK_CMCLIST (sctree));
800 sctree->selecting_range--;
805 gtk_sctree_column_auto_resize (GtkCMCList *clist,
806 GtkCMCListRow *clist_row,
810 /* resize column if needed for auto_resize */
811 GtkRequisition requisition;
813 if (!clist->column[column].auto_resize ||
814 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
818 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
819 column, &requisition);
821 requisition.width = 0;
823 if (requisition.width > clist->column[column].width)
824 gtk_cmclist_set_column_width (clist, column, requisition.width);
825 else if (requisition.width < old_width &&
826 old_width == clist->column[column].width)
829 GtkRequisition button_req;
832 /* run a "gtk_cmclist_optimal_column_width" but break, if
833 * the column doesn't shrink */
834 if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button)
836 gtk_widget_get_requisition (clist->column[column].button, &button_req);
837 new_width = (button_req.width -
838 (CELL_SPACING + (2 * COLUMN_INSET)));
843 for (list = clist->row_list; list; list = list->next)
845 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
846 (clist, GTK_CMCLIST_ROW (list), column, &requisition);
847 new_width = MAX (new_width, requisition.width);
848 if (new_width == clist->column[column].width)
851 if (new_width < clist->column[column].width)
852 gtk_cmclist_set_column_width (clist, column, new_width);
857 gtk_sctree_auto_resize_columns (GtkCMCList *clist)
861 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
864 for (i = 0; i < clist->columns; i++)
865 gtk_sctree_column_auto_resize (clist, NULL, i, clist->column[i].width);
869 gtk_sctree_real_tree_collapse (GtkCMCTree *ctree,
870 GtkCMCTreeNode *node)
873 GtkCMCTreeNode *work;
874 GtkRequisition requisition;
878 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
880 if (!node || !GTK_CMCTREE_ROW (node)->expanded ||
881 GTK_CMCTREE_ROW (node)->is_leaf)
884 clist = GTK_CMCLIST (ctree);
886 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
888 GTK_CMCTREE_ROW (node)->expanded = FALSE;
889 level = GTK_CMCTREE_ROW (node)->level;
891 visible = gtk_cmctree_is_viewable (ctree, node);
892 /* get cell width if tree_column is auto resized */
893 if (visible && clist->column[ctree->tree_column].auto_resize &&
894 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
895 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
896 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
898 /* unref/unset opened pixbuf */
899 if (GTK_CMCELL_PIXTEXT
900 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
904 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
907 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
910 /* set/ref closed pixbuf */
911 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
914 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf =
915 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
918 work = GTK_CMCTREE_ROW (node)->children;
925 while (work && GTK_CMCTREE_ROW (work)->level > level)
927 work = GTK_CMCTREE_NODE_NEXT (work);
933 list = (GList *)node;
934 list->next = (GList *)work;
935 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
937 list = (GList *)work;
938 list->prev = (GList *)node;
942 list = (GList *)node;
944 clist->row_list_end = (GList *)node;
949 /* resize auto_resize columns if needed */
950 gtk_sctree_auto_resize_columns (clist);
952 if (!GTK_SCTREE(clist)->sorting) {
953 row = g_list_position (clist->row_list, (GList *)node);
954 if (row < clist->focus_row)
955 clist->focus_row -= tmp;
958 CLIST_REFRESH (clist);
961 else if (visible && clist->column[ctree->tree_column].auto_resize &&
962 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
963 /* resize tree_column if needed */
964 gtk_sctree_column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
970 GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column,
975 cm_return_val_if_fail (columns > 0, NULL);
976 cm_return_val_if_fail (tree_column >= 0, NULL);
978 if (tree_column >= columns) {
979 g_warning("Wrong tree column");
984 widget = gtk_widget_new (TYPE_GTK_SCTREE,
985 "n_columns", columns,
986 "tree_column", tree_column,
989 GtkCMCList *clist = GTK_CMCLIST (widget);
992 for (i = 0; i < columns; i++)
993 gtk_cmclist_set_column_title (clist, i, titles[i]);
994 gtk_cmclist_column_titles_show (clist);
997 GTK_SCTREE(widget)->show_stripes = TRUE;
998 GTK_SCTREE(widget)->always_expand_recursively = TRUE;
999 GTK_SCTREE(widget)->force_additive_sel = FALSE;
1001 GTK_SCTREE(widget)->use_markup = g_new0(gboolean, columns);
1006 void gtk_sctree_set_use_markup (GtkSCTree *sctree,
1011 GValue value = { 0 };
1013 cm_return_if_fail(GTK_IS_SCTREE(sctree));
1015 g_value_init (&value, G_TYPE_INT);
1016 g_object_get_property (G_OBJECT (sctree), "n-columns", &value);
1017 columns = g_value_get_int (&value);
1018 g_value_unset (&value);
1020 cm_return_if_fail(column < columns);
1022 sctree->use_markup[column] = markup;
1025 void gtk_sctree_select (GtkSCTree *sctree, GtkCMCTreeNode *node)
1028 g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)node),
1032 void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCMCTreeNode *node, int state)
1035 g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)node),
1039 void gtk_sctree_unselect_all (GtkSCTree *sctree)
1041 gtk_cmclist_unselect_all(GTK_CMCLIST(sctree));
1042 sctree->anchor_row = NULL;
1045 void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCMCTreeNode *node)
1047 sctree->anchor_row = node;
1050 void gtk_sctree_remove_node (GtkSCTree *sctree, GtkCMCTreeNode *node)
1052 if (sctree->anchor_row == node)
1053 sctree->anchor_row = NULL;
1054 gtk_cmctree_remove_node(GTK_CMCTREE(sctree), node);
1057 void gtk_sctree_set_stripes(GtkSCTree *sctree, gboolean show_stripes)
1059 sctree->show_stripes = show_stripes;
1062 void gtk_sctree_set_recursive_expand(GtkSCTree *sctree, gboolean rec_exp)
1064 sctree->always_expand_recursively = rec_exp;
1067 /***********************************************************
1068 * Tree sorting functions *
1069 ***********************************************************/
1071 static void sink(GtkCMCList *clist, GPtrArray *numbers, gint root, gint bottom)
1074 GtkCMCTreeNode *temp;
1079 /* find the maximum element of numbers[root],
1080 numbers[2*root] and numbers[2*root+1] */
1082 if (clist->compare( clist, GTK_CMCTREE_ROW (g_ptr_array_index(numbers, root)),
1083 GTK_CMCTREE_ROW(g_ptr_array_index( numbers, j))) >= 0)
1086 if (clist->compare( clist, GTK_CMCTREE_ROW (g_ptr_array_index(numbers, k)),
1087 GTK_CMCTREE_ROW (g_ptr_array_index( numbers, j))) > 0)
1089 /* if numbers[root] wasn't the maximum element then
1092 temp = g_ptr_array_index( numbers,root);
1093 g_ptr_array_index( numbers, root) = g_ptr_array_index( numbers, j);
1094 g_ptr_array_index( numbers, j) = temp;
1095 sink( clist, numbers, j, bottom);
1100 static void heap_sort(GtkCMCList *clist, GPtrArray *numbers, gint array_size)
1103 GtkCMCTreeNode *temp;
1105 /* build the Heap */
1106 for (i = (array_size / 2); i >= 1; i--)
1107 sink( clist, numbers, i, array_size);
1108 /* output the Heap */
1109 for (i = array_size; i >= 2; i--) {
1110 temp = g_ptr_array_index( numbers, 1);
1111 g_ptr_array_index( numbers, 1) = g_ptr_array_index( numbers, i);
1112 g_ptr_array_index( numbers, i) = temp;
1113 sink( clist, numbers, 1, i-1);
1118 stree_sort (GtkCMCTree *ctree,
1119 GtkCMCTreeNode *node,
1122 GtkCMCTreeNode *list_start, *work, *next;
1123 GPtrArray *row_array, *viewable_array;
1127 clist = GTK_CMCLIST (ctree);
1130 work = GTK_CMCTREE_ROW (node)->children;
1132 work = GTK_CMCTREE_NODE (clist->row_list);
1134 row_array = g_ptr_array_new();
1135 viewable_array = g_ptr_array_new();
1138 g_ptr_array_add( row_array, NULL);
1140 /* add all rows to row_array */
1141 g_ptr_array_add( row_array, work);
1142 if (GTK_CMCTREE_ROW (work)->parent && gtk_cmctree_is_viewable( ctree, work))
1143 g_ptr_array_add( viewable_array, GTK_CMCTREE_ROW (work)->parent);
1144 next = GTK_CMCTREE_ROW (work)->sibling;
1145 gtk_sctree_unlink( ctree, work, FALSE);
1149 heap_sort( clist, row_array, (row_array->len)-1);
1152 list_start = GTK_CMCTREE_ROW (node)->children;
1154 list_start = GTK_CMCTREE_NODE (clist->row_list);
1156 if (clist->sort_type == GTK_SORT_ASCENDING) {
1157 for (i=(row_array->len)-1; i>=1; i--) {
1158 work = g_ptr_array_index( row_array, i);
1159 gtk_sctree_link( ctree, work, node, list_start, FALSE);
1161 /* insert work at the beginning of the list */
1164 for (i=1; i<row_array->len; i++) {
1165 work = g_ptr_array_index( row_array, i);
1166 gtk_sctree_link( ctree, work, node, list_start, FALSE);
1168 /* insert work at the beginning of the list */
1172 for (i=0; i<viewable_array->len; i++) {
1173 gtk_cmctree_expand( ctree, g_ptr_array_index( viewable_array, i));
1177 g_ptr_array_free( row_array, TRUE);
1178 g_ptr_array_free( viewable_array, TRUE);
1182 gtk_sctree_sort_recursive (GtkCMCTree *ctree,
1183 GtkCMCTreeNode *node)
1186 GtkCMCTreeNode *focus_node = NULL;
1188 cm_return_if_fail (ctree != NULL);
1189 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1191 clist = GTK_CMCLIST (ctree);
1193 gtk_cmclist_freeze (clist);
1195 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1196 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1198 g_list_free (clist->undo_selection);
1199 g_list_free (clist->undo_unselection);
1200 clist->undo_selection = NULL;
1201 clist->undo_unselection = NULL;
1204 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
1205 focus_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
1207 GTK_SCTREE(ctree)->sorting = TRUE;
1209 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (stree_sort), NULL);
1212 stree_sort (ctree, NULL, NULL);
1214 GTK_SCTREE(ctree)->sorting = FALSE;
1217 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
1218 clist->undo_anchor = clist->focus_row;
1221 gtk_cmclist_thaw (clist);
1225 gtk_sctree_sort_node (GtkCMCTree *ctree,
1226 GtkCMCTreeNode *node)
1229 GtkCMCTreeNode *focus_node = NULL;
1231 cm_return_if_fail (ctree != NULL);
1232 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1234 clist = GTK_CMCLIST (ctree);
1236 gtk_cmclist_freeze (clist);
1238 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1239 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1241 g_list_free (clist->undo_selection);
1242 g_list_free (clist->undo_unselection);
1243 clist->undo_selection = NULL;
1244 clist->undo_unselection = NULL;
1247 if (!node || (node && gtk_cmctree_is_viewable (ctree, node)))
1248 focus_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
1250 GTK_SCTREE(ctree)->sorting = TRUE;
1252 stree_sort (ctree, node, NULL);
1254 GTK_SCTREE(ctree)->sorting = FALSE;
1257 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
1258 clist->undo_anchor = clist->focus_row;
1261 gtk_cmclist_thaw (clist);
1264 /************************************************************************/
1267 gtk_sctree_unlink (GtkCMCTree *ctree,
1268 GtkCMCTreeNode *node,
1269 gboolean update_focus_row)
1275 GtkCMCTreeNode *work;
1276 GtkCMCTreeNode *parent;
1279 cm_return_if_fail (ctree != NULL);
1280 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1281 cm_return_if_fail (node != NULL);
1283 clist = GTK_CMCLIST (ctree);
1285 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1286 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1288 g_list_free (clist->undo_selection);
1289 g_list_free (clist->undo_unselection);
1290 clist->undo_selection = NULL;
1291 clist->undo_unselection = NULL;
1294 visible = gtk_cmctree_is_viewable (ctree, node);
1296 /* clist->row_list_end unlinked ? */
1297 if (visible && (GTK_CMCTREE_NODE_NEXT (node) == NULL ||
1298 (GTK_CMCTREE_ROW (node)->children && gtk_cmctree_is_ancestor (ctree, node,
1299 GTK_CMCTREE_NODE (clist->row_list_end)))))
1300 clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node));
1304 level = GTK_CMCTREE_ROW (node)->level;
1305 work = GTK_CMCTREE_NODE_NEXT (node);
1306 while (work && GTK_CMCTREE_ROW (work)->level > level) {
1307 work = GTK_CMCTREE_NODE_NEXT (work);
1312 clist->rows -= (rows + 1);
1314 if (update_focus_row) {
1316 pos = g_list_position (clist->row_list, (GList *)node);
1317 if (pos + rows < clist->focus_row)
1318 clist->focus_row -= (rows + 1);
1319 else if (pos <= clist->focus_row) {
1320 if (!GTK_CMCTREE_ROW (node)->sibling)
1321 clist->focus_row = MAX (pos - 1, 0);
1323 clist->focus_row = pos;
1325 clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
1327 clist->undo_anchor = clist->focus_row;
1332 list = (GList *)GTK_CMCTREE_NODE_PREV (work);
1334 list = (GList *)work;
1335 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node);
1338 if (GTK_CMCTREE_NODE_PREV (node) &&
1339 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node) {
1340 list = (GList *)GTK_CMCTREE_NODE_PREV (node);
1341 list->next = (GList *)work;
1345 parent = GTK_CMCTREE_ROW (node)->parent;
1347 if (GTK_CMCTREE_ROW (parent)->children == node) {
1348 GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling;
1351 GtkCMCTreeNode *sibling;
1353 sibling = GTK_CMCTREE_ROW (parent)->children;
1354 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1355 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1356 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1360 if (clist->row_list == (GList *)node)
1361 clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling);
1363 GtkCMCTreeNode *sibling;
1365 sibling = GTK_CMCTREE_NODE (clist->row_list);
1366 while (GTK_CMCTREE_ROW (sibling)->sibling != node)
1367 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1368 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling;
1374 gtk_sctree_link (GtkCMCTree *ctree,
1375 GtkCMCTreeNode *node,
1376 GtkCMCTreeNode *parent,
1377 GtkCMCTreeNode *sibling,
1378 gboolean update_focus_row)
1384 gboolean visible = FALSE;
1388 cm_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent);
1389 cm_return_if_fail (node != NULL);
1390 cm_return_if_fail (node != sibling);
1391 cm_return_if_fail (node != parent);
1393 clist = GTK_CMCLIST (ctree);
1395 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) {
1396 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1398 g_list_free (clist->undo_selection);
1399 g_list_free (clist->undo_unselection);
1400 clist->undo_selection = NULL;
1401 clist->undo_unselection = NULL;
1404 for (rows = 1, list_end = (GList *)node; list_end->next;
1405 list_end = list_end->next)
1408 GTK_CMCTREE_ROW (node)->parent = parent;
1409 GTK_CMCTREE_ROW (node)->sibling = sibling;
1411 if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) &&
1412 GTK_CMCTREE_ROW (parent)->expanded))) {
1414 clist->rows += rows;
1418 work = (GList *)(GTK_CMCTREE_ROW (parent)->children);
1420 work = clist->row_list;
1423 if (work != (GList *)sibling) {
1424 while (GTK_CMCTREE_ROW (work)->sibling != sibling)
1425 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1426 GTK_CMCTREE_ROW (work)->sibling = node;
1429 if (sibling == GTK_CMCTREE_NODE (clist->row_list))
1430 clist->row_list = (GList *) node;
1431 if (GTK_CMCTREE_NODE_PREV (sibling) &&
1432 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling) {
1433 list = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1434 list->next = (GList *)node;
1437 list = (GList *)node;
1438 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling);
1439 list_end->next = (GList *)sibling;
1440 list = (GList *)sibling;
1441 list->prev = list_end;
1442 if (parent && GTK_CMCTREE_ROW (parent)->children == sibling)
1443 GTK_CMCTREE_ROW (parent)->children = node;
1448 while (GTK_CMCTREE_ROW (work)->sibling)
1449 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling);
1450 GTK_CMCTREE_ROW (work)->sibling = node;
1452 /* find last visible child of sibling */
1453 work = (GList *) gtk_sctree_last_visible (ctree,
1454 GTK_CMCTREE_NODE (work));
1456 list_end->next = work->next;
1458 work->next->prev = list_end;
1459 work->next = (GList *)node;
1460 list = (GList *)node;
1465 GTK_CMCTREE_ROW (parent)->children = node;
1466 list = (GList *)node;
1467 list->prev = (GList *)parent;
1468 if (GTK_CMCTREE_ROW (parent)->expanded) {
1469 list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1470 if (GTK_CMCTREE_NODE_NEXT(parent)) {
1471 list = (GList *)GTK_CMCTREE_NODE_NEXT (parent);
1472 list->prev = list_end;
1474 list = (GList *)parent;
1475 list->next = (GList *)node;
1478 list_end->next = NULL;
1481 clist->row_list = (GList *)node;
1482 list = (GList *)node;
1484 list_end->next = NULL;
1489 gtk_cmctree_pre_recursive (ctree, node, stree_update_level, NULL);
1491 if (clist->row_list_end == NULL ||
1492 clist->row_list_end->next == (GList *)node)
1493 clist->row_list_end = list_end;
1495 if (visible && update_focus_row) {
1497 pos = g_list_position (clist->row_list, (GList *)node);
1499 if (pos <= clist->focus_row) {
1500 clist->focus_row += rows;
1501 clist->undo_anchor = clist->focus_row;
1507 stree_update_level (GtkCMCTree *ctree,
1508 GtkCMCTreeNode *node,
1514 if (GTK_CMCTREE_ROW (node)->parent)
1515 GTK_CMCTREE_ROW (node)->level =
1516 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1;
1518 GTK_CMCTREE_ROW (node)->level = 1;
1521 static GtkCMCTreeNode *
1522 gtk_sctree_last_visible (GtkCMCTree *ctree,
1523 GtkCMCTreeNode *node)
1525 GtkCMCTreeNode *work;
1530 work = GTK_CMCTREE_ROW (node)->children;
1532 if (!work || !GTK_CMCTREE_ROW (node)->expanded)
1535 while (GTK_CMCTREE_ROW (work)->sibling)
1536 work = GTK_CMCTREE_ROW (work)->sibling;
1538 return gtk_sctree_last_visible (ctree, work);
1542 sset_node_info (GtkCMCTree *ctree,
1543 GtkCMCTreeNode *node,
1546 GdkPixbuf *pixbuf_closed,
1547 GdkPixbuf *pixbuf_opened,
1551 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
1553 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
1555 if (GTK_CMCTREE_ROW (node)->pixbuf_closed)
1557 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_closed);
1560 GTK_CMCTREE_ROW (node)->pixbuf_opened = NULL;
1561 GTK_CMCTREE_ROW (node)->pixbuf_closed = NULL;
1565 GTK_CMCTREE_ROW (node)->pixbuf_closed = g_object_ref (pixbuf_closed);
1569 GTK_CMCTREE_ROW (node)->pixbuf_opened = g_object_ref (pixbuf_opened);
1572 GTK_CMCTREE_ROW (node)->is_leaf = is_leaf;
1573 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
1575 if (GTK_CMCTREE_ROW (node)->expanded)
1576 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
1577 text, spacing, pixbuf_opened);
1579 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column,
1580 text, spacing, pixbuf_closed);
1583 static GtkCMCTreeRow *
1584 srow_new (GtkCMCTree *ctree)
1587 GtkCMCTreeRow *ctree_row;
1590 clist = GTK_CMCLIST (ctree);
1591 ctree_row = g_slice_new (GtkCMCTreeRow);
1592 ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns);
1593 for (i = 0; i < clist->columns; i++)
1595 ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY;
1596 ctree_row->row.cell[i].vertical = 0;
1597 ctree_row->row.cell[i].horizontal = 0;
1598 ctree_row->row.cell[i].style = NULL;
1601 GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
1603 ctree_row->row.fg_set = FALSE;
1604 ctree_row->row.bg_set = FALSE;
1605 ctree_row->row.style = NULL;
1606 ctree_row->row.selectable = TRUE;
1607 ctree_row->row.state = GTK_STATE_NORMAL;
1608 ctree_row->row.data = NULL;
1609 ctree_row->row.destroy = NULL;
1611 ctree_row->level = 0;
1612 ctree_row->expanded = FALSE;
1613 ctree_row->parent = NULL;
1614 ctree_row->sibling = NULL;
1615 ctree_row->children = NULL;
1616 ctree_row->pixbuf_closed = NULL;
1617 ctree_row->pixbuf_opened = NULL;
1623 srow_delete (GtkCMCTree *ctree,
1624 GtkCMCTreeRow *ctree_row)
1629 clist = GTK_CMCLIST (ctree);
1631 for (i = 0; i < clist->columns; i++)
1633 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
1634 (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL);
1635 if (ctree_row->row.cell[i].style)
1637 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
1638 gtk_style_detach (ctree_row->row.cell[i].style);
1639 g_object_unref (ctree_row->row.cell[i].style);
1643 if (ctree_row->row.style)
1645 if (gtk_widget_get_realized (GTK_WIDGET(ctree)))
1646 gtk_style_detach (ctree_row->row.style);
1647 g_object_unref (ctree_row->row.style);
1650 if (ctree_row->pixbuf_closed)
1652 g_object_unref (ctree_row->pixbuf_closed);
1655 if (ctree_row->pixbuf_opened)
1657 g_object_unref (ctree_row->pixbuf_opened);
1660 if (ctree_row->row.destroy)
1662 GDestroyNotify dnotify = ctree_row->row.destroy;
1663 gpointer ddata = ctree_row->row.data;
1665 ctree_row->row.destroy = NULL;
1666 ctree_row->row.data = NULL;
1671 g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell);
1672 g_slice_free (GtkCMCTreeRow, ctree_row);
1676 stree_delete_row (GtkCMCTree *ctree,
1677 GtkCMCTreeNode *node,
1680 srow_delete (ctree, GTK_CMCTREE_ROW (node));
1681 g_list_free_1 ((GList *)node);
1685 gtk_sctree_real_tree_expand (GtkCMCTree *ctree,
1686 GtkCMCTreeNode *node)
1689 GtkCMCTreeNode *work;
1690 GtkRequisition requisition;
1693 cm_return_if_fail (GTK_IS_CMCTREE (ctree));
1695 if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf)
1698 clist = GTK_CMCLIST (ctree);
1700 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1702 GTK_CMCTREE_ROW (node)->expanded = TRUE;
1704 visible = gtk_cmctree_is_viewable (ctree, node);
1705 /* get cell width if tree_column is auto resized */
1706 if (visible && clist->column[ctree->tree_column].auto_resize &&
1707 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1708 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1709 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition);
1711 /* unref/unset closed pixbuf */
1712 if (GTK_CMCELL_PIXTEXT
1713 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf)
1717 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf);
1720 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL;
1723 /* set/ref opened pixbuf */
1724 if (GTK_CMCTREE_ROW (node)->pixbuf_opened)
1727 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf =
1728 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_opened);
1732 work = GTK_CMCTREE_ROW (node)->children;
1735 GList *list = (GList *)work;
1736 gint *cell_width = NULL;
1741 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1743 cell_width = g_new0 (gint, clist->columns);
1744 if (clist->column[ctree->tree_column].auto_resize)
1745 cell_width[ctree->tree_column] = requisition.width;
1749 /* search maximum cell widths of auto_resize columns */
1750 for (i = 0; i < clist->columns; i++)
1751 if (clist->column[i].auto_resize)
1753 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request
1754 (clist, >K_CMCTREE_ROW (work)->row, i, &requisition);
1755 cell_width[i] = MAX (requisition.width, cell_width[i]);
1758 list = (GList *)work;
1759 work = GTK_CMCTREE_NODE_NEXT (work);
1766 list = (GList *)work;
1767 work = GTK_CMCTREE_NODE_NEXT (work);
1771 list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node);
1773 if (GTK_CMCTREE_NODE_NEXT (node))
1777 if (clist->row_list_end == list)
1778 clist->row_list_end = g_list_last(list);
1780 tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node);
1781 tmp_list->prev = list;
1784 clist->row_list_end = list;
1786 list = (GList *)node;
1787 list->next = (GList *)(GTK_CMCTREE_ROW (node)->children);
1789 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist))
1791 /* resize auto_resize columns if needed */
1792 for (i = 0; i < clist->columns; i++)
1793 if (clist->column[i].auto_resize &&
1794 cell_width[i] > clist->column[i].width)
1795 gtk_cmclist_set_column_width (clist, i, cell_width[i]);
1796 g_free (cell_width);
1798 if (!GTK_SCTREE(ctree)->sorting) {
1799 /* update focus_row position */
1800 row = g_list_position (clist->row_list, (GList *)node);
1801 if (row < clist->focus_row)
1802 clist->focus_row += tmp;
1805 CLIST_REFRESH (clist);
1808 else if (visible && clist->column[ctree->tree_column].auto_resize)
1809 /* resize tree_column if needed */
1810 gtk_sctree_column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column,
1816 gtk_sctree_insert_node (GtkCMCTree *ctree,
1817 GtkCMCTreeNode *parent,
1818 GtkCMCTreeNode *sibling,
1821 GdkPixbuf *pixbuf_closed,
1822 GdkPixbuf *pixbuf_opened,
1827 GtkCMCTreeRow *new_row;
1828 GtkCMCTreeNode *node;
1832 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
1834 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
1836 if (parent && GTK_CMCTREE_ROW (parent)->is_leaf)
1839 clist = GTK_CMCLIST (ctree);
1841 /* create the row */
1842 new_row = srow_new (ctree);
1843 list = g_list_alloc ();
1844 list->data = new_row;
1845 node = GTK_CMCTREE_NODE (list);
1848 for (i = 0; i < clist->columns; i++)
1849 if (text[i] && i != ctree->tree_column)
1850 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents
1851 (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL);
1853 sset_node_info (ctree, node, text ?
1854 text[ctree->tree_column] : NULL, spacing, pixbuf_closed,
1855 pixbuf_opened, is_leaf, expanded);
1857 /* sorted insertion */
1858 if (GTK_CMCLIST_AUTO_SORT (clist))
1861 sibling = GTK_CMCTREE_ROW (parent)->children;
1863 sibling = GTK_CMCTREE_NODE (clist->row_list);
1865 while (sibling && clist->compare
1866 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0)
1867 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1870 gtk_sctree_link (ctree, node, parent, sibling, FALSE);
1872 if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
1873 gtk_cmctree_is_viewable (ctree, node))
1875 for (i = 0; i < clist->columns; i++)
1876 if (clist->column[i].auto_resize)
1877 gtk_sctree_column_auto_resize (clist, &(new_row->row), i, 0);
1880 if (clist->rows == 1)
1882 clist->focus_row = 0;
1883 if (clist->selection_mode == GTK_SELECTION_BROWSE)
1884 gtk_sctree_select (GTK_SCTREE(ctree), node);
1888 CLIST_REFRESH (clist);
1894 gtk_sctree_insert_gnode (GtkCMCTree *ctree,
1895 GtkCMCTreeNode *parent,
1896 GtkCMCTreeNode *sibling,
1898 GtkCMCTreeGNodeFunc func,
1902 GtkCMCTreeNode *cnode = NULL;
1903 GtkCMCTreeNode *child = NULL;
1904 GtkCMCTreeNode *new_child;
1909 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL);
1910 cm_return_val_if_fail (gnode != NULL, NULL);
1911 cm_return_val_if_fail (func != NULL, NULL);
1913 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL);
1915 clist = GTK_CMCLIST (ctree);
1918 depth = GTK_CMCTREE_ROW (parent)->level + 1;
1920 list = g_list_alloc ();
1921 list->data = srow_new (ctree);
1922 cnode = GTK_CMCTREE_NODE (list);
1924 gtk_cmclist_freeze (clist);
1926 sset_node_info (ctree, cnode, "", 0, NULL, NULL, TRUE, FALSE);
1928 if (!func (ctree, depth, gnode, cnode, data))
1930 stree_delete_row (ctree, cnode, NULL);
1931 gtk_cmclist_thaw (clist);
1935 if (GTK_CMCLIST_AUTO_SORT (clist))
1938 sibling = GTK_CMCTREE_ROW (parent)->children;
1940 sibling = GTK_CMCTREE_NODE (clist->row_list);
1942 while (sibling && clist->compare
1943 (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0)
1944 sibling = GTK_CMCTREE_ROW (sibling)->sibling;
1947 gtk_sctree_link (ctree, cnode, parent, sibling, FALSE);
1949 for (work = g_node_last_child (gnode); work; work = work->prev)
1951 new_child = gtk_sctree_insert_gnode (ctree, cnode, child,
1957 gtk_cmclist_thaw (clist);
1963 sreal_tree_move (GtkCMCTree *ctree,
1964 GtkCMCTreeNode *node,
1965 GtkCMCTreeNode *new_parent,
1966 GtkCMCTreeNode *new_sibling)
1969 GtkCMCTreeNode *work;
1970 gboolean visible = FALSE;
1972 cm_return_if_fail (ctree != NULL);
1973 cm_return_if_fail (node != NULL);
1974 cm_return_if_fail (!new_sibling ||
1975 GTK_CMCTREE_ROW (new_sibling)->parent == new_parent);
1977 if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf)
1980 /* new_parent != child of child */
1981 for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent)
1985 clist = GTK_CMCLIST (ctree);
1987 visible = gtk_cmctree_is_viewable (ctree, node);
1989 if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
1991 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
1993 g_list_free (clist->undo_selection);
1994 g_list_free (clist->undo_unselection);
1995 clist->undo_selection = NULL;
1996 clist->undo_unselection = NULL;
1999 if (GTK_CMCLIST_AUTO_SORT (clist))
2001 if (new_parent == GTK_CMCTREE_ROW (node)->parent)
2005 new_sibling = GTK_CMCTREE_ROW (new_parent)->children;
2007 new_sibling = GTK_CMCTREE_NODE (clist->row_list);
2009 while (new_sibling && clist->compare
2010 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0)
2011 new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling;
2014 if (new_parent == GTK_CMCTREE_ROW (node)->parent &&
2015 new_sibling == GTK_CMCTREE_ROW (node)->sibling)
2018 gtk_cmclist_freeze (clist);
2022 if (!GTK_SCTREE(ctree)->sorting && gtk_cmctree_is_viewable (ctree, node))
2023 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
2025 gtk_sctree_unlink (ctree, node, FALSE);
2026 gtk_sctree_link (ctree, node, new_parent, new_sibling, FALSE);
2028 if (!GTK_SCTREE(ctree)->sorting && work)
2030 while (work && !gtk_cmctree_is_viewable (ctree, work))
2031 work = GTK_CMCTREE_ROW (work)->parent;
2032 clist->focus_row = g_list_position (clist->row_list, (GList *)work);
2033 clist->undo_anchor = clist->focus_row;
2036 if (clist->column[ctree->tree_column].auto_resize &&
2037 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) &&
2038 (visible || gtk_cmctree_is_viewable (ctree, node)))
2039 gtk_cmclist_set_column_width
2040 (clist, ctree->tree_column,
2041 gtk_cmclist_optimal_column_width (clist, ctree->tree_column));
2043 gtk_cmclist_thaw (clist);
2046 void gtk_sctree_set_column_tooltip (GtkSCTree *sctree,
2050 CLAWS_SET_TIP(GTK_CMCLIST(sctree)->column[column].button,