1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/dataview.cpp
3 // Purpose:     wxDataViewCtrl GTK+2 implementation
4 // Author:      Robert Roebling
5 // Id:          $Id: dataview.cpp 44701 2007-03-09 16:25:07Z VZ $
6 // Copyright:   (c) 1998 Robert Roebling
7 // Licence:     wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9 
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12 
13 #if wxUSE_DATAVIEWCTRL
14 
15 #include "wx/dataview.h"
16 
17 #ifndef wxUSE_GENERICDATAVIEWCTRL
18 
19 #ifndef WX_PRECOMP
20     #include "wx/log.h"
21     #include "wx/dcclient.h"
22     #include "wx/sizer.h"
23 #endif
24 
25 #include "wx/stockitem.h"
26 #include "wx/calctrl.h"
27 #include "wx/popupwin.h"
28 #include "wx/icon.h"
29 
30 
31 #include "wx/gtk/private.h"
32 #include "wx/gtk/win_gtk.h"
33 
34 #include <gobject/gvaluecollector.h>
35 #include <gtk/gtktreemodel.h>
36 #include <gtk/gtktreednd.h>
37 
38 #include <gdk/gdkkeysyms.h>
39 
40 //-----------------------------------------------------------------------------
41 // classes
42 //-----------------------------------------------------------------------------
43 
44 class wxDataViewCtrl;
45 
46 //-----------------------------------------------------------------------------
47 // data
48 //-----------------------------------------------------------------------------
49 
50 extern bool   g_blockEventsOnDrag;
51 
52 //-----------------------------------------------------------------------------
53 // define new GTK+ class wxGtkListStore
54 //-----------------------------------------------------------------------------
55 
56 extern "C" {
57 
58 #define GTK_TYPE_WX_LIST_STORE               (gtk_wx_list_store_get_type ())
59 #define GTK_WX_LIST_STORE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_LIST_STORE, GtkWxListStore))
60 #define GTK_WX_LIST_STORE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_LIST_STORE, GtkWxListStoreClass))
61 #define GTK_IS_WX_LIST_STORE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_LIST_STORE))
62 #define GTK_IS_WX_LIST_STORE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_LIST_STORE))
63 #define GTK_WX_LIST_STORE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_LIST_STORE, GtkWxListStoreClass))
64 
65 GType         gtk_wx_list_store_get_type         (void);
66 
67 typedef struct _GtkWxListStore       GtkWxListStore;
68 typedef struct _GtkWxListStoreClass  GtkWxListStoreClass;
69 
70 struct _GtkWxListStore
71 {
72   GObject parent;
73 
74   /*< private >*/
75   gint stamp;
76   wxDataViewListModel *model;
77 };
78 
79 struct _GtkWxListStoreClass
80 {
81   GObjectClass list_parent_class;
82 };
83 
84 static GtkWxListStore *wxgtk_list_store_new          (void);
85 static void         wxgtk_list_store_init            (GtkWxListStore      *list_store);
86 static void         wxgtk_list_store_class_init      (GtkWxListStoreClass *klass);
87 static void         wxgtk_list_store_tree_model_init (GtkTreeModelIface *iface);
88 static void         wxgtk_list_store_finalize        (GObject           *object);
89 static GtkTreeModelFlags wxgtk_list_store_get_flags  (GtkTreeModel      *tree_model);
90 static gint         wxgtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
91 static GType        wxgtk_list_store_get_column_type (GtkTreeModel      *tree_model,
92                                                       gint               index);
93 static gboolean     wxgtk_list_store_get_iter        (GtkTreeModel      *tree_model,
94                                                       GtkTreeIter       *iter,
95                                                       GtkTreePath       *path);
96 static GtkTreePath *wxgtk_list_store_get_path        (GtkTreeModel      *tree_model,
97                                                       GtkTreeIter       *iter);
98 static void         wxgtk_list_store_get_value       (GtkTreeModel      *tree_model,
99                                                       GtkTreeIter       *iter,
100                                                       gint               column,
101                                                       GValue            *value);
102 static gboolean     wxgtk_list_store_iter_next       (GtkTreeModel      *tree_model,
103                                                       GtkTreeIter       *iter);
104 static gboolean     wxgtk_list_store_iter_children   (GtkTreeModel      *tree_model,
105                                                       GtkTreeIter       *iter,
106                                                       GtkTreeIter       *parent);
107 static gboolean     wxgtk_list_store_iter_has_child  (GtkTreeModel      *tree_model,
108                                                       GtkTreeIter       *iter);
109 static gint         wxgtk_list_store_iter_n_children (GtkTreeModel      *tree_model,
110                                                       GtkTreeIter       *iter);
111 static gboolean     wxgtk_list_store_iter_nth_child  (GtkTreeModel      *tree_model,
112                                                       GtkTreeIter       *iter,
113                                                       GtkTreeIter       *parent,
114                                                       gint               n);
115 static gboolean     wxgtk_list_store_iter_parent     (GtkTreeModel      *tree_model,
116                                                       GtkTreeIter       *iter,
117                                                       GtkTreeIter       *child);
118 
119 static GObjectClass *list_parent_class = NULL;
120 
121 GType
gtk_wx_list_store_get_type(void)122 gtk_wx_list_store_get_type (void)
123 {
124     static GType list_store_type = 0;
125 
126     if (!list_store_type)
127     {
128         static const GTypeInfo list_store_info =
129         {
130             sizeof (GtkWxListStoreClass),
131             NULL,   /* base_init */
132             NULL,   /* base_finalize */
133             (GClassInitFunc) wxgtk_list_store_class_init,
134             NULL,   /* class_finalize */
135             NULL,   /* class_data */
136             sizeof (GtkWxListStore),
137             0,
138             (GInstanceInitFunc) wxgtk_list_store_init,
139         };
140 
141       static const GInterfaceInfo tree_model_info =
142       {
143           (GInterfaceInitFunc) wxgtk_list_store_tree_model_init,
144           NULL,
145           NULL
146       };
147 
148       list_store_type = g_type_register_static (G_TYPE_OBJECT, "GtkWxListStore",
149                                                 &list_store_info, (GTypeFlags)0 );
150 
151       g_type_add_interface_static (list_store_type,
152                                    GTK_TYPE_TREE_MODEL,
153                                    &tree_model_info);
154     }
155 
156   return list_store_type;
157 }
158 
159 static GtkWxListStore *
wxgtk_list_store_new(void)160 wxgtk_list_store_new(void)
161 {
162     GtkWxListStore *retval = (GtkWxListStore *) g_object_new (GTK_TYPE_WX_LIST_STORE, NULL);
163     return retval;
164 }
165 
166 static void
wxgtk_list_store_class_init(GtkWxListStoreClass * klass)167 wxgtk_list_store_class_init (GtkWxListStoreClass *klass)
168 {
169     list_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
170     GObjectClass *object_class = (GObjectClass*) klass;
171     object_class->finalize = wxgtk_list_store_finalize;
172 }
173 
174 static void
wxgtk_list_store_tree_model_init(GtkTreeModelIface * iface)175 wxgtk_list_store_tree_model_init (GtkTreeModelIface *iface)
176 {
177     iface->get_flags = wxgtk_list_store_get_flags;
178     iface->get_n_columns = wxgtk_list_store_get_n_columns;
179     iface->get_column_type = wxgtk_list_store_get_column_type;
180     iface->get_iter = wxgtk_list_store_get_iter;
181     iface->get_path = wxgtk_list_store_get_path;
182     iface->get_value = wxgtk_list_store_get_value;
183     iface->iter_next = wxgtk_list_store_iter_next;
184     iface->iter_children = wxgtk_list_store_iter_children;
185     iface->iter_has_child = wxgtk_list_store_iter_has_child;
186     iface->iter_n_children = wxgtk_list_store_iter_n_children;
187     iface->iter_nth_child = wxgtk_list_store_iter_nth_child;
188     iface->iter_parent = wxgtk_list_store_iter_parent;
189 }
190 
191 static void
wxgtk_list_store_init(GtkWxListStore * list_store)192 wxgtk_list_store_init (GtkWxListStore *list_store)
193 {
194     list_store->model = NULL;
195     list_store->stamp = g_random_int();
196 }
197 
198 static void
wxgtk_list_store_finalize(GObject * object)199 wxgtk_list_store_finalize (GObject *object)
200 {
201     /* GtkWxListStore *list_store = GTK_WX_LIST_STORE (object); */
202 
203     /* we need to sort out, which class deletes what */
204     /* delete list_store->model; */
205 
206     /* must chain up */
207     (* list_parent_class->finalize) (object);
208 }
209 
210 } // extern "C"
211 
212 //-----------------------------------------------------------------------------
213 // implement callbacks from wxGtkListStore class by letting
214 // them call the methods of wxWidgets' wxDataViewListModel
215 //-----------------------------------------------------------------------------
216 
217 static GtkTreeModelFlags
wxgtk_list_store_get_flags(GtkTreeModel * tree_model)218 wxgtk_list_store_get_flags (GtkTreeModel *tree_model)
219 {
220     g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), (GtkTreeModelFlags)0 );
221 
222     // GTK+ list store uses a linked list for storing the
223     // items and a pointer to a child is used as the member
224     // field of a GtkTreeIter. This means that the iter is
225     // valid in the GtkListStore as long as the child exists.
226     // We use the index of the row and since the index of a
227     // specific row will change if a row above is deleted,
228     // the iter does not persist
229     return /* GTK_TREE_MODEL_ITERS_PERSIST | */ GTK_TREE_MODEL_LIST_ONLY;
230 }
231 
232 static gint
wxgtk_list_store_get_n_columns(GtkTreeModel * tree_model)233 wxgtk_list_store_get_n_columns (GtkTreeModel *tree_model)
234 {
235     GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
236     g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), 0);
237 
238     return list_store->model->GetNumberOfCols();
239 }
240 
241 static GType
wxgtk_list_store_get_column_type(GtkTreeModel * tree_model,gint index)242 wxgtk_list_store_get_column_type (GtkTreeModel *tree_model,
243                                   gint          index)
244 {
245     GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
246     g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), G_TYPE_INVALID);
247 
248     GType gtype = G_TYPE_INVALID;
249 
250     wxString wxtype = list_store->model->GetColType( (unsigned int) index );
251 
252     if (wxtype == wxT("string"))
253         gtype = G_TYPE_STRING;
254     else
255     {
256         wxFAIL_MSG( _T("non-string columns not supported yet") );
257     }
258 
259     return gtype;
260 }
261 
262 static gboolean
wxgtk_list_store_get_iter(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreePath * path)263 wxgtk_list_store_get_iter (GtkTreeModel *tree_model,
264                            GtkTreeIter  *iter,
265                            GtkTreePath  *path)
266 {
267     GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
268     g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
269     g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
270 
271     unsigned int i = (unsigned int)gtk_tree_path_get_indices (path)[0];
272 
273     if (i >= list_store->model->GetNumberOfRows())
274         return FALSE;
275 
276     iter->stamp = list_store->stamp;
277     // user_data is just the index
278     iter->user_data = (gpointer) i;
279 
280     return TRUE;
281 }
282 
283 static GtkTreePath *
wxgtk_list_store_get_path(GtkTreeModel * tree_model,GtkTreeIter * iter)284 wxgtk_list_store_get_path (GtkTreeModel *tree_model,
285                            GtkTreeIter  *iter)
286 {
287     g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), NULL);
288     g_return_val_if_fail (iter->stamp == GTK_WX_LIST_STORE (tree_model)->stamp, NULL);
289 
290     GtkTreePath *retval = gtk_tree_path_new ();
291     // user_data is just the index
292     int i = (wxUIntPtr) iter->user_data;
293     gtk_tree_path_append_index (retval, i);
294     return retval;
295 }
296 
297 static void
wxgtk_list_store_get_value(GtkTreeModel * tree_model,GtkTreeIter * iter,gint column,GValue * value)298 wxgtk_list_store_get_value (GtkTreeModel *tree_model,
299                             GtkTreeIter  *iter,
300                             gint          column,
301                             GValue       *value)
302 {
303     GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
304     g_return_if_fail (GTK_IS_WX_LIST_STORE (tree_model) );
305 
306     wxDataViewListModel *model = list_store->model;
307     wxString mtype = model->GetColType( (unsigned int) column );
308     if (mtype == wxT("string"))
309     {
310         wxVariant variant;
311         g_value_init( value, G_TYPE_STRING );
312         model->GetValue( variant,
313                          (unsigned int) column,
314                          (unsigned int) iter->user_data );
315 
316         // FIXME: we should support different encodings here
317         g_value_set_string( value, wxGTK_CONV_SYS(variant.GetString()) );
318     }
319     else
320     {
321         wxFAIL_MSG( _T("non-string columns not supported yet") );
322     }
323 }
324 
325 static gboolean
wxgtk_list_store_iter_next(GtkTreeModel * tree_model,GtkTreeIter * iter)326 wxgtk_list_store_iter_next (GtkTreeModel  *tree_model,
327                             GtkTreeIter   *iter)
328 {
329     g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
330     GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
331 
332     g_return_val_if_fail (list_store->stamp == iter->stamp, FALSE);
333 
334     int n = (wxUIntPtr) iter->user_data;
335 
336     if (n == -1)
337         return FALSE;
338 
339     if (n >= (int) list_store->model->GetNumberOfRows()-1)
340         return FALSE;
341 
342     iter->user_data = (gpointer) ++n;
343 
344     return TRUE;
345 }
346 
347 static gboolean
wxgtk_list_store_iter_children(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent)348 wxgtk_list_store_iter_children (GtkTreeModel *tree_model,
349                                 GtkTreeIter  *iter,
350                                 GtkTreeIter  *parent)
351 {
352     g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
353     GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
354 
355     // this is a list, nodes have no children
356     if (parent)
357         return FALSE;
358 
359     iter->stamp = list_store->stamp;
360     iter->user_data = (gpointer) -1;
361 
362     return TRUE;
363 }
364 
365 static gboolean
wxgtk_list_store_iter_has_child(GtkTreeModel * tree_model,GtkTreeIter * iter)366 wxgtk_list_store_iter_has_child (GtkTreeModel *tree_model,
367                                  GtkTreeIter  *iter)
368 {
369     return FALSE;
370 }
371 
372 static gint
wxgtk_list_store_iter_n_children(GtkTreeModel * tree_model,GtkTreeIter * iter)373 wxgtk_list_store_iter_n_children (GtkTreeModel *tree_model,
374                                   GtkTreeIter  *iter)
375 {
376     g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), -1);
377     GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
378 
379     if (iter == NULL)
380         return (gint) list_store->model->GetNumberOfRows();
381 
382     g_return_val_if_fail (list_store->stamp == iter->stamp, -1);
383 
384     return 0;
385 }
386 
387 static gboolean
wxgtk_list_store_iter_nth_child(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent,gint n)388 wxgtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
389                                  GtkTreeIter  *iter,
390                                  GtkTreeIter  *parent,
391                                  gint          n)
392 {
393     g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
394     GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
395 
396     if (parent)
397         return FALSE;
398 
399     if (n < 0)
400         return FALSE;
401 
402     if (n >= (gint) list_store->model->GetNumberOfRows())
403         return FALSE;
404 
405     iter->stamp = list_store->stamp;
406     iter->user_data = (gpointer) n;
407 
408     return TRUE;
409 }
410 
411 static gboolean
wxgtk_list_store_iter_parent(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * child)412 wxgtk_list_store_iter_parent (GtkTreeModel *tree_model,
413                               GtkTreeIter  *iter,
414                               GtkTreeIter  *child)
415 {
416     return FALSE;
417 }
418 
419 //-----------------------------------------------------------------------------
420 // define new GTK+ class wxGtkRendererRenderer
421 //-----------------------------------------------------------------------------
422 
423 extern "C" {
424 
425 #define GTK_TYPE_WX_CELL_RENDERER               (gtk_wx_cell_renderer_get_type ())
426 #define GTK_WX_CELL_RENDERER(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRenderer))
427 #define GTK_WX_CELL_RENDERER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
428 #define GTK_IS_WX_CELL_RENDERER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_CELL_RENDERER))
429 #define GTK_IS_WX_CELL_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_CELL_RENDERER))
430 #define GTK_WX_CELL_RENDERER_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
431 
432 GType            gtk_wx_cell_renderer_get_type (void);
433 
434 typedef struct _GtkWxCellRenderer GtkWxCellRenderer;
435 typedef struct _GtkWxCellRendererClass GtkWxCellRendererClass;
436 
437 struct _GtkWxCellRenderer
438 {
439   GtkCellRenderer parent;
440 
441   /*< private >*/
442   wxDataViewCustomRenderer *cell;
443   guint32 last_click;
444 };
445 
446 struct _GtkWxCellRendererClass
447 {
448   GtkCellRendererClass cell_parent_class;
449 };
450 
451 
452 static GtkCellRenderer *gtk_wx_cell_renderer_new   (void);
453 static void gtk_wx_cell_renderer_init (
454                         GtkWxCellRenderer      *cell );
455 static void gtk_wx_cell_renderer_class_init(
456                         GtkWxCellRendererClass *klass );
457 static void gtk_wx_cell_renderer_finalize (
458                         GObject                *object );
459 static void gtk_wx_cell_renderer_get_size (
460                         GtkCellRenderer         *cell,
461                         GtkWidget               *widget,
462                         GdkRectangle            *rectangle,
463                         gint                    *x_offset,
464                         gint                    *y_offset,
465                         gint                    *width,
466                         gint                    *height );
467 static void gtk_wx_cell_renderer_render (
468                         GtkCellRenderer         *cell,
469                         GdkWindow               *window,
470                         GtkWidget               *widget,
471                         GdkRectangle            *background_area,
472                         GdkRectangle            *cell_area,
473                         GdkRectangle            *expose_area,
474                         GtkCellRendererState     flags );
475 static gboolean gtk_wx_cell_renderer_activate(
476                         GtkCellRenderer         *cell,
477                         GdkEvent                *event,
478                         GtkWidget               *widget,
479                         const gchar             *path,
480                         GdkRectangle            *background_area,
481                         GdkRectangle            *cell_area,
482                         GtkCellRendererState     flags );
483 
484 static GObjectClass *cell_parent_class = NULL;
485 
486 }  // extern "C"
487 
488 GType
gtk_wx_cell_renderer_get_type(void)489 gtk_wx_cell_renderer_get_type (void)
490 {
491     static GType cell_wx_type = 0;
492 
493     if (!cell_wx_type)
494     {
495         static const GTypeInfo cell_wx_info =
496         {
497             sizeof (GtkWxCellRendererClass),
498             NULL, /* base_init */
499             NULL, /* base_finalize */
500             (GClassInitFunc) gtk_wx_cell_renderer_class_init,
501             NULL, /* class_finalize */
502             NULL, /* class_data */
503             sizeof (GtkWxCellRenderer),
504             0,          /* n_preallocs */
505             (GInstanceInitFunc) gtk_wx_cell_renderer_init,
506         };
507 
508         cell_wx_type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
509             "GtkWxCellRenderer", &cell_wx_info, (GTypeFlags)0 );
510     }
511 
512     return cell_wx_type;
513 }
514 
515 static void
gtk_wx_cell_renderer_init(GtkWxCellRenderer * cell)516 gtk_wx_cell_renderer_init (GtkWxCellRenderer *cell)
517 {
518     cell->cell = NULL;
519     cell->last_click = 0;
520 }
521 
522 static void
gtk_wx_cell_renderer_class_init(GtkWxCellRendererClass * klass)523 gtk_wx_cell_renderer_class_init (GtkWxCellRendererClass *klass)
524 {
525     GObjectClass *object_class = G_OBJECT_CLASS (klass);
526     GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
527 
528     cell_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
529 
530     object_class->finalize = gtk_wx_cell_renderer_finalize;
531 
532     cell_class->get_size = gtk_wx_cell_renderer_get_size;
533     cell_class->render = gtk_wx_cell_renderer_render;
534     cell_class->activate = gtk_wx_cell_renderer_activate;
535 }
536 
537 static void
gtk_wx_cell_renderer_finalize(GObject * object)538 gtk_wx_cell_renderer_finalize (GObject *object)
539 {
540     /* must chain up */
541     (* G_OBJECT_CLASS (cell_parent_class)->finalize) (object);
542 }
543 
544 GtkCellRenderer*
gtk_wx_cell_renderer_new(void)545 gtk_wx_cell_renderer_new (void)
546 {
547     return (GtkCellRenderer*) g_object_new (GTK_TYPE_WX_CELL_RENDERER, NULL);
548 }
549 
550 static void
gtk_wx_cell_renderer_get_size(GtkCellRenderer * renderer,GtkWidget * widget,GdkRectangle * cell_area,gint * x_offset,gint * y_offset,gint * width,gint * height)551 gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer,
552                                GtkWidget       *widget,
553                                GdkRectangle    *cell_area,
554                                gint            *x_offset,
555                                gint            *y_offset,
556                                gint            *width,
557                                gint            *height)
558 {
559     GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
560     wxDataViewCustomRenderer *cell = wxrenderer->cell;
561 
562     wxSize size = cell->GetSize();
563 
564     gint calc_width  = (gint) renderer->xpad * 2 + size.x;
565     gint calc_height = (gint) renderer->ypad * 2 + size.y;
566 
567     if (x_offset)
568         *x_offset = 0;
569     if (y_offset)
570         *y_offset = 0;
571 
572     if (cell_area && size.x > 0 && size.y > 0)
573     {
574         if (x_offset)
575         {
576             *x_offset = (gint)((renderer->xalign *
577                                (cell_area->width - calc_width - 2 * renderer->xpad)));
578             *x_offset = MAX (*x_offset, 0) + renderer->xpad;
579         }
580         if (y_offset)
581         {
582             *y_offset = (gint)((renderer->yalign *
583                                (cell_area->height - calc_height - 2 * renderer->ypad)));
584             *y_offset = MAX (*y_offset, 0) + renderer->ypad;
585         }
586     }
587 
588     if (width)
589         *width = calc_width;
590 
591     if (height)
592         *height = calc_height;
593 }
594 
595 static void
gtk_wx_cell_renderer_render(GtkCellRenderer * renderer,GdkWindow * window,GtkWidget * widget,GdkRectangle * background_area,GdkRectangle * cell_area,GdkRectangle * expose_area,GtkCellRendererState flags)596 gtk_wx_cell_renderer_render (GtkCellRenderer      *renderer,
597                              GdkWindow            *window,
598                              GtkWidget            *widget,
599                              GdkRectangle         *background_area,
600                              GdkRectangle         *cell_area,
601                              GdkRectangle         *expose_area,
602                              GtkCellRendererState  flags)
603 
604 {
605     GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
606     wxDataViewCustomRenderer *cell = wxrenderer->cell;
607 
608     GdkRectangle rect;
609     gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
610                                    &rect.x,
611                                    &rect.y,
612                                    &rect.width,
613                                    &rect.height);
614 
615     rect.x += cell_area->x;
616     rect.y += cell_area->y;
617     rect.width  -= renderer->xpad * 2;
618     rect.height -= renderer->ypad * 2;
619 
620     GdkRectangle dummy;
621     if (gdk_rectangle_intersect (expose_area, &rect, &dummy))
622     {
623         wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
624         wxWindowDC* dc = (wxWindowDC*) cell->GetDC();
625         if (dc->m_window == NULL)
626         {
627             dc->m_window = window;
628             dc->SetUpDC();
629         }
630 
631         int state = 0;
632         if (flags & GTK_CELL_RENDERER_SELECTED)
633             state |= wxDATAVIEW_CELL_SELECTED;
634         if (flags & GTK_CELL_RENDERER_PRELIT)
635             state |= wxDATAVIEW_CELL_PRELIT;
636         if (flags & GTK_CELL_RENDERER_INSENSITIVE)
637             state |= wxDATAVIEW_CELL_INSENSITIVE;
638         if (flags & GTK_CELL_RENDERER_INSENSITIVE)
639             state |= wxDATAVIEW_CELL_INSENSITIVE;
640         if (flags & GTK_CELL_RENDERER_FOCUSED)
641             state |= wxDATAVIEW_CELL_FOCUSED;
642         cell->Render( renderrect, dc, state );
643     }
644 }
645 
646 static gboolean
gtk_wx_cell_renderer_activate(GtkCellRenderer * renderer,GdkEvent * event,GtkWidget * widget,const gchar * path,GdkRectangle * background_area,GdkRectangle * cell_area,GtkCellRendererState flags)647 gtk_wx_cell_renderer_activate(
648                         GtkCellRenderer         *renderer,
649                         GdkEvent                *event,
650                         GtkWidget               *widget,
651                         const gchar             *path,
652                         GdkRectangle            *background_area,
653                         GdkRectangle            *cell_area,
654                         GtkCellRendererState     flags )
655 {
656     GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
657     wxDataViewCustomRenderer *cell = wxrenderer->cell;
658 
659     GdkRectangle rect;
660     gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
661                                    &rect.x,
662                                    &rect.y,
663                                    &rect.width,
664                                    &rect.height);
665 
666     rect.x += cell_area->x;
667     rect.y += cell_area->y;
668     rect.width  -= renderer->xpad * 2;
669     rect.height -= renderer->ypad * 2;
670 
671     wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
672 
673     wxDataViewListModel *model = cell->GetOwner()->GetOwner()->GetModel();
674 
675     GtkTreePath *treepath = gtk_tree_path_new_from_string( path );
676     unsigned int model_row = (unsigned int)gtk_tree_path_get_indices (treepath)[0];
677     gtk_tree_path_free( treepath );
678 
679     unsigned int model_col = cell->GetOwner()->GetModelColumn();
680 
681     if (event->type == GDK_BUTTON_PRESS)
682     {
683         GdkEventButton *button_event = (GdkEventButton*) event;
684         wxPoint pt( ((int) button_event->x) - renderrect.x,
685                     ((int) button_event->y) - renderrect.y );
686 
687         bool ret = false;
688         if (button_event->button == 1)
689         {
690             if (cell->LeftClick( pt, renderrect, model, model_col, model_row ))
691                 ret = true;
692             // TODO: query system double-click time
693             if (button_event->time - wxrenderer->last_click < 400)
694                 if (cell->Activate( renderrect, model, model_col, model_row ))
695                     ret = true;
696         }
697         if (button_event->button == 3)
698         {
699             if (cell->RightClick( pt, renderrect, model, model_col, model_row ))
700                 ret = true;
701         }
702 
703         wxrenderer->last_click = button_event->time;
704 
705         return ret;
706     }
707 
708     return false;
709 }
710 
711 // ---------------------------------------------------------
712 // wxGtkDataViewListModelNotifier
713 // ---------------------------------------------------------
714 
715 class wxGtkDataViewListModelNotifier: public wxDataViewListModelNotifier
716 {
717 public:
718     wxGtkDataViewListModelNotifier( GtkWxListStore* gtk_store, wxDataViewListModel *wx_model );
719 
720     virtual bool RowAppended();
721     virtual bool RowPrepended();
722     virtual bool RowInserted( unsigned int before );
723     virtual bool RowDeleted( unsigned int row );
724     virtual bool RowChanged( unsigned int row );
725     virtual bool ValueChanged( unsigned int col, unsigned int row );
726     virtual bool RowsReordered( unsigned int *new_order );
727     virtual bool Cleared();
728 
729     GtkWxListStore      *m_gtk_store;
730     wxDataViewListModel *m_wx_model;
731 };
732 
733 // ---------------------------------------------------------
734 // wxGtkDataViewListModelNotifier
735 // ---------------------------------------------------------
736 
wxGtkDataViewListModelNotifier(GtkWxListStore * gtk_store,wxDataViewListModel * wx_model)737 wxGtkDataViewListModelNotifier::wxGtkDataViewListModelNotifier(
738     GtkWxListStore* gtk_store, wxDataViewListModel *wx_model )
739 {
740     m_gtk_store = gtk_store;
741     m_wx_model = wx_model;
742 }
743 
RowAppended()744 bool wxGtkDataViewListModelNotifier::RowAppended()
745 {
746     unsigned int pos = m_wx_model->GetNumberOfRows()-1;
747 
748     GtkTreeIter iter;
749     iter.stamp = m_gtk_store->stamp;
750     iter.user_data = (gpointer) pos;
751 
752     GtkTreePath *path = gtk_tree_path_new ();
753     gtk_tree_path_append_index (path, (gint) pos);
754     gtk_tree_model_row_inserted (GTK_TREE_MODEL (m_gtk_store), path, &iter);
755     gtk_tree_path_free (path);
756 
757     return true;
758 }
759 
RowPrepended()760 bool wxGtkDataViewListModelNotifier::RowPrepended()
761 {
762     GtkTreeIter iter;
763     iter.stamp = m_gtk_store->stamp;
764     iter.user_data = (gpointer) 0;
765 
766     GtkTreePath *path = gtk_tree_path_new ();
767     gtk_tree_path_append_index (path, (gint) 0);
768     gtk_tree_model_row_inserted (GTK_TREE_MODEL (m_gtk_store), path, &iter);
769     gtk_tree_path_free (path);
770 
771     return true;
772 }
773 
RowInserted(unsigned int before)774 bool wxGtkDataViewListModelNotifier::RowInserted( unsigned int before )
775 {
776     GtkTreeIter iter;
777     iter.stamp = m_gtk_store->stamp;
778     iter.user_data = (gpointer) before;
779 
780     GtkTreePath *path = gtk_tree_path_new ();
781     gtk_tree_path_append_index (path, (gint) before);
782     gtk_tree_model_row_inserted (GTK_TREE_MODEL (m_gtk_store), path, &iter);
783     gtk_tree_path_free (path);
784 
785     return true;
786 }
787 
RowDeleted(unsigned int row)788 bool wxGtkDataViewListModelNotifier::RowDeleted( unsigned int row )
789 {
790     GtkTreePath *path = gtk_tree_path_new ();
791     gtk_tree_path_append_index (path, (gint) row);
792     gtk_tree_model_row_deleted (GTK_TREE_MODEL (m_gtk_store), path);
793     gtk_tree_path_free (path);
794 
795     return true;
796 }
797 
RowChanged(unsigned int row)798 bool wxGtkDataViewListModelNotifier::RowChanged( unsigned int row )
799 {
800     GtkTreeIter iter;
801     iter.stamp = m_gtk_store->stamp;
802     iter.user_data = (gpointer) row;
803     GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (m_gtk_store), &iter);
804     gtk_tree_model_row_changed (GTK_TREE_MODEL (m_gtk_store), path, &iter);
805     gtk_tree_path_free (path);
806 
807     return true;
808 }
809 
ValueChanged(unsigned int model_col,unsigned int model_row)810 bool wxGtkDataViewListModelNotifier::ValueChanged( unsigned int model_col, unsigned int model_row )
811 {
812     // This adds GTK+'s missing MVC logic for ValueChanged
813     wxObjectList::compatibility_iterator
814         node = GetOwner()->m_viewingColumns.GetFirst();
815     while (node)
816     {
817         wxDataViewViewingColumn* viewing_column = (wxDataViewViewingColumn*) node->GetData();
818         if (viewing_column->m_modelColumn == model_col)
819         {
820             GtkTreeView *widget = GTK_TREE_VIEW(viewing_column->m_viewColumn->GetOwner()->m_treeview);
821             GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(viewing_column->m_viewColumn->GetGtkHandle());
822 
823             // Get cell area
824             GtkTreePath *path = gtk_tree_path_new();
825             gtk_tree_path_append_index( path, model_row );
826             GdkRectangle cell_area;
827             gtk_tree_view_get_cell_area( widget, path, column, &cell_area );
828             gtk_tree_path_free( path );
829 
830             int ydiff = column->button->allocation.height;
831             // Redraw
832             gtk_widget_queue_draw_area( GTK_WIDGET(widget),
833                 cell_area.x, ydiff + cell_area.y, cell_area.width, cell_area.height );
834         }
835 
836         node = node->GetNext();
837     }
838 
839     return true;
840 }
841 
RowsReordered(unsigned int * new_order)842 bool wxGtkDataViewListModelNotifier::RowsReordered( unsigned int *new_order )
843 {
844     // Assume sizeof(unsigned int)= == sizeof(gint)
845 
846     GtkTreePath *path = gtk_tree_path_new ();
847     gtk_tree_model_rows_reordered (GTK_TREE_MODEL (m_gtk_store), path, NULL, (gint*)new_order);
848     gtk_tree_path_free (path);
849 
850     // This adds GTK+'s missing MVC logic for RowsReordered
851     wxObjectList::compatibility_iterator
852         node = GetOwner()->m_viewingColumns.GetFirst();
853     while (node)
854     {
855         wxDataViewViewingColumn* viewing_column = (wxDataViewViewingColumn*) node->GetData();
856         GtkTreeView *widget = GTK_TREE_VIEW(viewing_column->m_viewColumn->GetOwner()->m_treeview);
857         // Doesn't work yet...
858         gtk_widget_queue_draw( GTK_WIDGET(widget) );
859 
860         node = node->GetNext();
861     }
862 
863     return true;
864 }
865 
Cleared()866 bool wxGtkDataViewListModelNotifier::Cleared()
867 {
868     return false;
869 }
870 
871 // ---------------------------------------------------------
872 // wxDataViewRenderer
873 // ---------------------------------------------------------
874 
IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer,wxDataViewRendererBase)875 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
876 
877 wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode ) :
878     wxDataViewRendererBase( varianttype, mode )
879 {
880     m_renderer = NULL;
881 }
882 
883 // ---------------------------------------------------------
884 // wxDataViewTextRenderer
885 // ---------------------------------------------------------
886 
887 extern "C" {
888 static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer,
889     gchar *arg1, gchar *arg2, gpointer user_data );
890 }
891 
wxGtkTextRendererEditedCallback(GtkCellRendererText * renderer,gchar * arg1,gchar * arg2,gpointer user_data)892 static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer,
893     gchar *arg1, gchar *arg2, gpointer user_data )
894 {
895     wxDataViewTextRenderer *cell = (wxDataViewTextRenderer*) user_data;
896 
897     wxString tmp = wxGTK_CONV_BACK( arg2 );
898     wxVariant value = tmp;
899     if (!cell->Validate( value ))
900         return;
901 
902     wxDataViewListModel *model = cell->GetOwner()->GetOwner()->GetModel();
903 
904     GtkTreePath *path = gtk_tree_path_new_from_string( arg1 );
905     unsigned int model_row = (unsigned int)gtk_tree_path_get_indices (path)[0];
906     gtk_tree_path_free( path );
907 
908     unsigned int model_col = cell->GetOwner()->GetModelColumn();
909 
910     model->SetValue( value, model_col, model_row );
911     model->ValueChanged( model_col, model_row );
912 }
913 
IMPLEMENT_CLASS(wxDataViewTextRenderer,wxDataViewRenderer)914 IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewRenderer)
915 
916 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode ) :
917     wxDataViewRenderer( varianttype, mode )
918 {
919     m_renderer = (void*) gtk_cell_renderer_text_new();
920 
921     if (m_mode & wxDATAVIEW_CELL_EDITABLE)
922     {
923         GValue gvalue = { 0, };
924         g_value_init( &gvalue, G_TYPE_BOOLEAN );
925         g_value_set_boolean( &gvalue, true );
926         g_object_set_property( G_OBJECT(m_renderer), "editable", &gvalue );
927         g_value_unset( &gvalue );
928 
929         g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
930     }
931 }
932 
SetValue(const wxVariant & value)933 bool wxDataViewTextRenderer::SetValue( const wxVariant &value )
934 {
935     wxString tmp = value;
936 
937     GValue gvalue = { 0, };
938     g_value_init( &gvalue, G_TYPE_STRING );
939     g_value_set_string( &gvalue, wxGTK_CONV_FONT( tmp, GetOwner()->GetOwner()->GetFont() ) );
940     g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
941     g_value_unset( &gvalue );
942 
943     return true;
944 }
945 
GetValue(wxVariant & value)946 bool wxDataViewTextRenderer::GetValue( wxVariant &value )
947 {
948     GValue gvalue = { 0, };
949     g_value_init( &gvalue, G_TYPE_STRING );
950     g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
951     wxString tmp = wxGTK_CONV_BACK( g_value_get_string( &gvalue ) );
952     g_value_unset( &gvalue );
953 
954     value = tmp;
955 
956     return true;
957 }
958 
959 // ---------------------------------------------------------
960 // wxDataViewBitmapRenderer
961 // ---------------------------------------------------------
962 
IMPLEMENT_CLASS(wxDataViewBitmapRenderer,wxDataViewRenderer)963 IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewRenderer)
964 
965 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode ) :
966     wxDataViewRenderer( varianttype, mode )
967 {
968     m_renderer = (void*) gtk_cell_renderer_pixbuf_new();
969 }
970 
SetValue(const wxVariant & value)971 bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
972 {
973     if (value.GetType() == wxT("wxBitmap"))
974     {
975         wxBitmap bitmap;
976         bitmap << value;
977 
978         // This may create a Pixbuf representation in the
979         // wxBitmap object (and it will stay there)
980         GdkPixbuf *pixbuf = bitmap.GetPixbuf();
981 
982         GValue gvalue = { 0, };
983         g_value_init( &gvalue, G_TYPE_OBJECT );
984         g_value_set_object( &gvalue, pixbuf );
985         g_object_set_property( G_OBJECT(m_renderer), "pixbuf", &gvalue );
986         g_value_unset( &gvalue );
987 
988         return true;
989     }
990 
991     if (value.GetType() == wxT("wxIcon"))
992     {
993         wxIcon bitmap;
994         bitmap << value;
995 
996         // This may create a Pixbuf representation in the
997         // wxBitmap object (and it will stay there)
998         GdkPixbuf *pixbuf = bitmap.GetPixbuf();
999 
1000         GValue gvalue = { 0, };
1001         g_value_init( &gvalue, G_TYPE_OBJECT );
1002         g_value_set_object( &gvalue, pixbuf );
1003         g_object_set_property( G_OBJECT(m_renderer), "pixbuf", &gvalue );
1004         g_value_unset( &gvalue );
1005 
1006         return true;
1007     }
1008 
1009     return false;
1010 }
1011 
GetValue(wxVariant & value)1012 bool wxDataViewBitmapRenderer::GetValue( wxVariant &value )
1013 {
1014     return false;
1015 }
1016 
1017 // ---------------------------------------------------------
1018 // wxDataViewToggleRenderer
1019 // ---------------------------------------------------------
1020 
1021 extern "C" {
1022 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
1023     gchar *path, gpointer user_data );
1024 }
1025 
wxGtkToggleRendererToggledCallback(GtkCellRendererToggle * renderer,gchar * path,gpointer user_data)1026 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
1027     gchar *path, gpointer user_data )
1028 {
1029     wxDataViewToggleRenderer *cell = (wxDataViewToggleRenderer*) user_data;
1030 
1031     // get old value
1032     GValue gvalue = { 0, };
1033     g_value_init( &gvalue, G_TYPE_BOOLEAN );
1034     g_object_get_property( G_OBJECT(renderer), "active", &gvalue );
1035     bool tmp = g_value_get_boolean( &gvalue );
1036     g_value_unset( &gvalue );
1037     // invert it
1038     tmp = !tmp;
1039 
1040     wxVariant value = tmp;
1041     if (!cell->Validate( value ))
1042         return;
1043 
1044     wxDataViewListModel *model = cell->GetOwner()->GetOwner()->GetModel();
1045 
1046     GtkTreePath *gtk_path = gtk_tree_path_new_from_string( path );
1047     unsigned int model_row = (unsigned int)gtk_tree_path_get_indices (gtk_path)[0];
1048     gtk_tree_path_free( gtk_path );
1049 
1050     unsigned int model_col = cell->GetOwner()->GetModelColumn();
1051 
1052     model->SetValue( value, model_col, model_row );
1053     model->ValueChanged( model_col, model_row );
1054 }
1055 
IMPLEMENT_CLASS(wxDataViewToggleRenderer,wxDataViewRenderer)1056 IMPLEMENT_CLASS(wxDataViewToggleRenderer, wxDataViewRenderer)
1057 
1058 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
1059                         wxDataViewCellMode mode ) :
1060     wxDataViewRenderer( varianttype, mode )
1061 {
1062     m_renderer = (void*) gtk_cell_renderer_toggle_new();
1063 
1064     if (m_mode & wxDATAVIEW_CELL_ACTIVATABLE)
1065     {
1066         g_signal_connect_after( m_renderer, "toggled", G_CALLBACK(wxGtkToggleRendererToggledCallback), this );
1067     }
1068     else
1069     {
1070 
1071         GValue gvalue = { 0, };
1072         g_value_init( &gvalue, G_TYPE_BOOLEAN );
1073         g_value_set_boolean( &gvalue, false );
1074         g_object_set_property( G_OBJECT(m_renderer), "activatable", &gvalue );
1075         g_value_unset( &gvalue );
1076 
1077         GValue gvalue2 = { 0, };
1078         g_value_init( &gvalue2, gtk_cell_renderer_mode_get_type() );
1079         g_value_set_enum( &gvalue2, GTK_CELL_RENDERER_MODE_INERT );
1080         g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue2 );
1081         g_value_unset( &gvalue2 );
1082 
1083     }
1084 }
1085 
SetValue(const wxVariant & value)1086 bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
1087 {
1088     bool tmp = value;
1089 
1090     GValue gvalue = { 0, };
1091     g_value_init( &gvalue, G_TYPE_BOOLEAN );
1092     g_value_set_boolean( &gvalue, tmp );
1093     g_object_set_property( G_OBJECT(m_renderer), "active", &gvalue );
1094     g_value_unset( &gvalue );
1095 
1096     return true;
1097 }
1098 
GetValue(wxVariant & value)1099 bool wxDataViewToggleRenderer::GetValue( wxVariant &value )
1100 {
1101     GValue gvalue = { 0, };
1102     g_value_init( &gvalue, G_TYPE_BOOLEAN );
1103     g_object_get_property( G_OBJECT(m_renderer), "active", &gvalue );
1104     bool tmp = g_value_get_boolean( &gvalue );
1105     g_value_unset( &gvalue );
1106 
1107     value = tmp;
1108 
1109     return true;
1110 }
1111 
1112 // ---------------------------------------------------------
1113 // wxDataViewCustomRenderer
1114 // ---------------------------------------------------------
1115 
1116 class wxDataViewCtrlDC: public wxWindowDC
1117 {
1118 public:
wxDataViewCtrlDC(wxDataViewCtrl * window)1119     wxDataViewCtrlDC( wxDataViewCtrl *window )
1120     {
1121         GtkWidget *widget = window->m_treeview;
1122         // Set later
1123         m_window = NULL;
1124 
1125         m_context = window->GtkGetPangoDefaultContext();
1126         m_layout = pango_layout_new( m_context );
1127         m_fontdesc = pango_font_description_copy( widget->style->font_desc );
1128 
1129         m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
1130 
1131         // Set m_window later
1132         // SetUpDC();
1133         // m_owner = window;
1134     }
1135 };
1136 
1137 // ---------------------------------------------------------
1138 // wxDataViewCustomRenderer
1139 // ---------------------------------------------------------
1140 
IMPLEMENT_CLASS(wxDataViewCustomRenderer,wxDataViewRenderer)1141 IMPLEMENT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
1142 
1143 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
1144                           wxDataViewCellMode mode, bool no_init ) :
1145     wxDataViewRenderer( varianttype, mode )
1146 {
1147     m_dc = NULL;
1148 
1149     if (no_init)
1150         m_renderer = NULL;
1151     else
1152         Init();
1153 }
1154 
Init()1155 bool wxDataViewCustomRenderer::Init()
1156 {
1157     GtkWxCellRenderer *renderer = (GtkWxCellRenderer *) gtk_wx_cell_renderer_new();
1158     renderer->cell = this;
1159 
1160     m_renderer = (void*) renderer;
1161 
1162     if (m_mode & wxDATAVIEW_CELL_ACTIVATABLE)
1163     {
1164         GValue gvalue = { 0, };
1165         g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
1166         g_value_set_enum( &gvalue, GTK_CELL_RENDERER_MODE_ACTIVATABLE );
1167         g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue );
1168         g_value_unset( &gvalue );
1169     }
1170 
1171     return true;
1172 }
1173 
~wxDataViewCustomRenderer()1174 wxDataViewCustomRenderer::~wxDataViewCustomRenderer()
1175 {
1176     if (m_dc)
1177         delete m_dc;
1178 }
1179 
GetDC()1180 wxDC *wxDataViewCustomRenderer::GetDC()
1181 {
1182     if (m_dc == NULL)
1183     {
1184         if (GetOwner() == NULL)
1185             return NULL;
1186         if (GetOwner()->GetOwner() == NULL)
1187             return NULL;
1188         m_dc = new wxDataViewCtrlDC( GetOwner()->GetOwner() );
1189     }
1190 
1191     return m_dc;
1192 }
1193 
1194 // ---------------------------------------------------------
1195 // wxDataViewProgressRenderer
1196 // ---------------------------------------------------------
1197 
IMPLEMENT_CLASS(wxDataViewProgressRenderer,wxDataViewCustomRenderer)1198 IMPLEMENT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
1199 
1200 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
1201     const wxString &varianttype, wxDataViewCellMode mode ) :
1202     wxDataViewCustomRenderer( varianttype, mode, true )
1203 {
1204     m_label = label;
1205     m_value = 0;
1206 
1207 #ifdef __WXGTK26__
1208     if (!gtk_check_version(2,6,0))
1209     {
1210         m_renderer = (void*) gtk_cell_renderer_progress_new();
1211 
1212         GValue gvalue = { 0, };
1213         g_value_init( &gvalue, G_TYPE_STRING );
1214 
1215         // FIXME: font encoding support
1216         g_value_set_string( &gvalue, wxGTK_CONV_SYS(m_label) );
1217         g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
1218         g_value_unset( &gvalue );
1219     }
1220     else
1221 #endif
1222     {
1223         // Use custom cell code
1224         wxDataViewCustomRenderer::Init();
1225     }
1226 }
1227 
~wxDataViewProgressRenderer()1228 wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
1229 {
1230 }
1231 
SetValue(const wxVariant & value)1232 bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
1233 {
1234 #ifdef __WXGTK26__
1235     if (!gtk_check_version(2,6,0))
1236     {
1237         gint tmp = (long) value;
1238         GValue gvalue = { 0, };
1239         g_value_init( &gvalue, G_TYPE_INT );
1240         g_value_set_int( &gvalue, tmp );
1241         g_object_set_property( G_OBJECT(m_renderer), "value", &gvalue );
1242         g_value_unset( &gvalue );
1243     }
1244     else
1245 #endif
1246     {
1247         m_value = (long) value;
1248 
1249         if (m_value < 0) m_value = 0;
1250         if (m_value > 100) m_value = 100;
1251     }
1252 
1253     return true;
1254 }
1255 
Render(wxRect cell,wxDC * dc,int state)1256 bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int state )
1257 {
1258     double pct = (double)m_value / 100.0;
1259     wxRect bar = cell;
1260     bar.width = (int)(cell.width * pct);
1261     dc->SetPen( *wxTRANSPARENT_PEN );
1262     dc->SetBrush( *wxBLUE_BRUSH );
1263     dc->DrawRectangle( bar );
1264 
1265     dc->SetBrush( *wxTRANSPARENT_BRUSH );
1266     dc->SetPen( *wxBLACK_PEN );
1267     dc->DrawRectangle( cell );
1268 
1269     return true;
1270 }
1271 
GetSize()1272 wxSize wxDataViewProgressRenderer::GetSize()
1273 {
1274     return wxSize(40,12);
1275 }
1276 
1277 // ---------------------------------------------------------
1278 // wxDataViewDateRenderer
1279 // ---------------------------------------------------------
1280 
1281 class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
1282 {
1283 public:
wxDataViewDateRendererPopupTransient(wxWindow * parent,wxDateTime * value,wxDataViewListModel * model,unsigned int col,unsigned int row)1284     wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
1285         wxDataViewListModel *model, unsigned int col, unsigned int row ) :
1286         wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
1287     {
1288         m_model = model;
1289         m_col = col;
1290         m_row = row;
1291         m_cal = new wxCalendarCtrl( this, -1, *value );
1292         wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
1293         sizer->Add( m_cal, 1, wxGROW );
1294         SetSizer( sizer );
1295         sizer->Fit( this );
1296     }
1297 
OnDismiss()1298     virtual void OnDismiss()
1299     {
1300     }
1301 
1302     void OnCalendar( wxCalendarEvent &event );
1303 
1304     wxCalendarCtrl      *m_cal;
1305     wxDataViewListModel *m_model;
1306     unsigned int               m_col;
1307     unsigned int               m_row;
1308 
1309 private:
1310     DECLARE_EVENT_TABLE()
1311 };
1312 
BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)1313 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
1314     EVT_CALENDAR( -1, wxDataViewDateRendererPopupTransient::OnCalendar )
1315 END_EVENT_TABLE()
1316 
1317 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
1318 {
1319     wxDateTime date = event.GetDate();
1320     wxVariant value = date;
1321     m_model->SetValue( value, m_col, m_row );
1322     m_model->ValueChanged( m_col, m_row );
1323     DismissAndNotify();
1324 }
1325 
IMPLEMENT_CLASS(wxDataViewDateRenderer,wxDataViewCustomRenderer)1326 IMPLEMENT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
1327 
1328 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
1329                         wxDataViewCellMode mode ) :
1330     wxDataViewCustomRenderer( varianttype, mode )
1331 {
1332 }
1333 
SetValue(const wxVariant & value)1334 bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
1335 {
1336     m_date = value.GetDateTime();
1337 
1338     return true;
1339 }
1340 
Render(wxRect cell,wxDC * dc,int state)1341 bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state )
1342 {
1343     dc->SetFont( GetOwner()->GetOwner()->GetFont() );
1344     wxString tmp = m_date.FormatDate();
1345     dc->DrawText( tmp, cell.x, cell.y );
1346 
1347     return true;
1348 }
1349 
GetSize()1350 wxSize wxDataViewDateRenderer::GetSize()
1351 {
1352     wxDataViewCtrl* view = GetOwner()->GetOwner();
1353     wxString tmp = m_date.FormatDate();
1354     wxCoord x,y,d;
1355     view->GetTextExtent( tmp, &x, &y, &d );
1356     return wxSize(x,y+d);
1357 }
1358 
Activate(wxRect cell,wxDataViewListModel * model,unsigned int col,unsigned int row)1359 bool wxDataViewDateRenderer::Activate( wxRect cell, wxDataViewListModel *model, unsigned int col, unsigned int row )
1360 {
1361     wxVariant variant;
1362     model->GetValue( variant, col, row );
1363     wxDateTime value = variant.GetDateTime();
1364 
1365     wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
1366         GetOwner()->GetOwner()->GetParent(), &value, model, col, row );
1367     wxPoint pos = wxGetMousePosition();
1368     popup->Move( pos );
1369     popup->Layout();
1370     popup->Popup( popup->m_cal );
1371 
1372     return true;
1373 }
1374 
1375 // ---------------------------------------------------------
1376 // wxDataViewColumn
1377 // ---------------------------------------------------------
1378 
1379 
1380 static gboolean
gtk_dataview_header_button_press_callback(GtkWidget * widget,GdkEventButton * gdk_event,wxDataViewColumn * column)1381 gtk_dataview_header_button_press_callback( GtkWidget *widget,
1382                                            GdkEventButton *gdk_event,
1383                                            wxDataViewColumn *column )
1384 {
1385     if (gdk_event->type != GDK_BUTTON_PRESS)
1386         return TRUE;
1387 
1388     if (gdk_event->button == 1)
1389     {
1390         wxDataViewCtrl *dv = column->GetOwner();
1391         wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, dv->GetId() );
1392         event.SetDataViewColumn( column );
1393         event.SetModel( dv->GetModel() );
1394         dv->GetEventHandler()->ProcessEvent( event );
1395     }
1396 
1397     return TRUE;
1398 }
1399 
1400 extern "C" {
1401 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
1402                             GtkCellRenderer *cell,
1403                             GtkTreeModel *model,
1404                             GtkTreeIter *iter,
1405                             gpointer data );
1406 }
1407 
1408 
wxGtkTreeCellDataFunc(GtkTreeViewColumn * column,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)1409 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
1410                             GtkCellRenderer *renderer,
1411                             GtkTreeModel *model,
1412                             GtkTreeIter *iter,
1413                             gpointer data )
1414 {
1415     g_return_if_fail (GTK_IS_WX_LIST_STORE (model));
1416     GtkWxListStore *list_store = (GtkWxListStore *) model;
1417 
1418     wxDataViewRenderer *cell = (wxDataViewRenderer*) data;
1419 
1420     unsigned int model_row = (unsigned int) iter->user_data;
1421 
1422     wxVariant value;
1423     list_store->model->GetValue( value, cell->GetOwner()->GetModelColumn(), model_row );
1424 
1425     if (value.GetType() != cell->GetVariantType())
1426         wxLogError( wxT("Wrong type, required: %s but: %s"),
1427                     value.GetType().c_str(),
1428                     cell->GetVariantType().c_str() );
1429 
1430     cell->SetValue( value );
1431 }
1432 
IMPLEMENT_CLASS(wxDataViewColumn,wxDataViewColumnBase)1433 IMPLEMENT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
1434 
1435 wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell, unsigned int model_column,
1436     int width, int flags ) :
1437     wxDataViewColumnBase( title, cell, model_column, width, flags )
1438 {
1439     m_isConnected = false;
1440 
1441     GtkCellRenderer *renderer = (GtkCellRenderer *) cell->GetGtkHandle();
1442 
1443     GtkTreeViewColumn *column = gtk_tree_view_column_new();
1444     m_column = (void*) column;
1445 
1446     gtk_tree_view_column_set_clickable( column, true );
1447 
1448     SetTitle( title );
1449 
1450     if (flags & wxDATAVIEW_COL_RESIZABLE)
1451         gtk_tree_view_column_set_resizable( column, true );
1452     if (flags & wxDATAVIEW_COL_HIDDEN)
1453         gtk_tree_view_column_set_visible( column, false );
1454     if (flags & wxDATAVIEW_COL_SORTABLE)
1455         gtk_tree_view_column_set_sort_indicator( column, true );
1456 
1457     if (width > 0)
1458         gtk_tree_view_column_set_fixed_width( column, width );
1459     else
1460         gtk_tree_view_column_set_fixed_width( column, 70 );  // FIXME
1461 
1462     gtk_tree_view_column_set_sizing( column, GTK_TREE_VIEW_COLUMN_FIXED );
1463 
1464     gtk_tree_view_column_pack_end( column, renderer, FALSE );
1465 
1466     gtk_tree_view_column_set_cell_data_func( column, renderer,
1467         wxGtkTreeCellDataFunc, (gpointer) cell, NULL );
1468 
1469 }
1470 
wxDataViewColumn(const wxBitmap & bitmap,wxDataViewRenderer * cell,unsigned int model_column,int width,int flags)1471 wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell, unsigned int model_column,
1472     int width, int flags ) :
1473     wxDataViewColumnBase( bitmap, cell, model_column, width, flags )
1474 {
1475     m_isConnected = false;
1476 
1477     GtkCellRenderer *renderer = (GtkCellRenderer *) cell->GetGtkHandle();
1478 
1479     GtkTreeViewColumn *column = gtk_tree_view_column_new();
1480     m_column = (void*) column;
1481 
1482     SetBitmap( bitmap );
1483 
1484     if (flags & wxDATAVIEW_COL_RESIZABLE)
1485         gtk_tree_view_column_set_resizable( column, true );
1486     if (flags & wxDATAVIEW_COL_HIDDEN)
1487         gtk_tree_view_column_set_visible( column, false );
1488     if (flags & wxDATAVIEW_COL_SORTABLE)
1489         gtk_tree_view_column_set_sort_indicator( column, true );
1490 
1491     if (width > 0)
1492         gtk_tree_view_column_set_fixed_width( column, width );
1493     else
1494         gtk_tree_view_column_set_fixed_width( column, 70 );  // FIXME
1495 
1496     gtk_tree_view_column_set_sizing( column, GTK_TREE_VIEW_COLUMN_FIXED );
1497 
1498     gtk_tree_view_column_pack_end( column, renderer, FALSE );
1499 
1500     gtk_tree_view_column_set_cell_data_func( column, renderer,
1501         wxGtkTreeCellDataFunc, (gpointer) cell, NULL );
1502 }
1503 
~wxDataViewColumn()1504 wxDataViewColumn::~wxDataViewColumn()
1505 {
1506 }
1507 
OnInternalIdle()1508 void wxDataViewColumn::OnInternalIdle()
1509 {
1510     if (m_isConnected)
1511         return;
1512 
1513     if (GTK_WIDGET_REALIZED(GetOwner()->m_treeview))
1514     {
1515         GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column;
1516         if (column->button)
1517         {
1518             g_signal_connect(column->button, "button_press_event",
1519                       G_CALLBACK (gtk_dataview_header_button_press_callback), this);
1520 
1521             m_isConnected = true;
1522         }
1523     }
1524 }
1525 
SetOwner(wxDataViewCtrl * owner)1526 void wxDataViewColumn::SetOwner( wxDataViewCtrl *owner )
1527 {
1528     wxDataViewColumnBase::SetOwner( owner );
1529 
1530     GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column;
1531 
1532     gtk_tree_view_column_set_title( column, wxGTK_CONV_FONT(GetTitle(), GetOwner()->GetFont() ) );
1533 }
1534 
SetTitle(const wxString & title)1535 void wxDataViewColumn::SetTitle( const wxString &title )
1536 {
1537     wxDataViewColumnBase::SetTitle( title );
1538 
1539     GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column;
1540 
1541     if (m_isConnected)
1542     {
1543         // disconnect before column->button gets recreated
1544         g_signal_handlers_disconnect_by_func( column->button,
1545                       (void*) gtk_dataview_header_button_press_callback, this);
1546 
1547         m_isConnected = false;
1548     }
1549 
1550     // FIXME: can it really happen that we don't have the owner here??
1551     wxDataViewCtrl *ctrl = GetOwner();
1552     gtk_tree_view_column_set_title( column, ctrl ? wxGTK_CONV_FONT(title, ctrl->GetFont())
1553                                                  : wxGTK_CONV_SYS(title) );
1554 
1555     gtk_tree_view_column_set_widget( column, NULL );
1556 }
1557 
SetBitmap(const wxBitmap & bitmap)1558 void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap )
1559 {
1560     wxDataViewColumnBase::SetBitmap( bitmap );
1561 
1562     GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column;
1563     if (bitmap.Ok())
1564     {
1565         GtkImage *gtk_image = GTK_IMAGE( gtk_image_new() );
1566 
1567         GdkBitmap *mask = (GdkBitmap *) NULL;
1568         if (bitmap.GetMask())
1569             mask = bitmap.GetMask()->GetBitmap();
1570 
1571         if (bitmap.HasPixbuf())
1572         {
1573             gtk_image_set_from_pixbuf(GTK_IMAGE(gtk_image),
1574                                       bitmap.GetPixbuf());
1575         }
1576         else
1577         {
1578             gtk_image_set_from_pixmap(GTK_IMAGE(gtk_image),
1579                                       bitmap.GetPixmap(), mask);
1580         }
1581         gtk_widget_show( GTK_WIDGET(gtk_image) );
1582 
1583         gtk_tree_view_column_set_widget( column, GTK_WIDGET(gtk_image) );
1584     }
1585     else
1586     {
1587         gtk_tree_view_column_set_widget( column, NULL );
1588     }
1589 }
1590 
SetAlignment(wxAlignment align)1591 void wxDataViewColumn::SetAlignment( wxAlignment align )
1592 {
1593     GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column;
1594 
1595     gfloat xalign = 0.0;
1596     if (align == wxALIGN_RIGHT)
1597         xalign = 1.0;
1598     if (align == wxALIGN_CENTER)
1599         xalign = 0.5;
1600 
1601     gtk_tree_view_column_set_alignment( column, xalign );
1602 }
1603 
SetSortable(bool sortable)1604 void wxDataViewColumn::SetSortable( bool sortable )
1605 {
1606     GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column;
1607     gtk_tree_view_column_set_sort_indicator( column, sortable );
1608 }
1609 
GetSortable()1610 bool wxDataViewColumn::GetSortable()
1611 {
1612     GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column;
1613     return gtk_tree_view_column_get_sort_indicator( column );
1614 }
1615 
SetSortOrder(bool ascending)1616 void wxDataViewColumn::SetSortOrder( bool ascending )
1617 {
1618     GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column;
1619 
1620     if (ascending)
1621         gtk_tree_view_column_set_sort_order( column, GTK_SORT_ASCENDING );
1622     else
1623         gtk_tree_view_column_set_sort_order( column, GTK_SORT_DESCENDING );
1624 }
1625 
IsSortOrderAscending()1626 bool wxDataViewColumn::IsSortOrderAscending()
1627 {
1628     GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column;
1629 
1630     return (gtk_tree_view_column_get_sort_order( column ) != GTK_SORT_DESCENDING);
1631 }
1632 
GetWidth()1633 int wxDataViewColumn::GetWidth()
1634 {
1635     return gtk_tree_view_column_get_width( (GtkTreeViewColumn *)m_column );
1636 }
1637 
SetFixedWidth(int width)1638 void wxDataViewColumn::SetFixedWidth( int width )
1639 {
1640     gtk_tree_view_column_set_fixed_width( (GtkTreeViewColumn *)m_column, width );
1641 }
1642 
GetFixedWidth()1643 int wxDataViewColumn::GetFixedWidth()
1644 {
1645     return gtk_tree_view_column_get_fixed_width( (GtkTreeViewColumn *)m_column );
1646 }
1647 
1648 //-----------------------------------------------------------------------------
1649 // wxDataViewCtrl signal callbacks
1650 //-----------------------------------------------------------------------------
1651 
1652 static void
wxdataview_selection_changed_callback(GtkTreeSelection * selection,wxDataViewCtrl * dv)1653 wxdataview_selection_changed_callback( GtkTreeSelection* selection, wxDataViewCtrl *dv )
1654 {
1655     if (!GTK_WIDGET_REALIZED(dv->m_widget))
1656         return;
1657 
1658     wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ROW_SELECTED, dv->GetId() );
1659     event.SetRow( dv->GetSelection() );
1660     event.SetModel( dv->GetModel() );
1661     dv->GetEventHandler()->ProcessEvent( event );
1662 }
1663 
1664 static void
wxdataview_row_activated_callback(GtkTreeView * treeview,GtkTreePath * path,GtkTreeViewColumn * column,wxDataViewCtrl * dv)1665 wxdataview_row_activated_callback( GtkTreeView* treeview, GtkTreePath *path,
1666                                    GtkTreeViewColumn *column, wxDataViewCtrl *dv )
1667 {
1668     wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ROW_ACTIVATED, dv->GetId() );
1669     unsigned int row = (unsigned int)gtk_tree_path_get_indices (path)[0];
1670     event.SetRow( row );
1671     event.SetModel( dv->GetModel() );
1672     dv->GetEventHandler()->ProcessEvent( event );
1673 }
1674 
1675 //-----------------------------------------------------------------------------
1676 // wxDataViewCtrl
1677 //-----------------------------------------------------------------------------
1678 
IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl,wxDataViewCtrlBase)1679 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
1680 
1681 wxDataViewCtrl::~wxDataViewCtrl()
1682 {
1683     if (m_notifier)
1684         GetModel()->RemoveNotifier( m_notifier );
1685 }
1686 
Init()1687 void wxDataViewCtrl::Init()
1688 {
1689     m_notifier = NULL;
1690 }
1691 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator)1692 bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
1693            const wxPoint& pos, const wxSize& size,
1694            long style, const wxValidator& validator )
1695 {
1696     Init();
1697 
1698     m_needParent = true;
1699     m_acceptsFocus = true;
1700 
1701     if (!PreCreation( parent, pos, size ) ||
1702         !CreateBase( parent, id, pos, size, style, validator ))
1703     {
1704         wxFAIL_MSG( wxT("wxDataViewCtrl creation failed") );
1705         return false;
1706     }
1707 
1708     m_widget = gtk_scrolled_window_new (NULL, NULL);
1709 
1710     GtkScrolledWindowSetBorder(m_widget, style);
1711 
1712     m_treeview = gtk_tree_view_new();
1713     gtk_container_add (GTK_CONTAINER (m_widget), m_treeview);
1714 
1715 #ifdef __WXGTK26__
1716     if (!gtk_check_version(2,6,0))
1717         gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), TRUE );
1718 #endif
1719 
1720     if (style & wxDV_MULTIPLE)
1721     {
1722         GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
1723         gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
1724     }
1725 
1726     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_widget),
1727         GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1728     gtk_widget_show (m_treeview);
1729 
1730     m_parent->DoAddChild( this );
1731 
1732     PostCreation(size);
1733 
1734     GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
1735     g_signal_connect_after (selection, "changed",
1736                             G_CALLBACK (wxdataview_selection_changed_callback), this);
1737     g_signal_connect_after (m_treeview, "row_activated",
1738                             G_CALLBACK (wxdataview_row_activated_callback), this);
1739 
1740     return true;
1741 }
1742 
OnInternalIdle()1743 void wxDataViewCtrl::OnInternalIdle()
1744 {
1745     wxWindow::OnInternalIdle();
1746 
1747     unsigned int cols = GetNumberOfColumns();
1748     unsigned int i;
1749     for (i = 0; i < cols; i++)
1750     {
1751         wxDataViewColumn *col = GetColumn( i );
1752         col->OnInternalIdle();
1753     }
1754 }
1755 
AssociateModel(wxDataViewListModel * model)1756 bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model )
1757 {
1758     if (!wxDataViewCtrlBase::AssociateModel( model ))
1759         return false;
1760 
1761     GtkWxListStore *gtk_store = wxgtk_list_store_new();
1762     gtk_store->model = model;
1763 
1764     m_notifier = new wxGtkDataViewListModelNotifier( gtk_store, model );
1765 
1766     model->AddNotifier( m_notifier );
1767 
1768     gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview), GTK_TREE_MODEL(gtk_store) );
1769     g_object_unref( gtk_store );
1770 
1771     return true;
1772 }
1773 
AppendColumn(wxDataViewColumn * col)1774 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
1775 {
1776     if (!wxDataViewCtrlBase::AppendColumn(col))
1777         return false;
1778 
1779     GtkTreeViewColumn *column = (GtkTreeViewColumn *)col->GetGtkHandle();
1780 
1781     gtk_tree_view_append_column( GTK_TREE_VIEW(m_treeview), column );
1782 
1783     return true;
1784 }
1785 
SetSelection(int row)1786 void wxDataViewCtrl::SetSelection( int row )
1787 {
1788     GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
1789 
1790     if (row < 0)
1791     {
1792         gtk_tree_selection_unselect_all( selection );
1793     }
1794     else
1795     {
1796         GtkTreePath *path = gtk_tree_path_new ();
1797         gtk_tree_path_append_index( path, row );
1798 
1799         gtk_tree_selection_select_path( selection, path );
1800 
1801         gtk_tree_path_free( path );
1802     }
1803 }
1804 
Unselect(unsigned int row)1805 void wxDataViewCtrl::Unselect( unsigned int row )
1806 {
1807     GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
1808 
1809     GtkTreePath *path = gtk_tree_path_new ();
1810     gtk_tree_path_append_index( path, row );
1811 
1812     gtk_tree_selection_unselect_path( selection, path );
1813 
1814     gtk_tree_path_free( path );
1815 }
1816 
SetSelectionRange(unsigned int from,unsigned int to)1817 void wxDataViewCtrl::SetSelectionRange( unsigned int from, unsigned int to )
1818 {
1819 }
1820 
SetSelections(const wxArrayInt & aSelections)1821 void wxDataViewCtrl::SetSelections( const wxArrayInt& aSelections)
1822 {
1823 }
1824 
IsSelected(unsigned int row) const1825 bool wxDataViewCtrl::IsSelected( unsigned int row ) const
1826 {
1827     GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
1828 
1829     GtkTreePath *path = gtk_tree_path_new ();
1830     gtk_tree_path_append_index( path, row );
1831 
1832     gboolean ret =  gtk_tree_selection_path_is_selected( selection, path );
1833 
1834     gtk_tree_path_free( path );
1835 
1836     return ret;
1837 }
1838 
GetSelection() const1839 int wxDataViewCtrl::GetSelection() const
1840 {
1841     GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
1842     if (HasFlag(wxDV_MULTIPLE))
1843     {
1844         GtkTreeModel *model;
1845         GList *list = gtk_tree_selection_get_selected_rows( selection, &model );
1846 
1847         // do something
1848         if (list)
1849         {
1850             // list = g_list_nth( list, 0 );  should be a noop
1851             GtkTreePath *path = (GtkTreePath*) list->data;
1852 
1853             unsigned int row = (unsigned int)gtk_tree_path_get_indices (path)[0];
1854 
1855             // delete list
1856             g_list_foreach( list, (GFunc) gtk_tree_path_free, NULL );
1857             g_list_free( list );
1858 
1859             return (int) row;
1860         }
1861     }
1862     else
1863     {
1864 
1865         GtkTreeModel *model;
1866         GtkTreeIter iter;
1867         gboolean has_selection = gtk_tree_selection_get_selected( selection, &model, &iter );
1868         if (has_selection)
1869         {
1870             unsigned int row = (wxUIntPtr) iter.user_data;
1871             return (int) row;
1872         }
1873     }
1874 
1875     return -1;
1876 }
1877 
GetSelections(wxArrayInt & aSelections) const1878 int wxDataViewCtrl::GetSelections(wxArrayInt& aSelections) const
1879 {
1880     aSelections.Clear();
1881 
1882     GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
1883     if (HasFlag(wxDV_MULTIPLE))
1884     {
1885         GtkTreeModel *model;
1886         GList *list = gtk_tree_selection_get_selected_rows( selection, &model );
1887 
1888         int count = 0;
1889         while (list)
1890         {
1891 
1892             // list = g_list_nth( list, 0 );  should be a noop
1893             GtkTreePath *path = (GtkTreePath*) list->data;
1894 
1895             unsigned int row = (unsigned int)gtk_tree_path_get_indices (path)[0];
1896 
1897             aSelections.Add( (int) row );
1898 
1899             list = g_list_next( list );
1900         }
1901 
1902         // delete list
1903         g_list_foreach( list, (GFunc) gtk_tree_path_free, NULL );
1904         g_list_free( list );
1905 
1906         return count;
1907     }
1908     else
1909     {
1910         GtkTreeModel *model;
1911         GtkTreeIter iter;
1912         gboolean has_selection = gtk_tree_selection_get_selected( selection, &model, &iter );
1913         if (has_selection)
1914         {
1915             unsigned int row = (wxUIntPtr) iter.user_data;
1916             aSelections.Add( (int) row );
1917             return 1;
1918         }
1919     }
1920 
1921     return 0;
1922 }
1923 
1924 // static
1925 wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant WXUNUSED (variant))1926 wxDataViewCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
1927 {
1928     return GetDefaultAttributesFromGTKWidget(gtk_tree_view_new);
1929 }
1930 
1931 
1932 #endif
1933     // !wxUSE_GENERICDATAVIEWCTRL
1934 
1935 #endif
1936     // wxUSE_DATAVIEWCTRL
1937