1 /*
2 * ===========================
3 * VDK Visual Development Kit
4 * Version 0.5
5 * December 1998
6 * ===========================
7 *
8 * Copyright (C) 1998, Mario Motta
9 * Developed by Mario Motta <mmotta@guest.net>
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24 * 02111-130
25 */
26 #include "vdk/vdkctree.h"
27 #include <cstring>
28 typedef struct { VDKTreeNodeList* list; char* key; } FindInfo;
29
30 static void IterateOnTree(GtkCTree *ctree,
31 GtkCTreeNode *node,
32 gpointer i);
33 /*
34 answer to selection on
35 single selection mode
36 */
NodeSelection(GtkWidget * wid,GtkCTreeNode * node,int column,gpointer s)37 void VDKCustomTree::NodeSelection(GtkWidget* wid,
38 GtkCTreeNode* node,
39 int column,
40 gpointer s)
41 {
42 g_return_if_fail(s != NULL);
43 VDKObjectSignal* signal =
44 reinterpret_cast<VDKObjectSignal*>(s);
45 VDKCustomTree* obj = reinterpret_cast<VDKCustomTree*>(signal->obj);
46 obj->SelectedNode(node);
47 obj->SelectedColumn(column);
48 if(obj->mode != GTK_SELECTION_EXTENDED
49 &&
50 obj->mode != GTK_SELECTION_MULTIPLE
51 )
52 {
53 obj->SignalEmit(signal->signal);
54 obj->SignalEmit("tree_select_row");
55 }
56 #ifdef USE_SIGCPLUSPLUS
57 obj->OnNodeSelect(obj, node, column);
58 #endif /* USE_SIGCPLUSPLUS */
59 }
60 /*
61 answer to unselection on
62 single selection mode
63 */
NodeUnselection(GtkWidget * wid,GtkCTreeNode * node,int column,gpointer s)64 void VDKCustomTree::NodeUnselection(GtkWidget* wid,
65 GtkCTreeNode* node,
66 int column,
67 gpointer s)
68 {
69 g_return_if_fail(s != NULL);
70 VDKObjectSignal* signal =
71 reinterpret_cast<VDKObjectSignal*>(s);
72 VDKCustomTree* obj = reinterpret_cast<VDKCustomTree*>(signal->obj);
73 obj->UnselectedNode(node);
74 obj->UnselectedColumn(column);
75 obj->SelectedNode(NULL);
76 obj->SelectedColumn(-1);
77 if(obj->mode != GTK_SELECTION_EXTENDED
78 &&
79 obj->mode != GTK_SELECTION_MULTIPLE
80 )
81 {
82 obj->SignalEmit(signal->signal);
83 obj->SignalEmit("tree_unselect_row");
84 }
85 #ifdef USE_SIGCPLUSPLUS
86 obj->OnNodeUnselect(obj, node, column);
87 #endif /* USE_SIGCPLUSPLUS */
88 }
89 /*
90 answer to dbl click on extended mode,
91 emits select_node signal
92 */
ButtonPress(GtkWidget * wid,GdkEventButton * ev,gpointer s)93 int VDKCustomTree::ButtonPress (GtkWidget* wid,
94 GdkEventButton *ev,
95 gpointer s)
96 {
97 g_return_val_if_fail(wid != NULL,FALSE);
98 g_return_val_if_fail(ev != NULL,FALSE);
99 g_return_val_if_fail(s != NULL,FALSE);
100 VDKCustomTree* obj = reinterpret_cast<VDKCustomTree*>(s);
101 if(obj->mode != GTK_SELECTION_EXTENDED)
102 return FALSE;
103 int row;
104 int column;
105 VDKTreeNode node;
106 int res;
107 res = gtk_clist_get_selection_info (GTK_CLIST (wid),
108 int(ev->x), int(ev->y),
109 &row, &column);
110 if( (!res) || (ev->type != GDK_2BUTTON_PRESS))
111 return FALSE;
112 node = GTK_CTREE_NODE (g_list_nth (GTK_CLIST (wid)->row_list, row));
113 if(node)
114 {
115 obj->SelectedNode(node);
116 obj->SelectedColumn(column);
117 obj->SignalEmit(select_node_signal);
118 }
119 return FALSE; //TRUE;
120 }
121
122 //////////////////////////////////
123 /*
124 constructor
125 */
VDKCustomTree(VDKForm * owner,int columns,char ** titles,GtkSelectionMode mode,int tree_column)126 VDKCustomTree::VDKCustomTree(VDKForm* owner,
127 int columns,
128 char **titles,
129 GtkSelectionMode mode,
130 int tree_column):
131 VDKCustom(owner,columns,titles,mode),
132 tree_column(tree_column),
133 Spacing("Spacing",this,5,&VDKCustomTree::SetSpacing),
134 SelectedNode("SelectedNode",this,NULL,&VDKCustomTree::SetSelectedNode),
135 SelectedColumn("SelectedColumn",this,-1),
136 UnselectedNode("UnselectedNode",this,NULL,&VDKCustomTree::SetUnselectedNode),
137 UnselectedColumn("UnselectedColumn",this,-1),
138 LineStyle("LineStyle",this,GTK_CTREE_LINES_SOLID,
139 &VDKCustomTree::SetLineStyle),
140 ExpanderStyle("ExpanderStyle",this,GTK_CTREE_EXPANDER_SQUARE,
141 &VDKCustomTree::SetExpanderStyle)
142
143 {
144 if(!titles)
145 sigwid = custom_widget = gtk_ctree_new(columns,tree_column);
146 else
147 sigwid = custom_widget = gtk_ctree_new_with_titles (columns, tree_column, titles);
148 GtkRcStyle *rc_style = gtk_widget_get_modifier_style (custom_widget);
149 GdkFont* font = rc_style ?
150 gdk_font_from_description (rc_style->font_desc): NULL;
151 if(font)
152 {
153 int rh = font->ascent + font->descent+1;
154 RowHeight(rh);
155 }
156 /*
157 int rh = custom_widget->style->font->ascent +
158 custom_widget->style->font->descent+1;
159 RowHeight(rh);
160 */
161 // gtk_clist_set_row_height(GTK_CLIST(custom_widget),rh);
162 gtk_clist_set_selection_mode(GTK_CLIST(custom_widget),mode);
163 gtk_clist_set_shadow_type(GTK_CLIST(custom_widget), GTK_SHADOW_ETCHED_OUT);
164
165 if(titles)
166 {
167 int t;
168 for (t = 0; t < columns; t++)
169 {
170 Titles[t] = new VDKObject(owner,
171 GTK_CLIST(custom_widget)->column[t].button);
172 AddItem(Titles[t]);
173 }
174 }
175 gtk_container_add (GTK_CONTAINER (widget), custom_widget);
176 gtk_widget_show(GTK_WIDGET(custom_widget));
177 ConnectSignals();
178 #ifdef USE_SIGCPLUSPLUS
179 make_gtksigc_connection(this);
180 #endif
181 }
182 /*
183 */
184 void
ConnectSignals()185 VDKCustomTree::ConnectSignals()
186 {
187 // call ancestor
188 VDKCustom::ConnectSignals();
189
190 s_list_select.obj = this;
191 s_list_select.signal = select_node_signal;
192 s_list_unselect.obj = this;
193 s_list_unselect.signal = unselect_node_signal;
194
195 select_connect =
196 gtk_signal_connect( GTK_OBJECT(custom_widget),
197 "tree_select_row",
198 GTK_SIGNAL_FUNC(VDKCustomTree::NodeSelection),
199 (gpointer) &s_list_select);
200 unselect_connect =
201 gtk_signal_connect(GTK_OBJECT(custom_widget),
202 "tree_unselect_row",
203 GTK_SIGNAL_FUNC(VDKCustomTree::NodeUnselection),
204 (gpointer) &s_list_unselect);
205 gtk_signal_connect (GTK_OBJECT (custom_widget),
206 "button_press_event",
207 GTK_SIGNAL_FUNC (VDKCustomTree::ButtonPress),
208 this);
209 // specialized connect to realize signal
210 s_realize.obj = this;
211 s_realize.signal = realize_signal;
212 gtk_signal_connect(GTK_OBJECT(CustomWidget()),"realize",
213 GTK_SIGNAL_FUNC(VDKObject::VDKSignalPipe),
214 (gpointer) &s_realize);
215 }
216
217 /*
218 */
219 void
SetStyle(VDKTreeNode node)220 VDKCustomTree::SetStyle(VDKTreeNode node)
221 {
222 /*
223 GtkStyle *style =
224 gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(custom_widget)));
225 g_return_if_fail(style != NULL);
226 gtk_style_ref(style);
227 if(UnselectedBackground)
228 {
229 GdkColor c = *(*UnselectedBackground);
230 style->base[GTK_STATE_NORMAL] = c;
231 }
232 if(SelectedBackground)
233 style->bg[GTK_STATE_SELECTED] = *(*SelectedBackground);
234 if(UnselectedForeground)
235 {
236 GdkColor c = *(*UnselectedForeground);
237 style->fg[GTK_STATE_NORMAL] = c;
238 }
239 if(SelectedForeground)
240 style->fg[GTK_STATE_SELECTED] = *(*SelectedForeground);
241 gtk_ctree_node_set_row_style (GTK_CTREE (custom_widget), node, style);
242 */
243 }
244
245 /*
246 */
~VDKCustomTree()247 VDKCustomTree::~VDKCustomTree()
248 {
249 }
250 /*
251 add a node to tree,
252 if parent == NULL add a root,
253 otherwise a child
254 */
255 VDKTreeNode
AddNode(char * text[],VDKTreeNode parent,bool expanded,bool isLeaf,char ** pixmap_closed,char ** pixmap_opened)256 VDKCustomTree::AddNode(
257 char *text[],
258 VDKTreeNode parent,
259 bool expanded,
260 bool isLeaf,
261 char **pixmap_closed,
262 char **pixmap_opened)
263 {
264 VDKTreeNode node;
265 GdkBitmap *mask = NULL,*mask1 = NULL;
266 GdkPixmap *pixmap = NULL,*pixmap1 = NULL;
267 GtkStyle* style = gtk_widget_get_style(owner->Window());
268 if(pixmap_closed)
269 pixmap =
270 gdk_pixmap_create_from_xpm_d(owner->Window()->window,
271 &mask,
272 &style->bg[GTK_STATE_NORMAL],
273 pixmap_closed);
274 if(pixmap_opened)
275 pixmap1 =
276 gdk_pixmap_create_from_xpm_d(owner->Window()->window,
277 &mask,
278 &style->bg[GTK_STATE_NORMAL],
279 pixmap_opened);
280
281 node = gtk_ctree_insert_node (GTK_CTREE(custom_widget),
282 parent, NULL,
283 text, Spacing,
284 pixmap, mask,
285 pixmap1, mask1,
286 isLeaf, expanded);
287 // sets row height
288 // unuseful
289 /*
290 if(pixmap || pixmap1)
291 {
292 int w = 0, h = 0;
293 sscanf (pixmap_closed ? pixmap_closed[0] : pixmap_opened[0],
294 "%d %d", &w, &h);
295 printf("\nh:%d",h);
296 fflush(stdout);
297 gtk_clist_set_row_height (GTK_CLIST(custom_widget),h);
298 }
299 */
300 if(node)
301 SetStyle(node);
302 return node;
303 }
304 ////////////////////////////////////////////////////
305 Tuple
operator [](VDKTreeNode node)306 VDKCustomTree::operator[](VDKTreeNode node)
307 {
308 int t;
309 Tuple temp(columns,tree_column);
310 char *text;
311 if(node == NULL)
312 return temp;
313 for(t=0; t < columns;t++)
314 {
315 if (
316 (GTK_CTREE_ROW (node)->row.cell[t].type == GTK_CELL_TEXT)
317 &&
318 (gtk_ctree_node_get_text(GTK_CTREE(custom_widget), node, t, &text))
319 )
320 temp[t] = text;
321 else if (
322 (GTK_CTREE_ROW (node)->row.cell[t].type == GTK_CELL_PIXTEXT)
323 &&
324 (gtk_ctree_node_get_pixtext (GTK_CTREE(custom_widget),
325 node, t,&text,NULL,NULL,NULL))
326 )
327 temp[t] = text;
328 }
329 return temp;
330 }
331
332 /*
333 return an array filled with selected nodes,
334 empty on single selection mode.
335 Tip:
336 array sequence is in a recursive form,
337 */
338 VDKTreeNodeArray&
Selections()339 VDKCustomTree::Selections()
340 {
341 GList* list,*head;
342 int listSize = 0, t;
343 WideSelection = VDKTreeNodeArray(0);
344 if(Size() == 0)
345 return WideSelection;
346 else if(
347 (mode == GTK_SELECTION_EXTENDED)
348 ||
349 (mode == GTK_SELECTION_MULTIPLE)
350 )
351
352 {
353 list = head = GTK_CLIST(custom_widget)->selection;
354 // count list size and goes to tail as well
355 if(head)
356 for(t=0; head; head = head->next,listSize++)
357 ;
358 // load array;
359 WideSelection = VDKTreeNodeArray(listSize);
360 for(t = 0; t < WideSelection.size();t++,list = list->next)
361 WideSelection[t] = (VDKTreeNode) list->data;
362 }
363 return WideSelection;
364 }
365 /*
366 some useful node functions
367 */
368 bool
IsLeaf(VDKTreeNode node)369 VDKCustomTree::IsLeaf(VDKTreeNode node)
370 {
371 int is_leaf;
372 if(node == NULL)
373 return false;
374 else if(gtk_ctree_get_node_info(GTK_CTREE(custom_widget),
375 node,NULL,NULL,NULL,NULL,
376 NULL,NULL,&is_leaf,NULL))
377 return is_leaf == 1;
378 else
379 return false;
380 }
381 /*
382 return node key
383 */
384 char*
Key(VDKTreeNode node)385 VDKCustomTree::Key(VDKTreeNode node)
386 {
387 char* text;
388 if(Size() == 0)
389 return NULL;
390 else if(node == NULL)
391 node = GTK_CTREE_NODE (GTK_CLIST(custom_widget)->row_list);
392 if(gtk_ctree_get_node_info(GTK_CTREE(custom_widget),
393 node,&text,NULL,NULL,NULL, NULL,
394 NULL,NULL,NULL))
395 return text;
396 else
397 return NULL;
398 }
399 /*
400 */
401 bool
IsExpanded(VDKTreeNode node)402 VDKCustomTree::IsExpanded(VDKTreeNode node)
403 {
404 int expanded = 0;
405 if(node == NULL)
406 return false;
407 gtk_ctree_get_node_info(GTK_CTREE(custom_widget),
408 node,NULL,NULL,NULL,NULL, NULL,
409 NULL,NULL,&expanded);
410 return expanded;
411 }
412 /*
413 prunes entire tree
414 */
415 void
Clear()416 VDKCustomTree::Clear()
417 {
418 VDKCustom::Clear();
419 SelectedNode(NULL);
420 UnselectedNode(NULL);
421 }
422 /*
423
424 */
425 bool
RemoveNode(VDKTreeNode node)426 VDKCustomTree::RemoveNode(VDKTreeNode node)
427 {
428 if(gtk_ctree_find(GTK_CTREE(custom_widget),NULL,node) )
429 gtk_ctree_remove_node (GTK_CTREE(custom_widget),node);
430 else
431 return false;
432 if(Size() == 0)
433 {
434 SelectedNode(NULL);
435 UnselectedNode(NULL);
436 }
437 return true;
438 }
439 /*
440 */
441 void
SetSelectedNode(VDKTreeNode node)442 VDKCustomTree::SetSelectedNode(VDKTreeNode node)
443 {
444 if(Size() == 0)
445 return;
446 else if(node == NULL)
447 node = GTK_CTREE_NODE (GTK_CLIST(custom_widget)->row_list);
448 gtk_ctree_select (GTK_CTREE(custom_widget),node);
449 }
450 /*
451 */
452 void
SetUnselectedNode(VDKTreeNode node)453 VDKCustomTree::SetUnselectedNode(VDKTreeNode node)
454 {
455 if(Size() == 0)
456 return;
457 else if(node == NULL)
458 node = GTK_CTREE_NODE (GTK_CLIST(custom_widget)->row_list);
459 gtk_ctree_unselect (GTK_CTREE(custom_widget),node);
460 }
461 /*
462 called by Find(char* key)->gtk_ctree_post_recursive(),
463 if node key matches with key
464 add that node to list
465 */
466 void
IterateOnTree(GtkCTree * ctree,GtkCTreeNode * node,gpointer i)467 IterateOnTree(GtkCTree *ctree,
468 GtkCTreeNode *node,
469 gpointer i)
470 {
471 FindInfo* info = (FindInfo*) i;
472 char *text;
473 int res = gtk_ctree_get_node_info (ctree, node, &text,
474 NULL, NULL, NULL, NULL,NULL,NULL,NULL);
475 if(res && !std::strcmp(text,info->key))
476 info->list->add(node);
477 }
478 /*
479 return a list of nodes that match
480 <key>, user should delete list after use
481 */
482 VDKTreeNodeList*
Find(char * key)483 VDKCustomTree::Find(char* key)
484 {
485
486 VDKTreeNodeList* nodelist = new VDKTreeNodeList;
487 FindInfo info = { nodelist, key };
488 gtk_ctree_post_recursive(GTK_CTREE(custom_widget),
489 NULL, IterateOnTree, (gpointer) &info);
490 return nodelist;
491 }
492
493 /*
494 remove all nodes that match <key>,
495 answer how many nodes has been removed
496 */
497 int
RemoveKey(char * key)498 VDKCustomTree::RemoveKey(char* key)
499 {
500 VDKTreeNodeList* list = Find(key);
501 int size = 0;
502 if( (size = list->size()) > 0)
503 {
504 VDKTreeNodeListIterator li(*list);
505 for(;li;li++)
506 RemoveNode(li.current());
507 }
508 delete list;
509 return size;
510 }
511
512 #ifdef USE_SIGCPLUSPLUS
513 void
make_gtksigc_connection(VDKCustomTree * obj)514 VDKCustomTree::make_gtksigc_connection(VDKCustomTree* obj)
515 {
516 VDKCustom::make_gtksigc_connection(obj);
517 gtk_signal_connect(GTK_OBJECT(obj->CustomWidget()),
518 "tree_move",
519 GTK_SIGNAL_FUNC(&VDKCustomTree::_handle_tree_move),
520 reinterpret_cast<gpointer>(obj));
521 gtk_signal_connect(GTK_OBJECT(obj->CustomWidget()),
522 "tree_expand",
523 GTK_SIGNAL_FUNC(&VDKCustomTree::_handle_tree_expand),
524 reinterpret_cast<gpointer>(obj));
525 }
526
527 void
_handle_tree_move(GtkWidget *,GtkCTreeNode * node,GtkCTreeNode * new_parent,GtkCTreeNode * new_sibling,gpointer gp)528 VDKCustomTree::_handle_tree_move(GtkWidget*, GtkCTreeNode* node,
529 GtkCTreeNode* new_parent,
530 GtkCTreeNode* new_sibling,
531 gpointer gp)
532 {
533 VDKCustomTree* obj=reinterpret_cast<VDKCustomTree*>(gp);
534 obj->OnTreeMove(obj, node, new_parent, new_sibling);
535 }
536
537 void
_handle_tree_expand(GtkWidget *,GtkCTreeNode * node,gpointer gp)538 VDKCustomTree::_handle_tree_expand(GtkWidget*, GtkCTreeNode* node,
539 gpointer gp)
540 {
541 VDKCustomTree* obj=reinterpret_cast<VDKCustomTree*>(gp);
542 obj->OnTreeExpand(obj, node);
543 }
544 #endif
545