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