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, &GTK_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, &GTK_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, &GTK_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, &GTK_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, &GTK_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