2 * Claws Mail -- 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/>.
33 #include "gtksctree.h"
34 #include "claws-marshal.h"
35 #include "prefs_common.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)); \
44 #define CELL_SPACING 1
45 #define CLIST_OPTIMUM_SIZE 64
46 #define COLUMN_INSET 3
48 #define TAB_SIZE (PM_SIZE + 6)
49 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
50 (((row) + 1) * CELL_SPACING) + \
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 \
56 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
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
,
94 GtkCMCTreeNode
*parent
,
95 GtkCMCTreeNode
*sibling
,
96 gboolean update_focus_row
);
98 static void gtk_sctree_unlink (GtkCMCTree
*ctree
,
100 gboolean update_focus_row
);
102 static void stree_update_level (GtkCMCTree
*ctree
,
103 GtkCMCTreeNode
*node
,
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
);
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:
126 * Creates the GtkSCTree class and its type information
128 * Return value: The type ID for GtkSCTreeClass
131 gtk_sctree_get_type (void)
133 static GType sctree_type
= 0;
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 */
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);
160 gtk_sctree_change_focus_row_expansion (GtkCMCTree
*ctree
,
161 GtkCMCTreeExpansionType action
)
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
)))
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
))
181 case GTK_CMCTREE_EXPANSION_EXPAND
:
182 if (GTK_SCTREE(ctree
)->always_expand_recursively
)
183 gtk_cmctree_expand_recursive (ctree
, node
);
185 gtk_cmctree_expand (ctree
, node
);
188 case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE
:
189 gtk_cmctree_expand_recursive (ctree
, node
);
191 case GTK_CMCTREE_EXPANSION_COLLAPSE
:
192 gtk_cmctree_collapse (ctree
, node
);
194 case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE
:
195 gtk_cmctree_collapse_recursive (ctree
, node
);
197 case GTK_CMCTREE_EXPANSION_TOGGLE
:
198 if (GTK_SCTREE(ctree
)->always_expand_recursively
)
199 gtk_cmctree_toggle_expansion_recursive (ctree
, node
);
201 gtk_cmctree_toggle_expansion (ctree
, node
);
203 case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE
:
204 gtk_cmctree_toggle_expansion_recursive (ctree
, node
);
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 */
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
),
236 G_STRUCT_OFFSET (GtkSCTreeClass
, row_popup_menu
),
238 claws_marshal_VOID__POINTER
,
241 sctree_signals
[EMPTY_POPUP_MENU
] =
242 g_signal_new ("empty_popup_menu",
243 G_TYPE_FROM_CLASS (klass
),
245 G_STRUCT_OFFSET (GtkSCTreeClass
, empty_popup_menu
),
247 claws_marshal_VOID__POINTER
,
250 sctree_signals
[OPEN_ROW
] =
251 g_signal_new ("open_row",
252 G_TYPE_FROM_CLASS (klass
),
254 G_STRUCT_OFFSET (GtkSCTreeClass
, open_row
),
256 g_cclosure_marshal_VOID__VOID
,
258 sctree_signals
[START_DRAG
] =
259 g_signal_new ("start_drag",
260 G_TYPE_FROM_CLASS (klass
),
262 G_STRUCT_OFFSET (GtkSCTreeClass
, start_drag
),
264 claws_marshal_VOID__INT_POINTER
,
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 */
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. */
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. */
315 select_range (GtkSCTree
*sctree
, gint row
)
321 if (sctree
->anchor_row
== NULL
) {
323 sctree
->anchor_row
= gtk_cmctree_node_nth(GTK_CMCTREE(sctree
), row
);
325 prev_row
= g_list_position(GTK_CMCLIST(sctree
)->row_list
,
326 (GList
*)sctree
->anchor_row
);
328 if (row
< prev_row
) {
331 GTK_CMCLIST(sctree
)->focus_row
= min
;
336 sctree
->selecting_range
++;
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",
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. */
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
)
384 GTK_CMCLIST(sctree
)->focus_row
= row
;
387 gtk_cmclist_unselect_all (GTK_CMCLIST (sctree
));
391 GtkCMCTreeNode
*node
;
393 node
= _node
? _node
: gtk_cmctree_node_nth (GTK_CMCTREE(sctree
), row
);
395 /*No need to manage overlapped list*/
397 if (row_is_selected(sctree
, row
))
398 gtk_cmclist_unselect_row (GTK_CMCLIST (sctree
), row
, col
);
400 g_signal_emit_by_name
402 "tree_select_row", node
, col
);
404 g_signal_emit_by_name
406 "tree_select_row", node
, col
);
408 sctree
->anchor_row
= node
;
410 select_range (sctree
, row
);
414 sctree_is_hot_spot (GtkSCTree
*sctree
,
415 GtkCMCTreeNode
*node
,
420 GtkCMCTreeRow
*tree_row
;
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
)
437 tree_row
= GTK_CMCTREE_ROW (node
);
438 if (!tree_row
->children
)
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);
449 yu
= (ROW_TOP_YPIXEL (clist
, row
) + (clist
->row_height
/2 - hotspot_size
) / 2 -
450 (clist
->row_height
/2 - 1) % 2);
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
;
458 xl
= clist
->column
[ctree
->tree_column
].area
.x
+ clist
->hoffset
+
459 (tree_row
->level
- 1) * ctree
->tree_indent
;
461 xmax
= xl
+ hotspot_size
;
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
+
474 xl
= clist
->column
[ctree
->tree_column
].area
.x
+ clist
->hoffset
+
475 (tree_row
->level
- 1) * ctree
->tree_indent
;
476 xmax
= xl
+ hotspot_size
;
479 return (x
>= xl
&& x
<= xmax
&& y
>= yu
&& y
<= yu
+ hotspot_size
);
483 gtk_sctree_is_hot_spot (GtkSCTree
*ctree
,
487 GtkCMCTreeNode
*node
;
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
);
500 /* Our handler for button_press events. We override all of GtkCMCList's broken
504 gtk_sctree_button_press (GtkWidget
*widget
, GdkEventButton
*event
)
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
);
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
);
536 gtk_cmctree_expand(GTK_CMCTREE(sctree
), node
);
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
);
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
;
560 select_row (sctree
, row
, col
, event
->state
, NULL
);
563 gtk_cmclist_unselect_all (clist
);
567 } else if (event
->button
== 3) {
568 /* Emit *_popup_menu signal*/
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
],
576 gtk_cmclist_unselect_all(clist
);
577 g_signal_emit (G_OBJECT (sctree
),
578 sctree_signals
[EMPTY_POPUP_MENU
],
586 case GDK_2BUTTON_PRESS
:
587 if (event
->button
!= 1)
590 sctree
->dnd_select_pending
= FALSE
;
591 sctree
->dnd_select_pending_state
= 0;
594 g_signal_emit (G_OBJECT (sctree
),
595 sctree_signals
[OPEN_ROW
], 0);
607 /* Our handler for button_release events. We override all of GtkCMCList's broken
611 gtk_sctree_button_release (GtkWidget
*widget
, GdkEventButton
*event
)
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
);
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))
635 sctree
->dnd_press_button
= 0;
636 sctree
->dnd_press_x
= 0;
637 sctree
->dnd_press_y
= 0;
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;
652 /* Our handler for motion_notify events. We override all of GtkCMCList's broken
656 gtk_sctree_motion (GtkWidget
*widget
, GdkEventMotion
*event
)
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
))))
675 /* This is the same threshold value that is used in gtkdnd.c */
682 if (MAX (ABS (sctree
->dnd_press_x
- event
->x
),
683 ABS (sctree
->dnd_press_y
- event
->y
)) <= THRESHOLD
)
686 /* Handle any pending selections */
688 if (sctree
->dnd_select_pending
) {
689 if (!row_is_selected(sctree
,sctree
->dnd_select_pending_row
))
691 sctree
->dnd_select_pending_row
,
693 sctree
->dnd_select_pending_state
,
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
,
708 /* We override the drag_begin signal to do nothing */
710 gtk_sctree_drag_begin (GtkWidget
*widget
, GdkDragContext
*context
)
715 /* We override the drag_end signal to do nothing */
717 gtk_sctree_drag_end (GtkWidget
*widget
, GdkDragContext
*context
)
722 /* We override the drag_data_get signal to do nothing */
724 gtk_sctree_drag_data_get (GtkWidget
*widget
, GdkDragContext
*context
,
725 GtkSelectionData
*data
, guint info
, guint time
)
730 /* We override the drag_leave signal to do nothing */
732 gtk_sctree_drag_leave (GtkWidget
*widget
, GdkDragContext
*context
, guint time
)
737 /* We override the drag_motion signal to do nothing */
739 gtk_sctree_drag_motion (GtkWidget
*widget
, GdkDragContext
*context
,
740 gint x
, gint y
, guint time
)
745 /* We override the drag_drop signal to do nothing */
747 gtk_sctree_drag_drop (GtkWidget
*widget
, GdkDragContext
*context
,
748 gint x
, gint y
, guint time
)
753 /* We override the drag_data_received signal to do nothing */
755 gtk_sctree_drag_data_received (GtkWidget
*widget
, GdkDragContext
*context
,
756 gint x
, gint y
, GtkSelectionData
*data
,
757 guint info
, guint time
)
762 /* Our handler for the clear signal of the clist. We have to reset the anchor
766 gtk_sctree_clear (GtkCMCList
*clist
)
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
);
781 gtk_sctree_real_unselect_all (GtkCMCList
*clist
)
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
);
801 gtk_cmclist_thaw (GTK_CMCLIST (sctree
));
802 sctree
->selecting_range
--;
807 gtk_sctree_column_auto_resize (GtkCMCList
*clist
,
808 GtkCMCListRow
*clist_row
,
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
))
820 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request (clist
, clist_row
,
821 column
, &requisition
);
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
)
831 GtkRequisition button_req
;
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
)));
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
)
853 if (new_width
< clist
->column
[column
].width
)
854 gtk_cmclist_set_column_width (clist
, column
, new_width
);
859 gtk_sctree_auto_resize_columns (GtkCMCList
*clist
)
863 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
866 for (i
= 0; i
< clist
->columns
; i
++)
867 gtk_sctree_column_auto_resize (clist
, NULL
, i
, clist
->column
[i
].width
);
871 gtk_sctree_real_tree_collapse (GtkCMCTree
*ctree
,
872 GtkCMCTreeNode
*node
)
875 GtkCMCTreeNode
*work
;
876 GtkRequisition requisition
;
880 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
882 if (!node
|| !GTK_CMCTREE_ROW (node
)->expanded
||
883 GTK_CMCTREE_ROW (node
)->is_leaf
)
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
, >K_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
)
906 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->pixbuf
);
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
)
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
;
927 while (work
&& GTK_CMCTREE_ROW (work
)->level
> level
)
929 work
= GTK_CMCTREE_NODE_NEXT (work
);
935 list
= (GList
*)node
;
936 list
->next
= (GList
*)work
;
937 list
= (GList
*)GTK_CMCTREE_NODE_PREV (work
);
939 list
= (GList
*)work
;
940 list
->prev
= (GList
*)node
;
944 list
= (GList
*)node
;
946 clist
->row_list_end
= (GList
*)node
;
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
;
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
, >K_CMCTREE_ROW (node
)->row
, ctree
->tree_column
,
972 GtkWidget
*gtk_sctree_new_with_titles (gint columns
, gint tree_column
,
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");
986 widget
= gtk_widget_new (TYPE_GTK_SCTREE
,
987 "n_columns", columns
,
988 "tree_column", tree_column
,
991 GtkCMCList
*clist
= GTK_CMCLIST (widget
);
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
);
1008 void gtk_sctree_set_use_markup (GtkSCTree
*sctree
,
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
)
1030 g_list_position(GTK_CMCLIST(sctree
)->row_list
, (GList
*)node
),
1034 void gtk_sctree_select_with_state (GtkSCTree
*sctree
, GtkCMCTreeNode
*node
, int state
)
1037 g_list_position(GTK_CMCLIST(sctree
)->row_list
, (GList
*)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
)
1076 GtkCMCTreeNode
*temp
;
1081 /* find the maximum element of numbers[root],
1082 numbers[2*root] and numbers[2*root+1] */
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)
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)
1091 /* if numbers[root] wasn't the maximum element then
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
)
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);
1120 stree_sort (GtkCMCTree
*ctree
,
1121 GtkCMCTreeNode
*node
,
1124 GtkCMCTreeNode
*list_start
, *work
, *next
;
1125 GPtrArray
*row_array
, *viewable_array
;
1129 clist
= GTK_CMCLIST (ctree
);
1132 work
= GTK_CMCTREE_ROW (node
)->children
;
1134 work
= GTK_CMCTREE_NODE (clist
->row_list
);
1136 row_array
= g_ptr_array_new();
1137 viewable_array
= g_ptr_array_new();
1140 g_ptr_array_add( row_array
, NULL
);
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
);
1151 heap_sort( clist
, row_array
, (row_array
->len
)-1);
1154 list_start
= GTK_CMCTREE_ROW (node
)->children
;
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
);
1163 /* insert work at the beginning of the list */
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
);
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
);
1184 gtk_sctree_sort_recursive (GtkCMCTree
*ctree
,
1185 GtkCMCTreeNode
*node
)
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
);
1214 stree_sort (ctree
, NULL
, NULL
);
1216 GTK_SCTREE(ctree
)->sorting
= FALSE
;
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
);
1227 gtk_sctree_sort_node (GtkCMCTree
*ctree
,
1228 GtkCMCTreeNode
*node
)
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
;
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 /************************************************************************/
1269 gtk_sctree_unlink (GtkCMCTree
*ctree
,
1270 GtkCMCTreeNode
*node
,
1271 gboolean update_focus_row
)
1277 GtkCMCTreeNode
*work
;
1278 GtkCMCTreeNode
*parent
;
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
));
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
);
1314 clist
->rows
-= (rows
+ 1);
1316 if (update_focus_row
) {
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);
1325 clist
->focus_row
= pos
;
1327 clist
->focus_row
= MIN (clist
->focus_row
, clist
->rows
- 1);
1329 clist
->undo_anchor
= clist
->focus_row
;
1334 list
= (GList
*)GTK_CMCTREE_NODE_PREV (work
);
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
;
1347 parent
= GTK_CMCTREE_ROW (node
)->parent
;
1349 if (GTK_CMCTREE_ROW (parent
)->children
== node
) {
1350 GTK_CMCTREE_ROW (parent
)->children
= GTK_CMCTREE_ROW (node
)->sibling
;
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
;
1362 if (clist
->row_list
== (GList
*)node
)
1363 clist
->row_list
= (GList
*) (GTK_CMCTREE_ROW (node
)->sibling
);
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
;
1376 gtk_sctree_link (GtkCMCTree
*ctree
,
1377 GtkCMCTreeNode
*node
,
1378 GtkCMCTreeNode
*parent
,
1379 GtkCMCTreeNode
*sibling
,
1380 gboolean update_focus_row
)
1386 gboolean visible
= FALSE
;
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
)
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
))) {
1416 clist
->rows
+= rows
;
1420 work
= (GList
*)(GTK_CMCTREE_ROW (parent
)->children
);
1422 work
= clist
->row_list
;
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
;
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
;
1460 work
->next
->prev
= list_end
;
1461 work
->next
= (GList
*)node
;
1462 list
= (GList
*)node
;
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
;
1480 list_end
->next
= NULL
;
1483 clist
->row_list
= (GList
*)node
;
1484 list
= (GList
*)node
;
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
) {
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
;
1509 stree_update_level (GtkCMCTree
*ctree
,
1510 GtkCMCTreeNode
*node
,
1516 if (GTK_CMCTREE_ROW (node
)->parent
)
1517 GTK_CMCTREE_ROW (node
)->level
=
1518 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node
)->parent
)->level
+ 1;
1520 GTK_CMCTREE_ROW (node
)->level
= 1;
1523 static GtkCMCTreeNode
*
1524 gtk_sctree_last_visible (GtkCMCTree
*ctree
,
1525 GtkCMCTreeNode
*node
)
1527 GtkCMCTreeNode
*work
;
1532 work
= GTK_CMCTREE_ROW (node
)->children
;
1534 if (!work
|| !GTK_CMCTREE_ROW (node
)->expanded
)
1537 while (GTK_CMCTREE_ROW (work
)->sibling
)
1538 work
= GTK_CMCTREE_ROW (work
)->sibling
;
1540 return gtk_sctree_last_visible (ctree
, work
);
1544 sset_node_info (GtkCMCTree
*ctree
,
1545 GtkCMCTreeNode
*node
,
1548 GdkPixbuf
*pixbuf_closed
,
1549 GdkPixbuf
*pixbuf_opened
,
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
;
1567 GTK_CMCTREE_ROW (node
)->pixbuf_closed
= g_object_ref (pixbuf_closed
);
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
);
1581 gtk_cmctree_node_set_pixtext (ctree
, node
, ctree
->tree_column
,
1582 text
, spacing
, pixbuf_closed
);
1585 static GtkCMCTreeRow
*
1586 srow_new (GtkCMCTree
*ctree
)
1589 GtkCMCTreeRow
*ctree_row
;
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
;
1625 srow_delete (GtkCMCTree
*ctree
,
1626 GtkCMCTreeRow
*ctree_row
)
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
;
1673 g_slice_free1 (sizeof (GtkCMCell
) * clist
->columns
, ctree_row
->row
.cell
);
1674 g_slice_free (GtkCMCTreeRow
, ctree_row
);
1678 stree_delete_row (GtkCMCTree
*ctree
,
1679 GtkCMCTreeNode
*node
,
1682 srow_delete (ctree
, GTK_CMCTREE_ROW (node
));
1683 g_list_free_1 ((GList
*)node
);
1687 gtk_sctree_real_tree_expand (GtkCMCTree
*ctree
,
1688 GtkCMCTreeNode
*node
)
1691 GtkCMCTreeNode
*work
;
1692 GtkRequisition requisition
;
1695 cm_return_if_fail (GTK_IS_CMCTREE (ctree
));
1697 if (!node
|| GTK_CMCTREE_ROW (node
)->expanded
|| GTK_CMCTREE_ROW (node
)->is_leaf
)
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
, >K_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
)
1719 (GTK_CMCTREE_ROW (node
)->row
.cell
[ctree
->tree_column
])->pixbuf
);
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
)
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
;
1737 GList
*list
= (GList
*)work
;
1738 gint
*cell_width
= NULL
;
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
;
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
, >K_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
);
1768 list
= (GList
*)work
;
1769 work
= GTK_CMCTREE_NODE_NEXT (work
);
1773 list
->next
= (GList
*)GTK_CMCTREE_NODE_NEXT (node
);
1775 if (GTK_CMCTREE_NODE_NEXT (node
))
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
;
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
;
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
, >K_CMCTREE_ROW (node
)->row
, ctree
->tree_column
,
1818 gtk_sctree_insert_node (GtkCMCTree
*ctree
,
1819 GtkCMCTreeNode
*parent
,
1820 GtkCMCTreeNode
*sibling
,
1823 GdkPixbuf
*pixbuf_closed
,
1824 GdkPixbuf
*pixbuf_opened
,
1829 GtkCMCTreeRow
*new_row
;
1830 GtkCMCTreeNode
*node
;
1834 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree
), NULL
);
1836 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling
)->parent
== parent
, NULL
);
1838 if (parent
&& GTK_CMCTREE_ROW (parent
)->is_leaf
)
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
);
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
))
1863 sibling
= GTK_CMCTREE_ROW (parent
)->children
;
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
);
1896 gtk_sctree_insert_gnode (GtkCMCTree
*ctree
,
1897 GtkCMCTreeNode
*parent
,
1898 GtkCMCTreeNode
*sibling
,
1900 GtkCMCTreeGNodeFunc func
,
1904 GtkCMCTreeNode
*cnode
= NULL
;
1905 GtkCMCTreeNode
*child
= NULL
;
1906 GtkCMCTreeNode
*new_child
;
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
);
1915 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling
)->parent
== parent
, NULL
);
1917 clist
= GTK_CMCLIST (ctree
);
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
);
1937 if (GTK_CMCLIST_AUTO_SORT (clist
))
1940 sibling
= GTK_CMCTREE_ROW (parent
)->children
;
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
,
1959 gtk_cmclist_thaw (clist
);
1965 sreal_tree_move (GtkCMCTree
*ctree
,
1966 GtkCMCTreeNode
*node
,
1967 GtkCMCTreeNode
*new_parent
,
1968 GtkCMCTreeNode
*new_sibling
)
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
)
1982 /* new_parent != child of child */
1983 for (work
= new_parent
; work
; work
= GTK_CMCTREE_ROW (work
)->parent
)
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
)
2007 new_sibling
= GTK_CMCTREE_ROW (new_parent
)->children
;
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
)
2020 gtk_cmclist_freeze (clist
);
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
,
2052 CLAWS_SET_TIP(GTK_CMCLIST(sctree
)->column
[column
].button
,