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