1 /*
2 * ===========================
3 * VDK Visual Development Kit
4 * Version 2.0
5 * November 2001
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-1307, USA.
25 */
26 #include <vdk/vdktreeview.h>
27 #include <vdk/colors.h>
28 #include <string.h>
29 #include <stdlib.h>
30 static void col_clicked_cb (GtkTreeViewColumn *col, gpointer data);
31 static void selection_cb (GtkTreeSelection *selection, gpointer *gp);
32 static void row_activated_cb (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column,gpointer *gp);
33
VDKTreeViewModelTuple(int n,int key,VDKUStringCompareFunction less,VDKUStringCompareFunction equal)34 VDKTreeViewModelTuple::VDKTreeViewModelTuple(int n, int key, VDKUStringCompareFunction less,
35 VDKUStringCompareFunction equal) :
36 StringRow(n),
37 KeyIndex("KeyIndex",this,key),
38 Less("Less",this,less),
39 Equal("Equal",this,equal)
40 {
41 }
42
~VDKTreeViewModelTuple()43 VDKTreeViewModelTuple::~VDKTreeViewModelTuple()
44 {
45 }
46
47 int
operator <(VDKTreeViewModelTuple & t)48 VDKTreeViewModelTuple::operator < (VDKTreeViewModelTuple& t)
49 {
50 int key_index = KeyIndex;
51 VDKUStringCompareFunction less = Less;
52 if (less) return less((*this)[key_index],t[key_index]);
53 else return (*this)[key_index] < t[key_index];
54 }
55
56 int
operator ==(VDKTreeViewModelTuple & t)57 VDKTreeViewModelTuple::operator == (VDKTreeViewModelTuple& t)
58 {
59 int key_index = KeyIndex;
60 VDKUStringCompareFunction equal = Equal;
61 if(equal) return equal((*this)[key_index],t[key_index]);
62 else return (*this)[key_index] == t[key_index];
63 }
64
65 /*
66 */
VDKTreeViewModel(GType * types,int ncol)67 VDKTreeViewModel::VDKTreeViewModel(GType* types, int ncol)
68 {
69 model = gtk_tree_store_newv (ncol,types);
70 }
71 /*
72 */
VDKTreeViewModel(GtkTreeModel * tvmodel)73 VDKTreeViewModel::VDKTreeViewModel(GtkTreeModel *tvmodel)
74 {
75 model = GTK_TREE_STORE(tvmodel);
76 }
77 /*
78 */
79 void
AppendBlank(GtkTreeIter * iter,GtkTreeIter * parent)80 VDKTreeViewModel::AppendBlank(GtkTreeIter* iter,GtkTreeIter* parent)
81 {
82 gtk_tree_store_append (GTK_TREE_STORE (model), iter, parent);
83 }
84 /*
85 */
86 void
PrependBlank(GtkTreeIter * iter,GtkTreeIter * parent)87 VDKTreeViewModel::PrependBlank(GtkTreeIter* iter,GtkTreeIter* parent)
88 {
89 gtk_tree_store_prepend (GTK_TREE_STORE (model), iter, parent);
90 }
91 /*
92 */
93 void
InsertTuple(GtkTreeIter * iter,VDKTreeViewModelTuple & tuple,GtkTreeIter * parent,bool recurse)94 VDKTreeViewModel::InsertTuple(GtkTreeIter* iter,VDKTreeViewModelTuple &tuple, GtkTreeIter* parent, bool recurse)
95 {
96 int t = 0;
97 VDKTreeViewModelIterator ti(this,parent);
98 for(;ti;ti++)
99 {
100 VDKTreeViewModelTuple visited_tuple;
101 GetTuple(ti.current(),visited_tuple);
102 // sets key index and compare function in visited tuple
103 int key_index = tuple.KeyIndex;
104 VDKUStringCompareFunction less = tuple.Less;
105 VDKUStringCompareFunction equal = tuple.Equal;
106 visited_tuple.KeyIndex = key_index;
107 visited_tuple.Less = less;
108 visited_tuple.Equal = equal;
109 // insert before greater node
110 if(tuple < visited_tuple)
111 {
112 gtk_tree_store_insert_before (GTK_TREE_STORE(GtkModel()),
113 iter,
114 NULL,
115 ti.current());
116 for(t = 0; t < tuple.size(); t++)
117 SetCell(iter,t,(char*) tuple[t]);
118 return ;
119 }
120 else if(recurse && ti.HasChild())
121 {
122 InsertTuple(iter,tuple, ti.current(),recurse);
123 return;
124 }
125 }
126 // append to last node
127 AppendBlank(iter,parent);
128 for(t = 0; t < tuple.size(); t++)
129 SetCell(iter,t,(char*) tuple[t]);
130 return ;
131 }
132
133 /*
134 */
135 void
Remove(GtkTreeIter * i)136 VDKTreeViewModel::Remove(GtkTreeIter* i)
137 {
138 gtk_tree_store_remove (GTK_TREE_STORE (model), i);
139 return ;
140 }
141 /*
142 */
143 void
Clear()144 VDKTreeViewModel::Clear()
145 {
146 gtk_tree_store_clear(GTK_TREE_STORE (model));
147 }
148 /*
149 */
150 void
SetData(GtkTreeIter * node,...)151 VDKTreeViewModel::SetData(GtkTreeIter* node,...)
152 {
153 va_list ap;
154 va_start(ap,node);
155 gtk_tree_store_set_valist(GTK_TREE_STORE(model),node,ap);
156 va_end(ap);
157 }
158 /*
159 */
~VDKTreeViewModel()160 VDKTreeViewModel::~VDKTreeViewModel()
161 {
162 }
163
164 /*
165 */
166 bool
Root(GtkTreeIter * iter)167 VDKTreeViewModel::Root(GtkTreeIter* iter)
168 {
169 return gtk_tree_model_get_iter_root(GTK_TREE_MODEL(model),iter) ? true : false;
170 }
171 /*
172 */
173 bool
Next(GtkTreeIter * iter)174 VDKTreeViewModel::Next(GtkTreeIter* iter)
175 {
176 return gtk_tree_model_iter_next(GTK_TREE_MODEL(model), iter) ? true : false;
177 }
178
179 bool
Child(GtkTreeIter * iter,GtkTreeIter * parent)180 VDKTreeViewModel::Child(GtkTreeIter* iter,GtkTreeIter* parent)
181 {
182 return gtk_tree_model_iter_children (GTK_TREE_MODEL(model), iter, parent) ? true : false;
183 }
184
185 /*
186 local buffer should be freed by caller if not NULL.
187 */
188
189 char *
GetCell(GtkTreeIter * node,int column)190 VDKTreeViewModel::GetCell(GtkTreeIter* node, int column)
191 {
192 const char* buff;
193 char* local = NULL;
194 GValue value = {0, };
195 gtk_tree_model_get_value (GTK_TREE_MODEL(model), node, column, &value);
196 GType type = gtk_tree_model_get_column_type (GTK_TREE_MODEL(model), column);
197 switch(type)
198 {
199 case G_TYPE_CHAR:
200 {
201 char val = g_value_get_char(&value);
202 local = new char[2];
203 local[0] = val;
204 local[1] = '\0';
205 }
206 break;
207 case G_TYPE_STRING:
208 if ( (buff = g_value_get_string (&value)) )
209 {
210 local = new char[strlen(buff)+1];
211 strcpy(local,buff);
212 }
213 break;
214 case G_TYPE_BOOLEAN:
215 {
216 bool val = g_value_get_boolean (&value);
217 local = new char[8];
218 sprintf(local,"%s",val ? "1" : "0");
219 }
220 break;
221 case G_TYPE_INT:
222 {
223 int val = g_value_get_int(&value);
224 local = new char[32];
225 sprintf(local,"%d",val);
226 }
227 break;
228 case G_TYPE_UINT:
229 {
230 unsigned int val = g_value_get_uint(&value);
231 local = new char[32];
232 sprintf(local,"%u",val);
233 }
234 break;
235 case G_TYPE_LONG:
236 {
237 long val = g_value_get_long(&value);
238 local = new char[32];
239 sprintf(local,"%ld",val);
240 }
241 break;
242 case G_TYPE_ULONG:
243 {
244 unsigned long val = g_value_get_ulong(&value);
245 local = new char[32];
246 sprintf(local,"%lu",val);
247 }
248 break;
249 case G_TYPE_FLOAT:
250 {
251 float val = (float)g_value_get_ulong(&value);
252 local = new char[64];
253 sprintf(local,"%f",val);
254 }
255 break;
256 case G_TYPE_DOUBLE:
257 {
258 double val = g_value_get_double(&value);
259 local = new char[64];
260 sprintf(local,"%f",val);
261 }
262 break;
263 case G_TYPE_POINTER:
264 {
265 void* val = g_value_get_pointer(&value);
266 local = new char[16];
267 sprintf(local,"%p",val);
268 }
269 default:
270 {
271 if( type == GDK_TYPE_PIXBUF)
272 {
273 void* val = g_value_get_pointer(&value);
274 local = new char[16];
275 sprintf(local,"%p",val);
276 }
277 }
278 }
279 g_value_unset (&value);
280 return local;
281 }
282
283 /*
284 */
285 void
SetCell(GtkTreeIter * node,int column,const char * val)286 VDKTreeViewModel::SetCell(GtkTreeIter* node, int column, const char* val)
287 {
288 GValue value = {0, };
289 GType type = gtk_tree_model_get_column_type (GTK_TREE_MODEL(model), column);
290 g_value_init(&value,type);
291 switch(type)
292 {
293 case G_TYPE_CHAR:
294 g_value_set_char (&value,val[0]);
295 break;
296 case G_TYPE_STRING:
297 g_value_set_string (&value,val);
298 break;
299 case G_TYPE_BOOLEAN:
300 if(!strcasecmp("true",val))
301 g_value_set_boolean (&value, 1);
302 else if(!strcasecmp("false",val))
303 g_value_set_boolean (&value, 0);
304 else
305 g_value_set_boolean (&value, atoi(val));
306 break;
307 case G_TYPE_INT:
308 g_value_set_int (&value, atoi(val));
309 break;
310 case G_TYPE_UINT:
311 {
312 unsigned int v = (unsigned int) atoi(val);
313 g_value_set_uint (&value, v);
314 }
315 break;
316 case G_TYPE_LONG:
317 g_value_set_long (&value, atol(val));
318 break;
319 case G_TYPE_ULONG:
320 {
321 unsigned long v = (unsigned long) atol(val);
322 g_value_set_ulong (&value, v);
323 }
324 break;
325 case G_TYPE_FLOAT:
326 g_value_set_float(&value, (gfloat)atof(val));
327 break;
328 case G_TYPE_DOUBLE:
329 {
330 char * endptr;
331 double v = strtod(val,&endptr);
332 g_value_set_double (&value, v);
333 }
334 break;
335 default:
336 g_value_unset (&value);
337 return;
338 }
339 gtk_tree_store_set_value (GTK_TREE_STORE(model),node,column,&value);
340 g_value_unset (&value);
341 }
342
343 /*
344 linear search on tree (depth first)
345 */
346 static GtkTreeIter*
recurse(VDKTreeViewModel * model,int column,char * value,GtkTreeIter * iter)347 recurse(VDKTreeViewModel * model, int column, char* value, GtkTreeIter* iter)
348 {
349 VDKTreeViewModelIterator ti(model,iter);
350 GtkTreeIter * found = NULL;
351 for(;ti;ti++)
352 {
353 char* visited_value = model->GetCell(ti.current(),column);
354 if(visited_value && !strcmp(value,visited_value))
355 {
356 delete[] visited_value;
357 found = ti.current();
358 break;
359 }
360 else if(visited_value)
361 delete[] visited_value;
362 if(ti.HasChild())
363 {
364 found = recurse (model,column,value,ti.current());
365 if(found)
366 break;
367 }
368 }
369 return found;
370 }
371
372 bool
Find(GtkTreeIter * iter,int column,char * value)373 VDKTreeViewModel::Find(GtkTreeIter* iter,int column, char* value)
374 {
375 GtkTreeIter *found_iter = recurse(this,column,value,NULL);
376 if(found_iter)
377 {
378 *iter = *found_iter;
379 return true;
380 }
381 else
382 return false;
383 }
384
385
386 /*
387 */
388 void
GetTuple(GtkTreeIter * node,VDKTreeViewModelTuple & tuple)389 VDKTreeViewModel::GetTuple(GtkTreeIter* node,VDKTreeViewModelTuple& tuple)
390 {
391 int t;
392 char* local;
393 int n_columns = gtk_tree_model_get_n_columns (GTK_TREE_MODEL(model));
394 tuple.resize(n_columns);
395 for(t = 0; t < n_columns; t++)
396 {
397 local = GetCell(node,t);
398 if(local)
399 {
400 tuple[t] = local;
401 delete[] local;
402 }
403 }
404 return ;
405 }
406
407
408 /*
409 VDK_TREE_VIEW_ITERAROR
410 */
411 /*
412 */
VDKTreeViewModelIterator(VDKTreeViewModel * model,GtkTreeIter * parent)413 VDKTreeViewModelIterator::VDKTreeViewModelIterator(VDKTreeViewModel* model,GtkTreeIter* parent):
414 model(model)
415 {
416 if(parent)
417 {
418 if(gtk_tree_model_iter_children (GTK_TREE_MODEL(model->GtkModel()), &iter, parent))
419 internal_iter = &iter;
420 else
421 internal_iter = NULL;
422 }
423 else if(gtk_tree_model_get_iter_root(GTK_TREE_MODEL(model->GtkModel()) ,&iter))
424 internal_iter = &iter;
425 else
426 internal_iter = NULL;
427
428 }
429
430
431 void
operator ++()432 VDKTreeViewModelIterator::operator++()
433 {
434 if(gtk_tree_model_iter_next(GTK_TREE_MODEL(model->GtkModel()), &iter))
435 internal_iter = &iter;
436 else
437 internal_iter = NULL;
438 }
439
440 void
operator ++(int)441 VDKTreeViewModelIterator::operator++(int)
442 {
443 if(gtk_tree_model_iter_next(GTK_TREE_MODEL(model->GtkModel()), &iter))
444 internal_iter = &iter;
445 else
446 internal_iter = NULL;
447 }
448
449 bool
HasChild()450 VDKTreeViewModelIterator::HasChild()
451 {
452 if(internal_iter)
453 {
454 if(gtk_tree_model_iter_has_child (GTK_TREE_MODEL(model->GtkModel()), &iter))
455 return true;
456 }
457 return false;
458 }
459
460
461 /*
462
463 VDKTREEVIEWCOLUMN
464 */
465
466 void
edited_callback(GtkCellRendererText * cell,gchar * path_string,gchar * new_text,gpointer data)467 VDKTreeViewColumn::edited_callback (GtkCellRendererText *cell,
468 gchar *path_string,
469 gchar *new_text,
470 gpointer data)
471 {
472 VDKTreeViewColumn* column = reinterpret_cast<VDKTreeViewColumn*>(data);
473 VDKTreeView* tree = column->Owner();
474 VDKTreeViewModel *model = tree->Model;
475 int t = 0;
476 VDKTreeViewIter iter(model ?
477 GTK_TREE_MODEL(model->GtkModel()) : NULL);
478 tree->Selections().flush();
479 GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
480 gtk_tree_model_get_iter (GTK_TREE_MODEL(model->GtkModel()), &iter, path);
481 tree->Selections().add(iter);
482 VDKTreeViewColumnListIterator li(*tree->Columns());
483 for(;li;li++,t++)
484 if(column == li.current())
485 break;
486 t = t < tree->Columns()->size() ? t : -1;
487 if(t>=0)
488 {
489 tree->ChangedColumn(t);
490 tree->ChangedText(new_text);
491 tree->SignalEmit(cell_edited_signal);
492 tree->SignalEmit("cell_edited_signal");
493 gtk_tree_path_free (path);
494 }
495
496 }
497 /*
498 */
499 void
toggled_callback(GtkCellRendererToggle * cell,gchar * path_string,gpointer data)500 VDKTreeViewColumn::toggled_callback (GtkCellRendererToggle *cell,
501 gchar *path_string,
502 gpointer data)
503 {
504 VDKTreeViewColumn* column = reinterpret_cast<VDKTreeViewColumn*>(data);
505 VDKTreeView* tree = dynamic_cast<VDKTreeView*>(column->Owner());
506 VDKTreeViewModel *model = tree->Model;
507 if(column && tree && model)
508 {
509 int t = 0;
510 VDKTreeViewIter iter(model ?
511 GTK_TREE_MODEL(model->GtkModel()) : NULL);
512 tree->Selections().flush();
513 GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
514 gtk_tree_model_get_iter (GTK_TREE_MODEL(model->GtkModel()), &iter, path);
515 tree->Selections().add(iter);
516 VDKTreeViewColumnListIterator li(*tree->Columns());
517 for(;li;li++,t++)
518 if(column == li.current())
519 break;
520 t = t < tree->Columns()->size() ? t : -1;
521 if(t>=0)
522 {
523 tree->ChangedColumn(t);
524 // gtk_tree_model_get (GTK_TREE_MODEL(model->GtkModel()),
525 // &iter, t, &value, -1);
526 tree->SignalEmit(cell_toggled_signal);
527 tree->SignalEmit("cell_toggled_signal");
528 gtk_tree_path_free (path);
529 }
530 }
531 }
532 /*
533 */
VDKTreeViewColumn(VDKTreeView * owner,int col,char * title,bool editable,int ecol)534 VDKTreeViewColumn::VDKTreeViewColumn(VDKTreeView *owner, int col,
535 char* title, bool editable, int ecol):
536 owner(owner), handler_seq_no(0),
537 NormalBackground("NormalBackground",this,VDKRgb(-1,-1,-1),
538 &VDKTreeViewColumn::SetNormalBackground),
539 Foreground("Foreground",this,VDKRgb(-1,-1,-1),
540 &VDKTreeViewColumn::SetForeground),
541 Font("Font",this,NULL,&VDKTreeViewColumn::SetFont),
542 Title("Title",this,NULL,&VDKTreeViewColumn::SetTitle,&VDKTreeViewColumn::GetTitle),
543 Width("Width",this,0,&VDKTreeViewColumn::SetWidth,&VDKTreeViewColumn::GetWidth),
544 Sortable("Sortable",this,false,&VDKTreeViewColumn::SetSortable)
545 {
546 VDKTreeViewModel* model = owner->Model;
547 // error if no model ..... and/or editable stuff
548 GType type = gtk_tree_model_get_column_type (GTK_TREE_MODEL(model->GtkModel()), col);
549 if( type == GDK_TYPE_PIXBUF)
550 {
551 cell = gtk_cell_renderer_pixbuf_new ();
552 column = gtk_tree_view_column_new_with_attributes (title,cell,"pixbuf",col, (gchar*)NULL);
553 }
554 else
555 {
556 switch(type)
557 {
558 case G_TYPE_STRING:
559 cell = gtk_cell_renderer_text_new ();
560 if(!editable)
561 column = gtk_tree_view_column_new_with_attributes (title,cell,
562 "text",col,(gchar*)NULL);
563 else
564 {
565 column = gtk_tree_view_column_new_with_attributes (title,cell,
566 "text",col,
567 "editable",ecol >= 0 ? ecol : 0,
568 (gchar*)NULL);
569 g_signal_connect_data (G_OBJECT (cell), "edited",
570 G_CALLBACK (VDKTreeViewColumn::edited_callback),
571 this, NULL,(GConnectFlags) 0);
572 }
573 break;
574
575 case G_TYPE_BOOLEAN:
576 cell = gtk_cell_renderer_toggle_new ();
577 /*
578 g_object_set (G_OBJECT (cell),"activatable", TRUE, "radio", FALSE, (gchar*)NULL);
579
580 */
581 column = gtk_tree_view_column_new_with_attributes (title,cell,
582 "active", col,(gchar*)NULL);
583 if(editable)
584 g_signal_connect_data (G_OBJECT (cell), "toggled",
585 G_CALLBACK (VDKTreeViewColumn::toggled_callback),
586 this, NULL,(GConnectFlags) 0);
587 break;
588 default:
589 column = NULL; // ERROR
590 }
591 }
592
593
594 if(column)
595 {
596 if(title)
597 Title = title;
598 SetWidth(0);
599 owner->Columns()->add(this);
600 gtk_tree_view_append_column (GTK_TREE_VIEW (owner->WrappedWidget()), GTK_TREE_VIEW_COLUMN (column));
601 }
602 }
603
604
605 /*
606 */
~VDKTreeViewColumn()607 VDKTreeViewColumn::~VDKTreeViewColumn()
608 {
609 }
610
611 /*
612 */
613 void
ActiveTitle(bool flag)614 VDKTreeViewColumn::ActiveTitle(bool flag)
615 {
616 gtk_tree_view_column_set_clickable (GtkColumn(), flag);
617 if(flag && (handler_seq_no == (gulong) 0))
618 handler_seq_no = g_signal_connect_data (G_OBJECT (GtkColumn()), "clicked",
619 (GCallback) ::col_clicked_cb, owner ,NULL,(GConnectFlags) 0);
620 }
621 /*
622 */
623 void
SetNormalBackground(VDKRgb rgb)624 VDKTreeViewColumn::SetNormalBackground(VDKRgb rgb)
625 {
626 VDKColor *color = NULL;
627 color = new VDKColor( owner->Owner() ,rgb.red, rgb.green, rgb.blue);
628 g_object_set (G_OBJECT (cell),"background-gdk", color->Color(),(gchar*)NULL);
629 }
630 /*
631 */
632 void
SetForeground(VDKRgb rgb)633 VDKTreeViewColumn::SetForeground(VDKRgb rgb)
634 {
635 VDKColor *color = NULL;
636 color = new VDKColor( owner->Owner() ,rgb.red, rgb.green, rgb.blue);
637 g_object_set (G_OBJECT (cell),"foreground-gdk", color->Color(),(gchar*)NULL);
638 }
639
640 /*
641 */
642 void
SetFont(VDKFont * font)643 VDKTreeViewColumn::SetFont(VDKFont* font)
644 {
645 g_object_set (G_OBJECT (cell),"font-desc", font->AsPangoFontDescription(),(gchar*)NULL);
646 }
647 /*
648 */
649 void
SetTitle(const char * title)650 VDKTreeViewColumn::SetTitle(const char* title)
651 {
652 gtk_tree_view_column_set_title (GTK_TREE_VIEW_COLUMN (column),title);
653 }
654 /*
655 */
656 const char*
GetTitle()657 VDKTreeViewColumn::GetTitle()
658 {
659 return gtk_tree_view_column_get_title (GTK_TREE_VIEW_COLUMN (column));
660 }
661 /*
662 */
663 void
SetWidth(int w)664 VDKTreeViewColumn::SetWidth(int w)
665 {
666 if(w > 0)
667 {
668 gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column), GTK_TREE_VIEW_COLUMN_FIXED);
669 gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column),w);
670 }
671 else
672 gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column), GTK_TREE_VIEW_COLUMN_AUTOSIZE);
673 }
674 /*
675 */
676 int
GetWidth()677 VDKTreeViewColumn::GetWidth()
678 {
679 return gtk_tree_view_column_get_width (GTK_TREE_VIEW_COLUMN (column));
680 }
681
682 /*
683 */
684 void
SetSortable(bool flag)685 VDKTreeViewColumn::SetSortable(bool flag )
686 {
687 int t = 0;
688 if(flag)
689 {
690 VDKTreeViewColumnListIterator li(*owner->Columns());
691 for(;li;li++,t++)
692 if(this == li.current())
693 gtk_tree_view_column_set_sort_column_id (GtkColumn(),t);
694 }
695 else
696 gtk_tree_view_column_set_sort_column_id (GtkColumn(),-1);
697 }
698
699 /*
700
701
702 VDKTREEVIEWITERATOR CLASS
703 =========================
704
705 */
706 bool
Child(VDKTreeViewIter * child_iter)707 VDKTreeViewIter::Child(VDKTreeViewIter* child_iter)
708 {
709 if(model && gtk_tree_model_iter_children(model,child_iter,this))
710 {
711 child_iter->Model(model);
712 return true;
713 }
714 else
715 return false;
716 }
717
718 bool
Parent(VDKTreeViewIter * parent_iter)719 VDKTreeViewIter::Parent(VDKTreeViewIter* parent_iter)
720 {
721 if (model && gtk_tree_model_iter_parent (model,parent_iter,this))
722 {
723 parent_iter->Model(model);
724 return true;
725 }
726 else
727 return false;
728 }
729 /*
730
731 VDKTREEVIEW CLASS
732
733 */
734 void
col_clicked_cb(GtkTreeViewColumn * col,gpointer gp)735 col_clicked_cb (GtkTreeViewColumn *col, gpointer gp)
736 {
737 VDKTreeView * tree = reinterpret_cast<VDKTreeView*>(gp);
738 VDKTreeViewColumnListIterator li(*(tree->Columns()));
739 int t = 0;
740 for(;li;li++,t++)
741 {
742 if(li.current()->GtkColumn() == col)
743 {
744 tree->SelectedColumn(t);
745 tree->SignalEmit(click_column_signal);
746 tree->SignalEmit("click_column_signal");
747 return;
748 }
749 }
750 tree->SelectedColumn(-1);
751 }
752
753 void
selection_cb(GtkTreeSelection * selection,gpointer * gp)754 selection_cb (GtkTreeSelection *selection,
755 gpointer *gp)
756 {
757 VDKTreeView* tree = reinterpret_cast<VDKTreeView*>(gp);
758 VDKTreeViewModel *model = tree->Model;
759 VDKTreeViewIter iter(model ? GTK_TREE_MODEL(model->GtkModel()) : NULL);
760 tree->Selections().flush();
761 if (!gtk_tree_selection_get_selected (selection, NULL,&iter))
762 return;
763 else
764 {
765 tree->Selections().add(iter);
766 tree->SignalEmit(select_row_signal);
767 tree->SignalEmit("select_row_signal");
768 }
769 }
770
771
772 static
visit_selection(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer gp)773 void visit_selection (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer gp)
774 {
775 VDKTreeViewIter i(model);
776 VDKTreeView* tree = reinterpret_cast<VDKTreeView*>(gp);
777 // gtk_tree_model_get_iter (model, &i, path);
778 /*
779 uhmmm...
780 using GtkTreeIter private data could not be a good idea on compatibility side,
781 in other hand i suspect a O(n2) time using gtk_tree_model_get_iter()
782 */
783 i.stamp = iter->stamp;
784 i.user_data = iter->user_data;
785 i.user_data2 = iter->user_data2;
786 i.user_data3 = iter->user_data3;
787 tree->Selections().add(i);
788 }
789
790
791 void
row_activated_cb(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer * gp)792 row_activated_cb (GtkTreeView *tree_view,
793 GtkTreePath *path,
794 GtkTreeViewColumn *column,
795 gpointer *gp)
796 {
797 VDKTreeView* tree = reinterpret_cast<VDKTreeView*>(gp);
798 tree->SignalEmit(row_activated_signal);
799 tree->SignalEmit("row_activated_signal");
800 }
801
802
803 void
GetSelections()804 VDKTreeView::GetSelections()
805 {
806 Selections().flush();
807 gtk_tree_selection_selected_foreach(selection, visit_selection, this);
808 }
809
810 /*
811 */
VDKTreeView(VDKForm * owner,VDKTreeViewModel * model,GtkSelectionMode mode)812 VDKTreeView::VDKTreeView(VDKForm* owner, VDKTreeViewModel* model, GtkSelectionMode mode):
813 VDKObject(owner),
814 ActiveSearch("ActiveSearch", this, false,
815 &VDKTreeView::SetActiveSearch, &VDKTreeView::GetActiveSearch),
816 SearchColumn("SearchColumn", this, -1,
817 &VDKTreeView::SetSearchColumn, &VDKTreeView::GetSearchColumn),
818 SearchEqualFunc("SearchEqualFunc", this, ::SearchTVDefaultEqualFunc,
819 &VDKTreeView::SetSearchEqualFunc, &VDKTreeView::GetSearchEqualFunc),
820 Model("Model",this, NULL, &VDKTreeView::SetModel, NULL),
821 SelectedColumn("SelectedColumn", this, -1),
822 ChangedColumn("ChangedColumn", this, -1),
823 ChangedText("ChangedText", this, NULL)
824 {
825 if(model)
826 {
827 widget = sigwid = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model->GtkModel()));
828 Model(model);
829 }
830 else
831 widget = sigwid = gtk_tree_view_new ();
832 ConnectDefaultSignals();
833 gtk_tree_selection_set_mode (GTK_TREE_SELECTION (gtk_tree_view_get_selection (GTK_TREE_VIEW (sigwid))),mode);
834 //
835 columns = new VDKTreeViewColumnList;
836 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sigwid));
837 switch(mode)
838 {
839 case GTK_SELECTION_SINGLE:
840 case GTK_SELECTION_BROWSE:
841 g_signal_connect_data(selection, "changed",
842 G_CALLBACK (selection_cb), this,
843 NULL,(GConnectFlags) 0);
844 g_signal_connect_data (sigwid, "row_activated",
845 G_CALLBACK (row_activated_cb), this,
846 NULL,(GConnectFlags) 0);
847 break;
848 case GTK_SELECTION_MULTIPLE:
849 g_signal_connect_data (sigwid, "row_activated", G_CALLBACK (row_activated_cb), this, NULL,(GConnectFlags) 0);
850 break;
851 case GTK_SELECTION_NONE:
852 break;
853 }
854 SetSearchColumn(-1);
855 }
856 /*
857 */
~VDKTreeView()858 VDKTreeView::~VDKTreeView()
859 {
860 VDKTreeViewModel *model = Model;
861 if(model)
862 delete model;
863 delete columns;
864 }
865
866 /*
867 */
868 void
SetModel(VDKTreeViewModel * mod)869 VDKTreeView::SetModel(VDKTreeViewModel* mod)
870 {
871 VDKTreeViewModel *old = Model;
872 gtk_tree_view_set_model (GTK_TREE_VIEW(widget),GTK_TREE_MODEL (mod->GtkModel()));
873 if(old)
874 {
875 delete old;
876 }
877 }
878
879 /*
880 */
881 void
SelectNode(GtkTreeIter * iter)882 VDKTreeView::SelectNode(GtkTreeIter* iter)
883 {
884 if(iter)
885 gtk_tree_selection_select_iter (selection,iter);
886 }
887 /*
888 */
889 void
UnselectNode(GtkTreeIter * iter)890 VDKTreeView::UnselectNode(GtkTreeIter* iter)
891 {
892 if(iter)
893 gtk_tree_selection_unselect_iter (selection,iter);
894 }
895 /*
896 */
897 void
Expand(GtkTreeIter * iter,bool expand_all)898 VDKTreeView::Expand(GtkTreeIter* iter, bool expand_all)
899 {
900 if(!iter)
901 gtk_tree_view_expand_all(GTK_TREE_VIEW(sigwid));
902 else
903 {
904 VDKTreeViewModel *model = Model;
905 GtkTreePath* path = gtk_tree_model_get_path (GTK_TREE_MODEL(model->GtkModel()),iter);
906 if(path)
907 {
908 gtk_tree_view_expand_row (GTK_TREE_VIEW(sigwid),path,expand_all);
909 gtk_tree_path_free(path);
910 }
911 }
912 }
913 /*
914 */
915 void
RemoveSelected(void)916 VDKTreeView::RemoveSelected(void)
917 {
918 GetSelections();
919 VDKTreeViewModel* model = Model;
920 VDKTreeViewIterListIterator li(Selections());
921 for(li.last();li;li--)
922 model->Remove(&li.current());
923 Selections().flush();
924 }
925 /*
926 */
927 void
SetSearchColumn(int colnum)928 VDKTreeView::SetSearchColumn(int colnum)
929 {
930 if (colnum < -1) colnum = -1;
931 if (colnum >= 0) SetActiveSearch(true);
932 else SetActiveSearch(false);
933 gtk_tree_view_set_search_column(GTK_TREE_VIEW(widget), colnum);
934 }
935
936 // This function is used for default interactive search
937 gboolean
SearchTVDefaultEqualFunc(GtkTreeModel * model,gint column,const gchar * key,GtkTreeIter * iter,gpointer search_data)938 SearchTVDefaultEqualFunc(GtkTreeModel *model, gint column, const gchar *key,
939 GtkTreeIter *iter, gpointer search_data)
940 {
941 gboolean result;
942
943 VDKTreeViewModel tvmodel(model);
944 char *local = tvmodel.GetCell(iter, column);
945 if (!local) return true;
946 result = (strstr(local, key) == NULL);
947 delete[] local;
948 return result;
949 }
950 /*
951 */
952 void
SetSearchEqualFunc(GtkTreeViewSearchEqualFunc func)953 VDKTreeView::SetSearchEqualFunc(GtkTreeViewSearchEqualFunc func)
954 {
955 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(widget), func, NULL, NULL);
956 }
957 /*
958 */
959 void
SetBackground(VDKRgb rgb,GtkStateType state)960 VDKTreeView::SetBackground(VDKRgb rgb, GtkStateType state)
961 {
962 VDKColor *color = new VDKColor(Owner(),rgb.red,rgb.green,rgb.blue);
963 gtk_widget_modify_base (widget, state, color->Color());
964 }
965
966
967