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