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