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