]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/dataview.cpp
Some code renaming to avoid confusion. Test editable column in sample.
[wxWidgets.git] / src / gtk / dataview.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/dataview.cpp
3 // Purpose: wxDataViewCtrl GTK+2 implementation
4 // Author: Robert Roebling
5 // Id: $Id$
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/gtktreesortable.h>
37 #include <gtk/gtktreednd.h>
38
39 #include <gdk/gdkkeysyms.h>
40
41 //-----------------------------------------------------------------------------
42 // classes
43 //-----------------------------------------------------------------------------
44
45 //-----------------------------------------------------------------------------
46 // wxGtkTreeModelNode
47 //-----------------------------------------------------------------------------
48
49 class wxGtkTreeModelNode;
50 WX_DEFINE_ARRAY_PTR( wxGtkTreeModelNode*, wxGtkTreeModelNodes );
51
52 class wxGtkTreeModelNode
53 {
54 public:
55 wxGtkTreeModelNode( wxGtkTreeModelNode* parent, const wxDataViewItem &item )
56 {
57 m_parent = parent;
58 m_item = item;
59 }
60
61 ~wxGtkTreeModelNode()
62 {
63 size_t count = m_children.GetCount();
64 size_t i;
65 for (i = 0; i < count; i++)
66 {
67 wxGtkTreeModelNode *child = m_children[i];
68 delete child;
69 }
70 }
71
72 wxGtkTreeModelNode* GetParent()
73 { return m_parent; }
74 wxGtkTreeModelNodes &GetChildren()
75 { return m_children; }
76 wxGtkTreeModelNode* GetNthChild( unsigned int n )
77 { return m_children.Item( n ); }
78 void Insert( wxGtkTreeModelNode* child, unsigned int n)
79 { m_children.Insert( child, n); }
80 void Append( wxGtkTreeModelNode* child )
81 { m_children.Add( child ); }
82
83 unsigned int GetChildCount() { return m_children.GetCount(); }
84
85 wxDataViewItem &GetItem() { return m_item; }
86
87 bool HasChildren() { return m_hasChildren; }
88 void SetHasChildren( bool has ) { m_hasChildren = has; }
89
90 private:
91 wxGtkTreeModelNode *m_parent;
92 wxGtkTreeModelNodes m_children;
93 wxDataViewItem m_item;
94 bool m_hasChildren;
95 };
96
97
98 extern "C" {
99 typedef struct _GtkWxTreeModel GtkWxTreeModel;
100 }
101
102 class wxDataViewCtrlInternal
103 {
104 public:
105 wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataViewModel *wx_model, GtkWxTreeModel *owner );
106 ~wxDataViewCtrlInternal();
107
108 gboolean get_iter( GtkTreeIter *iter, GtkTreePath *path );
109 GtkTreePath *get_path( GtkTreeIter *iter);
110 gboolean iter_next( GtkTreeIter *iter );
111 gboolean iter_children( GtkTreeIter *iter, GtkTreeIter *parent);
112 gboolean iter_has_child( GtkTreeIter *iter );
113 gint iter_n_children( GtkTreeIter *iter );
114 gboolean iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n );
115 gboolean iter_parent( GtkTreeIter *iter, GtkTreeIter *child );
116
117 wxDataViewModel* GetDataViewModel() { return m_wx_model; }
118 GtkWxTreeModel* GetOwner() { return m_gtk_model; }
119
120 bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
121 bool ItemDeleted( const wxDataViewItem &item );
122
123 protected:
124 void InitTree();
125 wxGtkTreeModelNode *FindNode( const wxDataViewItem &item );
126 wxGtkTreeModelNode *FindNode( GtkTreeIter *iter );
127 void BuildBranch( wxGtkTreeModelNode *branch );
128
129 private:
130 wxGtkTreeModelNode *m_root;
131 wxDataViewModel *m_wx_model;
132 GtkWxTreeModel *m_gtk_model;
133 wxDataViewCtrl *m_owner;
134 };
135
136 //-----------------------------------------------------------------------------
137 // data
138 //-----------------------------------------------------------------------------
139
140 extern bool g_blockEventsOnDrag;
141
142 //-----------------------------------------------------------------------------
143 // define new GTK+ class wxGtkTreeModel
144 //-----------------------------------------------------------------------------
145
146 extern "C" {
147
148 #define GTK_TYPE_WX_TREE_MODEL (gtk_wx_tree_model_get_type ())
149 #define GTK_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModel))
150 #define GTK_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
151 #define GTK_IS_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_TREE_MODEL))
152 #define GTK_IS_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_TREE_MODEL))
153 #define GTK_WX_TREE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
154
155 GType gtk_wx_tree_model_get_type (void);
156
157 typedef struct _GtkWxTreeModelClass GtkWxTreeModelClass;
158
159 struct _GtkWxTreeModel
160 {
161 GObject parent;
162
163 /*< private >*/
164 gint stamp;
165 wxDataViewCtrlInternal *internal;
166
167 gint sort_column_id;
168 GtkSortType order;
169 };
170
171 struct _GtkWxTreeModelClass
172 {
173 GObjectClass list_parent_class;
174 };
175
176 static GtkWxTreeModel *wxgtk_tree_model_new (void);
177 static void wxgtk_tree_model_init (GtkWxTreeModel *tree_model);
178 static void wxgtk_tree_model_class_init (GtkWxTreeModelClass *klass);
179 static void wxgtk_tree_model_tree_model_init (GtkTreeModelIface *iface);
180 static void wxgtk_tree_model_sortable_init (GtkTreeSortableIface *iface);
181 static void wxgtk_tree_model_finalize (GObject *object);
182 static GtkTreeModelFlags wxgtk_tree_model_get_flags (GtkTreeModel *tree_model);
183 static gint wxgtk_tree_model_get_n_columns (GtkTreeModel *tree_model);
184 static GType wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model,
185 gint index);
186 static gboolean wxgtk_tree_model_get_iter (GtkTreeModel *tree_model,
187 GtkTreeIter *iter,
188 GtkTreePath *path);
189 static GtkTreePath *wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
190 GtkTreeIter *iter);
191 static void wxgtk_tree_model_get_value (GtkTreeModel *tree_model,
192 GtkTreeIter *iter,
193 gint column,
194 GValue *value);
195 static gboolean wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
196 GtkTreeIter *iter);
197 static gboolean wxgtk_tree_model_iter_children (GtkTreeModel *tree_model,
198 GtkTreeIter *iter,
199 GtkTreeIter *parent);
200 static gboolean wxgtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
201 GtkTreeIter *iter);
202 static gint wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
203 GtkTreeIter *iter);
204 static gboolean wxgtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
205 GtkTreeIter *iter,
206 GtkTreeIter *parent,
207 gint n);
208 static gboolean wxgtk_tree_model_iter_parent (GtkTreeModel *tree_model,
209 GtkTreeIter *iter,
210 GtkTreeIter *child);
211
212 /* sortable */
213 static gboolean wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
214 gint *sort_column_id,
215 GtkSortType *order);
216 static void wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
217 gint sort_column_id,
218 GtkSortType order);
219 static void wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable,
220 gint sort_column_id,
221 GtkTreeIterCompareFunc func,
222 gpointer data,
223 GtkDestroyNotify destroy);
224 static void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable,
225 GtkTreeIterCompareFunc func,
226 gpointer data,
227 GtkDestroyNotify destroy);
228 static gboolean wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable);
229
230
231
232 static GObjectClass *list_parent_class = NULL;
233
234 GType
235 gtk_wx_tree_model_get_type (void)
236 {
237 static GType tree_model_type = 0;
238
239 if (!tree_model_type)
240 {
241 const GTypeInfo tree_model_info =
242 {
243 sizeof (GtkWxTreeModelClass),
244 NULL, /* base_init */
245 NULL, /* base_finalize */
246 (GClassInitFunc) wxgtk_tree_model_class_init,
247 NULL, /* class_finalize */
248 NULL, /* class_data */
249 sizeof (GtkWxTreeModel),
250 0,
251 (GInstanceInitFunc) wxgtk_tree_model_init,
252 };
253
254 static const GInterfaceInfo tree_model_iface_info =
255 {
256 (GInterfaceInitFunc) wxgtk_tree_model_tree_model_init,
257 NULL,
258 NULL
259 };
260
261 static const GInterfaceInfo sortable_iface_info =
262 {
263 (GInterfaceInitFunc) wxgtk_tree_model_sortable_init,
264 NULL,
265 NULL
266 };
267
268 tree_model_type = g_type_register_static (G_TYPE_OBJECT, "GtkWxTreeModel",
269 &tree_model_info, (GTypeFlags)0 );
270
271 g_type_add_interface_static (tree_model_type,
272 GTK_TYPE_TREE_MODEL,
273 &tree_model_iface_info);
274 g_type_add_interface_static (tree_model_type,
275 GTK_TYPE_TREE_SORTABLE,
276 &sortable_iface_info);
277 }
278
279 return tree_model_type;
280 }
281
282 static GtkWxTreeModel *
283 wxgtk_tree_model_new(void)
284 {
285 GtkWxTreeModel *retval = (GtkWxTreeModel *) g_object_new (GTK_TYPE_WX_TREE_MODEL, NULL);
286 return retval;
287 }
288
289 static void
290 wxgtk_tree_model_class_init (GtkWxTreeModelClass *klass)
291 {
292 list_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
293 GObjectClass *object_class = (GObjectClass*) klass;
294 object_class->finalize = wxgtk_tree_model_finalize;
295 }
296
297 static void
298 wxgtk_tree_model_tree_model_init (GtkTreeModelIface *iface)
299 {
300 iface->get_flags = wxgtk_tree_model_get_flags;
301 iface->get_n_columns = wxgtk_tree_model_get_n_columns;
302 iface->get_column_type = wxgtk_tree_model_get_column_type;
303 iface->get_iter = wxgtk_tree_model_get_iter;
304 iface->get_path = wxgtk_tree_model_get_path;
305 iface->get_value = wxgtk_tree_model_get_value;
306 iface->iter_next = wxgtk_tree_model_iter_next;
307 iface->iter_children = wxgtk_tree_model_iter_children;
308 iface->iter_has_child = wxgtk_tree_model_iter_has_child;
309 iface->iter_n_children = wxgtk_tree_model_iter_n_children;
310 iface->iter_nth_child = wxgtk_tree_model_iter_nth_child;
311 iface->iter_parent = wxgtk_tree_model_iter_parent;
312 }
313
314 static void
315 wxgtk_tree_model_sortable_init (GtkTreeSortableIface *iface)
316 {
317 iface->get_sort_column_id = wxgtk_tree_model_get_sort_column_id;
318 iface->set_sort_column_id = wxgtk_tree_model_set_sort_column_id;
319 iface->set_sort_func = wxgtk_tree_model_set_sort_func;
320 iface->set_default_sort_func = wxgtk_tree_model_set_default_sort_func;
321 iface->has_default_sort_func = wxgtk_tree_model_has_default_sort_func;
322 }
323
324 static void
325 wxgtk_tree_model_init (GtkWxTreeModel *tree_model)
326 {
327 tree_model->internal = NULL;
328 tree_model->stamp = g_random_int();
329 tree_model->sort_column_id = -2;
330 tree_model->order = GTK_SORT_ASCENDING;
331 }
332
333 static void
334 wxgtk_tree_model_finalize (GObject *object)
335 {
336 /* must chain up */
337 (* list_parent_class->finalize) (object);
338 }
339
340 } // extern "C"
341
342 //-----------------------------------------------------------------------------
343 // implement callbacks from wxGtkTreeModel class by letting
344 // them call the methods of wxWidgets' wxDataViewModel
345 //-----------------------------------------------------------------------------
346
347 static GtkTreeModelFlags
348 wxgtk_tree_model_get_flags (GtkTreeModel *tree_model)
349 {
350 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (tree_model), (GtkTreeModelFlags)0 );
351
352 return GTK_TREE_MODEL_ITERS_PERSIST;
353 }
354
355 static gint
356 wxgtk_tree_model_get_n_columns (GtkTreeModel *tree_model)
357 {
358 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
359 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), 0);
360
361 return wxtree_model->internal->GetDataViewModel()->GetColumnCount();
362 }
363
364 static GType
365 wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model,
366 gint index)
367 {
368 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
369 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), G_TYPE_INVALID);
370
371 GType gtype = G_TYPE_INVALID;
372
373 wxString wxtype = wxtree_model->internal->GetDataViewModel()->GetColumnType( (unsigned int) index );
374
375 if (wxtype == wxT("string"))
376 gtype = G_TYPE_STRING;
377 else
378 {
379 wxFAIL_MSG( _T("non-string columns not supported yet") );
380 }
381
382 return gtype;
383 }
384
385 static gboolean
386 wxgtk_tree_model_get_iter (GtkTreeModel *tree_model,
387 GtkTreeIter *iter,
388 GtkTreePath *path)
389 {
390 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
391 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
392 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
393
394 return wxtree_model->internal->get_iter( iter, path );
395 }
396
397 static GtkTreePath *
398 wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
399 GtkTreeIter *iter)
400 {
401 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
402 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), NULL);
403 g_return_val_if_fail (iter->stamp == GTK_WX_TREE_MODEL (wxtree_model)->stamp, NULL);
404
405 return wxtree_model->internal->get_path( iter );
406 }
407
408 static void
409 wxgtk_tree_model_get_value (GtkTreeModel *tree_model,
410 GtkTreeIter *iter,
411 gint column,
412 GValue *value)
413 {
414 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
415 g_return_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model) );
416
417 wxDataViewModel *model = wxtree_model->internal->GetDataViewModel();
418 wxString mtype = model->GetColumnType( (unsigned int) column );
419 if (mtype == wxT("string"))
420 {
421 wxVariant variant;
422 g_value_init( value, G_TYPE_STRING );
423 wxDataViewItem item( (void*) iter->user_data );
424 model->GetValue( variant, item, (unsigned int) column );
425
426 g_value_set_string( value, variant.GetString().utf8_str() );
427 }
428 else
429 {
430 wxFAIL_MSG( _T("non-string columns not supported yet") );
431 }
432 }
433
434 static gboolean
435 wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
436 GtkTreeIter *iter)
437 {
438 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
439 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
440 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
441
442 return wxtree_model->internal->iter_next( iter );
443 }
444
445 static gboolean
446 wxgtk_tree_model_iter_children (GtkTreeModel *tree_model,
447 GtkTreeIter *iter,
448 GtkTreeIter *parent)
449 {
450 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
451 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
452 g_return_val_if_fail (wxtree_model->stamp == parent->stamp, FALSE);
453
454 return wxtree_model->internal->iter_children( iter, parent );
455 }
456
457 static gboolean
458 wxgtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
459 GtkTreeIter *iter)
460 {
461 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
462 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
463 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
464
465 return wxtree_model->internal->iter_has_child( iter );
466 }
467
468 static gint
469 wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
470 GtkTreeIter *iter)
471 {
472 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
473 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
474 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, 0);
475
476 return wxtree_model->internal->iter_n_children( iter );
477 }
478
479 static gboolean
480 wxgtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
481 GtkTreeIter *iter,
482 GtkTreeIter *parent,
483 gint n)
484 {
485 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
486 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
487
488 return wxtree_model->internal->iter_nth_child( iter, parent, n );
489 }
490
491 static gboolean
492 wxgtk_tree_model_iter_parent (GtkTreeModel *tree_model,
493 GtkTreeIter *iter,
494 GtkTreeIter *child)
495 {
496 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
497 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
498 g_return_val_if_fail (wxtree_model->stamp == child->stamp, FALSE);
499
500 return wxtree_model->internal->iter_parent( iter, child );
501 }
502
503 /* sortable */
504 gboolean wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
505 gint *sort_column_id,
506 GtkSortType *order)
507 {
508 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) sortable;
509
510 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (sortable), FALSE);
511
512 if (tree_model->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
513 return FALSE;
514
515 if (sort_column_id)
516 *sort_column_id = tree_model->sort_column_id;
517
518 if (order)
519 *order = tree_model->order;
520
521 return TRUE;
522 }
523
524 void wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
525 gint sort_column_id,
526 GtkSortType order)
527 {
528 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) sortable;
529
530 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
531
532 if ((tree_model->sort_column_id == sort_column_id) &&
533 (tree_model->order == order))
534 return;
535
536 tree_model->sort_column_id = sort_column_id;
537 tree_model->order = order;
538
539 gtk_tree_sortable_sort_column_changed (sortable);
540
541 wxPrintf( "wxgtk_tree_model_set_column_id, sort_column_id = %d, order = %d\n", sort_column_id, (int)order );
542 // sort
543 }
544
545 void wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable,
546 gint sort_column_id,
547 GtkTreeIterCompareFunc func,
548 gpointer data,
549 GtkDestroyNotify destroy)
550 {
551 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
552 g_return_if_fail (func != NULL);
553
554 wxPrintf( "wxgtk_tree_model_set_sort_func, sort_column_id = %d\n", sort_column_id );
555 // sort
556 }
557
558 void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable,
559 GtkTreeIterCompareFunc func,
560 gpointer data,
561 GtkDestroyNotify destroy)
562 {
563 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
564 g_return_if_fail (func != NULL);
565
566 wxPrintf( "wxgtk_tree_model_set_default_sort_func\n" );
567 }
568
569 gboolean wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable)
570 {
571 return FALSE;
572 }
573
574 //-----------------------------------------------------------------------------
575 // define new GTK+ class wxGtkRendererRenderer
576 //-----------------------------------------------------------------------------
577
578 extern "C" {
579
580 #define GTK_TYPE_WX_CELL_RENDERER (gtk_wx_cell_renderer_get_type ())
581 #define GTK_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRenderer))
582 #define GTK_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
583 #define GTK_IS_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_CELL_RENDERER))
584 #define GTK_IS_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_CELL_RENDERER))
585 #define GTK_WX_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
586
587 GType gtk_wx_cell_renderer_get_type (void);
588
589 typedef struct _GtkWxCellRenderer GtkWxCellRenderer;
590 typedef struct _GtkWxCellRendererClass GtkWxCellRendererClass;
591
592 struct _GtkWxCellRenderer
593 {
594 GtkCellRenderer parent;
595
596 /*< private >*/
597 wxDataViewCustomRenderer *cell;
598 guint32 last_click;
599 };
600
601 struct _GtkWxCellRendererClass
602 {
603 GtkCellRendererClass cell_parent_class;
604 };
605
606
607 static GtkCellRenderer *gtk_wx_cell_renderer_new (void);
608 static void gtk_wx_cell_renderer_init (
609 GtkWxCellRenderer *cell );
610 static void gtk_wx_cell_renderer_class_init(
611 GtkWxCellRendererClass *klass );
612 static void gtk_wx_cell_renderer_finalize (
613 GObject *object );
614 static void gtk_wx_cell_renderer_get_size (
615 GtkCellRenderer *cell,
616 GtkWidget *widget,
617 GdkRectangle *rectangle,
618 gint *x_offset,
619 gint *y_offset,
620 gint *width,
621 gint *height );
622 static void gtk_wx_cell_renderer_render (
623 GtkCellRenderer *cell,
624 GdkWindow *window,
625 GtkWidget *widget,
626 GdkRectangle *background_area,
627 GdkRectangle *cell_area,
628 GdkRectangle *expose_area,
629 GtkCellRendererState flags );
630 static gboolean gtk_wx_cell_renderer_activate(
631 GtkCellRenderer *cell,
632 GdkEvent *event,
633 GtkWidget *widget,
634 const gchar *path,
635 GdkRectangle *background_area,
636 GdkRectangle *cell_area,
637 GtkCellRendererState flags );
638 static GtkCellEditable *gtk_wx_cell_renderer_start_editing(
639 GtkCellRenderer *cell,
640 GdkEvent *event,
641 GtkWidget *widget,
642 const gchar *path,
643 GdkRectangle *background_area,
644 GdkRectangle *cell_area,
645 GtkCellRendererState flags );
646
647
648 static GObjectClass *cell_parent_class = NULL;
649
650 } // extern "C"
651
652 GType
653 gtk_wx_cell_renderer_get_type (void)
654 {
655 static GType cell_wx_type = 0;
656
657 if (!cell_wx_type)
658 {
659 const GTypeInfo cell_wx_info =
660 {
661 sizeof (GtkWxCellRendererClass),
662 NULL, /* base_init */
663 NULL, /* base_finalize */
664 (GClassInitFunc) gtk_wx_cell_renderer_class_init,
665 NULL, /* class_finalize */
666 NULL, /* class_data */
667 sizeof (GtkWxCellRenderer),
668 0, /* n_preallocs */
669 (GInstanceInitFunc) gtk_wx_cell_renderer_init,
670 };
671
672 cell_wx_type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
673 "GtkWxCellRenderer", &cell_wx_info, (GTypeFlags)0 );
674 }
675
676 return cell_wx_type;
677 }
678
679 static void
680 gtk_wx_cell_renderer_init (GtkWxCellRenderer *cell)
681 {
682 cell->cell = NULL;
683 cell->last_click = 0;
684 }
685
686 static void
687 gtk_wx_cell_renderer_class_init (GtkWxCellRendererClass *klass)
688 {
689 GObjectClass *object_class = G_OBJECT_CLASS (klass);
690 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
691
692 cell_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
693
694 object_class->finalize = gtk_wx_cell_renderer_finalize;
695
696 cell_class->get_size = gtk_wx_cell_renderer_get_size;
697 cell_class->render = gtk_wx_cell_renderer_render;
698 cell_class->activate = gtk_wx_cell_renderer_activate;
699 cell_class->start_editing = gtk_wx_cell_renderer_start_editing;
700 }
701
702 static void
703 gtk_wx_cell_renderer_finalize (GObject *object)
704 {
705 /* must chain up */
706 (* G_OBJECT_CLASS (cell_parent_class)->finalize) (object);
707 }
708
709 GtkCellRenderer*
710 gtk_wx_cell_renderer_new (void)
711 {
712 return (GtkCellRenderer*) g_object_new (GTK_TYPE_WX_CELL_RENDERER, NULL);
713 }
714
715
716
717 static GtkCellEditable *gtk_wx_cell_renderer_start_editing(
718 GtkCellRenderer *renderer,
719 GdkEvent *event,
720 GtkWidget *widget,
721 const gchar *path,
722 GdkRectangle *background_area,
723 GdkRectangle *cell_area,
724 GtkCellRendererState flags )
725 {
726 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
727 wxDataViewCustomRenderer *cell = wxrenderer->cell;
728 if (!cell->HasEditorCtrl())
729 return NULL;
730
731 GdkRectangle rect;
732 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
733 &rect.x,
734 &rect.y,
735 &rect.width,
736 &rect.height);
737
738 rect.x += cell_area->x;
739 rect.y += cell_area->y;
740 // rect.width -= renderer->xpad * 2;
741 // rect.height -= renderer->ypad * 2;
742
743 // wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
744 wxRect renderrect( cell_area->x, cell_area->y, cell_area->width, cell_area->height );
745
746 GtkTreePath *treepath = gtk_tree_path_new_from_string( path );
747 GtkTreeIter iter;
748 cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, treepath );
749 wxDataViewItem item( (void*) iter.user_data );
750 gtk_tree_path_free( treepath );
751
752 cell->StartEditing( item, renderrect );
753
754 return NULL;
755 }
756
757 static void
758 gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer,
759 GtkWidget *widget,
760 GdkRectangle *cell_area,
761 gint *x_offset,
762 gint *y_offset,
763 gint *width,
764 gint *height)
765 {
766 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
767 wxDataViewCustomRenderer *cell = wxrenderer->cell;
768
769 wxSize size = cell->GetSize();
770
771 gint calc_width = (gint) renderer->xpad * 2 + size.x;
772 gint calc_height = (gint) renderer->ypad * 2 + size.y;
773
774 if (x_offset)
775 *x_offset = 0;
776 if (y_offset)
777 *y_offset = 0;
778
779 if (cell_area && size.x > 0 && size.y > 0)
780 {
781 if (x_offset)
782 {
783 *x_offset = (gint)((renderer->xalign *
784 (cell_area->width - calc_width - 2 * renderer->xpad)));
785 *x_offset = MAX (*x_offset, 0) + renderer->xpad;
786 }
787 if (y_offset)
788 {
789 *y_offset = (gint)((renderer->yalign *
790 (cell_area->height - calc_height - 2 * renderer->ypad)));
791 *y_offset = MAX (*y_offset, 0) + renderer->ypad;
792 }
793 }
794
795 if (width)
796 *width = calc_width;
797
798 if (height)
799 *height = calc_height;
800 }
801
802 static void
803 gtk_wx_cell_renderer_render (GtkCellRenderer *renderer,
804 GdkWindow *window,
805 GtkWidget *widget,
806 GdkRectangle *background_area,
807 GdkRectangle *cell_area,
808 GdkRectangle *expose_area,
809 GtkCellRendererState flags)
810
811 {
812 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
813 wxDataViewCustomRenderer *cell = wxrenderer->cell;
814
815 GdkRectangle rect;
816 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
817 &rect.x,
818 &rect.y,
819 &rect.width,
820 &rect.height);
821
822 rect.x += cell_area->x;
823 rect.y += cell_area->y;
824 rect.width -= renderer->xpad * 2;
825 rect.height -= renderer->ypad * 2;
826
827 GdkRectangle dummy;
828 if (gdk_rectangle_intersect (expose_area, &rect, &dummy))
829 {
830 wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
831 wxWindowDC* dc = (wxWindowDC*) cell->GetDC();
832 if (dc->m_window == NULL)
833 {
834 dc->m_window = window;
835 dc->SetUpDC();
836 }
837
838 int state = 0;
839 if (flags & GTK_CELL_RENDERER_SELECTED)
840 state |= wxDATAVIEW_CELL_SELECTED;
841 if (flags & GTK_CELL_RENDERER_PRELIT)
842 state |= wxDATAVIEW_CELL_PRELIT;
843 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
844 state |= wxDATAVIEW_CELL_INSENSITIVE;
845 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
846 state |= wxDATAVIEW_CELL_INSENSITIVE;
847 if (flags & GTK_CELL_RENDERER_FOCUSED)
848 state |= wxDATAVIEW_CELL_FOCUSED;
849 cell->Render( renderrect, dc, state );
850 }
851 }
852
853 static gboolean
854 gtk_wx_cell_renderer_activate(
855 GtkCellRenderer *renderer,
856 GdkEvent *event,
857 GtkWidget *widget,
858 const gchar *path,
859 GdkRectangle *background_area,
860 GdkRectangle *cell_area,
861 GtkCellRendererState flags )
862 {
863 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
864 wxDataViewCustomRenderer *cell = wxrenderer->cell;
865
866 GdkRectangle rect;
867 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
868 &rect.x,
869 &rect.y,
870 &rect.width,
871 &rect.height);
872
873 rect.x += cell_area->x;
874 rect.y += cell_area->y;
875 rect.width -= renderer->xpad * 2;
876 rect.height -= renderer->ypad * 2;
877
878 wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
879
880 wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel();
881
882 GtkTreePath *treepath = gtk_tree_path_new_from_string( path );
883 // TODO
884 wxDataViewItem item;
885 gtk_tree_path_free( treepath );
886
887 unsigned int model_col = cell->GetOwner()->GetModelColumn();
888
889 if (!event)
890 {
891 bool ret = false;
892
893 // activated by <ENTER>
894 if (cell->Activate( renderrect, model, item, model_col ))
895 ret = true;
896
897 return ret;
898 }
899 else if (event->type == GDK_BUTTON_PRESS)
900 {
901 GdkEventButton *button_event = (GdkEventButton*) event;
902 wxPoint pt( ((int) button_event->x) - renderrect.x,
903 ((int) button_event->y) - renderrect.y );
904
905 bool ret = false;
906 if (button_event->button == 1)
907 {
908 if (cell->LeftClick( pt, renderrect, model, item, model_col ))
909 ret = true;
910 // TODO: query system double-click time
911 if (button_event->time - wxrenderer->last_click < 400)
912 if (cell->Activate( renderrect, model, item, model_col ))
913 ret = true;
914 }
915 if (button_event->button == 3)
916 {
917 if (cell->RightClick( pt, renderrect, model, item, model_col ))
918 ret = true;
919 }
920
921 wxrenderer->last_click = button_event->time;
922
923 return ret;
924 }
925
926 return false;
927 }
928
929 // ---------------------------------------------------------
930 // wxGtkDataViewModelNotifier
931 // ---------------------------------------------------------
932
933 class wxGtkDataViewModelNotifier: public wxDataViewModelNotifier
934 {
935 public:
936 wxGtkDataViewModelNotifier( GtkWxTreeModel *wxgtk_model,
937 wxDataViewModel *wx_model,
938 wxDataViewCtrl *ctrl );
939 ~wxGtkDataViewModelNotifier();
940
941 virtual bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
942 virtual bool ItemDeleted( const wxDataViewItem &item );
943 virtual bool ItemChanged( const wxDataViewItem &item );
944 virtual bool ValueChanged( const wxDataViewItem &item, unsigned int col );
945 virtual bool Cleared();
946
947 GtkWxTreeModel *m_wxgtk_model;
948 wxDataViewModel *m_wx_model;
949 wxDataViewCtrl *m_owner;
950 };
951
952 // ---------------------------------------------------------
953 // wxGtkDataViewListModelNotifier
954 // ---------------------------------------------------------
955
956 wxGtkDataViewModelNotifier::wxGtkDataViewModelNotifier(
957 GtkWxTreeModel* wxgtk_model, wxDataViewModel *wx_model,
958 wxDataViewCtrl *ctrl )
959 {
960 m_wxgtk_model = wxgtk_model;
961 m_wx_model = wx_model;
962 m_owner = ctrl;
963 }
964
965 wxGtkDataViewModelNotifier::~wxGtkDataViewModelNotifier()
966 {
967 m_wx_model = NULL;
968 m_wxgtk_model = NULL;
969 }
970
971 bool wxGtkDataViewModelNotifier::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
972 {
973 m_owner->GtkGetInternal()->ItemAdded( parent, item );
974
975 GtkTreeIter iter;
976 iter.stamp = m_wxgtk_model->stamp;
977 iter.user_data = (gpointer) item.GetID();
978
979 GtkTreePath *path = wxgtk_tree_model_get_path(
980 GTK_TREE_MODEL(m_wxgtk_model), &iter );
981 gtk_tree_model_row_inserted(
982 GTK_TREE_MODEL(m_wxgtk_model), path, &iter);
983 gtk_tree_path_free (path);
984
985 return true;
986 }
987
988 bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem &item )
989 {
990 GtkTreeIter iter;
991 iter.stamp = m_wxgtk_model->stamp;
992 iter.user_data = (gpointer) item.GetID();
993
994 GtkTreePath *path = wxgtk_tree_model_get_path(
995 GTK_TREE_MODEL(m_wxgtk_model), &iter );
996 gtk_tree_model_row_deleted(
997 GTK_TREE_MODEL(m_wxgtk_model), path );
998 gtk_tree_path_free (path);
999
1000 m_owner->GtkGetInternal()->ItemDeleted( item );
1001
1002 return true;
1003 }
1004
1005 bool wxGtkDataViewModelNotifier::ItemChanged( const wxDataViewItem &item )
1006 {
1007 GtkTreeIter iter;
1008 iter.stamp = m_wxgtk_model->stamp;
1009 iter.user_data = (gpointer) item.GetID();
1010
1011 GtkTreePath *path = wxgtk_tree_model_get_path(
1012 GTK_TREE_MODEL(m_wxgtk_model), &iter );
1013 gtk_tree_model_row_changed(
1014 GTK_TREE_MODEL(m_wxgtk_model), path, &iter );
1015 gtk_tree_path_free (path);
1016
1017 return true;
1018 }
1019
1020 bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsigned int model_col )
1021 {
1022 // This adds GTK+'s missing MVC logic for ValueChanged
1023 unsigned int index;
1024 for (index = 0; index < m_owner->GetColumnCount(); index++)
1025 {
1026 wxDataViewColumn *column = m_owner->GetColumn( index );
1027 if (column->GetModelColumn() == model_col)
1028 {
1029 GtkTreeView *widget = GTK_TREE_VIEW(m_owner->m_treeview);
1030 GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle());
1031
1032 // Get cell area
1033 GtkTreeIter iter;
1034 iter.stamp = m_wxgtk_model->stamp;
1035 iter.user_data = (gpointer) item.GetID();
1036 GtkTreePath *path = wxgtk_tree_model_get_path(
1037 GTK_TREE_MODEL(m_wxgtk_model), &iter );
1038 GdkRectangle cell_area;
1039 gtk_tree_view_get_cell_area( widget, path, gcolumn, &cell_area );
1040 gtk_tree_path_free( path );
1041
1042 GtkAdjustment* hadjust = gtk_tree_view_get_hadjustment( widget );
1043 double d = gtk_adjustment_get_value( hadjust );
1044 int xdiff = (int) d;
1045
1046 int ydiff = gcolumn->button->allocation.height;
1047 // Redraw
1048 gtk_widget_queue_draw_area( GTK_WIDGET(widget),
1049 cell_area.x - xdiff, ydiff + cell_area.y, cell_area.width, cell_area.height );
1050 }
1051 }
1052
1053 return true;
1054 }
1055
1056 bool wxGtkDataViewModelNotifier::Cleared()
1057 {
1058 return false;
1059 }
1060
1061 // ---------------------------------------------------------
1062 // wxDataViewRenderer
1063 // ---------------------------------------------------------
1064
1065 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
1066
1067 wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1068 int align ) :
1069 wxDataViewRendererBase( varianttype, mode, align )
1070 {
1071 m_renderer = NULL;
1072
1073 // NOTE: SetMode() and SetAlignment() needs to be called in the renderer's ctor,
1074 // after the m_renderer pointer has been initialized
1075 }
1076
1077 void wxDataViewRenderer::SetMode( wxDataViewCellMode mode )
1078 {
1079 GtkCellRendererMode gtkMode;
1080 switch (mode)
1081 {
1082 case wxDATAVIEW_CELL_INERT:
1083 gtkMode = GTK_CELL_RENDERER_MODE_INERT;
1084 break;
1085 case wxDATAVIEW_CELL_ACTIVATABLE:
1086 gtkMode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
1087 break;
1088 case wxDATAVIEW_CELL_EDITABLE:
1089 gtkMode = GTK_CELL_RENDERER_MODE_EDITABLE;
1090 break;
1091 }
1092
1093 GValue gvalue = { 0, };
1094 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
1095 g_value_set_enum( &gvalue, gtkMode );
1096 g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue );
1097 g_value_unset( &gvalue );
1098 }
1099
1100 wxDataViewCellMode wxDataViewRenderer::GetMode() const
1101 {
1102 wxDataViewCellMode ret;
1103
1104 GValue gvalue;
1105 g_object_get( G_OBJECT(m_renderer), "mode", &gvalue, NULL);
1106
1107 switch (g_value_get_enum(&gvalue))
1108 {
1109 case GTK_CELL_RENDERER_MODE_INERT:
1110 ret = wxDATAVIEW_CELL_INERT;
1111 break;
1112 case GTK_CELL_RENDERER_MODE_ACTIVATABLE:
1113 ret = wxDATAVIEW_CELL_ACTIVATABLE;
1114 break;
1115 case GTK_CELL_RENDERER_MODE_EDITABLE:
1116 ret = wxDATAVIEW_CELL_EDITABLE;
1117 break;
1118 }
1119
1120 g_value_unset( &gvalue );
1121
1122 return ret;
1123 }
1124
1125 void wxDataViewRenderer::SetAlignment( int align )
1126 {
1127 // horizontal alignment:
1128
1129 gfloat xalign = 0.0;
1130 if (align & wxALIGN_RIGHT)
1131 xalign = 1.0;
1132 else if (align & wxALIGN_CENTER_HORIZONTAL)
1133 xalign = 0.5;
1134
1135 GValue gvalue = { 0, };
1136 g_value_init( &gvalue, G_TYPE_FLOAT );
1137 g_value_set_float( &gvalue, xalign );
1138 g_object_set_property( G_OBJECT(m_renderer), "xalign", &gvalue );
1139 g_value_unset( &gvalue );
1140
1141 // vertical alignment:
1142
1143 gfloat yalign = 0.0;
1144 if (align & wxALIGN_BOTTOM)
1145 yalign = 1.0;
1146 else if (align & wxALIGN_CENTER_VERTICAL)
1147 yalign = 0.5;
1148
1149 GValue gvalue2 = { 0, };
1150 g_value_init( &gvalue2, G_TYPE_FLOAT );
1151 g_value_set_float( &gvalue2, yalign );
1152 g_object_set_property( G_OBJECT(m_renderer), "yalign", &gvalue2 );
1153 g_value_unset( &gvalue2 );
1154 }
1155
1156 int wxDataViewRenderer::GetAlignment() const
1157 {
1158 int ret = 0;
1159 GValue gvalue;
1160
1161 // horizontal alignment:
1162
1163 g_object_get( G_OBJECT(m_renderer), "xalign", &gvalue, NULL );
1164 float xalign = g_value_get_float( &gvalue );
1165 if (xalign < 0.5)
1166 ret |= wxALIGN_LEFT;
1167 else if (xalign == 0.5)
1168 ret |= wxALIGN_CENTER_HORIZONTAL;
1169 else
1170 ret |= wxALIGN_RIGHT;
1171 g_value_unset( &gvalue );
1172
1173
1174 // vertical alignment:
1175
1176 g_object_get( G_OBJECT(m_renderer), "yalign", &gvalue, NULL );
1177 float yalign = g_value_get_float( &gvalue );
1178 if (yalign < 0.5)
1179 ret |= wxALIGN_TOP;
1180 else if (yalign == 0.5)
1181 ret |= wxALIGN_CENTER_VERTICAL;
1182 else
1183 ret |= wxALIGN_BOTTOM;
1184 g_value_unset( &gvalue );
1185
1186 return ret;
1187 }
1188
1189
1190
1191 // ---------------------------------------------------------
1192 // wxDataViewTextRenderer
1193 // ---------------------------------------------------------
1194
1195 extern "C" {
1196 static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer,
1197 gchar *arg1, gchar *arg2, gpointer user_data );
1198 }
1199
1200 static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer,
1201 gchar *arg1, gchar *arg2, gpointer user_data )
1202 {
1203 wxDataViewTextRenderer *cell = (wxDataViewTextRenderer*) user_data;
1204
1205 wxString tmp = wxGTK_CONV_BACK_FONT(arg2, cell->GetOwner()->GetOwner()->GetFont());
1206 wxVariant value = tmp;
1207 if (!cell->Validate( value ))
1208 return;
1209
1210 wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel();
1211
1212 GtkTreePath *path = gtk_tree_path_new_from_string( arg1 );
1213 GtkTreeIter iter;
1214 cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, path );
1215 wxDataViewItem item( (void*) iter.user_data );;
1216 gtk_tree_path_free( path );
1217
1218 unsigned int model_col = cell->GetOwner()->GetModelColumn();
1219
1220 model->SetValue( value, item, model_col );
1221 model->ValueChanged( item, model_col );
1222 }
1223
1224 IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewRenderer)
1225
1226 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1227 int align ) :
1228 wxDataViewRenderer( varianttype, mode, align )
1229 {
1230 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_text_new();
1231
1232 if (mode & wxDATAVIEW_CELL_EDITABLE)
1233 {
1234 GValue gvalue = { 0, };
1235 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1236 g_value_set_boolean( &gvalue, true );
1237 g_object_set_property( G_OBJECT(m_renderer), "editable", &gvalue );
1238 g_value_unset( &gvalue );
1239
1240 g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
1241 }
1242
1243 SetMode(mode);
1244 SetAlignment(align);
1245 }
1246
1247 bool wxDataViewTextRenderer::SetValue( const wxVariant &value )
1248 {
1249 wxString tmp = value;
1250
1251 GValue gvalue = { 0, };
1252 g_value_init( &gvalue, G_TYPE_STRING );
1253 g_value_set_string( &gvalue, wxGTK_CONV_FONT( tmp, GetOwner()->GetOwner()->GetFont() ) );
1254 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
1255 g_value_unset( &gvalue );
1256
1257 return true;
1258 }
1259
1260 bool wxDataViewTextRenderer::GetValue( wxVariant &value ) const
1261 {
1262 GValue gvalue = { 0, };
1263 g_value_init( &gvalue, G_TYPE_STRING );
1264 g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
1265 wxString tmp = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ),
1266 wx_const_cast(wxDataViewTextRenderer*, this)->GetOwner()->GetOwner()->GetFont() );
1267 g_value_unset( &gvalue );
1268
1269 value = tmp;
1270
1271 return true;
1272 }
1273
1274 void wxDataViewTextRenderer::SetAlignment( int align )
1275 {
1276 wxDataViewRenderer::SetAlignment(align);
1277
1278 if (gtk_check_version(2,10,0))
1279 return;
1280
1281 // horizontal alignment:
1282 PangoAlignment pangoAlign = PANGO_ALIGN_LEFT;
1283 if (align & wxALIGN_RIGHT)
1284 pangoAlign = PANGO_ALIGN_RIGHT;
1285 else if (align & wxALIGN_CENTER_HORIZONTAL)
1286 pangoAlign = PANGO_ALIGN_CENTER;
1287
1288 GValue gvalue = { 0, };
1289 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
1290 g_value_set_enum( &gvalue, pangoAlign );
1291 g_object_set_property( G_OBJECT(m_renderer), "alignment", &gvalue );
1292 g_value_unset( &gvalue );
1293 }
1294
1295 // ---------------------------------------------------------
1296 // wxDataViewBitmapRenderer
1297 // ---------------------------------------------------------
1298
1299 IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewRenderer)
1300
1301 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1302 int align ) :
1303 wxDataViewRenderer( varianttype, mode, align )
1304 {
1305 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_pixbuf_new();
1306
1307 SetMode(mode);
1308 SetAlignment(align);
1309 }
1310
1311 bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
1312 {
1313 if (value.GetType() == wxT("wxBitmap"))
1314 {
1315 wxBitmap bitmap;
1316 bitmap << value;
1317
1318 // This may create a Pixbuf representation in the
1319 // wxBitmap object (and it will stay there)
1320 GdkPixbuf *pixbuf = bitmap.GetPixbuf();
1321
1322 GValue gvalue = { 0, };
1323 g_value_init( &gvalue, G_TYPE_OBJECT );
1324 g_value_set_object( &gvalue, pixbuf );
1325 g_object_set_property( G_OBJECT(m_renderer), "pixbuf", &gvalue );
1326 g_value_unset( &gvalue );
1327
1328 return true;
1329 }
1330
1331 if (value.GetType() == wxT("wxIcon"))
1332 {
1333 wxIcon bitmap;
1334 bitmap << value;
1335
1336 // This may create a Pixbuf representation in the
1337 // wxBitmap object (and it will stay there)
1338 GdkPixbuf *pixbuf = bitmap.GetPixbuf();
1339
1340 GValue gvalue = { 0, };
1341 g_value_init( &gvalue, G_TYPE_OBJECT );
1342 g_value_set_object( &gvalue, pixbuf );
1343 g_object_set_property( G_OBJECT(m_renderer), "pixbuf", &gvalue );
1344 g_value_unset( &gvalue );
1345
1346 return true;
1347 }
1348
1349 return false;
1350 }
1351
1352 bool wxDataViewBitmapRenderer::GetValue( wxVariant &value ) const
1353 {
1354 return false;
1355 }
1356
1357 // ---------------------------------------------------------
1358 // wxDataViewToggleRenderer
1359 // ---------------------------------------------------------
1360
1361 extern "C" {
1362 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
1363 gchar *path, gpointer user_data );
1364 }
1365
1366 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
1367 gchar *path, gpointer user_data )
1368 {
1369 wxDataViewToggleRenderer *cell = (wxDataViewToggleRenderer*) user_data;
1370
1371 // get old value
1372 GValue gvalue = { 0, };
1373 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1374 g_object_get_property( G_OBJECT(renderer), "active", &gvalue );
1375 bool tmp = g_value_get_boolean( &gvalue );
1376 g_value_unset( &gvalue );
1377 // invert it
1378 tmp = !tmp;
1379
1380 wxVariant value = tmp;
1381 if (!cell->Validate( value ))
1382 return;
1383
1384 wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel();
1385
1386 GtkTreePath *gtk_path = gtk_tree_path_new_from_string( path );
1387 GtkTreeIter iter;
1388 cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, gtk_path );
1389 wxDataViewItem item( (void*) iter.user_data );;
1390 gtk_tree_path_free( gtk_path );
1391
1392 unsigned int model_col = cell->GetOwner()->GetModelColumn();
1393
1394 model->SetValue( value, item, model_col );
1395 model->ValueChanged( item, model_col );
1396 }
1397
1398 IMPLEMENT_CLASS(wxDataViewToggleRenderer, wxDataViewRenderer)
1399
1400 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
1401 wxDataViewCellMode mode, int align ) :
1402 wxDataViewRenderer( varianttype, mode, align )
1403 {
1404 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_toggle_new();
1405
1406 if (mode & wxDATAVIEW_CELL_ACTIVATABLE)
1407 {
1408 g_signal_connect_after( m_renderer, "toggled",
1409 G_CALLBACK(wxGtkToggleRendererToggledCallback), this );
1410 }
1411 else
1412 {
1413 GValue gvalue = { 0, };
1414 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1415 g_value_set_boolean( &gvalue, false );
1416 g_object_set_property( G_OBJECT(m_renderer), "activatable", &gvalue );
1417 g_value_unset( &gvalue );
1418 }
1419
1420 SetMode(mode);
1421 SetAlignment(align);
1422 }
1423
1424 bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
1425 {
1426 bool tmp = value;
1427
1428 GValue gvalue = { 0, };
1429 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1430 g_value_set_boolean( &gvalue, tmp );
1431 g_object_set_property( G_OBJECT(m_renderer), "active", &gvalue );
1432 g_value_unset( &gvalue );
1433
1434 return true;
1435 }
1436
1437 bool wxDataViewToggleRenderer::GetValue( wxVariant &value ) const
1438 {
1439 GValue gvalue = { 0, };
1440 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1441 g_object_get_property( G_OBJECT(m_renderer), "active", &gvalue );
1442 bool tmp = g_value_get_boolean( &gvalue );
1443 g_value_unset( &gvalue );
1444
1445 value = tmp;
1446
1447 return true;
1448 }
1449
1450 // ---------------------------------------------------------
1451 // wxDataViewCustomRenderer
1452 // ---------------------------------------------------------
1453
1454 class wxDataViewCtrlDC: public wxWindowDC
1455 {
1456 public:
1457 wxDataViewCtrlDC( wxDataViewCtrl *window )
1458 {
1459 GtkWidget *widget = window->m_treeview;
1460 // Set later
1461 m_window = NULL;
1462
1463 m_context = window->GtkGetPangoDefaultContext();
1464 m_layout = pango_layout_new( m_context );
1465 m_fontdesc = pango_font_description_copy( widget->style->font_desc );
1466
1467 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
1468
1469 // Set m_window later
1470 // SetUpDC();
1471 // m_owner = window;
1472 }
1473 };
1474
1475 // ---------------------------------------------------------
1476 // wxDataViewCustomRenderer
1477 // ---------------------------------------------------------
1478
1479 IMPLEMENT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
1480
1481 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
1482 wxDataViewCellMode mode, int align,
1483 bool no_init ) :
1484 wxDataViewRenderer( varianttype, mode, align )
1485 {
1486 m_dc = NULL;
1487
1488 if (no_init)
1489 m_renderer = NULL;
1490 else
1491 Init(mode, align);
1492 }
1493
1494 bool wxDataViewCustomRenderer::Init(wxDataViewCellMode mode, int align)
1495 {
1496 GtkWxCellRenderer *renderer = (GtkWxCellRenderer *) gtk_wx_cell_renderer_new();
1497 renderer->cell = this;
1498
1499 m_renderer = (GtkCellRenderer*) renderer;
1500
1501 SetMode(mode);
1502 SetAlignment(align);
1503
1504 return true;
1505 }
1506
1507 wxDataViewCustomRenderer::~wxDataViewCustomRenderer()
1508 {
1509 if (m_dc)
1510 delete m_dc;
1511 }
1512
1513 wxDC *wxDataViewCustomRenderer::GetDC()
1514 {
1515 if (m_dc == NULL)
1516 {
1517 if (GetOwner() == NULL)
1518 return NULL;
1519 if (GetOwner()->GetOwner() == NULL)
1520 return NULL;
1521 m_dc = new wxDataViewCtrlDC( GetOwner()->GetOwner() );
1522 }
1523
1524 return m_dc;
1525 }
1526
1527 // ---------------------------------------------------------
1528 // wxDataViewProgressRenderer
1529 // ---------------------------------------------------------
1530
1531 IMPLEMENT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
1532
1533 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
1534 const wxString &varianttype, wxDataViewCellMode mode, int align ) :
1535 wxDataViewCustomRenderer( varianttype, mode, align, true )
1536 {
1537 m_label = label;
1538 m_value = 0;
1539
1540 #ifdef __WXGTK26__
1541 if (!gtk_check_version(2,6,0))
1542 {
1543 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_progress_new();
1544
1545 GValue gvalue = { 0, };
1546 g_value_init( &gvalue, G_TYPE_STRING );
1547
1548 // FIXME: font encoding support
1549 g_value_set_string( &gvalue, wxGTK_CONV_SYS(m_label) );
1550 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
1551 g_value_unset( &gvalue );
1552
1553 SetMode(mode);
1554 SetAlignment(align);
1555 }
1556 else
1557 #endif
1558 {
1559 // Use custom cell code
1560 wxDataViewCustomRenderer::Init(mode, align);
1561 }
1562 }
1563
1564 wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
1565 {
1566 }
1567
1568 bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
1569 {
1570 #ifdef __WXGTK26__
1571 if (!gtk_check_version(2,6,0))
1572 {
1573 gint tmp = (long) value;
1574 GValue gvalue = { 0, };
1575 g_value_init( &gvalue, G_TYPE_INT );
1576 g_value_set_int( &gvalue, tmp );
1577 g_object_set_property( G_OBJECT(m_renderer), "value", &gvalue );
1578 g_value_unset( &gvalue );
1579 }
1580 else
1581 #endif
1582 {
1583 m_value = (long) value;
1584
1585 if (m_value < 0) m_value = 0;
1586 if (m_value > 100) m_value = 100;
1587 }
1588
1589 return true;
1590 }
1591
1592 bool wxDataViewProgressRenderer::GetValue( wxVariant &value ) const
1593 {
1594 return false;
1595 }
1596
1597 bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int state )
1598 {
1599 double pct = (double)m_value / 100.0;
1600 wxRect bar = cell;
1601 bar.width = (int)(cell.width * pct);
1602 dc->SetPen( *wxTRANSPARENT_PEN );
1603 dc->SetBrush( *wxBLUE_BRUSH );
1604 dc->DrawRectangle( bar );
1605
1606 dc->SetBrush( *wxTRANSPARENT_BRUSH );
1607 dc->SetPen( *wxBLACK_PEN );
1608 dc->DrawRectangle( cell );
1609
1610 return true;
1611 }
1612
1613 wxSize wxDataViewProgressRenderer::GetSize() const
1614 {
1615 return wxSize(40,12);
1616 }
1617
1618 // ---------------------------------------------------------
1619 // wxDataViewDateRenderer
1620 // ---------------------------------------------------------
1621
1622 class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
1623 {
1624 public:
1625 wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
1626 wxDataViewModel *model, const wxDataViewItem &item, unsigned int col ) :
1627 wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
1628 {
1629 m_model = model;
1630 m_item = item;
1631 m_col = col;
1632 m_cal = new wxCalendarCtrl( this, -1, *value );
1633 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
1634 sizer->Add( m_cal, 1, wxGROW );
1635 SetSizer( sizer );
1636 sizer->Fit( this );
1637 }
1638
1639 virtual void OnDismiss()
1640 {
1641 }
1642
1643 void OnCalendar( wxCalendarEvent &event );
1644
1645 wxCalendarCtrl *m_cal;
1646 wxDataViewModel *m_model;
1647 wxDataViewItem m_item;
1648 unsigned int m_col;
1649
1650 private:
1651 DECLARE_EVENT_TABLE()
1652 };
1653
1654 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
1655 EVT_CALENDAR( -1, wxDataViewDateRendererPopupTransient::OnCalendar )
1656 END_EVENT_TABLE()
1657
1658 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
1659 {
1660 wxDateTime date = event.GetDate();
1661 wxVariant value = date;
1662 m_model->SetValue( value, m_item, m_col );
1663 m_model->ValueChanged( m_item, m_col );
1664 DismissAndNotify();
1665 }
1666
1667 IMPLEMENT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
1668
1669 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
1670 wxDataViewCellMode mode, int align ) :
1671 wxDataViewCustomRenderer( varianttype, mode, align )
1672 {
1673 SetMode(mode);
1674 SetAlignment(align);
1675 }
1676
1677 bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
1678 {
1679 m_date = value.GetDateTime();
1680
1681 return true;
1682 }
1683
1684 bool wxDataViewDateRenderer::GetValue( wxVariant &value ) const
1685 {
1686 return false;
1687 }
1688
1689 bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state )
1690 {
1691 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
1692 wxString tmp = m_date.FormatDate();
1693 dc->DrawText( tmp, cell.x, cell.y );
1694
1695 return true;
1696 }
1697
1698 wxSize wxDataViewDateRenderer::GetSize() const
1699 {
1700 wxString tmp = m_date.FormatDate();
1701 wxCoord x,y,d;
1702 GetView()->GetTextExtent( tmp, &x, &y, &d );
1703 return wxSize(x,y+d);
1704 }
1705
1706 bool wxDataViewDateRenderer::Activate( wxRect cell, wxDataViewModel *model,
1707 const wxDataViewItem &item, unsigned int col )
1708 {
1709 wxVariant variant;
1710 model->GetValue( variant, item, col );
1711 wxDateTime value = variant.GetDateTime();
1712
1713 wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
1714 GetOwner()->GetOwner()->GetParent(), &value, model, item, col );
1715 wxPoint pos = wxGetMousePosition();
1716 popup->Move( pos );
1717 popup->Layout();
1718 popup->Popup( popup->m_cal );
1719
1720 return true;
1721 }
1722
1723 // ---------------------------------------------------------
1724 // wxDataViewColumn
1725 // ---------------------------------------------------------
1726
1727
1728 static gboolean
1729 gtk_dataview_header_button_press_callback( GtkWidget *widget,
1730 GdkEventButton *gdk_event,
1731 wxDataViewColumn *column )
1732 {
1733 if (gdk_event->type != GDK_BUTTON_PRESS)
1734 return FALSE;
1735
1736 if (gdk_event->button == 1)
1737 {
1738 wxDataViewCtrl *dv = column->GetOwner();
1739 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, dv->GetId() );
1740 event.SetDataViewColumn( column );
1741 event.SetModel( dv->GetModel() );
1742 if (dv->GetEventHandler()->ProcessEvent( event ))
1743 return TRUE;
1744 }
1745
1746 return FALSE;
1747 }
1748
1749 extern "C" {
1750 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
1751 GtkCellRenderer *cell,
1752 GtkTreeModel *model,
1753 GtkTreeIter *iter,
1754 gpointer data );
1755 }
1756
1757
1758 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
1759 GtkCellRenderer *renderer,
1760 GtkTreeModel *model,
1761 GtkTreeIter *iter,
1762 gpointer data )
1763 {
1764 g_return_if_fail (GTK_IS_WX_TREE_MODEL (model));
1765 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) model;
1766
1767 wxDataViewRenderer *cell = (wxDataViewRenderer*) data;
1768
1769 wxDataViewItem item( (void*) iter->user_data );
1770
1771 wxVariant value;
1772 tree_model->internal->GetDataViewModel()->GetValue( value, item, cell->GetOwner()->GetModelColumn() );
1773
1774 if (value.GetType() != cell->GetVariantType())
1775 wxLogError( wxT("Wrong type, required: %s but: %s"),
1776 value.GetType().c_str(),
1777 cell->GetVariantType().c_str() );
1778
1779 cell->SetValue( value );
1780
1781 #if 0
1782 wxListItemAttr attr;
1783 tree_model->model->GetAttr( attr, cell->GetOwner()->GetModelColumn(), model_row );
1784
1785 if (attr.HasBackgroundColour())
1786 {
1787 wxColour colour = attr.GetBackgroundColour();
1788 const GdkColor * const gcol = colour.GetColor();
1789
1790 GValue gvalue = { 0, };
1791 g_value_init( &gvalue, GDK_TYPE_COLOR );
1792 g_value_set_boxed( &gvalue, gcol );
1793 g_object_set_property( G_OBJECT(renderer), "cell-background_gdk", &gvalue );
1794 g_value_unset( &gvalue );
1795 }
1796 else
1797 {
1798 GValue gvalue = { 0, };
1799 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1800 g_value_set_boolean( &gvalue, FALSE );
1801 g_object_set_property( G_OBJECT(renderer), "cell-background-set", &gvalue );
1802 g_value_unset( &gvalue );
1803 }
1804 #endif
1805
1806 }
1807
1808 IMPLEMENT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
1809
1810 wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell,
1811 unsigned int model_column, int width,
1812 wxAlignment align, int flags ) :
1813 wxDataViewColumnBase( title, cell, model_column, width, align, flags )
1814 {
1815 Init( align, flags, width );
1816
1817 gtk_tree_view_column_set_clickable( GTK_TREE_VIEW_COLUMN(m_column), TRUE );
1818 SetTitle( title );
1819 }
1820
1821 wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell,
1822 unsigned int model_column, int width,
1823 wxAlignment align, int flags ) :
1824 wxDataViewColumnBase( bitmap, cell, model_column, width, align, flags )
1825 {
1826 Init( align, flags, width );
1827
1828 SetBitmap( bitmap );
1829 }
1830
1831 void wxDataViewColumn::Init(wxAlignment align, int flags, int width)
1832 {
1833 m_isConnected = false;
1834
1835 GtkCellRenderer *renderer = (GtkCellRenderer *) GetRenderer()->GetGtkHandle();
1836 GtkTreeViewColumn *column = gtk_tree_view_column_new();
1837 m_column = (GtkWidget*) column;
1838
1839 SetFlags( flags );
1840 SetAlignment( align );
1841
1842 // NOTE: we prefer not to call SetMinWidth(wxDVC_DEFAULT_MINWIDTH);
1843 // as GTK+ is smart and unless explicitely told, will set the minimal
1844 // width to the title's lenght, which is a better default
1845
1846 // the GTK_TREE_VIEW_COLUMN_FIXED is required by the "fixed height" mode
1847 // that we use for the wxDataViewCtrl
1848 gtk_tree_view_column_set_fixed_width( column, width < 0 ? wxDVC_DEFAULT_WIDTH : width );
1849 gtk_tree_view_column_set_sizing( column, GTK_TREE_VIEW_COLUMN_FIXED );
1850
1851 gtk_tree_view_column_pack_end( column, renderer, TRUE );
1852
1853 gtk_tree_view_column_set_cell_data_func( column, renderer,
1854 wxGtkTreeCellDataFunc, (gpointer) GetRenderer(), NULL );
1855 }
1856
1857 wxDataViewColumn::~wxDataViewColumn()
1858 {
1859 }
1860
1861 void wxDataViewColumn::OnInternalIdle()
1862 {
1863 if (m_isConnected)
1864 return;
1865
1866 if (GTK_WIDGET_REALIZED(GetOwner()->m_treeview))
1867 {
1868 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
1869 if (column->button)
1870 {
1871 g_signal_connect(column->button, "button_press_event",
1872 G_CALLBACK (gtk_dataview_header_button_press_callback), this);
1873
1874 m_isConnected = true;
1875 }
1876 }
1877 }
1878
1879 void wxDataViewColumn::SetOwner( wxDataViewCtrl *owner )
1880 {
1881 wxDataViewColumnBase::SetOwner( owner );
1882
1883 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
1884
1885 gtk_tree_view_column_set_title( column, wxGTK_CONV_FONT(GetTitle(), GetOwner()->GetFont() ) );
1886 }
1887
1888 void wxDataViewColumn::SetTitle( const wxString &title )
1889 {
1890 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
1891
1892 if (m_isConnected)
1893 {
1894 // disconnect before column->button gets recreated
1895 g_signal_handlers_disconnect_by_func( column->button,
1896 (GtkWidget*) gtk_dataview_header_button_press_callback, this);
1897
1898 m_isConnected = false;
1899 }
1900
1901 // FIXME: can it really happen that we don't have the owner here??
1902 wxDataViewCtrl *ctrl = GetOwner();
1903 gtk_tree_view_column_set_title( column, ctrl ? wxGTK_CONV_FONT(title, ctrl->GetFont())
1904 : wxGTK_CONV_SYS(title) );
1905
1906 gtk_tree_view_column_set_widget( column, NULL );
1907 }
1908
1909 wxString wxDataViewColumn::GetTitle() const
1910 {
1911 const gchar *str = gtk_tree_view_column_get_title( GTK_TREE_VIEW_COLUMN(m_column) );
1912 return wxConvFileName->cMB2WX(str);
1913 }
1914
1915 void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap )
1916 {
1917 wxDataViewColumnBase::SetBitmap( bitmap );
1918
1919 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
1920 if (bitmap.Ok())
1921 {
1922 GtkImage *gtk_image = GTK_IMAGE( gtk_image_new() );
1923
1924 GdkBitmap *mask = (GdkBitmap *) NULL;
1925 if (bitmap.GetMask())
1926 mask = bitmap.GetMask()->GetBitmap();
1927
1928 if (bitmap.HasPixbuf())
1929 {
1930 gtk_image_set_from_pixbuf(GTK_IMAGE(gtk_image),
1931 bitmap.GetPixbuf());
1932 }
1933 else
1934 {
1935 gtk_image_set_from_pixmap(GTK_IMAGE(gtk_image),
1936 bitmap.GetPixmap(), mask);
1937 }
1938 gtk_widget_show( GTK_WIDGET(gtk_image) );
1939
1940 gtk_tree_view_column_set_widget( column, GTK_WIDGET(gtk_image) );
1941 }
1942 else
1943 {
1944 gtk_tree_view_column_set_widget( column, NULL );
1945 }
1946 }
1947
1948 void wxDataViewColumn::SetHidden( bool hidden )
1949 {
1950 gtk_tree_view_column_set_visible( GTK_TREE_VIEW_COLUMN(m_column), !hidden );
1951 }
1952
1953 void wxDataViewColumn::SetResizeable( bool resizeable )
1954 {
1955 gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizeable );
1956 }
1957
1958 void wxDataViewColumn::SetAlignment( wxAlignment align )
1959 {
1960 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
1961
1962 gfloat xalign = 0.0;
1963 if (align == wxALIGN_RIGHT)
1964 xalign = 1.0;
1965 if (align == wxALIGN_CENTER_HORIZONTAL ||
1966 align == wxALIGN_CENTER)
1967 xalign = 0.5;
1968
1969 gtk_tree_view_column_set_alignment( column, xalign );
1970 }
1971
1972 wxAlignment wxDataViewColumn::GetAlignment() const
1973 {
1974 gfloat xalign = gtk_tree_view_column_get_alignment( GTK_TREE_VIEW_COLUMN(m_column) );
1975
1976 if (xalign == 1.0)
1977 return wxALIGN_RIGHT;
1978 if (xalign == 0.5)
1979 return wxALIGN_CENTER_HORIZONTAL;
1980
1981 return wxALIGN_LEFT;
1982 }
1983
1984 void wxDataViewColumn::SetSortable( bool sortable )
1985 {
1986 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
1987
1988 if (sortable)
1989 gtk_tree_view_column_set_sort_column_id( column, GetModelColumn() );
1990 else
1991 gtk_tree_view_column_set_sort_column_id( column, -1 );
1992 }
1993
1994 bool wxDataViewColumn::IsSortable() const
1995 {
1996 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
1997 return (gtk_tree_view_column_get_sort_column_id( column ) != -1);
1998 }
1999
2000 bool wxDataViewColumn::IsResizeable() const
2001 {
2002 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2003 return gtk_tree_view_column_get_resizable( column );
2004 }
2005
2006 bool wxDataViewColumn::IsHidden() const
2007 {
2008 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2009 return !gtk_tree_view_column_get_visible( column );
2010 }
2011
2012 void wxDataViewColumn::SetSortOrder( bool ascending )
2013 {
2014 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2015
2016 if (ascending)
2017 gtk_tree_view_column_set_sort_order( column, GTK_SORT_ASCENDING );
2018 else
2019 gtk_tree_view_column_set_sort_order( column, GTK_SORT_DESCENDING );
2020 }
2021
2022 bool wxDataViewColumn::IsSortOrderAscending() const
2023 {
2024 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2025
2026 return (gtk_tree_view_column_get_sort_order( column ) != GTK_SORT_DESCENDING);
2027 }
2028
2029 void wxDataViewColumn::SetMinWidth( int width )
2030 {
2031 gtk_tree_view_column_set_min_width( GTK_TREE_VIEW_COLUMN(m_column), width );
2032 }
2033
2034 int wxDataViewColumn::GetMinWidth() const
2035 {
2036 return gtk_tree_view_column_get_min_width( GTK_TREE_VIEW_COLUMN(m_column) );
2037 }
2038
2039 int wxDataViewColumn::GetWidth() const
2040 {
2041 return gtk_tree_view_column_get_width( GTK_TREE_VIEW_COLUMN(m_column) );
2042 }
2043
2044 void wxDataViewColumn::SetWidth( int width )
2045 {
2046 gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), width );
2047 }
2048
2049
2050 //-----------------------------------------------------------------------------
2051 // wxDataViewCtrlInternal
2052 //-----------------------------------------------------------------------------
2053
2054 wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner,
2055 wxDataViewModel *wx_model, GtkWxTreeModel *gtk_model )
2056 {
2057 m_owner = owner;
2058 m_wx_model = wx_model;
2059 m_gtk_model = gtk_model;
2060 m_root = NULL;
2061 InitTree();
2062 }
2063
2064 wxDataViewCtrlInternal::~wxDataViewCtrlInternal()
2065 {
2066 g_object_unref( m_gtk_model );
2067 }
2068
2069 void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node )
2070 {
2071 if (node->GetChildCount() == 0)
2072 {
2073 wxDataViewItem child = m_wx_model->GetFirstChild( node->GetItem() );
2074 while (child.IsOk())
2075 {
2076 // wxPrintf( "AddItem %d\n", (int) child.GetID() );
2077 node->Append( new wxGtkTreeModelNode( node, child ) );
2078 child = m_wx_model->GetNextSibling( child );
2079 }
2080 }
2081 }
2082
2083 bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
2084 {
2085 wxGtkTreeModelNode *parent_node = FindNode( parent );
2086 parent_node->Append( new wxGtkTreeModelNode( parent_node, item ) );
2087 return true;
2088 }
2089
2090 bool wxDataViewCtrlInternal::ItemDeleted( const wxDataViewItem &item )
2091 {
2092 wxGtkTreeModelNode *node = FindNode( item );
2093 wxGtkTreeModelNode *parent = node->GetParent();
2094 parent->GetChildren().Remove( node );
2095 delete node;
2096
2097 return true;
2098 }
2099
2100 gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path )
2101 {
2102 int depth = gtk_tree_path_get_depth( path );
2103
2104 wxGtkTreeModelNode *node = m_root;
2105
2106 int i;
2107 for (i = 0; i < depth; i++)
2108 {
2109 BuildBranch( node );
2110
2111 gint pos = gtk_tree_path_get_indices (path)[i];
2112 if (pos < 0) return FALSE;
2113 if ((size_t)pos >= node->GetChildCount()) return FALSE;
2114
2115 node = node->GetChildren().Item( (size_t) pos );
2116 }
2117
2118 iter->stamp = m_gtk_model->stamp;
2119 iter->user_data = (gpointer) node->GetItem().GetID();
2120
2121 return TRUE;
2122 }
2123
2124 GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter )
2125 {
2126 GtkTreePath *retval = gtk_tree_path_new ();
2127
2128 wxGtkTreeModelNode *node = FindNode( iter );
2129 while (node->GetParent())
2130 {
2131 wxGtkTreeModelNode *parent = node->GetParent();
2132 int pos = parent->GetChildren().Index( node );
2133
2134 gtk_tree_path_prepend_index( retval, pos );
2135
2136 node = parent;
2137 }
2138
2139 return retval;
2140 }
2141
2142 gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter )
2143 {
2144 wxDataViewItem item( (void*) iter->user_data );
2145 item = m_wx_model->GetNextSibling( item );
2146 if (!item.IsOk())
2147 return FALSE;
2148
2149 iter->user_data = (gpointer) item.GetID();
2150
2151 return TRUE;
2152 }
2153
2154 gboolean wxDataViewCtrlInternal::iter_children( GtkTreeIter *iter, GtkTreeIter *parent )
2155 {
2156 wxDataViewItem item( (void*) parent->user_data );
2157
2158 if (!m_wx_model->HasChildren( item ))
2159 return FALSE;
2160
2161 wxGtkTreeModelNode *parent_node = FindNode( parent );
2162 BuildBranch( parent_node );
2163
2164 wxGtkTreeModelNode *first_child_node = parent_node->GetChildren().Item( 0 );
2165
2166 iter->stamp = m_gtk_model->stamp;
2167 iter->user_data = (gpointer) first_child_node->GetItem().GetID();
2168
2169 return TRUE;
2170 }
2171
2172 gboolean wxDataViewCtrlInternal::iter_has_child( GtkTreeIter *iter )
2173 {
2174 wxDataViewItem item( (void*) iter->user_data );
2175
2176 return m_wx_model->HasChildren( item );
2177 }
2178
2179 gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter )
2180 {
2181 wxDataViewItem item( (void*) iter->user_data );
2182
2183 if (!m_wx_model->HasChildren( item ))
2184 return 0;
2185
2186 wxGtkTreeModelNode *parent_node = FindNode( iter );
2187 BuildBranch( parent_node );
2188
2189 return parent_node->GetChildCount();
2190 }
2191
2192 gboolean wxDataViewCtrlInternal::iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n )
2193 {
2194 void* id = NULL;
2195 if (parent) id = (void*) parent->user_data;
2196 wxDataViewItem item( id );
2197
2198 if (!m_wx_model->HasChildren( item ))
2199 return FALSE;
2200
2201 wxGtkTreeModelNode *parent_node = FindNode( parent );
2202 BuildBranch( parent_node );
2203
2204 wxGtkTreeModelNode *child_node = parent_node->GetChildren().Item( (size_t) n );
2205 if (!child_node)
2206 return FALSE;
2207
2208 iter->stamp = m_gtk_model->stamp;
2209 iter->user_data = (gpointer) child_node->GetItem().GetID();
2210
2211 return TRUE;
2212 }
2213
2214 gboolean wxDataViewCtrlInternal::iter_parent( GtkTreeIter *iter, GtkTreeIter *child )
2215 {
2216 wxDataViewItem item( (void*) child->user_data );
2217
2218 wxGtkTreeModelNode *node = FindNode( child );
2219 node = node->GetParent();
2220 if (!node)
2221 return FALSE;
2222
2223 iter->stamp = m_gtk_model->stamp;
2224 iter->user_data = (gpointer) node->GetItem().GetID();
2225
2226 return TRUE;
2227 }
2228
2229 void wxDataViewCtrlInternal::InitTree()
2230 {
2231 wxDataViewItem item;
2232 m_root = new wxGtkTreeModelNode( NULL, item );
2233
2234 BuildBranch( m_root );
2235 }
2236
2237 static wxGtkTreeModelNode*
2238 wxDataViewCtrlInternal_FindNode( wxGtkTreeModelNode *node, const wxDataViewItem &item )
2239 {
2240 if (!node) return NULL;
2241
2242 size_t count = node->GetChildCount();
2243 size_t i;
2244 for (i = 0; i < count; i++)
2245 {
2246 wxGtkTreeModelNode *child = node->GetChildren().Item( i );
2247 if (child->GetItem().GetID() == item.GetID())
2248 return child;
2249
2250 wxGtkTreeModelNode *node2 = wxDataViewCtrlInternal_FindNode( child, item );
2251 if (node2)
2252 return node2;
2253 }
2254
2255 return NULL;
2256 }
2257
2258 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
2259 {
2260 if (!iter)
2261 return m_root;
2262
2263 wxDataViewItem item( (void*) iter->user_data );
2264
2265 wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_root, item );
2266
2267 if (!result)
2268 {
2269 wxPrintf( "Not found %d\n", (int) iter->user_data );
2270 char *crash = NULL;
2271 *crash = 0;
2272 }
2273
2274 return result;
2275 }
2276
2277 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item )
2278 {
2279 wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_root, item );
2280
2281 if (!result)
2282 {
2283 wxPrintf( "Not found %d\n", (int) item.GetID() );
2284 char *crash = NULL;
2285 *crash = 0;
2286 }
2287
2288 return result;
2289 }
2290
2291 //-----------------------------------------------------------------------------
2292 // wxDataViewCtrl signal callbacks
2293 //-----------------------------------------------------------------------------
2294
2295 static void
2296 wxdataview_selection_changed_callback( GtkTreeSelection* selection, wxDataViewCtrl *dv )
2297 {
2298 if (!GTK_WIDGET_REALIZED(dv->m_widget))
2299 return;
2300
2301 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_SELECTED, dv->GetId() );
2302 // TODO: item
2303 event.SetModel( dv->GetModel() );
2304 dv->GetEventHandler()->ProcessEvent( event );
2305 }
2306
2307 static void
2308 wxdataview_row_activated_callback( GtkTreeView* treeview, GtkTreePath *path,
2309 GtkTreeViewColumn *column, wxDataViewCtrl *dv )
2310 {
2311 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, dv->GetId() );
2312
2313 GtkTreeIter iter;
2314 dv->GtkGetInternal()->get_iter( &iter, path );
2315 wxDataViewItem item( (void*) iter.user_data );;
2316 event.SetItem( item );
2317 event.SetModel( dv->GetModel() );
2318 dv->GetEventHandler()->ProcessEvent( event );
2319 }
2320
2321 //-----------------------------------------------------------------------------
2322 // wxDataViewCtrl
2323 //-----------------------------------------------------------------------------
2324
2325 //-----------------------------------------------------------------------------
2326 // InsertChild for wxDataViewCtrl
2327 //-----------------------------------------------------------------------------
2328
2329 static void wxInsertChildInDataViewCtrl( wxWindowGTK* parent, wxWindowGTK* child )
2330 {
2331 wxDataViewCtrl * dvc = (wxDataViewCtrl*) parent;
2332 GtkWidget *treeview = dvc->GtkGetTreeView();
2333
2334 // Insert widget in GtkTreeView
2335 if (GTK_WIDGET_REALIZED(treeview))
2336 gtk_widget_set_parent_window( child->m_widget,
2337 gtk_tree_view_get_bin_window( GTK_TREE_VIEW(treeview) ) );
2338 gtk_widget_set_parent( child->m_widget, treeview );
2339 }
2340
2341 static
2342 void gtk_dataviewctrl_size_callback( GtkWidget *WXUNUSED(widget),
2343 GtkAllocation *alloc,
2344 wxDataViewCtrl *win )
2345 {
2346
2347 wxWindowList::Node *node = win->GetChildren().GetFirst();
2348 while (node)
2349 {
2350 wxWindow *child = node->GetData();
2351
2352 GtkRequisition req;
2353 gtk_widget_size_request( child->m_widget, &req );
2354
2355 GtkAllocation alloc;
2356 alloc.x = child->m_x;
2357 alloc.y = child->m_y;
2358 alloc.width = child->m_width;
2359 alloc.height = child->m_height;
2360 gtk_widget_size_allocate( child->m_widget, &alloc );
2361
2362 node = node->GetNext();
2363 }
2364 }
2365
2366
2367
2368 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
2369
2370 wxDataViewCtrl::~wxDataViewCtrl()
2371 {
2372 if (m_notifier)
2373 GetModel()->RemoveNotifier( m_notifier );
2374
2375 // remove the model from the GtkTreeView before it gets destroyed by the
2376 // wxDataViewCtrlBase's dtor
2377 gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview), NULL );
2378
2379 delete m_internal;
2380 }
2381
2382 void wxDataViewCtrl::Init()
2383 {
2384 m_notifier = NULL;
2385 }
2386
2387 bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
2388 const wxPoint& pos, const wxSize& size,
2389 long style, const wxValidator& validator )
2390 {
2391 Init();
2392
2393 if (!PreCreation( parent, pos, size ) ||
2394 !CreateBase( parent, id, pos, size, style, validator ))
2395 {
2396 wxFAIL_MSG( wxT("wxDataViewCtrl creation failed") );
2397 return false;
2398 }
2399
2400 m_insertCallback = wxInsertChildInDataViewCtrl;
2401
2402 m_widget = gtk_scrolled_window_new (NULL, NULL);
2403
2404 GtkScrolledWindowSetBorder(m_widget, style);
2405
2406 m_treeview = gtk_tree_view_new();
2407 gtk_container_add (GTK_CONTAINER (m_widget), m_treeview);
2408
2409 g_signal_connect (m_treeview, "size_allocate",
2410 G_CALLBACK (gtk_dataviewctrl_size_callback), this);
2411
2412 #ifdef __WXGTK26__
2413 if (!gtk_check_version(2,6,0))
2414 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), TRUE );
2415 #endif
2416
2417 if (style & wxDV_MULTIPLE)
2418 {
2419 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
2420 gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
2421 }
2422
2423 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(m_treeview), (style & wxDV_NO_HEADER) == 0 );
2424
2425 #ifdef __WXGTK210__
2426 if (!gtk_check_version(2,10,0))
2427 {
2428 GtkTreeViewGridLines grid = GTK_TREE_VIEW_GRID_LINES_NONE;
2429
2430 if ((style & wxDV_HORIZ_RULES) != 0 &&
2431 (style & wxDV_VERT_RULES) != 0)
2432 grid = GTK_TREE_VIEW_GRID_LINES_BOTH;
2433 else if (style & wxDV_VERT_RULES)
2434 grid = GTK_TREE_VIEW_GRID_LINES_VERTICAL;
2435 else if (style & wxDV_HORIZ_RULES)
2436 grid = GTK_TREE_VIEW_GRID_LINES_HORIZONTAL;
2437
2438 gtk_tree_view_set_grid_lines( GTK_TREE_VIEW(m_treeview), grid );
2439 }
2440 else
2441 #endif
2442 {
2443 gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(m_treeview), (style & wxDV_HORIZ_RULES) != 0 );
2444 }
2445
2446 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_widget),
2447 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2448 gtk_widget_show (m_treeview);
2449
2450 m_parent->DoAddChild( this );
2451
2452 PostCreation(size);
2453
2454 GtkEnableSelectionEvents();
2455
2456 g_signal_connect_after (m_treeview, "row_activated",
2457 G_CALLBACK (wxdataview_row_activated_callback), this);
2458
2459 return true;
2460 }
2461
2462 void wxDataViewCtrl::OnInternalIdle()
2463 {
2464 wxWindow::OnInternalIdle();
2465
2466 unsigned int cols = GetColumnCount();
2467 unsigned int i;
2468 for (i = 0; i < cols; i++)
2469 {
2470 wxDataViewColumn *col = GetColumn( i );
2471 col->OnInternalIdle();
2472 }
2473 }
2474
2475 bool wxDataViewCtrl::AssociateModel( wxDataViewModel *model )
2476 {
2477 if (!wxDataViewCtrlBase::AssociateModel( model ))
2478 return false;
2479
2480 GtkWxTreeModel *gtk_model = wxgtk_tree_model_new();
2481 m_internal = new wxDataViewCtrlInternal( this, model, gtk_model );
2482 gtk_model->internal = m_internal;
2483
2484 m_notifier = new wxGtkDataViewModelNotifier( gtk_model, model, this );
2485
2486 model->AddNotifier( m_notifier );
2487
2488 gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview), GTK_TREE_MODEL(gtk_model) );
2489
2490 // unref in wxDataViewCtrlInternal
2491 // g_object_unref( gtk_model );
2492
2493 return true;
2494 }
2495
2496 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
2497 {
2498 if (!wxDataViewCtrlBase::AppendColumn(col))
2499 return false;
2500
2501 GtkTreeViewColumn *column = (GtkTreeViewColumn *)col->GetGtkHandle();
2502
2503 gtk_tree_view_append_column( GTK_TREE_VIEW(m_treeview), column );
2504
2505 return true;
2506 }
2507
2508 wxDataViewItem wxDataViewCtrl::GetSelection()
2509 {
2510 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
2511
2512 if (m_windowStyle & wxDV_MULTIPLE)
2513 {
2514 }
2515 else
2516 {
2517 GtkTreeIter iter;
2518 if (gtk_tree_selection_get_selected( selection, NULL, &iter ))
2519 {
2520 wxDataViewItem item( (void*) iter.user_data );
2521 return item;
2522 }
2523 }
2524
2525 return wxDataViewItem(0);
2526 }
2527
2528 void wxDataViewCtrl::DoSetExpanderColumn()
2529 {
2530 }
2531
2532 void wxDataViewCtrl::DoSetIndent()
2533 {
2534 }
2535
2536 void wxDataViewCtrl::GtkDisableSelectionEvents()
2537 {
2538 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
2539 g_signal_connect_after (selection, "changed",
2540 G_CALLBACK (wxdataview_selection_changed_callback), this);
2541 }
2542
2543 void wxDataViewCtrl::GtkEnableSelectionEvents()
2544 {
2545 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
2546 g_signal_handlers_disconnect_by_func( selection,
2547 (gpointer) (wxdataview_selection_changed_callback), this);
2548 }
2549
2550 // static
2551 wxVisualAttributes
2552 wxDataViewCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
2553 {
2554 return GetDefaultAttributesFromGTKWidget(gtk_tree_view_new);
2555 }
2556
2557
2558 #endif
2559 // !wxUSE_GENERICDATAVIEWCTRL
2560
2561 #endif
2562 // wxUSE_DATAVIEWCTRL