1 /* Dia -- a diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
3 *
4 * diagram_tree.c : a tree showing open diagrams
5 * Copyright (C) 2001 Jose A Ortega Ruiz
6 *
7 * patch to center objects in drawing viewport when doing "Locate"
8 * Copyright (C) 2003 Andrew Halper
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 *
24 */
25
26 #include <string.h>
27
28 #undef GTK_DISABLE_DEPRECATED /* GtkCTree */
29
30 #include "properties-dialog.h"
31 #include "diagram_tree_menu.h"
32 #include "diagram_tree_menu_callbacks.h"
33 #include "diagram_tree.h"
34 #include "persistence.h"
35
36 struct _DiagramTree {
37 GtkCTree *tree; /* the tree widget */
38 GtkCTreeNode *last; /* last clicked node */
39 DiagramTreeMenus *menus; /* popup menus */
40 GtkCListCompareFunc dia_cmp; /* diagram ordering function */
41 GtkCListCompareFunc obj_cmp; /* object ordering function */
42 };
43
44 #define is_object_node(node) (GTK_CTREE_ROW(node)->is_leaf)
45
46 static gint
find_hidden_type(gconstpointer type,gconstpointer object_type)47 find_hidden_type(gconstpointer type, gconstpointer object_type)
48 {
49 return !type
50 || !object_type
51 || strcmp((const gchar *)object_type, (const gchar *)type);
52 }
53
54 #define is_hidden_type(dtree, type) \
55 g_list_find_custom(persistent_list_get_glist(HIDDEN_TYPES_NAME), \
56 (gpointer)type, find_hidden_type)
57
58 #define is_hidden_object(dtree, object) \
59 is_hidden_type(dtree, ((DiaObject *)object)->type->name)
60
61 static void
62 update_object(DiagramTree *tree, GtkCTreeNode *node, DiaObject *object);
63
64 static void
select_node(DiagramTree * tree,GtkCTreeNode * node,gboolean raise)65 select_node(DiagramTree *tree, GtkCTreeNode *node, gboolean raise)
66 {
67 Diagram *d = NULL;
68 GtkCTreeNode *dnode = (is_object_node(node)) ?
69 GTK_CTREE_ROW(node)->parent : node;
70 DiaObject *o = (DiaObject *)gtk_ctree_node_get_row_data(tree->tree, node);
71
72
73 d = (Diagram *)gtk_ctree_node_get_row_data(tree->tree, dnode);
74 if (d) {
75 GSList *dlist = d->displays;
76 if (is_object_node(node)) {
77 if (o) {
78 update_object(tree, node, o);
79 diagram_remove_all_selected(d, FALSE);
80 diagram_select(d, o);
81 }
82 }
83 while (dlist) {
84 DDisplay *ddisp = (DDisplay *)dlist->data;
85 if (raise) {
86 gdk_window_raise(ddisp->shell->window);
87 /* if object exists */
88 if (o) {
89 ddisplay_scroll_to_object(ddisp, o);
90 }
91 }
92 gtk_widget_draw(ddisp->shell, NULL);
93 dlist = g_slist_next(dlist);
94 }
95 }
96 }
97
98 static void
update_last_node(DiagramTree * tree)99 update_last_node(DiagramTree *tree)
100 {
101 if (is_object_node(tree->last)) {
102 DiaObject *o = (DiaObject *)gtk_ctree_node_get_row_data(tree->tree, tree->last);
103 if (o) update_object(tree, tree->last, o);
104 }
105 }
106
107 /* signal handlers */
108 static gint
button_press_callback(GtkCTree * tree,GdkEventButton * event,DiagramTree * dtree)109 button_press_callback(GtkCTree *tree, GdkEventButton *event,
110 DiagramTree *dtree)
111 {
112 gint row = -1;
113 gint column = -1;
114
115 gtk_clist_get_selection_info(GTK_CLIST(tree), event->x, event->y,
116 &row, &column);
117 if (row != -1) dtree->last = gtk_ctree_node_nth(tree, row);
118 else dtree->last = NULL;
119
120 if (dtree->last) update_last_node(dtree);
121
122 /* if doubleclick */
123 if (dtree->last && event->type == GDK_2BUTTON_PRESS) {
124 /* equivalent of "Locate" */
125 select_node(dtree, dtree->last, TRUE);
126 } else if (dtree->last && event->type == GDK_BUTTON_PRESS) {
127 if (event->button == 3) {
128 DiagramTreeMenuType menu = (is_object_node(dtree->last))?
129 DIA_MENU_OBJECT : DIA_MENU_DIAGRAM;
130 diagram_tree_menus_popup_menu(dtree->menus, menu, event->time);
131 } else if (event->button == 1) {
132 select_node(dtree, dtree->last, FALSE);
133 /* need to return FALSE to let gtk process it further */
134 return FALSE;
135 }
136 }
137 return TRUE;
138 }
139
140 /* private functions */
141 static void
sort_objects(DiagramTree * tree,GtkCTreeNode * node)142 sort_objects(DiagramTree *tree, GtkCTreeNode *node)
143 {
144 if (tree->obj_cmp) {
145 GtkCTreeNode *dnode =
146 (is_object_node(node))? GTK_CTREE_ROW(node)->parent : node;
147 gtk_clist_set_compare_func(GTK_CLIST(tree->tree), tree->obj_cmp);
148 gtk_ctree_sort_node(tree->tree, dnode);
149 }
150 }
151
152 static void
sort_diagrams(DiagramTree * tree)153 sort_diagrams(DiagramTree *tree)
154 {
155 if (tree->dia_cmp) {
156 gtk_clist_set_compare_func(GTK_CLIST(tree->tree), tree->dia_cmp);
157 gtk_ctree_sort_node(tree->tree, NULL);
158 }
159 }
160
161 static GList*
get_diagram_objects(Diagram * diagram)162 get_diagram_objects(Diagram *diagram)
163 {
164 GList *result = NULL;
165 GPtrArray *layers = diagram->data->layers;
166 if (layers) {
167 int k = 0;
168 Layer *lay;
169 for (k = 0; k < layers->len; k++) {
170 lay = (Layer *)g_ptr_array_index(layers, k);
171 result = g_list_concat(result, g_list_copy(lay->objects));
172 }
173 }
174 return result;
175 }
176
177 static void
create_object_pixmap(DiaObject * object,GtkWidget * parent,GdkPixmap ** pixmap,GdkBitmap ** mask)178 create_object_pixmap(DiaObject *object, GtkWidget *parent,
179 GdkPixmap **pixmap, GdkBitmap **mask)
180 {
181 GtkStyle *style;
182
183 g_assert(object);
184 g_assert(pixmap);
185 g_assert(mask);
186
187 style = gtk_widget_get_style(parent);
188
189 if (object->type->pixmap != NULL) {
190 if (strncmp((char *)object->type->pixmap, "GdkP", 4) == 0) {
191 GdkPixbuf *p;
192 p = gdk_pixbuf_new_from_inline(-1, (guint8*)object->type->pixmap, TRUE, NULL);
193 gdk_pixbuf_render_pixmap_and_mask_for_colormap(p, gtk_widget_get_colormap(parent), pixmap, mask, 128);
194 g_object_unref (p);
195 } else {
196 *pixmap =
197 gdk_pixmap_colormap_create_from_xpm_d(NULL,
198 gtk_widget_get_colormap(parent),
199 mask,
200 &style->bg[GTK_STATE_NORMAL],
201 object->type->pixmap);
202 }
203 } else if (object->type->pixmap_file != NULL) {
204 *pixmap =
205 gdk_pixmap_colormap_create_from_xpm(NULL,
206 gtk_widget_get_colormap(parent),
207 mask,
208 &style->bg[GTK_STATE_NORMAL],
209 object->type->pixmap_file);
210 } else {
211 *pixmap = NULL;
212 *mask = NULL;
213 }
214 }
215
216 static gchar *
get_object_name(DiaObject * object)217 get_object_name(DiaObject *object)
218 {
219 enum {SIZE = 31};
220 static gchar BUFFER[SIZE];
221
222 gchar *name = object_get_displayname (object);
223 g_snprintf(BUFFER, SIZE, " %s", name);
224 g_free(name);
225
226 return BUFFER;
227 }
228
229 static void
update_object(DiagramTree * tree,GtkCTreeNode * node,DiaObject * object)230 update_object(DiagramTree *tree, GtkCTreeNode *node, DiaObject *object)
231 {
232 char *text = get_object_name(object);
233 char *old = NULL;
234 gtk_ctree_node_get_text(tree->tree, node, 0, &old);
235 if (!old || (text && strcmp(text, old))) {
236 GdkPixmap *pixmap;
237 GdkBitmap *mask;
238 create_object_pixmap(object, GTK_WIDGET(tree->tree), &pixmap, &mask);
239 gtk_ctree_set_node_info(tree->tree, node, text, 3, pixmap, mask,
240 pixmap, mask, TRUE, TRUE);
241 sort_objects(tree, node);
242 }
243 }
244
245 typedef struct _PixmapsAndMasks
246 {
247 GdkPixmap *pixmap;
248 GdkBitmap *mask;
249 } PixmapsAndMasks;
250
251 static GHashTable *_pixmaps_and_masks = NULL;
252
253 static void
create_object_node(DiagramTree * tree,GtkCTreeNode * dnode,DiaObject * obj)254 create_object_node(DiagramTree *tree, GtkCTreeNode *dnode, DiaObject *obj)
255 {
256 gboolean expanded = GTK_CTREE_ROW(dnode)->expanded;
257 char *text[] = {NULL};
258 GdkPixmap *pixmap;
259 GdkBitmap *mask;
260 GtkCTreeNode *node;
261 PixmapsAndMasks *pnm;
262
263 text[0] = get_object_name(obj);
264
265 if (!_pixmaps_and_masks)
266 _pixmaps_and_masks = g_hash_table_new_full(
267 g_str_hash, g_str_equal, NULL, g_free);
268
269 pnm = g_hash_table_lookup (_pixmaps_and_masks, obj->type->name);
270 if (!pnm) {
271 pnm = g_new0 (PixmapsAndMasks, 1);
272 create_object_pixmap(obj, GTK_WIDGET(tree->tree), &pnm->pixmap, &pnm->mask);
273 g_hash_table_insert (_pixmaps_and_masks, obj->type->name, pnm);
274 }
275 node = gtk_ctree_insert_node(tree->tree, dnode, NULL, text, 3,
276 pnm->pixmap ? g_object_ref (pnm->pixmap) : NULL,
277 pnm->mask ? g_object_ref (pnm->mask) : NULL,
278 NULL, NULL, TRUE, FALSE);
279 gtk_ctree_node_set_row_data(tree->tree, node, (gpointer)obj);
280 if (expanded) gtk_ctree_expand(tree->tree, dnode);
281 sort_objects(tree, dnode);
282 }
283
284
285 static void
create_diagram_children(DiagramTree * tree,GtkCTreeNode * node,Diagram * diagram)286 create_diagram_children(DiagramTree *tree, GtkCTreeNode *node,
287 Diagram *diagram)
288 {
289 GList *objects = get_diagram_objects(diagram);
290 GList *org = objects;
291 while (objects) {
292 if (!is_hidden_object(tree, objects->data)) {
293 create_object_node(tree, node, (DiaObject *)objects->data);
294 }
295 objects = g_list_next(objects);
296 }
297 g_list_free(org);
298 }
299
300 static void
update_diagram_children(DiagramTree * tree,GtkCTreeNode * node,Diagram * diagram)301 update_diagram_children(DiagramTree *tree, GtkCTreeNode *node,
302 Diagram *diagram)
303 {
304 GList *dobjects = get_diagram_objects(diagram);
305 GList *org = dobjects;
306 GtkCTreeNode *child = GTK_CTREE_ROW(node)->children;
307 if (dobjects) {
308 while (child) {
309 GtkCTreeNode *current = child;
310 gpointer obj = gtk_ctree_node_get_row_data(tree->tree, current);
311 child = GTK_CTREE_ROW(child)->sibling;
312 if (!g_list_find(dobjects, obj) || is_hidden_object(tree, obj))
313 gtk_ctree_remove_node(tree->tree, current);
314 }
315 }
316 while (dobjects) {
317 if (!is_hidden_object(tree, dobjects->data)
318 && !gtk_ctree_find_by_row_data(tree->tree, node, dobjects->data))
319 create_object_node(tree, node, (DiaObject *)dobjects->data);
320 dobjects = g_list_next(dobjects);
321 }
322 g_list_free(org);
323 sort_objects(tree, node);
324 }
325
326 /* external interface */
327 DiagramTree*
diagram_tree_new(GList * diagrams,GtkWindow * window,DiagramTreeSortType dia_sort,DiagramTreeSortType obj_sort)328 diagram_tree_new(GList *diagrams, GtkWindow *window,
329 DiagramTreeSortType dia_sort,
330 DiagramTreeSortType obj_sort)
331 {
332 GList *tmplist;
333 DiagramTree *result = g_new(DiagramTree, 1);
334 result->tree = GTK_CTREE(gtk_ctree_new(1, 0));
335 result->last = NULL;
336 result->dia_cmp = result->obj_cmp = NULL;
337
338 g_signal_connect(GTK_OBJECT(result->tree),
339 "button_press_event",
340 G_CALLBACK(button_press_callback),
341 (gpointer)result);
342 while (diagrams) {
343 diagram_tree_add(result, (Diagram *)diagrams->data);
344 diagrams = g_list_next(diagrams);
345 }
346 diagram_tree_set_diagram_sort_type(result, dia_sort);
347 diagram_tree_set_object_sort_type(result, obj_sort);
348 result->menus = diagram_tree_menus_new(result, window);
349 /* Set up menu items for the list of hidden types */
350 tmplist = persistent_list_get_glist(HIDDEN_TYPES_NAME);
351 for (; tmplist != NULL; tmplist = g_list_next(tmplist)) {
352 diagram_tree_menus_add_hidden_type(result->menus, tmplist->data);
353 }
354 return result;
355 }
356
357 void
diagram_tree_delete(DiagramTree * tree)358 diagram_tree_delete(DiagramTree *tree)
359 {
360 g_return_if_fail(tree);
361 gtk_widget_destroy(GTK_WIDGET(tree->tree));
362 }
363
364 void
diagram_tree_add(DiagramTree * tree,Diagram * diagram)365 diagram_tree_add(DiagramTree *tree, Diagram *diagram)
366 {
367 if (tree) {
368 if (diagram
369 && !gtk_ctree_find_by_row_data(tree->tree, NULL, (gpointer)diagram))
370 {
371 char *text[] = {(char *)g_basename(diagram->filename)};
372 GtkCTreeNode *node =
373 gtk_ctree_insert_node(tree->tree, NULL, NULL, text, 1,
374 NULL, NULL, NULL, NULL, FALSE, FALSE);
375 gtk_ctree_node_set_row_data(tree->tree, node, (gpointer)diagram);
376 create_diagram_children(tree, node, diagram);
377 sort_diagrams(tree);
378 }
379 }
380 }
381
382 void
diagram_tree_remove(DiagramTree * tree,Diagram * diagram)383 diagram_tree_remove(DiagramTree *tree, Diagram *diagram)
384 {
385 if (tree) {
386 GtkCTreeNode *node;
387 if (diagram
388 && (node = gtk_ctree_find_by_row_data(tree->tree, NULL,
389 (gpointer)diagram)))
390 gtk_ctree_remove_node(tree->tree, node);
391 }
392 }
393
394 void
diagram_tree_update(DiagramTree * tree,Diagram * diagram)395 diagram_tree_update(DiagramTree *tree, Diagram *diagram)
396 {
397 if (tree) {
398 if (diagram_is_modified(diagram)) {
399 GtkCTreeNode *dnode =
400 gtk_ctree_find_by_row_data(tree->tree, NULL, (gpointer)diagram);
401 if (dnode) update_diagram_children(tree, dnode, diagram);
402 else diagram_tree_add(tree, diagram);
403 }
404 }
405 }
406
407 void
diagram_tree_update_all(DiagramTree * tree)408 diagram_tree_update_all(DiagramTree *tree)
409 {
410 if (tree) {
411 GtkCTreeNode *node = gtk_ctree_node_nth(tree->tree, 0);
412 while (node) {
413 Diagram *d = (Diagram *)gtk_ctree_node_get_row_data(tree->tree, node);
414 if (d) update_diagram_children(tree, node, d);
415 node = GTK_CTREE_ROW(node)->sibling;
416 }
417 }
418 }
419
420 void
diagram_tree_update_name(DiagramTree * tree,Diagram * diagram)421 diagram_tree_update_name(DiagramTree *tree, Diagram *diagram)
422 {
423 if (tree) {
424 GtkCTreeNode *node;
425 g_return_if_fail(diagram);
426 node = gtk_ctree_find_by_row_data(tree->tree, NULL, (gpointer)diagram);
427 if (node) {
428 gtk_ctree_node_set_text(tree->tree, node, 0,
429 g_basename(diagram->filename));
430 sort_diagrams(tree);
431 }
432 }
433 }
434
435 void
diagram_tree_add_object(DiagramTree * tree,Diagram * diagram,DiaObject * object)436 diagram_tree_add_object(DiagramTree *tree, Diagram *diagram, DiaObject *object)
437 {
438 if (tree) {
439 g_return_if_fail(diagram);
440 if (object && !is_hidden_object(tree, object)) {
441 GtkCTreeNode *dnode =
442 gtk_ctree_find_by_row_data(tree->tree, NULL, (gpointer)diagram);
443 if (!dnode) diagram_tree_add(tree, diagram);
444 else if (!gtk_ctree_find_by_row_data(tree->tree, dnode, (gpointer)object))
445 create_object_node(tree, dnode, object);
446 }
447 }
448 }
449
450 void
diagram_tree_add_objects(DiagramTree * tree,Diagram * diagram,GList * objects)451 diagram_tree_add_objects(DiagramTree *tree, Diagram *diagram, GList *objects)
452 {
453 if (tree) {
454 g_return_if_fail(diagram);
455 while (objects) {
456 diagram_tree_add_object(tree, diagram, (DiaObject *)objects->data);
457 objects = g_list_next(objects);
458 }
459 }
460 }
461
462
463 void
diagram_tree_remove_object(DiagramTree * tree,DiaObject * object)464 diagram_tree_remove_object(DiagramTree *tree, DiaObject *object)
465 {
466 if (tree) {
467 if (object) {
468 GtkCTreeNode *node =
469 gtk_ctree_find_by_row_data(tree->tree, NULL, (gpointer)object);
470 if (node) gtk_ctree_remove_node(tree->tree, node);
471 }
472 }
473 }
474
475 void
diagram_tree_remove_objects(DiagramTree * tree,GList * objects)476 diagram_tree_remove_objects(DiagramTree *tree, GList *objects)
477 {
478 if (tree) {
479 while (objects) {
480 diagram_tree_remove_object(tree, (DiaObject *)objects->data);
481 objects = g_list_next(objects);
482 }
483 }
484 }
485
486 void
diagram_tree_update_object(DiagramTree * tree,Diagram * diagram,DiaObject * object)487 diagram_tree_update_object(DiagramTree *tree, Diagram *diagram,
488 DiaObject *object)
489 {
490 if (tree) {
491 g_return_if_fail(diagram);
492 if (object) {
493 GtkCTreeNode *node =
494 gtk_ctree_find_by_row_data(tree->tree, NULL,(gpointer)object);
495 if (node) {
496 update_object(tree, node, object);
497 }
498 }
499 }
500 }
501
502 void
diagram_tree_raise(DiagramTree * tree)503 diagram_tree_raise(DiagramTree *tree)
504 {
505 if (tree && tree->last) {
506 select_node(tree, tree->last, TRUE);
507 }
508 }
509
510 void
diagram_tree_show_properties(const DiagramTree * tree)511 diagram_tree_show_properties(const DiagramTree *tree)
512 {
513 if (tree && tree->last && is_object_node(tree->last)) {
514 GtkCTreeNode *parent = GTK_CTREE_ROW(tree->last)->parent;
515 if (parent) {
516 Diagram *dia = (Diagram *)gtk_ctree_node_get_row_data(tree->tree, parent);
517 DiaObject *obj =
518 (DiaObject *)gtk_ctree_node_get_row_data(tree->tree, tree->last);
519 object_properties_show(dia, obj);
520 }
521 }
522 }
523
524 const gchar *
diagram_tree_hide_type(DiagramTree * tree)525 diagram_tree_hide_type(DiagramTree *tree)
526 {
527 if (tree && tree->last && is_object_node(tree->last)) {
528 DiaObject *obj =
529 (DiaObject *)gtk_ctree_node_get_row_data(tree->tree, tree->last);
530 g_assert(!is_hidden_object(tree, obj));
531 diagram_tree_hide_explicit_type(tree, obj->type->name);
532 return obj->type->name;
533 }
534 return NULL;
535 }
536
537 void
diagram_tree_hide_explicit_type(DiagramTree * tree,const gchar * type)538 diagram_tree_hide_explicit_type(DiagramTree *tree, const gchar *type)
539 {
540 if (tree && type) {
541 persistent_list_add(HIDDEN_TYPES_NAME, type);
542 diagram_tree_menus_add_hidden_type(tree->menus, type);
543 diagram_tree_update_all(tree);
544 }
545 }
546
547 void
diagram_tree_unhide_type(DiagramTree * tree,const gchar * type)548 diagram_tree_unhide_type(DiagramTree *tree, const gchar *type)
549 {
550 if (tree && type) {
551 GList *t = is_hidden_type(tree, type);
552 if (t) {
553 persistent_list_remove(HIDDEN_TYPES_NAME, type);
554 diagram_tree_update_all(tree);
555 }
556 }
557 }
558
559 /* sorting functions */
560 static gint
cmp_name_(GtkCList * tree,GtkCListRow * lhm,GtkCListRow * rhm)561 cmp_name_(GtkCList *tree, GtkCListRow *lhm, GtkCListRow *rhm)
562 {
563 int k;
564 gchar *name1 = lhm->cell->u.text;
565 gchar *name2 = rhm->cell->u.text;
566 if (name1 && !name2) k = -1;
567 else if (!name1 && name2) k = 1;
568 else if (!name1 && !name2) k = 0;
569 else k = strcmp(name1, name2);
570 if (k > 0) return 1;
571 if (k < 0) return -1;
572 return 0;
573 }
574
575 static gint
cmp_type_(GtkCList * tree,GtkCListRow * lhm,GtkCListRow * rhm)576 cmp_type_(GtkCList *tree, GtkCListRow *lhm, GtkCListRow *rhm)
577 {
578 int k;
579 DiaObject *o1 = (DiaObject *)lhm->data;
580 DiaObject *o2 = (DiaObject *)rhm->data;
581 k = strcmp(o1->type->name, o2->type->name);
582 if (k > 0) return 1;
583 if (k < 0) return -1;
584 return 0;
585 }
586
587 static GtkCListCompareFunc cmp_funcs_[] = {
588 (GtkCListCompareFunc)cmp_name_,
589 (GtkCListCompareFunc)cmp_type_,
590 NULL
591 };
592
593 void
diagram_tree_sort_objects(DiagramTree * tree,DiagramTreeSortType type)594 diagram_tree_sort_objects(DiagramTree *tree, DiagramTreeSortType type)
595 {
596 if (tree && type <= DIA_TREE_SORT_INSERT && tree->last) {
597 GtkCTreeNode *node = is_object_node(tree->last)?
598 GTK_CTREE_ROW(tree->last)->parent : tree->last;
599 gtk_clist_set_compare_func(GTK_CLIST(tree->tree), cmp_funcs_[type]);
600 gtk_ctree_sort_node(tree->tree, node);
601 }
602 }
603
604 void
diagram_tree_sort_all_objects(DiagramTree * tree,DiagramTreeSortType type)605 diagram_tree_sort_all_objects(DiagramTree *tree, DiagramTreeSortType type)
606 {
607 /* FIXME: should not depend on tree->last != NULL */
608 if (tree && type <= DIA_TREE_SORT_INSERT && tree->last) {
609 GtkCTreeNode *node = is_object_node(tree->last)?
610 GTK_CTREE_ROW(tree->last)->parent : tree->last;
611 while (GTK_CTREE_NODE_PREV(node)) node = GTK_CTREE_NODE_PREV(node);
612 while (node) {
613 gtk_clist_set_compare_func(GTK_CLIST(tree->tree), cmp_funcs_[type]);
614 gtk_ctree_sort_node(tree->tree, node);
615 node = GTK_CTREE_ROW(node)->sibling;
616 }
617 }
618 }
619
620 void
diagram_tree_sort_diagrams(DiagramTree * tree,DiagramTreeSortType type)621 diagram_tree_sort_diagrams(DiagramTree *tree, DiagramTreeSortType type)
622 {
623 if (tree && type <= DIA_TREE_SORT_INSERT && type != DIA_TREE_SORT_TYPE) {
624 gtk_clist_set_compare_func(GTK_CLIST(tree->tree), cmp_funcs_[type]);
625 gtk_ctree_sort_node(tree->tree, NULL);
626 }
627 }
628
629 void
diagram_tree_set_object_sort_type(DiagramTree * tree,DiagramTreeSortType type)630 diagram_tree_set_object_sort_type(DiagramTree *tree, DiagramTreeSortType type)
631 {
632 if (tree && type <= DIA_TREE_SORT_INSERT) {
633 tree->obj_cmp = cmp_funcs_[type];
634 diagram_tree_sort_all_objects(tree, type);
635 }
636 }
637
638 void
diagram_tree_set_diagram_sort_type(DiagramTree * tree,DiagramTreeSortType type)639 diagram_tree_set_diagram_sort_type(DiagramTree *tree, DiagramTreeSortType type)
640 {
641 if (tree && type <= DIA_TREE_SORT_INSERT && type != DIA_TREE_SORT_TYPE) {
642 tree->dia_cmp = cmp_funcs_[type];
643 diagram_tree_sort_diagrams(tree, type);
644 }
645 }
646
647 static DiagramTreeSortType
sort_type_lookup(GtkCListCompareFunc func)648 sort_type_lookup(GtkCListCompareFunc func)
649 {
650 int k;
651 for (k = 0; k <= DIA_TREE_SORT_INSERT; ++k) {
652 if (cmp_funcs_[k] == func) return k;
653 }
654 g_assert_not_reached();
655 return 0;
656 }
657
658 DiagramTreeSortType
diagram_tree_diagram_sort_type(const DiagramTree * tree)659 diagram_tree_diagram_sort_type(const DiagramTree *tree)
660 {
661 if (tree) {
662 return sort_type_lookup(tree->dia_cmp);
663 } else
664 return DIA_TREE_SORT_INSERT;
665 }
666
667
668 DiagramTreeSortType
diagram_tree_object_sort_type(const DiagramTree * tree)669 diagram_tree_object_sort_type(const DiagramTree *tree)
670 {
671 if (tree) {
672 return sort_type_lookup(tree->obj_cmp);
673 } else
674 return DIA_TREE_SORT_INSERT;
675 }
676
677 GtkWidget*
diagram_tree_widget(const DiagramTree * tree)678 diagram_tree_widget(const DiagramTree *tree)
679 {
680 g_return_val_if_fail(tree, NULL);
681 return GTK_WIDGET(tree->tree);
682 }
683