No changes, just add wxGtkList to ensure g_list_free() is always called.
[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 #include "wx/settings.h"
24 #include "wx/crt.h"
25 #endif
26
27 #include "wx/stockitem.h"
28 #include "wx/calctrl.h"
29 #include "wx/popupwin.h"
30 #include "wx/listimpl.cpp"
31
32 #include "wx/gtk/private.h"
33 #include "wx/gtk/dc.h"
34 #include "wx/gtk/dcclient.h"
35
36 #include "wx/gtk/private/gdkconv.h"
37 #include "wx/gtk/private/list.h"
38 using namespace wxGTKImpl;
39
40 class wxGtkDataViewModelNotifier;
41
42 //-----------------------------------------------------------------------------
43 //-----------------------------------------------------------------------------
44
45 static wxDataViewCtrlInternal *gs_internal = NULL;
46
47 class wxGtkTreeModelNode;
48
49 extern "C" {
50 typedef struct _GtkWxTreeModel GtkWxTreeModel;
51 }
52
53 // ----------------------------------------------------------------------------
54 // wxGtkTreePath: self-destroying GtkTreePath
55 // ----------------------------------------------------------------------------
56
57 // Usually this object is initialized with the associated GtkTreePath
58 // immediately when it's constructed but it can also be changed later either by
59 // using Assign() or by getting the pointer to the internally stored pointer
60 // value using ByRef(). The latter should be avoided but is very convenient
61 // when using GTK functions with GtkTreePath output parameters.
62 class wxGtkTreePath
63 {
64 public:
65 // Ctor takes ownership of the given path and will free it if non-NULL.
66 wxGtkTreePath(GtkTreePath *path = NULL) : m_path(path) { }
67
68 // Creates a tree path for the given string path.
69 wxGtkTreePath(const gchar *strpath)
70 : m_path(gtk_tree_path_new_from_string(strpath))
71 {
72 }
73
74 // Set the stored pointer if not done by ctor.
75 void Assign(GtkTreePath *path)
76 {
77 wxASSERT_MSG( !m_path, "shouldn't be already initialized" );
78
79 m_path = path;
80 }
81
82 // Return the pointer to the internally stored pointer. This should only be
83 // used to initialize the object by passing it to some GTK function.
84 GtkTreePath **ByRef()
85 {
86 wxASSERT_MSG( !m_path, "shouldn't be already initialized" );
87
88 return &m_path;
89 }
90
91
92 operator GtkTreePath *() const { return m_path; }
93
94 ~wxGtkTreePath() { if ( m_path ) gtk_tree_path_free(m_path); }
95
96 private:
97 GtkTreePath *m_path;
98
99 wxDECLARE_NO_COPY_CLASS(wxGtkTreePath);
100 };
101
102 // ----------------------------------------------------------------------------
103 // wxGtkTreePathList: self-destroying list of GtkTreePath objects.
104 // ----------------------------------------------------------------------------
105
106 class wxGtkTreePathList : public wxGtkList
107 {
108 public:
109 // Ctor takes ownership of the list.
110 explicit wxGtkTreePathList(GList* list)
111 : wxGtkList(list)
112 {
113 }
114
115 ~wxGtkTreePathList()
116 {
117 // Delete the list contents, wxGtkList will delete the list itself.
118 g_list_foreach(m_list, (GFunc)gtk_tree_path_free, NULL);
119 }
120 };
121
122 // ----------------------------------------------------------------------------
123 // wxGtkTreeSelectionLock: prevent selection from changing during the
124 // lifetime of this object
125 // ----------------------------------------------------------------------------
126
127 // Implementation note: it could be expected that setting the selection
128 // function in this class ctor and resetting it back to the old value in its
129 // dtor would work. However currently gtk_tree_selection_get_select_function()
130 // can't be passed NULL (see https://bugzilla.gnome.org/show_bug.cgi?id=626276)
131 // so we can't do this. Instead, we always use the selection function (which
132 // imposes extra overhead, albeit minimal one, on all selection operations) and
133 // just set/reset the flag telling it whether it should allow or forbid the
134 // selection.
135 //
136 // Also notice that currently only a single object of this class may exist at
137 // any given moment. It's just simpler like this and we don't need anything
138 // more for now.
139
140 extern "C"
141 gboolean wxdataview_selection_func(GtkTreeSelection * WXUNUSED(selection),
142 GtkTreeModel * WXUNUSED(model),
143 GtkTreePath * WXUNUSED(path),
144 gboolean WXUNUSED(path_currently_selected),
145 gpointer data)
146 {
147 return data == NULL;
148 }
149
150 class wxGtkTreeSelectionLock
151 {
152 public:
153 wxGtkTreeSelectionLock(GtkTreeSelection *selection)
154 : m_selection(selection)
155 {
156 wxASSERT_MSG( !ms_instance, "this class is not reentrant currently" );
157
158 ms_instance = this;
159
160 CheckCurrentSelectionFunc(NULL);
161
162 // Pass some non-NULL pointer as "data" for the callback, it doesn't
163 // matter what it is as long as it's non-NULL.
164 gtk_tree_selection_set_select_function(selection,
165 wxdataview_selection_func,
166 this,
167 NULL);
168 }
169
170 ~wxGtkTreeSelectionLock()
171 {
172 CheckCurrentSelectionFunc(wxdataview_selection_func);
173
174 gtk_tree_selection_set_select_function(m_selection,
175 wxdataview_selection_func,
176 NULL,
177 NULL);
178
179 ms_instance = NULL;
180 }
181
182 private:
183 void CheckCurrentSelectionFunc(GtkTreeSelectionFunc func)
184 {
185 // We can only use gtk_tree_selection_get_select_function() with 2.14+
186 // so check for its availability both during compile- and run-time.
187 #if GTK_CHECK_VERSION(2, 14, 0)
188 if ( gtk_check_version(2, 14, 0) != NULL )
189 return;
190
191 // If this assert is triggered, it means the code elsewhere has called
192 // gtk_tree_selection_set_select_function() but currently doing this
193 // breaks this class so the code here needs to be changed.
194 wxASSERT_MSG
195 (
196 gtk_tree_selection_get_select_function(m_selection) == func,
197 "selection function has changed unexpectedly, review this code!"
198 );
199 #endif // GTK+ 2.14+
200
201 wxUnusedVar(func);
202 }
203
204 static wxGtkTreeSelectionLock *ms_instance;
205
206 GtkTreeSelection * const m_selection;
207
208 wxDECLARE_NO_COPY_CLASS(wxGtkTreeSelectionLock);
209 };
210
211 wxGtkTreeSelectionLock *wxGtkTreeSelectionLock::ms_instance = NULL;
212
213 //-----------------------------------------------------------------------------
214 // wxDataViewCtrlInternal
215 //-----------------------------------------------------------------------------
216
217 WX_DECLARE_LIST(wxDataViewItem, ItemList);
218 WX_DEFINE_LIST(ItemList)
219
220 class wxDataViewCtrlInternal
221 {
222 public:
223 wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataViewModel *wx_model );
224 ~wxDataViewCtrlInternal();
225
226 // model iface
227 GtkTreeModelFlags get_flags();
228 gboolean get_iter( GtkTreeIter *iter, GtkTreePath *path );
229 GtkTreePath *get_path( GtkTreeIter *iter);
230 gboolean iter_next( GtkTreeIter *iter );
231 gboolean iter_children( GtkTreeIter *iter, GtkTreeIter *parent);
232 gboolean iter_has_child( GtkTreeIter *iter );
233 gint iter_n_children( GtkTreeIter *iter );
234 gboolean iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n );
235 gboolean iter_parent( GtkTreeIter *iter, GtkTreeIter *child );
236
237 // dnd iface
238
239 bool EnableDragSource( const wxDataFormat &format );
240 bool EnableDropTarget( const wxDataFormat &format );
241
242 gboolean row_draggable( GtkTreeDragSource *drag_source, GtkTreePath *path );
243 gboolean drag_data_delete( GtkTreeDragSource *drag_source, GtkTreePath* path );
244 gboolean drag_data_get( GtkTreeDragSource *drag_source, GtkTreePath *path,
245 GtkSelectionData *selection_data );
246 gboolean drag_data_received( GtkTreeDragDest *drag_dest, GtkTreePath *dest,
247 GtkSelectionData *selection_data );
248 gboolean row_drop_possible( GtkTreeDragDest *drag_dest, GtkTreePath *dest_path,
249 GtkSelectionData *selection_data );
250
251 // notifactions from wxDataViewModel
252 bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
253 bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
254 bool ItemChanged( const wxDataViewItem &item );
255 bool ValueChanged( const wxDataViewItem &item, unsigned int model_column );
256 bool Cleared();
257 bool BeforeReset();
258 bool AfterReset();
259 void Resort();
260
261 // sorting interface
262 void SetSortOrder( GtkSortType sort_order ) { m_sort_order = sort_order; }
263 GtkSortType GetSortOrder() const { return m_sort_order; }
264
265 void SetSortColumn( int column ) { m_sort_column = column; }
266 int GetSortColumn() const { return m_sort_column; }
267
268 void SetDataViewSortColumn( wxDataViewColumn *column ) { m_dataview_sort_column = column; }
269 wxDataViewColumn *GetDataViewSortColumn() { return m_dataview_sort_column; }
270
271 bool IsSorted() { return (m_sort_column >= 0); }
272
273 // accessors
274 wxDataViewModel* GetDataViewModel() { return m_wx_model; }
275 const wxDataViewModel* GetDataViewModel() const { return m_wx_model; }
276 wxDataViewCtrl* GetOwner() { return m_owner; }
277 GtkWxTreeModel* GetGtkModel() { return m_gtk_model; }
278
279 // item can be deleted already in the model
280 int GetIndexOf( const wxDataViewItem &parent, const wxDataViewItem &item );
281
282 virtual void OnInternalIdle();
283
284 protected:
285 void InitTree();
286 void ScheduleRefresh();
287
288 wxGtkTreeModelNode *FindNode( const wxDataViewItem &item );
289 wxGtkTreeModelNode *FindNode( GtkTreeIter *iter );
290 wxGtkTreeModelNode *FindParentNode( const wxDataViewItem &item );
291 wxGtkTreeModelNode *FindParentNode( GtkTreeIter *iter );
292 void BuildBranch( wxGtkTreeModelNode *branch );
293
294 private:
295 wxGtkTreeModelNode *m_root;
296 wxDataViewModel *m_wx_model;
297 GtkWxTreeModel *m_gtk_model;
298 wxDataViewCtrl *m_owner;
299 GtkSortType m_sort_order;
300 wxDataViewColumn *m_dataview_sort_column;
301 int m_sort_column;
302
303 GtkTargetEntry m_dragSourceTargetEntry;
304 wxCharBuffer m_dragSourceTargetEntryTarget;
305 wxDataObject *m_dragDataObject;
306
307 GtkTargetEntry m_dropTargetTargetEntry;
308 wxCharBuffer m_dropTargetTargetEntryTarget;
309 wxDataObject *m_dropDataObject;
310
311 wxGtkDataViewModelNotifier *m_notifier;
312
313 bool m_dirty;
314 };
315
316
317 //-----------------------------------------------------------------------------
318 // wxGtkTreeModelNode
319 //-----------------------------------------------------------------------------
320
321 static
322 int LINKAGEMODE wxGtkTreeModelChildCmp( void** id1, void** id2 )
323 {
324 int ret = gs_internal->GetDataViewModel()->Compare( wxDataViewItem(*id1), wxDataViewItem(*id2),
325 gs_internal->GetSortColumn(), (gs_internal->GetSortOrder() == GTK_SORT_ASCENDING) );
326
327 return ret;
328 }
329
330 WX_DEFINE_ARRAY_PTR( wxGtkTreeModelNode*, wxGtkTreeModelNodes );
331 WX_DEFINE_ARRAY_PTR( void*, wxGtkTreeModelChildren );
332
333 class wxGtkTreeModelNode
334 {
335 public:
336 wxGtkTreeModelNode( wxGtkTreeModelNode* parent, const wxDataViewItem &item,
337 wxDataViewCtrlInternal *internal )
338 {
339 m_parent = parent;
340 m_item = item;
341 m_internal = internal;
342 }
343
344 ~wxGtkTreeModelNode()
345 {
346 size_t count = m_nodes.GetCount();
347 size_t i;
348 for (i = 0; i < count; i++)
349 {
350 wxGtkTreeModelNode *child = m_nodes.Item( i );
351 delete child;
352 }
353 }
354
355 unsigned int AddNode( wxGtkTreeModelNode* child )
356 {
357 m_nodes.Add( child );
358
359 void *id = child->GetItem().GetID();
360
361 m_children.Add( id );
362
363 if (m_internal->IsSorted() || m_internal->GetDataViewModel()->HasDefaultCompare())
364 {
365 gs_internal = m_internal;
366 m_children.Sort( &wxGtkTreeModelChildCmp );
367 return m_children.Index( id );
368 }
369
370 return m_children.GetCount()-1;
371 }
372
373 unsigned int AddLeave( void* id )
374 {
375 m_children.Add( id );
376
377 if (m_internal->IsSorted() || m_internal->GetDataViewModel()->HasDefaultCompare())
378 {
379 gs_internal = m_internal;
380 m_children.Sort( &wxGtkTreeModelChildCmp );
381 return m_children.Index( id );
382 }
383
384 return m_children.GetCount()-1;
385 }
386
387 void DeleteChild( void* id )
388 {
389 m_children.Remove( id );
390
391 unsigned int count = m_nodes.GetCount();
392 unsigned int pos;
393 for (pos = 0; pos < count; pos++)
394 {
395 wxGtkTreeModelNode *node = m_nodes.Item( pos );
396 if (node->GetItem().GetID() == id)
397 {
398 m_nodes.RemoveAt( pos );
399 delete node;
400 break;
401 }
402 }
403 }
404
405 wxGtkTreeModelNode* GetParent()
406 { return m_parent; }
407 wxGtkTreeModelNodes &GetNodes()
408 { return m_nodes; }
409 wxGtkTreeModelChildren &GetChildren()
410 { return m_children; }
411
412 unsigned int GetChildCount() const { return m_children.GetCount(); }
413 unsigned int GetNodesCount() const { return m_nodes.GetCount(); }
414
415 wxDataViewItem &GetItem() { return m_item; }
416 wxDataViewCtrlInternal *GetInternal() { return m_internal; }
417
418 void Resort();
419
420 private:
421 wxGtkTreeModelNode *m_parent;
422 wxGtkTreeModelNodes m_nodes;
423 wxGtkTreeModelChildren m_children;
424 wxDataViewItem m_item;
425 wxDataViewCtrlInternal *m_internal;
426 };
427
428
429 //-----------------------------------------------------------------------------
430 // data
431 //-----------------------------------------------------------------------------
432
433 extern bool g_blockEventsOnDrag;
434
435 //-----------------------------------------------------------------------------
436 // define new GTK+ class wxGtkTreeModel
437 //-----------------------------------------------------------------------------
438
439 extern "C" {
440
441 #define GTK_TYPE_WX_TREE_MODEL (gtk_wx_tree_model_get_type ())
442 #define GTK_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModel))
443 #define GTK_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
444 #define GTK_IS_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_TREE_MODEL))
445 #define GTK_IS_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_TREE_MODEL))
446 #define GTK_WX_TREE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
447
448 GType gtk_wx_tree_model_get_type (void);
449
450 typedef struct _GtkWxTreeModelClass GtkWxTreeModelClass;
451
452 struct _GtkWxTreeModel
453 {
454 GObject parent;
455
456 /*< private >*/
457 gint stamp;
458 wxDataViewCtrlInternal *internal;
459 };
460
461 struct _GtkWxTreeModelClass
462 {
463 GObjectClass list_parent_class;
464 };
465
466 static GtkWxTreeModel *wxgtk_tree_model_new (void);
467 static void wxgtk_tree_model_init (GtkWxTreeModel *tree_model);
468 static void wxgtk_tree_model_class_init (GtkWxTreeModelClass *klass);
469
470 static void wxgtk_tree_model_tree_model_init (GtkTreeModelIface *iface);
471 static void wxgtk_tree_model_sortable_init (GtkTreeSortableIface *iface);
472 static void wxgtk_tree_model_drag_source_init(GtkTreeDragSourceIface *iface);
473 static void wxgtk_tree_model_drag_dest_init (GtkTreeDragDestIface *iface);
474
475 static void wxgtk_tree_model_finalize (GObject *object);
476 static GtkTreeModelFlags wxgtk_tree_model_get_flags (GtkTreeModel *tree_model);
477 static gint wxgtk_tree_model_get_n_columns (GtkTreeModel *tree_model);
478 static GType wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model,
479 gint index);
480 static gboolean wxgtk_tree_model_get_iter (GtkTreeModel *tree_model,
481 GtkTreeIter *iter,
482 GtkTreePath *path);
483 static GtkTreePath *wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
484 GtkTreeIter *iter);
485 static void wxgtk_tree_model_get_value (GtkTreeModel *tree_model,
486 GtkTreeIter *iter,
487 gint column,
488 GValue *value);
489 static gboolean wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
490 GtkTreeIter *iter);
491 static gboolean wxgtk_tree_model_iter_children (GtkTreeModel *tree_model,
492 GtkTreeIter *iter,
493 GtkTreeIter *parent);
494 static gboolean wxgtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
495 GtkTreeIter *iter);
496 static gint wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
497 GtkTreeIter *iter);
498 static gboolean wxgtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
499 GtkTreeIter *iter,
500 GtkTreeIter *parent,
501 gint n);
502 static gboolean wxgtk_tree_model_iter_parent (GtkTreeModel *tree_model,
503 GtkTreeIter *iter,
504 GtkTreeIter *child);
505
506 /* sortable */
507 static gboolean wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
508 gint *sort_column_id,
509 GtkSortType *order);
510 static void wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
511 gint sort_column_id,
512 GtkSortType order);
513 static void wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable,
514 gint sort_column_id,
515 GtkTreeIterCompareFunc func,
516 gpointer data,
517 GDestroyNotify destroy);
518 static void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable,
519 GtkTreeIterCompareFunc func,
520 gpointer data,
521 GDestroyNotify destroy);
522 static gboolean wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable);
523
524 /* drag'n'drop */
525 static gboolean wxgtk_tree_model_row_draggable (GtkTreeDragSource *drag_source,
526 GtkTreePath *path);
527 static gboolean wxgtk_tree_model_drag_data_delete (GtkTreeDragSource *drag_source,
528 GtkTreePath *path);
529 static gboolean wxgtk_tree_model_drag_data_get (GtkTreeDragSource *drag_source,
530 GtkTreePath *path,
531 GtkSelectionData *selection_data);
532 static gboolean wxgtk_tree_model_drag_data_received (GtkTreeDragDest *drag_dest,
533 GtkTreePath *dest,
534 GtkSelectionData *selection_data);
535 static gboolean wxgtk_tree_model_row_drop_possible (GtkTreeDragDest *drag_dest,
536 GtkTreePath *dest_path,
537 GtkSelectionData *selection_data);
538
539
540 static GObjectClass *list_parent_class = NULL;
541
542 GType
543 gtk_wx_tree_model_get_type (void)
544 {
545 static GType tree_model_type = 0;
546
547 if (!tree_model_type)
548 {
549 const GTypeInfo tree_model_info =
550 {
551 sizeof (GtkWxTreeModelClass),
552 NULL, /* base_init */
553 NULL, /* base_finalize */
554 (GClassInitFunc) wxgtk_tree_model_class_init,
555 NULL, /* class_finalize */
556 NULL, /* class_data */
557 sizeof (GtkWxTreeModel),
558 0,
559 (GInstanceInitFunc) wxgtk_tree_model_init,
560 };
561
562 static const GInterfaceInfo tree_model_iface_info =
563 {
564 (GInterfaceInitFunc) wxgtk_tree_model_tree_model_init,
565 NULL,
566 NULL
567 };
568
569 static const GInterfaceInfo sortable_iface_info =
570 {
571 (GInterfaceInitFunc) wxgtk_tree_model_sortable_init,
572 NULL,
573 NULL
574 };
575
576 static const GInterfaceInfo drag_source_iface_info =
577 {
578 (GInterfaceInitFunc) wxgtk_tree_model_drag_source_init,
579 NULL,
580 NULL
581 };
582
583 static const GInterfaceInfo drag_dest_iface_info =
584 {
585 (GInterfaceInitFunc) wxgtk_tree_model_drag_dest_init,
586 NULL,
587 NULL
588 };
589
590 tree_model_type = g_type_register_static (G_TYPE_OBJECT, "GtkWxTreeModel",
591 &tree_model_info, (GTypeFlags)0 );
592
593 g_type_add_interface_static (tree_model_type,
594 GTK_TYPE_TREE_MODEL,
595 &tree_model_iface_info);
596 g_type_add_interface_static (tree_model_type,
597 GTK_TYPE_TREE_SORTABLE,
598 &sortable_iface_info);
599 g_type_add_interface_static (tree_model_type,
600 GTK_TYPE_TREE_DRAG_DEST,
601 &drag_dest_iface_info);
602 g_type_add_interface_static (tree_model_type,
603 GTK_TYPE_TREE_DRAG_SOURCE,
604 &drag_source_iface_info);
605 }
606
607 return tree_model_type;
608 }
609
610 static GtkWxTreeModel *
611 wxgtk_tree_model_new(void)
612 {
613 GtkWxTreeModel *retval = (GtkWxTreeModel *) g_object_new (GTK_TYPE_WX_TREE_MODEL, NULL);
614 return retval;
615 }
616
617 static void
618 wxgtk_tree_model_class_init (GtkWxTreeModelClass *klass)
619 {
620 list_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
621 GObjectClass *object_class = (GObjectClass*) klass;
622 object_class->finalize = wxgtk_tree_model_finalize;
623 }
624
625 static void
626 wxgtk_tree_model_tree_model_init (GtkTreeModelIface *iface)
627 {
628 iface->get_flags = wxgtk_tree_model_get_flags;
629 iface->get_n_columns = wxgtk_tree_model_get_n_columns;
630 iface->get_column_type = wxgtk_tree_model_get_column_type;
631 iface->get_iter = wxgtk_tree_model_get_iter;
632 iface->get_path = wxgtk_tree_model_get_path;
633 iface->get_value = wxgtk_tree_model_get_value;
634 iface->iter_next = wxgtk_tree_model_iter_next;
635 iface->iter_children = wxgtk_tree_model_iter_children;
636 iface->iter_has_child = wxgtk_tree_model_iter_has_child;
637 iface->iter_n_children = wxgtk_tree_model_iter_n_children;
638 iface->iter_nth_child = wxgtk_tree_model_iter_nth_child;
639 iface->iter_parent = wxgtk_tree_model_iter_parent;
640 }
641
642 static void
643 wxgtk_tree_model_sortable_init (GtkTreeSortableIface *iface)
644 {
645 iface->get_sort_column_id = wxgtk_tree_model_get_sort_column_id;
646 iface->set_sort_column_id = wxgtk_tree_model_set_sort_column_id;
647 iface->set_sort_func = wxgtk_tree_model_set_sort_func;
648 iface->set_default_sort_func = wxgtk_tree_model_set_default_sort_func;
649 iface->has_default_sort_func = wxgtk_tree_model_has_default_sort_func;
650 }
651
652 static void
653 wxgtk_tree_model_drag_source_init(GtkTreeDragSourceIface *iface)
654 {
655 iface->row_draggable = wxgtk_tree_model_row_draggable;
656 iface->drag_data_delete = wxgtk_tree_model_drag_data_delete;
657 iface->drag_data_get = wxgtk_tree_model_drag_data_get;
658 }
659
660 static void
661 wxgtk_tree_model_drag_dest_init (GtkTreeDragDestIface *iface)
662 {
663 iface->drag_data_received = wxgtk_tree_model_drag_data_received;
664 iface->row_drop_possible = wxgtk_tree_model_row_drop_possible;
665 }
666
667 static void
668 wxgtk_tree_model_init (GtkWxTreeModel *tree_model)
669 {
670 tree_model->internal = NULL;
671 tree_model->stamp = g_random_int();
672 }
673
674 static void
675 wxgtk_tree_model_finalize (GObject *object)
676 {
677 /* must chain up */
678 (* list_parent_class->finalize) (object);
679 }
680
681 } // extern "C"
682
683 //-----------------------------------------------------------------------------
684 // implement callbacks from wxGtkTreeModel class by letting
685 // them call the methods of wxWidgets' wxDataViewModel
686 //-----------------------------------------------------------------------------
687
688 static GtkTreeModelFlags
689 wxgtk_tree_model_get_flags (GtkTreeModel *tree_model)
690 {
691 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
692 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), (GtkTreeModelFlags)0 );
693
694 return wxtree_model->internal->get_flags();
695 }
696
697 static gint
698 wxgtk_tree_model_get_n_columns (GtkTreeModel *tree_model)
699 {
700 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
701 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), 0);
702
703 return wxtree_model->internal->GetDataViewModel()->GetColumnCount();
704 }
705
706 static GType
707 wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model,
708 gint index)
709 {
710 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
711 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), G_TYPE_INVALID);
712
713 GType gtype = G_TYPE_INVALID;
714
715 wxString wxtype = wxtree_model->internal->GetDataViewModel()->GetColumnType( (unsigned int) index );
716
717 if (wxtype == wxT("string"))
718 gtype = G_TYPE_STRING;
719 else
720 {
721 gtype = G_TYPE_POINTER;
722 // wxFAIL_MSG( wxT("non-string columns not supported for searching yet") );
723 }
724
725 return gtype;
726 }
727
728 static gboolean
729 wxgtk_tree_model_get_iter (GtkTreeModel *tree_model,
730 GtkTreeIter *iter,
731 GtkTreePath *path)
732 {
733 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
734 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
735 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
736
737 return wxtree_model->internal->get_iter( iter, path );
738 }
739
740 static GtkTreePath *
741 wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
742 GtkTreeIter *iter)
743 {
744 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
745 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), NULL);
746 g_return_val_if_fail (iter->stamp == GTK_WX_TREE_MODEL (wxtree_model)->stamp, NULL);
747
748 return wxtree_model->internal->get_path( iter );
749 }
750
751 static void
752 wxgtk_tree_model_get_value (GtkTreeModel *tree_model,
753 GtkTreeIter *iter,
754 gint column,
755 GValue *value)
756 {
757 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
758 g_return_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model) );
759
760 wxDataViewModel *model = wxtree_model->internal->GetDataViewModel();
761 wxString mtype = model->GetColumnType( (unsigned int) column );
762 if (mtype == wxT("string"))
763 {
764 wxVariant variant;
765 g_value_init( value, G_TYPE_STRING );
766 wxDataViewItem item( (void*) iter->user_data );
767 model->GetValue( variant, item, (unsigned int) column );
768
769 g_value_set_string( value, variant.GetString().utf8_str() );
770 }
771 else
772 {
773 wxFAIL_MSG( wxT("non-string columns not supported yet") );
774 }
775 }
776
777 static gboolean
778 wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
779 GtkTreeIter *iter)
780 {
781 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
782
783 // This happens when clearing the view by calling .._set_model( NULL );
784 if (iter->stamp == 0) return FALSE;
785
786 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
787 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
788
789 return wxtree_model->internal->iter_next( iter );
790 }
791
792 static gboolean
793 wxgtk_tree_model_iter_children (GtkTreeModel *tree_model,
794 GtkTreeIter *iter,
795 GtkTreeIter *parent)
796 {
797 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
798 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
799 if (parent)
800 {
801 g_return_val_if_fail (wxtree_model->stamp == parent->stamp, FALSE);
802 }
803
804 return wxtree_model->internal->iter_children( iter, parent );
805 }
806
807 static gboolean
808 wxgtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
809 GtkTreeIter *iter)
810 {
811 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
812 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
813 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
814
815 return wxtree_model->internal->iter_has_child( iter );
816 }
817
818 static gint
819 wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
820 GtkTreeIter *iter)
821 {
822 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
823 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), 0);
824 g_return_val_if_fail ( !iter || wxtree_model->stamp == iter->stamp, 0);
825
826 return wxtree_model->internal->iter_n_children( iter );
827 }
828
829 static gboolean
830 wxgtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
831 GtkTreeIter *iter,
832 GtkTreeIter *parent,
833 gint n)
834 {
835 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
836 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
837
838 return wxtree_model->internal->iter_nth_child( iter, parent, n );
839 }
840
841 static gboolean
842 wxgtk_tree_model_iter_parent (GtkTreeModel *tree_model,
843 GtkTreeIter *iter,
844 GtkTreeIter *child)
845 {
846 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
847 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
848 g_return_val_if_fail (wxtree_model->stamp == child->stamp, FALSE);
849
850 return wxtree_model->internal->iter_parent( iter, child );
851 }
852
853 /* drag'n'drop iface */
854 static gboolean
855 wxgtk_tree_model_row_draggable (GtkTreeDragSource *drag_source,
856 GtkTreePath *path)
857 {
858 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_source;
859 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
860
861 return wxtree_model->internal->row_draggable( drag_source, path );
862 }
863
864 static gboolean
865 wxgtk_tree_model_drag_data_delete (GtkTreeDragSource *drag_source,
866 GtkTreePath *path)
867 {
868 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_source;
869 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
870
871 return wxtree_model->internal->drag_data_delete( drag_source, path );
872 }
873
874 static gboolean
875 wxgtk_tree_model_drag_data_get (GtkTreeDragSource *drag_source,
876 GtkTreePath *path,
877 GtkSelectionData *selection_data)
878 {
879 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_source;
880 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
881
882 #if 0
883 wxPrintf( "drag_get_data\n");
884
885 wxGtkString atom_selection(gdk_atom_name(selection_data->selection));
886 wxPrintf( "selection %s\n", wxString::FromAscii(atom_selection) );
887
888 wxGtkString atom_target(gdk_atom_name(selection_data->target));
889 wxPrintf( "target %s\n", wxString::FromAscii(atom_target) );
890
891 wxGtkString atom_type(gdk_atom_name(selection_data->type));
892 wxPrintf( "type %s\n", wxString::FromAscii(atom_type) );
893
894 wxPrintf( "format %d\n", selection_data->format );
895 #endif
896
897 return wxtree_model->internal->drag_data_get( drag_source, path, selection_data );
898 }
899
900 static gboolean
901 wxgtk_tree_model_drag_data_received (GtkTreeDragDest *drag_dest,
902 GtkTreePath *dest,
903 GtkSelectionData *selection_data)
904 {
905 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_dest;
906 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
907
908 return wxtree_model->internal->drag_data_received( drag_dest, dest, selection_data );
909 }
910
911 static gboolean
912 wxgtk_tree_model_row_drop_possible (GtkTreeDragDest *drag_dest,
913 GtkTreePath *dest_path,
914 GtkSelectionData *selection_data)
915 {
916 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_dest;
917 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
918
919 return wxtree_model->internal->row_drop_possible( drag_dest, dest_path, selection_data );
920 }
921
922 /* sortable iface */
923 static gboolean
924 wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
925 gint *sort_column_id,
926 GtkSortType *order)
927 {
928 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) sortable;
929
930 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (sortable), FALSE);
931
932 if (!wxtree_model->internal->IsSorted())
933 {
934 if (sort_column_id)
935 *sort_column_id = -1;
936
937 return TRUE;
938 }
939
940
941 if (sort_column_id)
942 *sort_column_id = wxtree_model->internal->GetSortColumn();
943
944 if (order)
945 *order = wxtree_model->internal->GetSortOrder();
946
947 return TRUE;
948 }
949
950 wxDataViewColumn *gs_lastLeftClickHeader = NULL;
951
952 static void
953 wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
954 gint sort_column_id,
955 GtkSortType order)
956 {
957 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) sortable;
958 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
959
960 tree_model->internal->SetDataViewSortColumn( gs_lastLeftClickHeader );
961
962 if ((sort_column_id != (gint) tree_model->internal->GetSortColumn()) ||
963 (order != tree_model->internal->GetSortOrder()))
964 {
965 tree_model->internal->SetSortColumn( sort_column_id );
966 tree_model->internal->SetSortOrder( order );
967
968 gtk_tree_sortable_sort_column_changed (sortable);
969
970 tree_model->internal->GetDataViewModel()->Resort();
971 }
972
973 if (gs_lastLeftClickHeader)
974 {
975 wxDataViewCtrl *dv = tree_model->internal->GetOwner();
976 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, dv->GetId() );
977 event.SetDataViewColumn( gs_lastLeftClickHeader );
978 event.SetModel( dv->GetModel() );
979 dv->HandleWindowEvent( event );
980 }
981
982 gs_lastLeftClickHeader = NULL;
983 }
984
985 static void
986 wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable,
987 gint WXUNUSED(sort_column_id),
988 GtkTreeIterCompareFunc func,
989 gpointer WXUNUSED(data),
990 GDestroyNotify WXUNUSED(destroy))
991 {
992 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
993 g_return_if_fail (func != NULL);
994 }
995
996 static void
997 wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable,
998 GtkTreeIterCompareFunc func,
999 gpointer WXUNUSED(data),
1000 GDestroyNotify WXUNUSED(destroy))
1001 {
1002 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
1003 g_return_if_fail (func != NULL);
1004
1005 //wxPrintf( "wxgtk_tree_model_set_default_sort_func\n" );
1006 // TODO: remove this code
1007 }
1008
1009 static gboolean
1010 wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable)
1011 {
1012 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (sortable), FALSE );
1013
1014 return FALSE;
1015 }
1016
1017 //-----------------------------------------------------------------------------
1018 // define new GTK+ class GtkWxRendererText
1019 //-----------------------------------------------------------------------------
1020
1021 extern "C" {
1022
1023 #define GTK_TYPE_WX_CELL_RENDERER_TEXT (gtk_wx_cell_renderer_text_get_type ())
1024 #define GTK_WX_CELL_RENDERER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_CELL_RENDERER_TEXT, GtkWxCellRendererText))
1025 #define GTK_WX_CELL_RENDERER_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_CELL_RENDERER_TEXT, GtkWxCellRendererTextClass))
1026 #define GTK_IS_WX_CELL_RENDERER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_CELL_RENDERER_TEXT))
1027 #define GTK_IS_WX_CELL_RENDERER_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_CELL_RENDERER_TEXT))
1028 #define GTK_WX_CELL_RENDERER_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_CELL_RENDERER_TEXT, GtkWxCellRendererTextClass))
1029
1030 GType gtk_wx_cell_renderer_text_get_type (void);
1031
1032 typedef struct _GtkWxCellRendererText GtkWxCellRendererText;
1033 typedef struct _GtkWxCellRendererTextClass GtkWxCellRendererTextClass;
1034
1035 struct _GtkWxCellRendererText
1036 {
1037 GtkCellRendererText parent;
1038
1039 wxDataViewRenderer *wx_renderer;
1040 };
1041
1042 struct _GtkWxCellRendererTextClass
1043 {
1044 GtkCellRendererTextClass cell_parent_class;
1045 };
1046
1047
1048 static GtkWxCellRendererText *gtk_wx_cell_renderer_text_new (void);
1049 static void gtk_wx_cell_renderer_text_init (
1050 GtkWxCellRendererText *cell );
1051 static void gtk_wx_cell_renderer_text_class_init(
1052 GtkWxCellRendererTextClass *klass );
1053 static void gtk_wx_cell_renderer_text_finalize (
1054 GObject *object );
1055 static GtkCellEditable *gtk_wx_cell_renderer_text_start_editing(
1056 GtkCellRenderer *cell,
1057 GdkEvent *event,
1058 GtkWidget *widget,
1059 const gchar *path,
1060 GdkRectangle *background_area,
1061 GdkRectangle *cell_area,
1062 GtkCellRendererState flags );
1063
1064
1065 static GObjectClass *text_cell_parent_class = NULL;
1066
1067 } // extern "C"
1068
1069 GType
1070 gtk_wx_cell_renderer_text_get_type (void)
1071 {
1072 static GType cell_wx_type = 0;
1073
1074 if (!cell_wx_type)
1075 {
1076 const GTypeInfo cell_wx_info =
1077 {
1078 sizeof (GtkWxCellRendererTextClass),
1079 NULL, /* base_init */
1080 NULL, /* base_finalize */
1081 (GClassInitFunc) gtk_wx_cell_renderer_text_class_init,
1082 NULL, /* class_finalize */
1083 NULL, /* class_data */
1084 sizeof (GtkWxCellRendererText),
1085 0, /* n_preallocs */
1086 (GInstanceInitFunc) gtk_wx_cell_renderer_text_init,
1087 };
1088
1089 cell_wx_type = g_type_register_static( GTK_TYPE_CELL_RENDERER_TEXT,
1090 "GtkWxCellRendererText", &cell_wx_info, (GTypeFlags)0 );
1091 }
1092
1093 return cell_wx_type;
1094 }
1095
1096 static void
1097 gtk_wx_cell_renderer_text_init (GtkWxCellRendererText *cell)
1098 {
1099 cell->wx_renderer = NULL;
1100 }
1101
1102 static void
1103 gtk_wx_cell_renderer_text_class_init (GtkWxCellRendererTextClass *klass)
1104 {
1105 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1106 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
1107
1108 text_cell_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
1109
1110 object_class->finalize = gtk_wx_cell_renderer_text_finalize;
1111
1112 cell_class->start_editing = gtk_wx_cell_renderer_text_start_editing;
1113 }
1114
1115 static void
1116 gtk_wx_cell_renderer_text_finalize (GObject *object)
1117 {
1118 /* must chain up */
1119 (* G_OBJECT_CLASS (text_cell_parent_class)->finalize) (object);
1120 }
1121
1122 GtkWxCellRendererText*
1123 gtk_wx_cell_renderer_text_new (void)
1124 {
1125 return (GtkWxCellRendererText*) g_object_new (GTK_TYPE_WX_CELL_RENDERER_TEXT, NULL);
1126 }
1127
1128 static GtkCellEditable *gtk_wx_cell_renderer_text_start_editing(
1129 GtkCellRenderer *gtk_renderer,
1130 GdkEvent *gdk_event,
1131 GtkWidget *widget,
1132 const gchar *path,
1133 GdkRectangle *background_area,
1134 GdkRectangle *cell_area,
1135 GtkCellRendererState flags )
1136 {
1137 GtkWxCellRendererText *wxgtk_renderer = (GtkWxCellRendererText *) gtk_renderer;
1138 wxDataViewRenderer *wx_renderer = wxgtk_renderer->wx_renderer;
1139 wxDataViewColumn *column = wx_renderer->GetOwner();
1140
1141 wxDataViewItem
1142 item(column->GetOwner()->GTKPathToItem(wxGtkTreePath(path)));
1143
1144 wxDataViewCtrl *dv = column->GetOwner();
1145 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_START_EDITING, dv->GetId() );
1146 event.SetDataViewColumn( column );
1147 event.SetModel( dv->GetModel() );
1148 event.SetColumn( column->GetModelColumn() );
1149 event.SetItem( item );
1150 dv->HandleWindowEvent( event );
1151
1152 if (event.IsAllowed())
1153 return GTK_CELL_RENDERER_CLASS(text_cell_parent_class)->
1154 start_editing( gtk_renderer, gdk_event, widget, path, background_area, cell_area, flags );
1155 else
1156 return NULL;
1157 }
1158
1159 //-----------------------------------------------------------------------------
1160 // define new GTK+ class GtkWxCellRenderer
1161 //-----------------------------------------------------------------------------
1162
1163 extern "C" {
1164
1165 #define GTK_TYPE_WX_CELL_RENDERER (gtk_wx_cell_renderer_get_type ())
1166 #define GTK_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRenderer))
1167 #define GTK_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
1168 #define GTK_IS_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_CELL_RENDERER))
1169 #define GTK_IS_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_CELL_RENDERER))
1170 #define GTK_WX_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
1171
1172 GType gtk_wx_cell_renderer_get_type (void);
1173
1174 typedef struct _GtkWxCellRenderer GtkWxCellRenderer;
1175 typedef struct _GtkWxCellRendererClass GtkWxCellRendererClass;
1176
1177 struct _GtkWxCellRenderer
1178 {
1179 GtkCellRenderer parent;
1180
1181 /*< private >*/
1182 wxDataViewCustomRenderer *cell;
1183 guint32 last_click;
1184 };
1185
1186 struct _GtkWxCellRendererClass
1187 {
1188 GtkCellRendererClass cell_parent_class;
1189 };
1190
1191
1192 static GtkCellRenderer *gtk_wx_cell_renderer_new (void);
1193 static void gtk_wx_cell_renderer_init (
1194 GtkWxCellRenderer *cell );
1195 static void gtk_wx_cell_renderer_class_init(
1196 GtkWxCellRendererClass *klass );
1197 static void gtk_wx_cell_renderer_finalize (
1198 GObject *object );
1199 static void gtk_wx_cell_renderer_get_size (
1200 GtkCellRenderer *cell,
1201 GtkWidget *widget,
1202 GdkRectangle *rectangle,
1203 gint *x_offset,
1204 gint *y_offset,
1205 gint *width,
1206 gint *height );
1207 static void gtk_wx_cell_renderer_render (
1208 GtkCellRenderer *cell,
1209 GdkWindow *window,
1210 GtkWidget *widget,
1211 GdkRectangle *background_area,
1212 GdkRectangle *cell_area,
1213 GdkRectangle *expose_area,
1214 GtkCellRendererState flags );
1215 static gboolean gtk_wx_cell_renderer_activate(
1216 GtkCellRenderer *cell,
1217 GdkEvent *event,
1218 GtkWidget *widget,
1219 const gchar *path,
1220 GdkRectangle *background_area,
1221 GdkRectangle *cell_area,
1222 GtkCellRendererState flags );
1223 static GtkCellEditable *gtk_wx_cell_renderer_start_editing(
1224 GtkCellRenderer *cell,
1225 GdkEvent *event,
1226 GtkWidget *widget,
1227 const gchar *path,
1228 GdkRectangle *background_area,
1229 GdkRectangle *cell_area,
1230 GtkCellRendererState flags );
1231
1232
1233 static GObjectClass *cell_parent_class = NULL;
1234
1235 } // extern "C"
1236
1237 GType
1238 gtk_wx_cell_renderer_get_type (void)
1239 {
1240 static GType cell_wx_type = 0;
1241
1242 if (!cell_wx_type)
1243 {
1244 const GTypeInfo cell_wx_info =
1245 {
1246 sizeof (GtkWxCellRendererClass),
1247 NULL, /* base_init */
1248 NULL, /* base_finalize */
1249 (GClassInitFunc) gtk_wx_cell_renderer_class_init,
1250 NULL, /* class_finalize */
1251 NULL, /* class_data */
1252 sizeof (GtkWxCellRenderer),
1253 0, /* n_preallocs */
1254 (GInstanceInitFunc) gtk_wx_cell_renderer_init,
1255 };
1256
1257 cell_wx_type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
1258 "GtkWxCellRenderer", &cell_wx_info, (GTypeFlags)0 );
1259 }
1260
1261 return cell_wx_type;
1262 }
1263
1264 static void
1265 gtk_wx_cell_renderer_init (GtkWxCellRenderer *cell)
1266 {
1267 cell->cell = NULL;
1268 cell->last_click = 0;
1269 }
1270
1271 static void
1272 gtk_wx_cell_renderer_class_init (GtkWxCellRendererClass *klass)
1273 {
1274 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1275 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
1276
1277 cell_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
1278
1279 object_class->finalize = gtk_wx_cell_renderer_finalize;
1280
1281 cell_class->get_size = gtk_wx_cell_renderer_get_size;
1282 cell_class->render = gtk_wx_cell_renderer_render;
1283 cell_class->activate = gtk_wx_cell_renderer_activate;
1284 cell_class->start_editing = gtk_wx_cell_renderer_start_editing;
1285 }
1286
1287 static void
1288 gtk_wx_cell_renderer_finalize (GObject *object)
1289 {
1290 /* must chain up */
1291 (* G_OBJECT_CLASS (cell_parent_class)->finalize) (object);
1292 }
1293
1294 GtkCellRenderer*
1295 gtk_wx_cell_renderer_new (void)
1296 {
1297 return (GtkCellRenderer*) g_object_new (GTK_TYPE_WX_CELL_RENDERER, NULL);
1298 }
1299
1300 static GtkCellEditable *gtk_wx_cell_renderer_start_editing(
1301 GtkCellRenderer *renderer,
1302 GdkEvent *WXUNUSED(event),
1303 GtkWidget *widget,
1304 const gchar *path,
1305 GdkRectangle *WXUNUSED(background_area),
1306 GdkRectangle *cell_area,
1307 GtkCellRendererState WXUNUSED(flags) )
1308 {
1309 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
1310 wxDataViewCustomRenderer *cell = wxrenderer->cell;
1311
1312 // Renderer doesn't support in-place editing
1313 if (!cell->HasEditorCtrl())
1314 return NULL;
1315
1316 // An in-place editing control is still around
1317 if (cell->GetEditorCtrl())
1318 return NULL;
1319
1320 GdkRectangle rect;
1321 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
1322 &rect.x,
1323 &rect.y,
1324 &rect.width,
1325 &rect.height);
1326
1327 rect.x += cell_area->x;
1328 rect.y += cell_area->y;
1329 // rect.width -= renderer->xpad * 2;
1330 // rect.height -= renderer->ypad * 2;
1331
1332 // wxRect renderrect(wxRectFromGDKRect(&rect));
1333 wxRect renderrect(wxRectFromGDKRect(cell_area));
1334
1335 wxDataViewItem
1336 item(cell->GetOwner()->GetOwner()->GTKPathToItem(wxGtkTreePath(path)));
1337
1338 cell->StartEditing( item, renderrect );
1339
1340 return NULL;
1341 }
1342
1343 static void
1344 gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer,
1345 GtkWidget *WXUNUSED(widget),
1346 GdkRectangle *cell_area,
1347 gint *x_offset,
1348 gint *y_offset,
1349 gint *width,
1350 gint *height)
1351 {
1352 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
1353 wxDataViewCustomRenderer *cell = wxrenderer->cell;
1354
1355 wxSize size = cell->GetSize();
1356
1357 wxDataViewCtrl * const ctrl = cell->GetOwner()->GetOwner();
1358
1359 // Uniform row height, if specified, overrides the value returned by the
1360 // renderer.
1361 if ( !ctrl->HasFlag(wxDV_VARIABLE_LINE_HEIGHT) )
1362 {
1363 const int uniformHeight = ctrl->GTKGetUniformRowHeight();
1364 if ( uniformHeight > 0 )
1365 size.y = uniformHeight;
1366 }
1367
1368 int xpad, ypad;
1369 gtk_cell_renderer_get_padding(renderer, &xpad, &ypad);
1370 int calc_width = xpad * 2 + size.x;
1371 int calc_height = ypad * 2 + size.y;
1372
1373 if (x_offset)
1374 *x_offset = 0;
1375 if (y_offset)
1376 *y_offset = 0;
1377
1378 if (cell_area && size.x > 0 && size.y > 0)
1379 {
1380 float xalign, yalign;
1381 gtk_cell_renderer_get_alignment(renderer, &xalign, &yalign);
1382 if (x_offset)
1383 {
1384 *x_offset = int(xalign * (cell_area->width - calc_width - 2 * xpad));
1385 *x_offset = MAX(*x_offset, 0) + xpad;
1386 }
1387 if (y_offset)
1388 {
1389 *y_offset = int(yalign * (cell_area->height - calc_height - 2 * ypad));
1390 *y_offset = MAX(*y_offset, 0) + ypad;
1391 }
1392 }
1393
1394 if (width)
1395 *width = calc_width;
1396
1397 if (height)
1398 *height = calc_height;
1399 }
1400
1401 static void
1402 gtk_wx_cell_renderer_render (GtkCellRenderer *renderer,
1403 GdkWindow *window,
1404 GtkWidget *widget,
1405 GdkRectangle *background_area,
1406 GdkRectangle *cell_area,
1407 GdkRectangle *expose_area,
1408 GtkCellRendererState flags)
1409
1410 {
1411 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
1412 wxDataViewCustomRenderer *cell = wxrenderer->cell;
1413
1414 cell->GTKStashRenderParams(window, widget,
1415 background_area, expose_area, flags);
1416
1417 wxRect rect(wxRectFromGDKRect(cell_area));
1418 int xpad, ypad;
1419 gtk_cell_renderer_get_padding(renderer, &xpad, &ypad);
1420 rect = rect.Deflate(xpad, ypad);
1421
1422 wxWindowDC* dc = (wxWindowDC*) cell->GetDC();
1423 wxWindowDCImpl *impl = (wxWindowDCImpl *) dc->GetImpl();
1424
1425 // Reinitialize wxWindowDC's GDK window if drawing occurs into a different
1426 // window such as a DnD drop window.
1427 if (window != impl->m_gdkwindow)
1428 {
1429 impl->Destroy();
1430 impl->m_gdkwindow = window;
1431 impl->SetUpDC();
1432 }
1433
1434 int state = 0;
1435 if (flags & GTK_CELL_RENDERER_SELECTED)
1436 state |= wxDATAVIEW_CELL_SELECTED;
1437 if (flags & GTK_CELL_RENDERER_PRELIT)
1438 state |= wxDATAVIEW_CELL_PRELIT;
1439 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
1440 state |= wxDATAVIEW_CELL_INSENSITIVE;
1441 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
1442 state |= wxDATAVIEW_CELL_INSENSITIVE;
1443 if (flags & GTK_CELL_RENDERER_FOCUSED)
1444 state |= wxDATAVIEW_CELL_FOCUSED;
1445 cell->WXCallRender( rect, dc, state );
1446 }
1447
1448 static gboolean
1449 gtk_wx_cell_renderer_activate(
1450 GtkCellRenderer *renderer,
1451 GdkEvent *event,
1452 GtkWidget *widget,
1453 const gchar *path,
1454 GdkRectangle *WXUNUSED(background_area),
1455 GdkRectangle *cell_area,
1456 GtkCellRendererState WXUNUSED(flags) )
1457 {
1458 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
1459 wxDataViewCustomRenderer *cell = wxrenderer->cell;
1460
1461 GdkRectangle rect;
1462 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
1463 &rect.x,
1464 &rect.y,
1465 &rect.width,
1466 &rect.height);
1467
1468 rect.x += cell_area->x;
1469 rect.y += cell_area->y;
1470 int xpad, ypad;
1471 gtk_cell_renderer_get_padding(renderer, &xpad, &ypad);
1472 rect.width -= xpad * 2;
1473 rect.height -= ypad * 2;
1474
1475 wxRect renderrect(wxRectFromGDKRect(&rect));
1476
1477 wxDataViewCtrl * const ctrl = cell->GetOwner()->GetOwner();
1478 wxDataViewModel *model = ctrl->GetModel();
1479
1480 wxDataViewItem item(ctrl->GTKPathToItem(wxGtkTreePath(path)));
1481
1482 unsigned int model_col = cell->GetOwner()->GetModelColumn();
1483
1484 if (!event)
1485 {
1486 bool ret = false;
1487
1488 // activated by <ENTER>
1489 if (cell->Activate( renderrect, model, item, model_col ))
1490 ret = true;
1491
1492 return ret;
1493 }
1494 else if (event->type == GDK_BUTTON_PRESS)
1495 {
1496 GdkEventButton *button_event = (GdkEventButton*) event;
1497 wxPoint pt( ((int) button_event->x) - renderrect.x,
1498 ((int) button_event->y) - renderrect.y );
1499
1500 bool ret = false;
1501 if (button_event->button == 1)
1502 {
1503 if (cell->LeftClick( pt, renderrect, model, item, model_col ))
1504 ret = true;
1505 // TODO: query system double-click time
1506 if (button_event->time - wxrenderer->last_click < 400)
1507 if (cell->Activate( renderrect, model, item, model_col ))
1508 ret = true;
1509 }
1510 wxrenderer->last_click = button_event->time;
1511
1512 return ret;
1513 }
1514
1515 return false;
1516 }
1517
1518 // ---------------------------------------------------------
1519 // wxGtkDataViewModelNotifier
1520 // ---------------------------------------------------------
1521
1522 class wxGtkDataViewModelNotifier: public wxDataViewModelNotifier
1523 {
1524 public:
1525 wxGtkDataViewModelNotifier( wxDataViewModel *wx_model, wxDataViewCtrlInternal *internal );
1526 ~wxGtkDataViewModelNotifier();
1527
1528 virtual bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
1529 virtual bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
1530 virtual bool ItemChanged( const wxDataViewItem &item );
1531 virtual bool ValueChanged( const wxDataViewItem &item, unsigned int model_column );
1532 virtual bool Cleared();
1533 virtual void Resort();
1534 virtual bool BeforeReset();
1535 virtual bool AfterReset();
1536
1537 void UpdateLastCount();
1538
1539 private:
1540 wxDataViewModel *m_wx_model;
1541 wxDataViewCtrlInternal *m_internal;
1542 };
1543
1544 // ---------------------------------------------------------
1545 // wxGtkDataViewListModelNotifier
1546 // ---------------------------------------------------------
1547
1548 wxGtkDataViewModelNotifier::wxGtkDataViewModelNotifier(
1549 wxDataViewModel *wx_model, wxDataViewCtrlInternal *internal )
1550 {
1551 m_wx_model = wx_model;
1552 m_internal = internal;
1553 }
1554
1555 wxGtkDataViewModelNotifier::~wxGtkDataViewModelNotifier()
1556 {
1557 m_wx_model = NULL;
1558 m_internal = NULL;
1559 }
1560
1561 bool wxGtkDataViewModelNotifier::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
1562 {
1563 m_internal->ItemAdded( parent, item );
1564 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
1565
1566 GtkTreeIter iter;
1567 iter.stamp = wxgtk_model->stamp;
1568 iter.user_data = item.GetID();
1569
1570 wxGtkTreePath path(wxgtk_tree_model_get_path(
1571 GTK_TREE_MODEL(wxgtk_model), &iter ));
1572 gtk_tree_model_row_inserted(
1573 GTK_TREE_MODEL(wxgtk_model), path, &iter);
1574
1575 return true;
1576 }
1577
1578 bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
1579 {
1580 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
1581 #if 0
1582 // using _get_path for a deleted item cannot be
1583 // a good idea
1584 GtkTreeIter iter;
1585 iter.stamp = wxgtk_model->stamp;
1586 iter.user_data = (gpointer) item.GetID();
1587 wxGtkTreePath path(wxgtk_tree_model_get_path(
1588 GTK_TREE_MODEL(wxgtk_model), &iter ));
1589 #else
1590 // so get the path from the parent
1591 GtkTreeIter iter;
1592 iter.stamp = wxgtk_model->stamp;
1593 iter.user_data = (gpointer) parent.GetID();
1594 wxGtkTreePath path(wxgtk_tree_model_get_path(
1595 GTK_TREE_MODEL(wxgtk_model), &iter ));
1596 // and add the final index ourselves
1597 int index = m_internal->GetIndexOf( parent, item );
1598 gtk_tree_path_append_index( path, index );
1599 #endif
1600
1601 gtk_tree_model_row_deleted(
1602 GTK_TREE_MODEL(wxgtk_model), path );
1603
1604 m_internal->ItemDeleted( parent, item );
1605
1606 return true;
1607 }
1608
1609 void wxGtkDataViewModelNotifier::Resort()
1610 {
1611 m_internal->Resort();
1612 }
1613
1614 bool wxGtkDataViewModelNotifier::ItemChanged( const wxDataViewItem &item )
1615 {
1616 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
1617
1618 GtkTreeIter iter;
1619 iter.stamp = wxgtk_model->stamp;
1620 iter.user_data = (gpointer) item.GetID();
1621
1622 wxGtkTreePath path(wxgtk_tree_model_get_path(
1623 GTK_TREE_MODEL(wxgtk_model), &iter ));
1624 gtk_tree_model_row_changed(
1625 GTK_TREE_MODEL(wxgtk_model), path, &iter );
1626
1627 m_internal->ItemChanged( item );
1628
1629 return true;
1630 }
1631
1632 bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsigned int model_column )
1633 {
1634 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
1635 wxDataViewCtrl *ctrl = m_internal->GetOwner();
1636
1637 // This adds GTK+'s missing MVC logic for ValueChanged
1638 unsigned int index;
1639 for (index = 0; index < ctrl->GetColumnCount(); index++)
1640 {
1641 wxDataViewColumn *column = ctrl->GetColumn( index );
1642 if (column->GetModelColumn() == model_column)
1643 {
1644 GtkTreeView *widget = GTK_TREE_VIEW(ctrl->GtkGetTreeView());
1645 GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle());
1646
1647 // Get cell area
1648 GtkTreeIter iter;
1649 iter.stamp = wxgtk_model->stamp;
1650 iter.user_data = (gpointer) item.GetID();
1651 wxGtkTreePath path(wxgtk_tree_model_get_path(
1652 GTK_TREE_MODEL(wxgtk_model), &iter ));
1653 GdkRectangle cell_area;
1654 gtk_tree_view_get_cell_area( widget, path, gcolumn, &cell_area );
1655
1656 GtkAdjustment* hadjust = gtk_tree_view_get_hadjustment( widget );
1657 double d = gtk_adjustment_get_value( hadjust );
1658 int xdiff = (int) d;
1659
1660 int ydiff = gcolumn->button->allocation.height;
1661 // Redraw
1662 gtk_widget_queue_draw_area( GTK_WIDGET(widget),
1663 cell_area.x - xdiff, ydiff + cell_area.y, cell_area.width, cell_area.height );
1664
1665 m_internal->ValueChanged( item, model_column );
1666
1667 return true;
1668 }
1669 }
1670
1671 return false;
1672 }
1673
1674 bool wxGtkDataViewModelNotifier::BeforeReset()
1675 {
1676 GtkWidget *treeview = m_internal->GetOwner()->GtkGetTreeView();
1677 gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), NULL );
1678
1679 return true;
1680 }
1681
1682 bool wxGtkDataViewModelNotifier::AfterReset()
1683 {
1684 GtkWidget *treeview = m_internal->GetOwner()->GtkGetTreeView();
1685 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
1686
1687 m_internal->Cleared();
1688
1689 gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(wxgtk_model) );
1690
1691 return true;
1692 }
1693
1694 bool wxGtkDataViewModelNotifier::Cleared()
1695 {
1696 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
1697
1698 // There is no call to tell the model that everything
1699 // has been deleted so call row_deleted() for every
1700 // child of root...
1701
1702 int count = m_internal->iter_n_children( NULL ); // number of children of root
1703
1704 GtkTreePath *path = gtk_tree_path_new_first(); // points to root
1705
1706 int i;
1707 for (i = 0; i < count; i++)
1708 gtk_tree_model_row_deleted( GTK_TREE_MODEL(wxgtk_model), path );
1709
1710 gtk_tree_path_free( path );
1711
1712 m_internal->Cleared();
1713
1714 return true;
1715 }
1716
1717 // ---------------------------------------------------------
1718 // wxDataViewRenderer
1719 // ---------------------------------------------------------
1720
1721 static gpointer s_user_data = NULL;
1722
1723 static void
1724 wxgtk_cell_editable_editing_done( GtkCellEditable *WXUNUSED(editable),
1725 wxDataViewRenderer *wxrenderer )
1726 {
1727 wxDataViewColumn *column = wxrenderer->GetOwner();
1728 wxDataViewCtrl *dv = column->GetOwner();
1729 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE, dv->GetId() );
1730 event.SetDataViewColumn( column );
1731 event.SetModel( dv->GetModel() );
1732 wxDataViewItem item( s_user_data );
1733 event.SetItem( item );
1734 dv->HandleWindowEvent( event );
1735 }
1736
1737 static void
1738 wxgtk_renderer_editing_started( GtkCellRenderer *WXUNUSED(cell), GtkCellEditable *editable,
1739 gchar *path, wxDataViewRenderer *wxrenderer )
1740 {
1741 if (!editable)
1742 return;
1743
1744 wxDataViewColumn *column = wxrenderer->GetOwner();
1745 wxDataViewCtrl *dv = column->GetOwner();
1746 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED, dv->GetId() );
1747 event.SetDataViewColumn( column );
1748 event.SetModel( dv->GetModel() );
1749 wxDataViewItem item(dv->GTKPathToItem(wxGtkTreePath(path)));
1750 event.SetItem( item );
1751 dv->HandleWindowEvent( event );
1752
1753 if (GTK_IS_CELL_EDITABLE(editable))
1754 {
1755 s_user_data = item.GetID();
1756
1757 g_signal_connect (GTK_CELL_EDITABLE (editable), "editing_done",
1758 G_CALLBACK (wxgtk_cell_editable_editing_done),
1759 (gpointer) wxrenderer );
1760
1761 }
1762 }
1763
1764
1765 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
1766
1767 wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1768 int align ) :
1769 wxDataViewRendererBase( varianttype, mode, align )
1770 {
1771 m_renderer = NULL;
1772 m_mode = mode;
1773
1774 // we haven't changed them yet
1775 m_usingDefaultAttrs = true;
1776
1777 // NOTE: SetMode() and SetAlignment() needs to be called in the renderer's ctor,
1778 // after the m_renderer pointer has been initialized
1779 }
1780
1781 void wxDataViewRenderer::GtkPackIntoColumn(GtkTreeViewColumn *column)
1782 {
1783 gtk_tree_view_column_pack_end( column, m_renderer, TRUE /* expand */);
1784 }
1785
1786 void wxDataViewRenderer::GtkInitHandlers()
1787 {
1788 if (!gtk_check_version(2,6,0))
1789 {
1790 g_signal_connect (GTK_CELL_RENDERER(m_renderer), "editing_started",
1791 G_CALLBACK (wxgtk_renderer_editing_started),
1792 this);
1793 }
1794 }
1795
1796 void wxDataViewRenderer::SetMode( wxDataViewCellMode mode )
1797 {
1798 GtkCellRendererMode gtkMode;
1799 switch (mode)
1800 {
1801 case wxDATAVIEW_CELL_INERT:
1802 gtkMode = GTK_CELL_RENDERER_MODE_INERT;
1803 break;
1804
1805 case wxDATAVIEW_CELL_ACTIVATABLE:
1806 gtkMode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
1807 break;
1808
1809 case wxDATAVIEW_CELL_EDITABLE:
1810 gtkMode = GTK_CELL_RENDERER_MODE_EDITABLE;
1811 break;
1812
1813 default:
1814 wxFAIL_MSG( "unknown wxDataViewCellMode value" );
1815 return;
1816 }
1817
1818 m_mode = mode;
1819
1820 // This value is most often ignored in GtkTreeView
1821 GValue gvalue = { 0, };
1822 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
1823 g_value_set_enum( &gvalue, gtkMode );
1824 g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue );
1825 g_value_unset( &gvalue );
1826 }
1827
1828 wxDataViewCellMode wxDataViewRenderer::GetMode() const
1829 {
1830 wxDataViewCellMode ret;
1831
1832 GValue gvalue;
1833 g_object_get( G_OBJECT(m_renderer), "mode", &gvalue, NULL);
1834
1835 switch (g_value_get_enum(&gvalue))
1836 {
1837 default:
1838 wxFAIL_MSG( "unknown GtkCellRendererMode value" );
1839 // fall through (we have to return something)
1840
1841 case GTK_CELL_RENDERER_MODE_INERT:
1842 ret = wxDATAVIEW_CELL_INERT;
1843 break;
1844
1845 case GTK_CELL_RENDERER_MODE_ACTIVATABLE:
1846 ret = wxDATAVIEW_CELL_ACTIVATABLE;
1847 break;
1848
1849 case GTK_CELL_RENDERER_MODE_EDITABLE:
1850 ret = wxDATAVIEW_CELL_EDITABLE;
1851 break;
1852 }
1853
1854 g_value_unset( &gvalue );
1855
1856 return ret;
1857 }
1858
1859 void wxDataViewRenderer::GtkApplyAlignment(GtkCellRenderer *renderer)
1860 {
1861 int align = m_alignment;
1862
1863 // query alignment from column ?
1864 if (align == -1)
1865 {
1866 // None there yet
1867 if (GetOwner() == NULL)
1868 return;
1869
1870 align = GetOwner()->GetAlignment();
1871 align |= wxALIGN_CENTRE_VERTICAL;
1872 }
1873
1874 // horizontal alignment:
1875
1876 gfloat xalign = 0.0;
1877 if (align & wxALIGN_RIGHT)
1878 xalign = 1.0;
1879 else if (align & wxALIGN_CENTER_HORIZONTAL)
1880 xalign = 0.5;
1881
1882 GValue gvalue = { 0, };
1883 g_value_init( &gvalue, G_TYPE_FLOAT );
1884 g_value_set_float( &gvalue, xalign );
1885 g_object_set_property( G_OBJECT(renderer), "xalign", &gvalue );
1886 g_value_unset( &gvalue );
1887
1888 // vertical alignment:
1889
1890 gfloat yalign = 0.0;
1891 if (align & wxALIGN_BOTTOM)
1892 yalign = 1.0;
1893 else if (align & wxALIGN_CENTER_VERTICAL)
1894 yalign = 0.5;
1895
1896 GValue gvalue2 = { 0, };
1897 g_value_init( &gvalue2, G_TYPE_FLOAT );
1898 g_value_set_float( &gvalue2, yalign );
1899 g_object_set_property( G_OBJECT(renderer), "yalign", &gvalue2 );
1900 g_value_unset( &gvalue2 );
1901 }
1902
1903 void wxDataViewRenderer::SetAlignment( int align )
1904 {
1905 m_alignment = align;
1906 GtkUpdateAlignment();
1907 }
1908
1909 int wxDataViewRenderer::GetAlignment() const
1910 {
1911 return m_alignment;
1912 }
1913
1914 void wxDataViewRenderer::EnableEllipsize(wxEllipsizeMode mode)
1915 {
1916 #ifdef __WXGTK26__
1917 if ( gtk_check_version(2, 6, 0) != NULL )
1918 return;
1919
1920 GtkCellRendererText * const rend = GtkGetTextRenderer();
1921 if ( !rend )
1922 return;
1923
1924 // we use the same values in wxEllipsizeMode as PangoEllipsizeMode so we
1925 // can just cast between them
1926 GValue gvalue = { 0, };
1927 g_value_init( &gvalue, PANGO_TYPE_ELLIPSIZE_MODE );
1928 g_value_set_enum( &gvalue, static_cast<PangoEllipsizeMode>(mode) );
1929 g_object_set_property( G_OBJECT(rend), "ellipsize", &gvalue );
1930 g_value_unset( &gvalue );
1931 #else // GTK < 2.6
1932 wxUnusedVar(mode);
1933 #endif // GTK 2.6/before
1934 }
1935
1936 wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const
1937 {
1938 #ifdef __WXGTK26__
1939 if ( gtk_check_version(2, 6, 0) != NULL )
1940 return wxELLIPSIZE_NONE;
1941
1942 GtkCellRendererText * const rend = GtkGetTextRenderer();
1943 if ( !rend )
1944 return wxELLIPSIZE_NONE;
1945
1946 GValue gvalue = { 0, };
1947 g_value_init( &gvalue, PANGO_TYPE_ELLIPSIZE_MODE );
1948 g_object_get_property( G_OBJECT(rend), "ellipsize", &gvalue );
1949 wxEllipsizeMode
1950 mode = static_cast<wxEllipsizeMode>(g_value_get_enum( &gvalue ));
1951 g_value_unset( &gvalue );
1952
1953 return mode;
1954 #else // GTK < 2.6
1955 return wxELLIPSIZE_NONE;
1956 #endif // GTK 2.6/before
1957 }
1958
1959 void
1960 wxDataViewRenderer::GtkOnTextEdited(const gchar *itempath, const wxString& str)
1961 {
1962 wxVariant value(str);
1963 if (!Validate( value ))
1964 return;
1965
1966 wxDataViewItem
1967 item(GetOwner()->GetOwner()->GTKPathToItem(wxGtkTreePath(itempath)));
1968
1969 GtkOnCellChanged(value, item, GetOwner()->GetModelColumn());
1970 }
1971
1972 void
1973 wxDataViewRenderer::GtkOnCellChanged(const wxVariant& value,
1974 const wxDataViewItem& item,
1975 unsigned col)
1976 {
1977 wxDataViewModel *model = GetOwner()->GetOwner()->GetModel();
1978 model->ChangeValue( value, item, col );
1979 }
1980
1981 // ---------------------------------------------------------
1982 // wxDataViewTextRenderer
1983 // ---------------------------------------------------------
1984
1985 extern "C"
1986 {
1987
1988 static void wxGtkTextRendererEditedCallback( GtkCellRendererText *WXUNUSED(renderer),
1989 gchar *arg1, gchar *arg2, gpointer user_data )
1990 {
1991 wxDataViewRenderer *cell = (wxDataViewRenderer*) user_data;
1992
1993 cell->GtkOnTextEdited(arg1, wxGTK_CONV_BACK_FONT(
1994 arg2, cell->GetOwner()->GetOwner()->GetFont()));
1995 }
1996
1997 }
1998
1999 namespace
2000 {
2001
2002 // helper function used by wxDataViewTextRenderer and
2003 // wxDataViewCustomRenderer::RenderText(): it applies the attributes to the
2004 // given text renderer and returns true if anything was done
2005 bool GtkApplyAttr(GtkCellRendererText *renderer, const wxDataViewItemAttr& attr)
2006 {
2007 bool usingDefaultAttrs = true;
2008 if (attr.HasColour())
2009 {
2010 const GdkColor * const gcol = attr.GetColour().GetColor();
2011
2012 GValue gvalue = { 0, };
2013 g_value_init( &gvalue, GDK_TYPE_COLOR );
2014 g_value_set_boxed( &gvalue, gcol );
2015 g_object_set_property( G_OBJECT(renderer), "foreground_gdk", &gvalue );
2016 g_value_unset( &gvalue );
2017
2018 usingDefaultAttrs = false;
2019 }
2020 else
2021 {
2022 GValue gvalue = { 0, };
2023 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2024 g_value_set_boolean( &gvalue, FALSE );
2025 g_object_set_property( G_OBJECT(renderer), "foreground-set", &gvalue );
2026 g_value_unset( &gvalue );
2027 }
2028
2029 if (attr.GetItalic())
2030 {
2031 GValue gvalue = { 0, };
2032 g_value_init( &gvalue, PANGO_TYPE_STYLE );
2033 g_value_set_enum( &gvalue, PANGO_STYLE_ITALIC );
2034 g_object_set_property( G_OBJECT(renderer), "style", &gvalue );
2035 g_value_unset( &gvalue );
2036
2037 usingDefaultAttrs = false;
2038 }
2039 else
2040 {
2041 GValue gvalue = { 0, };
2042 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2043 g_value_set_boolean( &gvalue, FALSE );
2044 g_object_set_property( G_OBJECT(renderer), "style-set", &gvalue );
2045 g_value_unset( &gvalue );
2046 }
2047
2048
2049 if (attr.GetBold())
2050 {
2051 GValue gvalue = { 0, };
2052 g_value_init( &gvalue, PANGO_TYPE_WEIGHT );
2053 g_value_set_enum( &gvalue, PANGO_WEIGHT_BOLD );
2054 g_object_set_property( G_OBJECT(renderer), "weight", &gvalue );
2055 g_value_unset( &gvalue );
2056
2057 usingDefaultAttrs = false;
2058 }
2059 else
2060 {
2061 GValue gvalue = { 0, };
2062 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2063 g_value_set_boolean( &gvalue, FALSE );
2064 g_object_set_property( G_OBJECT(renderer), "weight-set", &gvalue );
2065 g_value_unset( &gvalue );
2066 }
2067
2068 #if 0
2069 if (attr.HasBackgroundColour())
2070 {
2071 wxColour colour = attr.GetBackgroundColour();
2072 const GdkColor * const gcol = colour.GetColor();
2073
2074 GValue gvalue = { 0, };
2075 g_value_init( &gvalue, GDK_TYPE_COLOR );
2076 g_value_set_boxed( &gvalue, gcol );
2077 g_object_set_property( G_OBJECT(renderer), "cell-background_gdk", &gvalue );
2078 g_value_unset( &gvalue );
2079 }
2080 else
2081 {
2082 GValue gvalue = { 0, };
2083 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2084 g_value_set_boolean( &gvalue, FALSE );
2085 g_object_set_property( G_OBJECT(renderer), "cell-background-set", &gvalue );
2086 g_value_unset( &gvalue );
2087 }
2088 #endif
2089
2090 return !usingDefaultAttrs;
2091 }
2092
2093 } // anonymous namespace
2094
2095 IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewRenderer)
2096
2097 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode,
2098 int align ) :
2099 wxDataViewRenderer( varianttype, mode, align )
2100 {
2101 GtkWxCellRendererText *text_renderer = gtk_wx_cell_renderer_text_new();
2102 text_renderer->wx_renderer = this;
2103 m_renderer = (GtkCellRenderer*) text_renderer;
2104
2105 if (mode & wxDATAVIEW_CELL_EDITABLE)
2106 {
2107 GValue gvalue = { 0, };
2108 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2109 g_value_set_boolean( &gvalue, true );
2110 g_object_set_property( G_OBJECT(m_renderer), "editable", &gvalue );
2111 g_value_unset( &gvalue );
2112
2113 g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
2114
2115 GtkInitHandlers();
2116 }
2117
2118 SetMode(mode);
2119 SetAlignment(align);
2120 }
2121
2122 bool wxDataViewTextRenderer::SetTextValue(const wxString& str)
2123 {
2124 GValue gvalue = { 0, };
2125 g_value_init( &gvalue, G_TYPE_STRING );
2126 g_value_set_string( &gvalue, wxGTK_CONV_FONT( str, GetOwner()->GetOwner()->GetFont() ) );
2127 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
2128 g_value_unset( &gvalue );
2129
2130 return true;
2131 }
2132
2133 bool wxDataViewTextRenderer::GetTextValue(wxString& str) const
2134 {
2135 GValue gvalue = { 0, };
2136 g_value_init( &gvalue, G_TYPE_STRING );
2137 g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
2138 str = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ), const_cast<wxDataViewTextRenderer*>(this)->GetOwner()->GetOwner()->GetFont() );
2139 g_value_unset( &gvalue );
2140
2141 return true;
2142 }
2143
2144 void wxDataViewTextRenderer::SetAlignment( int align )
2145 {
2146 wxDataViewRenderer::SetAlignment(align);
2147
2148 if (gtk_check_version(2,10,0))
2149 return;
2150
2151 // horizontal alignment:
2152 PangoAlignment pangoAlign = PANGO_ALIGN_LEFT;
2153 if (align & wxALIGN_RIGHT)
2154 pangoAlign = PANGO_ALIGN_RIGHT;
2155 else if (align & wxALIGN_CENTER_HORIZONTAL)
2156 pangoAlign = PANGO_ALIGN_CENTER;
2157
2158 GValue gvalue = { 0, };
2159 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
2160 g_value_set_enum( &gvalue, pangoAlign );
2161 g_object_set_property( G_OBJECT(m_renderer), "alignment", &gvalue );
2162 g_value_unset( &gvalue );
2163 }
2164
2165 bool wxDataViewTextRenderer::GtkSetAttr(const wxDataViewItemAttr& attr)
2166 {
2167 return GtkApplyAttr(GtkGetTextRenderer(), attr);
2168 }
2169
2170 GtkCellRendererText *wxDataViewTextRenderer::GtkGetTextRenderer() const
2171 {
2172 return GTK_CELL_RENDERER_TEXT(m_renderer);
2173 }
2174
2175 // ---------------------------------------------------------
2176 // wxDataViewBitmapRenderer
2177 // ---------------------------------------------------------
2178
2179 namespace
2180 {
2181
2182 // set "pixbuf" property on the given renderer
2183 void SetPixbufProp(GtkCellRenderer *renderer, GdkPixbuf *pixbuf)
2184 {
2185 GValue gvalue = { 0, };
2186 g_value_init( &gvalue, G_TYPE_OBJECT );
2187 g_value_set_object( &gvalue, pixbuf );
2188 g_object_set_property( G_OBJECT(renderer), "pixbuf", &gvalue );
2189 g_value_unset( &gvalue );
2190 }
2191
2192 } // anonymous namespace
2193
2194 IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewRenderer)
2195
2196 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode,
2197 int align ) :
2198 wxDataViewRenderer( varianttype, mode, align )
2199 {
2200 m_renderer = gtk_cell_renderer_pixbuf_new();
2201
2202 SetMode(mode);
2203 SetAlignment(align);
2204 }
2205
2206 bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
2207 {
2208 if (value.GetType() == wxT("wxBitmap"))
2209 {
2210 wxBitmap bitmap;
2211 bitmap << value;
2212
2213 // GetPixbuf() may create a Pixbuf representation in the wxBitmap
2214 // object (and it will stay there and remain owned by wxBitmap)
2215 SetPixbufProp(m_renderer, bitmap.GetPixbuf());
2216 }
2217 else if (value.GetType() == wxT("wxIcon"))
2218 {
2219 wxIcon icon;
2220 icon << value;
2221
2222 SetPixbufProp(m_renderer, icon.GetPixbuf());
2223 }
2224 else
2225 {
2226 return false;
2227 }
2228
2229 return true;
2230 }
2231
2232 bool wxDataViewBitmapRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
2233 {
2234 return false;
2235 }
2236
2237 // ---------------------------------------------------------
2238 // wxDataViewToggleRenderer
2239 // ---------------------------------------------------------
2240
2241 extern "C" {
2242 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
2243 gchar *path, gpointer user_data );
2244 }
2245
2246 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
2247 gchar *path, gpointer user_data )
2248 {
2249 wxDataViewToggleRenderer *cell = (wxDataViewToggleRenderer*) user_data;
2250
2251 // get old value
2252 GValue gvalue = { 0, };
2253 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2254 g_object_get_property( G_OBJECT(renderer), "active", &gvalue );
2255 bool tmp = g_value_get_boolean( &gvalue );
2256 g_value_unset( &gvalue );
2257 // invert it
2258 tmp = !tmp;
2259
2260 wxVariant value = tmp;
2261 if (!cell->Validate( value ))
2262 return;
2263
2264 wxDataViewCtrl * const ctrl = cell->GetOwner()->GetOwner();
2265 wxDataViewModel *model = ctrl->GetModel();
2266
2267 wxDataViewItem item(ctrl->GTKPathToItem(wxGtkTreePath(path)));
2268
2269 unsigned int model_col = cell->GetOwner()->GetModelColumn();
2270
2271 model->ChangeValue( value, item, model_col );
2272 }
2273
2274 IMPLEMENT_CLASS(wxDataViewToggleRenderer, wxDataViewRenderer)
2275
2276 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
2277 wxDataViewCellMode mode, int align ) :
2278 wxDataViewRenderer( varianttype, mode, align )
2279 {
2280 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_toggle_new();
2281
2282 if (mode & wxDATAVIEW_CELL_ACTIVATABLE)
2283 {
2284 g_signal_connect_after( m_renderer, "toggled",
2285 G_CALLBACK(wxGtkToggleRendererToggledCallback), this );
2286 }
2287 else
2288 {
2289 GValue gvalue = { 0, };
2290 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2291 g_value_set_boolean( &gvalue, false );
2292 g_object_set_property( G_OBJECT(m_renderer), "activatable", &gvalue );
2293 g_value_unset( &gvalue );
2294 }
2295
2296 SetMode(mode);
2297 SetAlignment(align);
2298 }
2299
2300 bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
2301 {
2302 bool tmp = value;
2303
2304 GValue gvalue = { 0, };
2305 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2306 g_value_set_boolean( &gvalue, tmp );
2307 g_object_set_property( G_OBJECT(m_renderer), "active", &gvalue );
2308 g_value_unset( &gvalue );
2309
2310 return true;
2311 }
2312
2313 bool wxDataViewToggleRenderer::GetValue( wxVariant &value ) const
2314 {
2315 GValue gvalue = { 0, };
2316 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2317 g_object_get_property( G_OBJECT(m_renderer), "active", &gvalue );
2318 bool tmp = g_value_get_boolean( &gvalue );
2319 g_value_unset( &gvalue );
2320
2321 value = tmp;
2322
2323 return true;
2324 }
2325
2326 // ---------------------------------------------------------
2327 // wxDataViewCustomRenderer
2328 // ---------------------------------------------------------
2329
2330 class wxDataViewCtrlDCImpl: public wxWindowDCImpl
2331 {
2332 public:
2333 wxDataViewCtrlDCImpl( wxDC *owner, wxDataViewCtrl *window ) :
2334 wxWindowDCImpl( owner )
2335 {
2336 GtkWidget *widget = window->m_treeview;
2337 // Set later
2338 m_gdkwindow = NULL;
2339
2340 m_window = window;
2341
2342 m_context = window->GTKGetPangoDefaultContext();
2343 m_layout = pango_layout_new( m_context );
2344 m_fontdesc = pango_font_description_copy(gtk_widget_get_style(widget)->font_desc);
2345
2346 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
2347
2348 // Set m_gdkwindow later
2349 // SetUpDC();
2350 }
2351 };
2352
2353 class wxDataViewCtrlDC: public wxWindowDC
2354 {
2355 public:
2356 wxDataViewCtrlDC( wxDataViewCtrl *window ) :
2357 wxWindowDC( new wxDataViewCtrlDCImpl( this, window ) )
2358 { }
2359 };
2360
2361
2362 // ---------------------------------------------------------
2363 // wxDataViewCustomRenderer
2364 // ---------------------------------------------------------
2365
2366 IMPLEMENT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
2367
2368 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
2369 wxDataViewCellMode mode,
2370 int align,
2371 bool no_init )
2372 : wxDataViewCustomRendererBase( varianttype, mode, align )
2373 {
2374 m_dc = NULL;
2375 m_text_renderer = NULL;
2376
2377 if (no_init)
2378 m_renderer = NULL;
2379 else
2380 Init(mode, align);
2381 }
2382
2383 void wxDataViewCustomRenderer::GtkInitTextRenderer()
2384 {
2385 m_text_renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
2386 g_object_ref_sink(m_text_renderer);
2387
2388 GtkApplyAlignment(GTK_CELL_RENDERER(m_text_renderer));
2389 }
2390
2391 GtkCellRendererText *wxDataViewCustomRenderer::GtkGetTextRenderer() const
2392 {
2393 if ( !m_text_renderer )
2394 {
2395 // we create it on demand so need to do it even from a const function
2396 const_cast<wxDataViewCustomRenderer *>(this)->GtkInitTextRenderer();
2397 }
2398
2399 return m_text_renderer;
2400 }
2401
2402 void wxDataViewCustomRenderer::RenderText( const wxString &text,
2403 int xoffset,
2404 wxRect cell,
2405 wxDC *WXUNUSED(dc),
2406 int WXUNUSED(state) )
2407 {
2408
2409 GtkCellRendererText * const textRenderer = GtkGetTextRenderer();
2410
2411 GValue gvalue = { 0, };
2412 g_value_init( &gvalue, G_TYPE_STRING );
2413 g_value_set_string( &gvalue, wxGTK_CONV_FONT( text, GetOwner()->GetOwner()->GetFont() ) );
2414 g_object_set_property( G_OBJECT(textRenderer), "text", &gvalue );
2415 g_value_unset( &gvalue );
2416
2417 GtkApplyAttr(textRenderer, GetAttr());
2418
2419 GdkRectangle cell_area;
2420 wxRectToGDKRect(cell, cell_area);
2421 cell_area.x += xoffset;
2422 cell_area.width -= xoffset;
2423
2424 gtk_cell_renderer_render( GTK_CELL_RENDERER(textRenderer),
2425 m_renderParams.window,
2426 m_renderParams.widget,
2427 m_renderParams.background_area,
2428 &cell_area,
2429 m_renderParams.expose_area,
2430 (GtkCellRendererState) m_renderParams.flags );
2431 }
2432
2433 bool wxDataViewCustomRenderer::Init(wxDataViewCellMode mode, int align)
2434 {
2435 GtkWxCellRenderer *renderer = (GtkWxCellRenderer *) gtk_wx_cell_renderer_new();
2436 renderer->cell = this;
2437
2438 m_renderer = (GtkCellRenderer*) renderer;
2439
2440 SetMode(mode);
2441 SetAlignment(align);
2442
2443 GtkInitHandlers();
2444
2445 return true;
2446 }
2447
2448 wxDataViewCustomRenderer::~wxDataViewCustomRenderer()
2449 {
2450 if (m_dc)
2451 delete m_dc;
2452
2453 if (m_text_renderer)
2454 g_object_unref(m_text_renderer);
2455 }
2456
2457 wxDC *wxDataViewCustomRenderer::GetDC()
2458 {
2459 if (m_dc == NULL)
2460 {
2461 if (GetOwner() == NULL)
2462 return NULL;
2463 if (GetOwner()->GetOwner() == NULL)
2464 return NULL;
2465 m_dc = new wxDataViewCtrlDC( GetOwner()->GetOwner() );
2466 }
2467
2468 return m_dc;
2469 }
2470
2471 // ---------------------------------------------------------
2472 // wxDataViewProgressRenderer
2473 // ---------------------------------------------------------
2474
2475 IMPLEMENT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
2476
2477 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
2478 const wxString &varianttype, wxDataViewCellMode mode, int align ) :
2479 wxDataViewCustomRenderer( varianttype, mode, align, true )
2480 {
2481 m_label = label;
2482 m_value = 0;
2483
2484 #ifdef __WXGTK26__
2485 if (!gtk_check_version(2,6,0))
2486 {
2487 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_progress_new();
2488
2489 SetMode(mode);
2490 SetAlignment(align);
2491
2492 #if !wxUSE_UNICODE
2493 // We can't initialize the renderer just yet because we don't have the
2494 // pointer to the column that uses this renderer yet and so attempt to
2495 // dereference GetOwner() to get the font that is used as a source of
2496 // encoding in multibyte-to-Unicode conversion in GTKSetLabel() in
2497 // non-Unicode builds would crash. So simply remember to do it later.
2498 if ( !m_label.empty() )
2499 m_needsToSetLabel = true;
2500 else
2501 #endif // !wxUSE_UNICODE
2502 GTKSetLabel();
2503 }
2504 else
2505 #endif
2506 {
2507 // Use custom cell code
2508 wxDataViewCustomRenderer::Init(mode, align);
2509 }
2510 }
2511
2512 wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
2513 {
2514 }
2515
2516 void wxDataViewProgressRenderer::GTKSetLabel()
2517 {
2518 GValue gvalue = { 0, };
2519 g_value_init( &gvalue, G_TYPE_STRING );
2520
2521 // Take care to not use GetOwner() here if the label is empty, we can be
2522 // called from ctor when GetOwner() is still NULL in this case.
2523 g_value_set_string( &gvalue,
2524 m_label.empty() ? ""
2525 : wxGTK_CONV_FONT(m_label,
2526 GetOwner()->GetOwner()->GetFont())
2527 );
2528 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
2529 g_value_unset( &gvalue );
2530
2531 #if !wxUSE_UNICODE
2532 m_needsToSetLabel = false;
2533 #endif // !wxUSE_UNICODE
2534 }
2535
2536 bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
2537 {
2538 #ifdef __WXGTK26__
2539 if (!gtk_check_version(2,6,0))
2540 {
2541 #if !wxUSE_UNICODE
2542 if ( m_needsToSetLabel )
2543 GTKSetLabel();
2544 #endif // !wxUSE_UNICODE
2545
2546 gint tmp = (long) value;
2547 GValue gvalue = { 0, };
2548 g_value_init( &gvalue, G_TYPE_INT );
2549 g_value_set_int( &gvalue, tmp );
2550 g_object_set_property( G_OBJECT(m_renderer), "value", &gvalue );
2551 g_value_unset( &gvalue );
2552 }
2553 else
2554 #endif
2555 {
2556 m_value = (long) value;
2557
2558 if (m_value < 0) m_value = 0;
2559 if (m_value > 100) m_value = 100;
2560 }
2561
2562 return true;
2563 }
2564
2565 bool wxDataViewProgressRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
2566 {
2567 return false;
2568 }
2569
2570 bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
2571 {
2572 double pct = (double)m_value / 100.0;
2573 wxRect bar = cell;
2574 bar.width = (int)(cell.width * pct);
2575 dc->SetPen( *wxTRANSPARENT_PEN );
2576 dc->SetBrush( *wxBLUE_BRUSH );
2577 dc->DrawRectangle( bar );
2578
2579 dc->SetBrush( *wxTRANSPARENT_BRUSH );
2580 dc->SetPen( *wxBLACK_PEN );
2581 dc->DrawRectangle( cell );
2582
2583 return true;
2584 }
2585
2586 wxSize wxDataViewProgressRenderer::GetSize() const
2587 {
2588 return wxSize(40,12);
2589 }
2590
2591 // -------------------------------------
2592 // wxDataViewChoiceRenderer
2593 // -------------------------------------
2594
2595 wxDataViewChoiceRenderer::wxDataViewChoiceRenderer( const wxArrayString &choices,
2596 wxDataViewCellMode mode, int alignment ) :
2597 wxDataViewCustomRenderer( "string", mode, alignment, true )
2598 {
2599 m_choices = choices;
2600
2601 #ifdef __WXGTK26__
2602 if (!gtk_check_version(2,6,0))
2603 {
2604 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_combo_new();
2605
2606 GtkListStore *store = gtk_list_store_new( 1, G_TYPE_STRING );
2607 for (size_t n = 0; n < m_choices.GetCount(); n++)
2608 {
2609 gtk_list_store_insert_with_values(
2610 store, NULL, n, 0,
2611 static_cast<const char *>(m_choices[n].utf8_str()), -1 );
2612 }
2613
2614 g_object_set (m_renderer,
2615 "model", store,
2616 "text-column", 0,
2617 "has-entry", FALSE,
2618 NULL);
2619
2620 bool editable = (mode & wxDATAVIEW_CELL_EDITABLE);
2621 g_object_set (m_renderer, "editable", editable, NULL);
2622
2623 SetAlignment(alignment);
2624
2625 g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
2626
2627 GtkInitHandlers();
2628 }
2629 else
2630 #endif
2631 {
2632 // Use custom cell code
2633 wxDataViewCustomRenderer::Init(mode, alignment);
2634 }
2635 }
2636
2637 bool wxDataViewChoiceRenderer::Render( wxRect rect, wxDC *dc, int state )
2638 {
2639 RenderText( m_data, 0, rect, dc, state );
2640 return true;
2641 }
2642
2643 wxSize wxDataViewChoiceRenderer::GetSize() const
2644 {
2645 return wxSize(70,20);
2646 }
2647
2648 bool wxDataViewChoiceRenderer::SetValue( const wxVariant &value )
2649 {
2650
2651 #ifdef __WXGTK26__
2652 if (!gtk_check_version(2,6,0))
2653 {
2654 GValue gvalue = { 0, };
2655 g_value_init( &gvalue, G_TYPE_STRING );
2656 g_value_set_string(&gvalue,
2657 wxGTK_CONV_FONT(value.GetString(),
2658 GetOwner()->GetOwner()->GetFont()));
2659 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
2660 g_value_unset( &gvalue );
2661 }
2662 else
2663 #endif
2664 m_data = value.GetString();
2665
2666 return true;
2667 }
2668
2669 bool wxDataViewChoiceRenderer::GetValue( wxVariant &value ) const
2670 {
2671 #ifdef __WXGTK26__
2672 if (!gtk_check_version(2,6,0))
2673 {
2674 GValue gvalue = { 0, };
2675 g_value_init( &gvalue, G_TYPE_STRING );
2676 g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
2677 wxString temp = wxGTK_CONV_BACK_FONT(g_value_get_string(&gvalue),
2678 GetOwner()->GetOwner()->GetFont());
2679 g_value_unset( &gvalue );
2680 value = temp;
2681
2682 //wxPrintf( "temp %s\n", temp );
2683 // TODO: remove this code
2684 }
2685 else
2686 #endif
2687 value = m_data;
2688
2689 return true;
2690 }
2691
2692 void wxDataViewChoiceRenderer::SetAlignment( int align )
2693 {
2694 wxDataViewCustomRenderer::SetAlignment(align);
2695
2696 if (gtk_check_version(2,10,0))
2697 return;
2698
2699 // horizontal alignment:
2700 PangoAlignment pangoAlign = PANGO_ALIGN_LEFT;
2701 if (align & wxALIGN_RIGHT)
2702 pangoAlign = PANGO_ALIGN_RIGHT;
2703 else if (align & wxALIGN_CENTER_HORIZONTAL)
2704 pangoAlign = PANGO_ALIGN_CENTER;
2705
2706 GValue gvalue = { 0, };
2707 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
2708 g_value_set_enum( &gvalue, pangoAlign );
2709 g_object_set_property( G_OBJECT(m_renderer), "alignment", &gvalue );
2710 g_value_unset( &gvalue );
2711 }
2712
2713 // ----------------------------------------------------------------------------
2714 // wxDataViewChoiceByIndexRenderer
2715 // ----------------------------------------------------------------------------
2716
2717 wxDataViewChoiceByIndexRenderer::wxDataViewChoiceByIndexRenderer( const wxArrayString &choices,
2718 wxDataViewCellMode mode, int alignment ) :
2719 wxDataViewChoiceRenderer( choices, mode, alignment )
2720 {
2721 }
2722
2723 void wxDataViewChoiceByIndexRenderer::GtkOnTextEdited(const gchar *itempath, const wxString& str)
2724 {
2725 wxVariant value( (long) GetChoices().Index( str ) );
2726
2727 if (!Validate( value ))
2728 return;
2729
2730 wxDataViewItem
2731 item(GetOwner()->GetOwner()->GTKPathToItem(wxGtkTreePath(itempath)));
2732
2733 GtkOnCellChanged(value, item, GetOwner()->GetModelColumn());
2734 }
2735
2736 bool wxDataViewChoiceByIndexRenderer::SetValue( const wxVariant &value )
2737 {
2738 wxVariant string_value = GetChoice( value.GetLong() );
2739 return wxDataViewChoiceRenderer::SetValue( string_value );
2740 }
2741
2742 bool wxDataViewChoiceByIndexRenderer::GetValue( wxVariant &value ) const
2743 {
2744 wxVariant string_value;
2745 if (!wxDataViewChoiceRenderer::GetValue( string_value ))
2746 return false;
2747
2748 value = (long) GetChoices().Index( string_value.GetString() );
2749 return true;
2750 }
2751
2752 // ---------------------------------------------------------
2753 // wxDataViewDateRenderer
2754 // ---------------------------------------------------------
2755
2756 class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
2757 {
2758 public:
2759 wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
2760 wxDataViewModel *model, const wxDataViewItem &item, unsigned int col ) :
2761 wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
2762 {
2763 m_model = model;
2764 m_item = item;
2765 m_col = col;
2766 m_cal = new wxCalendarCtrl( this, -1, *value );
2767 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
2768 sizer->Add( m_cal, 1, wxGROW );
2769 SetSizer( sizer );
2770 sizer->Fit( this );
2771 }
2772
2773 virtual void OnDismiss()
2774 {
2775 }
2776
2777 void OnCalendar( wxCalendarEvent &event );
2778
2779 wxCalendarCtrl *m_cal;
2780 wxDataViewModel *m_model;
2781 wxDataViewItem m_item;
2782 unsigned int m_col;
2783
2784 private:
2785 DECLARE_EVENT_TABLE()
2786 };
2787
2788 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
2789 EVT_CALENDAR( -1, wxDataViewDateRendererPopupTransient::OnCalendar )
2790 END_EVENT_TABLE()
2791
2792 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
2793 {
2794 m_model->ChangeValue( event.GetDate(), m_item, m_col );
2795 DismissAndNotify();
2796 }
2797
2798 IMPLEMENT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
2799
2800 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
2801 wxDataViewCellMode mode, int align ) :
2802 wxDataViewCustomRenderer( varianttype, mode, align )
2803 {
2804 SetMode(mode);
2805 SetAlignment(align);
2806 }
2807
2808 bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
2809 {
2810 m_date = value.GetDateTime();
2811
2812 return true;
2813 }
2814
2815 bool wxDataViewDateRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
2816 {
2817 return false;
2818 }
2819
2820 bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state )
2821 {
2822 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
2823 wxString tmp = m_date.FormatDate();
2824 RenderText( tmp, 0, cell, dc, state );
2825 return true;
2826 }
2827
2828 wxSize wxDataViewDateRenderer::GetSize() const
2829 {
2830 wxString tmp = m_date.FormatDate();
2831 wxCoord x,y,d;
2832 GetView()->GetTextExtent( tmp, &x, &y, &d );
2833 return wxSize(x,y+d);
2834 }
2835
2836 bool wxDataViewDateRenderer::Activate( const wxRect& WXUNUSED(cell), wxDataViewModel *model,
2837 const wxDataViewItem &item, unsigned int col )
2838 {
2839 wxVariant variant;
2840 model->GetValue( variant, item, col );
2841 wxDateTime value = variant.GetDateTime();
2842
2843 wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
2844 GetOwner()->GetOwner()->GetParent(), &value, model, item, col );
2845 wxPoint pos = wxGetMousePosition();
2846 popup->Move( pos );
2847 popup->Layout();
2848 popup->Popup( popup->m_cal );
2849
2850 return true;
2851 }
2852
2853
2854 // ---------------------------------------------------------
2855 // wxDataViewIconTextRenderer
2856 // ---------------------------------------------------------
2857
2858 IMPLEMENT_CLASS(wxDataViewIconTextRenderer, wxDataViewCustomRenderer)
2859
2860 wxDataViewIconTextRenderer::wxDataViewIconTextRenderer
2861 (
2862 const wxString &varianttype,
2863 wxDataViewCellMode mode,
2864 int align
2865 )
2866 : wxDataViewTextRenderer(varianttype, mode, align)
2867 {
2868 m_rendererIcon = gtk_cell_renderer_pixbuf_new();
2869 }
2870
2871 wxDataViewIconTextRenderer::~wxDataViewIconTextRenderer()
2872 {
2873 }
2874
2875 void wxDataViewIconTextRenderer::GtkPackIntoColumn(GtkTreeViewColumn *column)
2876 {
2877 // add the icon renderer first
2878 gtk_tree_view_column_pack_start(column, m_rendererIcon, FALSE /* !expand */);
2879
2880 // add the text renderer too
2881 wxDataViewRenderer::GtkPackIntoColumn(column);
2882 }
2883
2884 bool wxDataViewIconTextRenderer::SetValue( const wxVariant &value )
2885 {
2886 m_value << value;
2887
2888 SetTextValue(m_value.GetText());
2889 SetPixbufProp(m_rendererIcon, m_value.GetIcon().GetPixbuf());
2890
2891 return true;
2892 }
2893
2894 bool wxDataViewIconTextRenderer::GetValue(wxVariant& value) const
2895 {
2896 wxString str;
2897 if ( !GetTextValue(str) )
2898 return false;
2899
2900 // user doesn't have any way to edit the icon so leave it unchanged
2901 value << wxDataViewIconText(str, m_value.GetIcon());
2902
2903 return true;
2904 }
2905
2906 void
2907 wxDataViewIconTextRenderer::GtkOnCellChanged(const wxVariant& value,
2908 const wxDataViewItem& item,
2909 unsigned col)
2910 {
2911 // we receive just the text part of our value as it's the only one which
2912 // can be edited, but we need the full wxDataViewIconText value for the
2913 // model
2914 wxVariant valueIconText;
2915 valueIconText << wxDataViewIconText(value.GetString(), m_value.GetIcon());
2916 wxDataViewTextRenderer::GtkOnCellChanged(valueIconText, item, col);
2917 }
2918
2919 // ---------------------------------------------------------
2920 // wxDataViewColumn
2921 // ---------------------------------------------------------
2922
2923
2924 static gboolean
2925 gtk_dataview_header_button_press_callback( GtkWidget *WXUNUSED(widget),
2926 GdkEventButton *gdk_event,
2927 wxDataViewColumn *column )
2928 {
2929 if (gdk_event->type != GDK_BUTTON_PRESS)
2930 return FALSE;
2931
2932 if (gdk_event->button == 1)
2933 {
2934 gs_lastLeftClickHeader = column;
2935
2936 wxDataViewCtrl *dv = column->GetOwner();
2937 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, dv->GetId() );
2938 event.SetDataViewColumn( column );
2939 event.SetModel( dv->GetModel() );
2940 if (dv->HandleWindowEvent( event ))
2941 return FALSE;
2942 }
2943
2944 if (gdk_event->button == 3)
2945 {
2946 wxDataViewCtrl *dv = column->GetOwner();
2947 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, dv->GetId() );
2948 event.SetDataViewColumn( column );
2949 event.SetModel( dv->GetModel() );
2950 if (dv->HandleWindowEvent( event ))
2951 return FALSE;
2952 }
2953
2954 return FALSE;
2955 }
2956
2957 extern "C"
2958 {
2959
2960 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column),
2961 GtkCellRenderer *renderer,
2962 GtkTreeModel *model,
2963 GtkTreeIter *iter,
2964 gpointer data )
2965 {
2966 g_return_if_fail (GTK_IS_WX_TREE_MODEL (model));
2967 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) model;
2968
2969 wxDataViewRenderer *cell = (wxDataViewRenderer*) data;
2970
2971 wxDataViewItem item( (void*) iter->user_data );
2972
2973 wxDataViewModel *wx_model = tree_model->internal->GetDataViewModel();
2974
2975 if (!wx_model->IsVirtualListModel())
2976 {
2977 gboolean visible;
2978 if (wx_model->IsContainer( item ))
2979 {
2980 visible = wx_model->HasContainerColumns( item ) ||
2981 (cell->GetOwner()->GetModelColumn() == 0);
2982 }
2983 else
2984 {
2985 visible = true;
2986 }
2987
2988 GValue gvalue = { 0, };
2989 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2990 g_value_set_boolean( &gvalue, visible );
2991 g_object_set_property( G_OBJECT(renderer), "visible", &gvalue );
2992 g_value_unset( &gvalue );
2993
2994 if ( !visible )
2995 return;
2996 }
2997
2998 wxVariant value;
2999 wx_model->GetValue( value, item, cell->GetOwner()->GetModelColumn() );
3000
3001 if (value.GetType() != cell->GetVariantType())
3002 {
3003 wxLogError( wxT("Wrong type, required: %s but: %s"),
3004 value.GetType().c_str(),
3005 cell->GetVariantType().c_str() );
3006 }
3007
3008 cell->SetValue( value );
3009
3010 // deal with disabled items
3011 bool enabled = wx_model->IsEnabled( item, cell->GetOwner()->GetModelColumn() );
3012
3013 // a) this sets the appearance to disabled grey
3014 GValue gvalue = { 0, };
3015 g_value_init( &gvalue, G_TYPE_BOOLEAN );
3016 g_value_set_boolean( &gvalue, enabled );
3017 g_object_set_property( G_OBJECT(renderer), "sensitive", &gvalue );
3018 g_value_unset( &gvalue );
3019
3020 // b) this actually disables the control/renderer
3021 if (enabled)
3022 cell->SetMode( cell->GtkGetMode() );
3023 else
3024 cell->SetMode( wxDATAVIEW_CELL_INERT );
3025
3026
3027 // deal with attributes: if the renderer doesn't support them at all, we
3028 // don't even need to query the model for them
3029 if ( !cell->GtkSupportsAttrs() )
3030 return;
3031
3032 // it can support attributes so check if this item has any
3033 wxDataViewItemAttr attr;
3034 if ( wx_model->GetAttr( item, cell->GetOwner()->GetModelColumn(), attr )
3035 || !cell->GtkIsUsingDefaultAttrs() )
3036 {
3037 bool usingDefaultAttrs = !cell->GtkSetAttr(attr);
3038 cell->GtkSetUsingDefaultAttrs(usingDefaultAttrs);
3039 }
3040 // else: no custom attributes specified and we're already using the default
3041 // ones -- nothing to do
3042
3043 }
3044
3045 } // extern "C"
3046
3047 #include <wx/listimpl.cpp>
3048 WX_DEFINE_LIST(wxDataViewColumnList)
3049
3050 wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell,
3051 unsigned int model_column, int width,
3052 wxAlignment align, int flags )
3053 : wxDataViewColumnBase( cell, model_column )
3054 {
3055 Init( align, flags, width );
3056
3057 SetTitle( title );
3058 }
3059
3060 wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell,
3061 unsigned int model_column, int width,
3062 wxAlignment align, int flags )
3063 : wxDataViewColumnBase( bitmap, cell, model_column )
3064 {
3065 Init( align, flags, width );
3066
3067 SetBitmap( bitmap );
3068 }
3069
3070 void wxDataViewColumn::Init(wxAlignment align, int flags, int width)
3071 {
3072 m_isConnected = false;
3073
3074 GtkTreeViewColumn *column = gtk_tree_view_column_new();
3075 m_column = (GtkWidget*) column;
3076
3077 SetFlags( flags );
3078 SetAlignment( align );
3079
3080 SetWidth( width );
3081
3082 // Create container for icon and label
3083 GtkWidget *box = gtk_hbox_new( FALSE, 1 );
3084 gtk_widget_show( box );
3085 // gtk_container_set_border_width((GtkContainer*)box, 2);
3086 m_image = gtk_image_new();
3087 gtk_box_pack_start(GTK_BOX(box), m_image, FALSE, FALSE, 1);
3088 m_label = gtk_label_new("");
3089 gtk_box_pack_end( GTK_BOX(box), GTK_WIDGET(m_label), FALSE, FALSE, 1 );
3090 gtk_tree_view_column_set_widget( column, box );
3091
3092 wxDataViewRenderer * const colRenderer = GetRenderer();
3093 GtkCellRenderer * const cellRenderer = colRenderer->GetGtkHandle();
3094
3095 colRenderer->GtkPackIntoColumn(column);
3096
3097 gtk_tree_view_column_set_cell_data_func( column, cellRenderer,
3098 wxGtkTreeCellDataFunc, (gpointer) colRenderer, NULL );
3099 }
3100
3101 void wxDataViewColumn::OnInternalIdle()
3102 {
3103 if (m_isConnected)
3104 return;
3105
3106 if (gtk_widget_get_realized(GetOwner()->m_treeview))
3107 {
3108 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3109 if (column->button)
3110 {
3111 g_signal_connect(column->button, "button_press_event",
3112 G_CALLBACK (gtk_dataview_header_button_press_callback), this);
3113
3114 // otherwise the event will be blocked by GTK+
3115 gtk_tree_view_column_set_clickable( column, TRUE );
3116
3117 m_isConnected = true;
3118 }
3119 }
3120 }
3121
3122 void wxDataViewColumn::SetOwner( wxDataViewCtrl *owner )
3123 {
3124 wxDataViewColumnBase::SetOwner( owner );
3125
3126 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3127
3128 gtk_tree_view_column_set_title( column, wxGTK_CONV_FONT(GetTitle(), GetOwner()->GetFont() ) );
3129 }
3130
3131 void wxDataViewColumn::SetTitle( const wxString &title )
3132 {
3133 wxDataViewCtrl *ctrl = GetOwner();
3134 gtk_label_set_text( GTK_LABEL(m_label), ctrl ? wxGTK_CONV_FONT(title, ctrl->GetFont())
3135 : wxGTK_CONV_SYS(title) );
3136 if (title.empty())
3137 gtk_widget_hide( m_label );
3138 else
3139 gtk_widget_show( m_label );
3140 }
3141
3142 wxString wxDataViewColumn::GetTitle() const
3143 {
3144 return wxGTK_CONV_BACK_FONT(
3145 gtk_label_get_text( GTK_LABEL(m_label) ),
3146 GetOwner()->GetFont()
3147 );
3148 }
3149
3150 void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap )
3151 {
3152 wxDataViewColumnBase::SetBitmap( bitmap );
3153
3154 if (bitmap.IsOk())
3155 {
3156 GtkImage *gtk_image = GTK_IMAGE(m_image);
3157
3158 GdkBitmap *mask = NULL;
3159 if (bitmap.GetMask())
3160 mask = bitmap.GetMask()->GetBitmap();
3161
3162 if (bitmap.HasPixbuf())
3163 {
3164 gtk_image_set_from_pixbuf(GTK_IMAGE(gtk_image),
3165 bitmap.GetPixbuf());
3166 }
3167 else
3168 {
3169 gtk_image_set_from_pixmap(GTK_IMAGE(gtk_image),
3170 bitmap.GetPixmap(), mask);
3171 }
3172 gtk_widget_show( m_image );
3173 }
3174 else
3175 {
3176 gtk_widget_hide( m_image );
3177 }
3178 }
3179
3180 void wxDataViewColumn::SetHidden( bool hidden )
3181 {
3182 gtk_tree_view_column_set_visible( GTK_TREE_VIEW_COLUMN(m_column), !hidden );
3183 }
3184
3185 void wxDataViewColumn::SetResizeable( bool resizable )
3186 {
3187 gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizable );
3188 }
3189
3190 void wxDataViewColumn::SetAlignment( wxAlignment align )
3191 {
3192 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3193
3194 gfloat xalign = 0.0;
3195 if (align == wxALIGN_RIGHT)
3196 xalign = 1.0;
3197 if (align == wxALIGN_CENTER_HORIZONTAL ||
3198 align == wxALIGN_CENTER)
3199 xalign = 0.5;
3200
3201 gtk_tree_view_column_set_alignment( column, xalign );
3202
3203 if (m_renderer && m_renderer->GetAlignment() == -1)
3204 m_renderer->GtkUpdateAlignment();
3205 }
3206
3207 wxAlignment wxDataViewColumn::GetAlignment() const
3208 {
3209 gfloat xalign = gtk_tree_view_column_get_alignment( GTK_TREE_VIEW_COLUMN(m_column) );
3210
3211 if (xalign == 1.0)
3212 return wxALIGN_RIGHT;
3213 if (xalign == 0.5)
3214 return wxALIGN_CENTER_HORIZONTAL;
3215
3216 return wxALIGN_LEFT;
3217 }
3218
3219 void wxDataViewColumn::SetSortable( bool sortable )
3220 {
3221 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3222
3223 if ( sortable )
3224 {
3225 gtk_tree_view_column_set_sort_column_id( column, GetModelColumn() );
3226 }
3227 else
3228 {
3229 gtk_tree_view_column_set_sort_column_id( column, -1 );
3230 gtk_tree_view_column_set_sort_indicator( column, FALSE );
3231 gtk_tree_view_column_set_clickable( column, FALSE );
3232 }
3233 }
3234
3235 bool wxDataViewColumn::IsSortable() const
3236 {
3237 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3238 return gtk_tree_view_column_get_clickable( column );
3239 }
3240
3241 void wxDataViewColumn::SetAsSortKey( bool WXUNUSED(sort) )
3242 {
3243 // it might not make sense to have this function in wxHeaderColumn at
3244 // all in fact, changing of the sort order should only be done using the
3245 // associated control API
3246 wxFAIL_MSG( "not implemented" );
3247 }
3248
3249 bool wxDataViewColumn::IsSortKey() const
3250 {
3251 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3252 return gtk_tree_view_column_get_sort_indicator( column );
3253 }
3254
3255 bool wxDataViewColumn::IsResizeable() const
3256 {
3257 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3258 return gtk_tree_view_column_get_resizable( column );
3259 }
3260
3261 bool wxDataViewColumn::IsHidden() const
3262 {
3263 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3264 return !gtk_tree_view_column_get_visible( column );
3265 }
3266
3267 void wxDataViewColumn::SetSortOrder( bool ascending )
3268 {
3269 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3270
3271 if (ascending)
3272 gtk_tree_view_column_set_sort_order( column, GTK_SORT_ASCENDING );
3273 else
3274 gtk_tree_view_column_set_sort_order( column, GTK_SORT_DESCENDING );
3275
3276 gtk_tree_view_column_set_sort_indicator( column, TRUE );
3277 }
3278
3279 bool wxDataViewColumn::IsSortOrderAscending() const
3280 {
3281 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3282
3283 return (gtk_tree_view_column_get_sort_order( column ) != GTK_SORT_DESCENDING);
3284 }
3285
3286 void wxDataViewColumn::SetMinWidth( int width )
3287 {
3288 gtk_tree_view_column_set_min_width( GTK_TREE_VIEW_COLUMN(m_column), width );
3289 }
3290
3291 int wxDataViewColumn::GetMinWidth() const
3292 {
3293 return gtk_tree_view_column_get_min_width( GTK_TREE_VIEW_COLUMN(m_column) );
3294 }
3295
3296 int wxDataViewColumn::GetWidth() const
3297 {
3298 return gtk_tree_view_column_get_width( GTK_TREE_VIEW_COLUMN(m_column) );
3299 }
3300
3301 void wxDataViewColumn::SetWidth( int width )
3302 {
3303 if ( width == wxCOL_WIDTH_AUTOSIZE )
3304 {
3305 // NB: this disables user resizing
3306 gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_AUTOSIZE );
3307 }
3308 else
3309 {
3310 if ( width == wxCOL_WIDTH_DEFAULT )
3311 {
3312 // TODO find a better calculation
3313 width = wxDVC_DEFAULT_WIDTH;
3314 }
3315
3316 gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED );
3317 gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), width );
3318 }
3319 }
3320
3321 void wxDataViewColumn::SetReorderable( bool reorderable )
3322 {
3323 gtk_tree_view_column_set_reorderable( GTK_TREE_VIEW_COLUMN(m_column), reorderable );
3324 }
3325
3326 bool wxDataViewColumn::IsReorderable() const
3327 {
3328 return gtk_tree_view_column_get_reorderable( GTK_TREE_VIEW_COLUMN(m_column) );
3329 }
3330
3331 //-----------------------------------------------------------------------------
3332 // wxGtkTreeModelNode
3333 //-----------------------------------------------------------------------------
3334
3335 #if 0
3336 class wxGtkTreeModelChildWithPos
3337 {
3338 public:
3339 unsigned int pos;
3340 void *id;
3341 };
3342
3343 static
3344 int wxGtkTreeModelChildWithPosCmp( const void* data1, const void* data2, const void* user_data )
3345 {
3346 const wxGtkTreeModelChildWithPos* child1 = (const wxGtkTreeModelChildWithPos*) data1;
3347 const wxGtkTreeModelChildWithPos* child2 = (const wxGtkTreeModelChildWithPos*) data2;
3348 const wxDataViewCtrlInternal *internal = (const wxDataViewCtrlInternal *) user_data;
3349 int ret = internal->GetDataViewModel()->Compare( child1->id, child2->id,
3350 internal->GetSortColumn(), (internal->GetSortOrder() == GTK_SORT_DESCENDING) );
3351
3352 return ret;
3353 }
3354 #else
3355 static
3356 int LINKAGEMODE wxGtkTreeModelChildPtrCmp( void*** data1, void*** data2 )
3357 {
3358 return gs_internal->GetDataViewModel()->Compare( wxDataViewItem(**data1), wxDataViewItem(**data2),
3359 gs_internal->GetSortColumn(), (gs_internal->GetSortOrder() == GTK_SORT_ASCENDING) );
3360 }
3361
3362 WX_DEFINE_ARRAY_PTR( void**, wxGtkTreeModelChildrenPtr );
3363 #endif
3364
3365 void wxGtkTreeModelNode::Resort()
3366 {
3367 size_t child_count = GetChildCount();
3368 if (child_count == 0)
3369 return;
3370
3371 size_t node_count = GetNodesCount();
3372
3373 if (child_count == 1)
3374 {
3375 if (node_count == 1)
3376 {
3377 wxGtkTreeModelNode *node = m_nodes.Item( 0 );
3378 node->Resort();
3379 }
3380 return;
3381 }
3382
3383 gint *new_order = new gint[child_count];
3384
3385 #if 1
3386 // m_children has the original *void
3387 // ptrs points to these
3388 wxGtkTreeModelChildrenPtr ptrs;
3389 size_t i;
3390 for (i = 0; i < child_count; i++)
3391 ptrs.Add( &(m_children[i]) );
3392 // Sort the ptrs
3393 gs_internal = m_internal;
3394 ptrs.Sort( &wxGtkTreeModelChildPtrCmp );
3395
3396 wxGtkTreeModelChildren temp;
3397 void** base_ptr = &(m_children[0]);
3398 // Transfer positions to new_order array and
3399 // IDs to temp
3400 for (i = 0; i < child_count; i++)
3401 {
3402 new_order[i] = ptrs[i] - base_ptr;
3403 temp.Add( *ptrs[i] );
3404 }
3405
3406 // Transfer IDs back to m_children
3407 m_children.Clear();
3408 WX_APPEND_ARRAY( temp, m_children );
3409 #endif
3410 #if 0
3411 // Too slow
3412
3413 // Build up array with IDs and original positions
3414 wxGtkTreeModelChildWithPos* temp = new wxGtkTreeModelChildWithPos[child_count];
3415 size_t i;
3416 for (i = 0; i < child_count; i++)
3417 {
3418 temp[i].pos = i;
3419 temp[i].id = m_children[i];
3420 }
3421 // Sort array keeping original positions
3422 wxQsort( temp, child_count, sizeof(wxGtkTreeModelChildWithPos),
3423 &wxGtkTreeModelChildWithPosCmp, m_internal );
3424 // Transfer positions to new_order array and
3425 // IDs to m_children
3426 m_children.Clear();
3427 for (i = 0; i < child_count; i++)
3428 {
3429 new_order[i] = temp[i].pos;
3430 m_children.Add( temp[i].id );
3431 }
3432 // Delete array
3433 delete [] temp;
3434 #endif
3435
3436 #if 0
3437 // Too slow
3438
3439 wxGtkTreeModelChildren temp;
3440 WX_APPEND_ARRAY( temp, m_children );
3441
3442 gs_internal = m_internal;
3443 m_children.Sort( &wxGtkTreeModelChildCmp );
3444
3445 unsigned int pos;
3446 for (pos = 0; pos < child_count; pos++)
3447 {
3448 void *id = m_children.Item( pos );
3449 int old_pos = temp.Index( id );
3450 new_order[pos] = old_pos;
3451 }
3452 #endif
3453
3454 GtkTreeModel *gtk_tree_model = GTK_TREE_MODEL( m_internal->GetGtkModel() );
3455
3456 GtkTreeIter iter;
3457 iter.user_data = GetItem().GetID();
3458 iter.stamp = m_internal->GetGtkModel()->stamp;
3459
3460 gtk_tree_model_rows_reordered( gtk_tree_model,
3461 wxGtkTreePath(m_internal->get_path(&iter)), &iter, new_order );
3462
3463 delete [] new_order;
3464
3465 unsigned int pos;
3466 for (pos = 0; pos < node_count; pos++)
3467 {
3468 wxGtkTreeModelNode *node = m_nodes.Item( pos );
3469 node->Resort();
3470 }
3471 }
3472
3473 //-----------------------------------------------------------------------------
3474 // wxDataViewCtrlInternal
3475 //-----------------------------------------------------------------------------
3476
3477 wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataViewModel *wx_model )
3478 {
3479 m_owner = owner;
3480 m_wx_model = wx_model;
3481
3482 m_gtk_model = NULL;
3483 m_root = NULL;
3484 m_sort_order = GTK_SORT_ASCENDING;
3485 m_sort_column = -1;
3486 m_dataview_sort_column = NULL;
3487
3488 m_dragDataObject = NULL;
3489 m_dropDataObject = NULL;
3490
3491 m_dirty = false;
3492
3493 m_gtk_model = wxgtk_tree_model_new();
3494 m_gtk_model->internal = this;
3495
3496 m_notifier = new wxGtkDataViewModelNotifier( wx_model, this );
3497
3498 wx_model->AddNotifier( m_notifier );
3499
3500 // g_object_unref( gtk_model ); ???
3501
3502 if (!m_wx_model->IsVirtualListModel())
3503 InitTree();
3504
3505 gtk_tree_view_set_model( GTK_TREE_VIEW(m_owner->GtkGetTreeView()), GTK_TREE_MODEL(m_gtk_model) );
3506 }
3507
3508 wxDataViewCtrlInternal::~wxDataViewCtrlInternal()
3509 {
3510 m_wx_model->RemoveNotifier( m_notifier );
3511
3512 // remove the model from the GtkTreeView before it gets destroyed
3513 gtk_tree_view_set_model( GTK_TREE_VIEW( m_owner->GtkGetTreeView() ), NULL );
3514
3515 g_object_unref( m_gtk_model );
3516
3517 delete m_dragDataObject;
3518 delete m_dropDataObject;
3519 }
3520
3521 void wxDataViewCtrlInternal::ScheduleRefresh()
3522 {
3523 m_dirty = true;
3524 }
3525
3526 void wxDataViewCtrlInternal::OnInternalIdle()
3527 {
3528 if (m_dirty)
3529 {
3530 GtkWidget *widget = m_owner->GtkGetTreeView();
3531 gtk_widget_queue_draw( widget );
3532 m_dirty = false;
3533 }
3534 }
3535
3536 void wxDataViewCtrlInternal::InitTree()
3537 {
3538 wxDataViewItem item;
3539 m_root = new wxGtkTreeModelNode( NULL, item, this );
3540
3541 BuildBranch( m_root );
3542 }
3543
3544 void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node )
3545 {
3546 if (node->GetChildCount() == 0)
3547 {
3548 wxDataViewItemArray children;
3549 unsigned int count = m_wx_model->GetChildren( node->GetItem(), children );
3550
3551 unsigned int pos;
3552 for (pos = 0; pos < count; pos++)
3553 {
3554 wxDataViewItem child = children[pos];
3555
3556 if (m_wx_model->IsContainer( child ))
3557 node->AddNode( new wxGtkTreeModelNode( node, child, this ) );
3558 else
3559 node->AddLeave( child.GetID() );
3560
3561 // Don't send any events here
3562 }
3563 }
3564 }
3565
3566 // GTK+ dnd iface
3567
3568 bool wxDataViewCtrlInternal::EnableDragSource( const wxDataFormat &format )
3569 {
3570 wxGtkString atom_str( gdk_atom_name( format ) );
3571 m_dragSourceTargetEntryTarget = wxCharBuffer( atom_str );
3572
3573 m_dragSourceTargetEntry.target = m_dragSourceTargetEntryTarget.data();
3574 m_dragSourceTargetEntry.flags = 0;
3575 m_dragSourceTargetEntry.info = static_cast<guint>(-1);
3576
3577 gtk_tree_view_enable_model_drag_source( GTK_TREE_VIEW(m_owner->GtkGetTreeView() ),
3578 GDK_BUTTON1_MASK, &m_dragSourceTargetEntry, 1, (GdkDragAction) GDK_ACTION_COPY );
3579
3580 return true;
3581 }
3582
3583 bool wxDataViewCtrlInternal::EnableDropTarget( const wxDataFormat &format )
3584 {
3585 wxGtkString atom_str( gdk_atom_name( format ) );
3586 m_dropTargetTargetEntryTarget = wxCharBuffer( atom_str );
3587
3588 m_dropTargetTargetEntry.target = m_dropTargetTargetEntryTarget.data();
3589 m_dropTargetTargetEntry.flags = 0;
3590 m_dropTargetTargetEntry.info = static_cast<guint>(-1);
3591
3592 gtk_tree_view_enable_model_drag_dest( GTK_TREE_VIEW(m_owner->GtkGetTreeView() ),
3593 &m_dropTargetTargetEntry, 1, (GdkDragAction) GDK_ACTION_COPY );
3594
3595 return true;
3596 }
3597
3598 gboolean wxDataViewCtrlInternal::row_draggable( GtkTreeDragSource *WXUNUSED(drag_source),
3599 GtkTreePath *path )
3600 {
3601 delete m_dragDataObject;
3602 m_dragDataObject = NULL;
3603
3604 wxDataViewItem item(GetOwner()->GTKPathToItem(path));
3605 if ( !item )
3606 return FALSE;
3607
3608 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_BEGIN_DRAG, m_owner->GetId() );
3609 event.SetEventObject( m_owner );
3610 event.SetItem( item );
3611 event.SetModel( m_wx_model );
3612 gint x, y;
3613 gtk_widget_get_pointer(m_owner->GtkGetTreeView(), &x, &y);
3614 event.SetPosition(x, y);
3615 if (!m_owner->HandleWindowEvent( event ))
3616 return FALSE;
3617
3618 if (!event.IsAllowed())
3619 return FALSE;
3620
3621 wxDataObject *obj = event.GetDataObject();
3622 if (!obj)
3623 return FALSE;
3624
3625 m_dragDataObject = obj;
3626
3627 return TRUE;
3628 }
3629
3630 gboolean
3631 wxDataViewCtrlInternal::drag_data_delete(GtkTreeDragSource *WXUNUSED(drag_source),
3632 GtkTreePath *WXUNUSED(path))
3633 {
3634 return FALSE;
3635 }
3636
3637 gboolean wxDataViewCtrlInternal::drag_data_get( GtkTreeDragSource *WXUNUSED(drag_source),
3638 GtkTreePath *path, GtkSelectionData *selection_data )
3639 {
3640 wxDataViewItem item(GetOwner()->GTKPathToItem(path));
3641 if ( !item )
3642 return FALSE;
3643
3644 GdkAtom target = gtk_selection_data_get_target(selection_data);
3645 if (!m_dragDataObject->IsSupported(target))
3646 return FALSE;
3647
3648 size_t size = m_dragDataObject->GetDataSize(target);
3649 if (size == 0)
3650 return FALSE;
3651
3652 void *buf = malloc( size );
3653
3654 gboolean res = FALSE;
3655 if (m_dragDataObject->GetDataHere(target, buf))
3656 {
3657 res = TRUE;
3658
3659 gtk_selection_data_set(selection_data, target,
3660 8, (const guchar*) buf, size );
3661 }
3662
3663 free( buf );
3664
3665 return res;
3666 }
3667
3668 gboolean
3669 wxDataViewCtrlInternal::drag_data_received(GtkTreeDragDest *WXUNUSED(drag_dest),
3670 GtkTreePath *path,
3671 GtkSelectionData *selection_data)
3672 {
3673 wxDataViewItem item(GetOwner()->GTKPathToItem(path));
3674 if ( !item )
3675 return FALSE;
3676
3677 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP, m_owner->GetId() );
3678 event.SetEventObject( m_owner );
3679 event.SetItem( item );
3680 event.SetModel( m_wx_model );
3681 event.SetDataFormat(gtk_selection_data_get_target(selection_data));
3682 event.SetDataSize(gtk_selection_data_get_length(selection_data));
3683 event.SetDataBuffer(const_cast<guchar*>(gtk_selection_data_get_data(selection_data)));
3684 if (!m_owner->HandleWindowEvent( event ))
3685 return FALSE;
3686
3687 if (!event.IsAllowed())
3688 return FALSE;
3689
3690 return TRUE;
3691 }
3692
3693 gboolean
3694 wxDataViewCtrlInternal::row_drop_possible(GtkTreeDragDest *WXUNUSED(drag_dest),
3695 GtkTreePath *path,
3696 GtkSelectionData *selection_data)
3697 {
3698 wxDataViewItem item(GetOwner()->GTKPathToItem(path));
3699 if ( !item )
3700 return FALSE;
3701
3702 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP_POSSIBLE, m_owner->GetId() );
3703 event.SetEventObject( m_owner );
3704 event.SetItem( item );
3705 event.SetModel( m_wx_model );
3706 event.SetDataFormat(gtk_selection_data_get_target(selection_data));
3707 if (!m_owner->HandleWindowEvent( event ))
3708 return FALSE;
3709
3710 if (!event.IsAllowed())
3711 return FALSE;
3712
3713 return TRUE;
3714 }
3715
3716 // notifications from wxDataViewModel
3717
3718 bool wxDataViewCtrlInternal::Cleared()
3719 {
3720 if (m_root)
3721 {
3722 delete m_root;
3723 m_root = NULL;
3724 }
3725
3726 InitTree();
3727
3728 ScheduleRefresh();
3729
3730 return true;
3731 }
3732
3733 void wxDataViewCtrlInternal::Resort()
3734 {
3735 if (!m_wx_model->IsVirtualListModel())
3736 m_root->Resort();
3737
3738 ScheduleRefresh();
3739 }
3740
3741 bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
3742 {
3743 if (!m_wx_model->IsVirtualListModel())
3744 {
3745 wxGtkTreeModelNode *parent_node = FindNode( parent );
3746 wxASSERT_MSG(parent_node,
3747 "Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
3748
3749 if (m_wx_model->IsContainer( item ))
3750 parent_node->AddNode( new wxGtkTreeModelNode( parent_node, item, this ) );
3751 else
3752 parent_node->AddLeave( item.GetID() );
3753 }
3754
3755 ScheduleRefresh();
3756
3757 return true;
3758 }
3759
3760 bool wxDataViewCtrlInternal::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
3761 {
3762 if (!m_wx_model->IsVirtualListModel())
3763 {
3764 wxGtkTreeModelNode *parent_node = FindNode( parent );
3765 wxASSERT_MSG(parent_node,
3766 "Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
3767
3768 parent_node->DeleteChild( item.GetID() );
3769 }
3770
3771 ScheduleRefresh();
3772
3773 return true;
3774 }
3775
3776 bool wxDataViewCtrlInternal::ItemChanged( const wxDataViewItem &item )
3777 {
3778 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, m_owner->GetId() );
3779 event.SetEventObject( m_owner );
3780 event.SetModel( m_owner->GetModel() );
3781 event.SetItem( item );
3782 m_owner->HandleWindowEvent( event );
3783
3784 return true;
3785 }
3786
3787 bool wxDataViewCtrlInternal::ValueChanged( const wxDataViewItem &item, unsigned int view_column )
3788 {
3789 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, m_owner->GetId() );
3790 event.SetEventObject( m_owner );
3791 event.SetModel( m_owner->GetModel() );
3792 event.SetColumn( view_column );
3793 event.SetDataViewColumn( GetOwner()->GetColumn(view_column) );
3794 event.SetItem( item );
3795 m_owner->HandleWindowEvent( event );
3796
3797 return true;
3798 }
3799
3800 // GTK+ model iface
3801
3802 GtkTreeModelFlags wxDataViewCtrlInternal::get_flags()
3803 {
3804 int flags = 0;
3805
3806 if ( m_wx_model->IsListModel() )
3807 flags |= GTK_TREE_MODEL_LIST_ONLY;
3808
3809 if ( !m_wx_model->IsVirtualListModel() )
3810 flags |= GTK_TREE_MODEL_ITERS_PERSIST;
3811
3812 return GtkTreeModelFlags(flags);
3813 }
3814
3815 gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path )
3816 {
3817
3818 if (m_wx_model->IsVirtualListModel())
3819 {
3820 wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model;
3821
3822 unsigned int i = (unsigned int)gtk_tree_path_get_indices (path)[0];
3823
3824 if (i >= wx_model->GetCount())
3825 return FALSE;
3826
3827 iter->stamp = m_gtk_model->stamp;
3828 // user_data is just the index +1
3829 iter->user_data = (gpointer) (i+1);
3830
3831 return TRUE;
3832 }
3833 else
3834 {
3835 int depth = gtk_tree_path_get_depth( path );
3836
3837 wxGtkTreeModelNode *node = m_root;
3838
3839 int i;
3840 for (i = 0; i < depth; i++)
3841 {
3842 BuildBranch( node );
3843
3844 gint pos = gtk_tree_path_get_indices (path)[i];
3845 if (pos < 0) return FALSE;
3846 if ((size_t)pos >= node->GetChildCount()) return FALSE;
3847
3848 void* id = node->GetChildren().Item( (size_t) pos );
3849
3850 if (i == depth-1)
3851 {
3852 iter->stamp = m_gtk_model->stamp;
3853 iter->user_data = id;
3854 return TRUE;
3855 }
3856
3857 size_t count = node->GetNodes().GetCount();
3858 size_t pos2;
3859 for (pos2 = 0; pos2 < count; pos2++)
3860 {
3861 wxGtkTreeModelNode *child_node = node->GetNodes().Item( pos2 );
3862 if (child_node->GetItem().GetID() == id)
3863 {
3864 node = child_node;
3865 break;
3866 }
3867 }
3868 }
3869 }
3870
3871 return FALSE;
3872 }
3873
3874 GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter )
3875 {
3876 // When this is called from ItemDeleted(), the item is already
3877 // deleted in the model.
3878
3879 GtkTreePath *retval = gtk_tree_path_new ();
3880
3881 if (m_wx_model->IsVirtualListModel())
3882 {
3883 // iter is root, add nothing
3884 if (!iter->user_data)
3885 return retval;
3886
3887 // user_data is just the index +1
3888 int i = ( (wxUIntPtr) iter->user_data ) -1;
3889 gtk_tree_path_append_index (retval, i);
3890 }
3891 else
3892 {
3893 void *id = iter->user_data;
3894
3895 wxGtkTreeModelNode *node = FindParentNode( iter );
3896 while (node)
3897 {
3898 int pos = node->GetChildren().Index( id );
3899
3900 gtk_tree_path_prepend_index( retval, pos );
3901
3902 id = node->GetItem().GetID();
3903 node = node->GetParent();
3904 }
3905 }
3906
3907 return retval;
3908 }
3909
3910 gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter )
3911 {
3912 if (m_wx_model->IsVirtualListModel())
3913 {
3914 wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model;
3915
3916 // user_data is just the index +1
3917 int n = ( (wxUIntPtr) iter->user_data ) -1;
3918
3919 if (n == -1)
3920 {
3921 iter->user_data = NULL;
3922 return FALSE;
3923 }
3924
3925 if (n >= (int) wx_model->GetCount()-1)
3926 {
3927 iter->user_data = NULL;
3928 return FALSE;
3929 }
3930
3931 // user_data is just the index +1 (+2 because we need the next)
3932 iter->user_data = (gpointer) (n+2);
3933 }
3934 else
3935 {
3936 wxGtkTreeModelNode *parent = FindParentNode( iter );
3937 if( parent == NULL )
3938 {
3939 iter->user_data = NULL;
3940 return FALSE;
3941 }
3942
3943 int pos = parent->GetChildren().Index( iter->user_data );
3944
3945 if (pos == (int) parent->GetChildCount()-1)
3946 {
3947 iter->user_data = NULL;
3948 return FALSE;
3949 }
3950
3951 iter->user_data = parent->GetChildren().Item( pos+1 );
3952 }
3953
3954 return TRUE;
3955 }
3956
3957 gboolean wxDataViewCtrlInternal::iter_children( GtkTreeIter *iter, GtkTreeIter *parent )
3958 {
3959 if (m_wx_model->IsVirtualListModel())
3960 {
3961 // this is a list, nodes have no children
3962 if (parent)
3963 return FALSE;
3964
3965 iter->stamp = m_gtk_model->stamp;
3966 iter->user_data = (gpointer) 1;
3967
3968 return TRUE;
3969 }
3970 else
3971 {
3972 if (iter == NULL)
3973 {
3974 if (m_root->GetChildCount() == 0) return FALSE;
3975 iter->stamp = m_gtk_model->stamp;
3976 iter->user_data = (gpointer) m_root->GetChildren().Item( 0 );
3977 return TRUE;
3978 }
3979
3980
3981 wxDataViewItem item;
3982 if (parent)
3983 item = wxDataViewItem( (void*) parent->user_data );
3984
3985 if (!m_wx_model->IsContainer( item ))
3986 return FALSE;
3987
3988 wxGtkTreeModelNode *parent_node = FindNode( parent );
3989 wxASSERT_MSG(parent_node,
3990 "Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
3991
3992 BuildBranch( parent_node );
3993
3994 if (parent_node->GetChildCount() == 0)
3995 return FALSE;
3996
3997 iter->stamp = m_gtk_model->stamp;
3998 iter->user_data = (gpointer) parent_node->GetChildren().Item( 0 );
3999 }
4000
4001 return TRUE;
4002 }
4003
4004 gboolean wxDataViewCtrlInternal::iter_has_child( GtkTreeIter *iter )
4005 {
4006 if (m_wx_model->IsVirtualListModel())
4007 {
4008 wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model;
4009
4010 if (iter == NULL)
4011 return (wx_model->GetCount() > 0);
4012
4013 // this is a list, nodes have no children
4014 return FALSE;
4015 }
4016 else
4017 {
4018 if (iter == NULL)
4019 return (m_root->GetChildCount() > 0);
4020
4021 wxDataViewItem item( (void*) iter->user_data );
4022
4023 bool is_container = m_wx_model->IsContainer( item );
4024
4025 if (!is_container)
4026 return FALSE;
4027
4028 wxGtkTreeModelNode *node = FindNode( iter );
4029 wxASSERT_MSG(node,
4030 "Did you forget a call to ItemAdded()? The iterator is unknown to the wxGtkTreeModel");
4031
4032 BuildBranch( node );
4033
4034 return (node->GetChildCount() > 0);
4035 }
4036 }
4037
4038 gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter )
4039 {
4040 if (m_wx_model->IsVirtualListModel())
4041 {
4042 wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model;
4043
4044 if (iter == NULL)
4045 return (gint) wx_model->GetCount();
4046
4047 return 0;
4048 }
4049 else
4050 {
4051 if (iter == NULL)
4052 return m_root->GetChildCount();
4053
4054 wxDataViewItem item( (void*) iter->user_data );
4055
4056 if (!m_wx_model->IsContainer( item ))
4057 return 0;
4058
4059 wxGtkTreeModelNode *parent_node = FindNode( iter );
4060 wxASSERT_MSG(parent_node,
4061 "Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
4062
4063 BuildBranch( parent_node );
4064
4065 return parent_node->GetChildCount();
4066 }
4067 }
4068
4069 gboolean wxDataViewCtrlInternal::iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n )
4070 {
4071 if (m_wx_model->IsVirtualListModel())
4072 {
4073 wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model;
4074
4075 if (parent)
4076 return FALSE;
4077
4078 if (n < 0)
4079 return FALSE;
4080
4081 if (n >= (gint) wx_model->GetCount())
4082 return FALSE;
4083
4084 iter->stamp = m_gtk_model->stamp;
4085 // user_data is just the index +1
4086 iter->user_data = (gpointer) (n+1);
4087
4088 return TRUE;
4089 }
4090 else
4091 {
4092 void* id = NULL;
4093 if (parent) id = (void*) parent->user_data;
4094 wxDataViewItem item( id );
4095
4096 if (!m_wx_model->IsContainer( item ))
4097 return FALSE;
4098
4099 wxGtkTreeModelNode *parent_node = FindNode( parent );
4100 wxASSERT_MSG(parent_node,
4101 "Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
4102
4103 BuildBranch( parent_node );
4104
4105 iter->stamp = m_gtk_model->stamp;
4106 iter->user_data = parent_node->GetChildren().Item( n );
4107
4108 return TRUE;
4109 }
4110 }
4111
4112 gboolean wxDataViewCtrlInternal::iter_parent( GtkTreeIter *iter, GtkTreeIter *child )
4113 {
4114 if (m_wx_model->IsVirtualListModel())
4115 {
4116 return FALSE;
4117 }
4118 else
4119 {
4120 wxGtkTreeModelNode *node = FindParentNode( child );
4121 if (!node)
4122 return FALSE;
4123
4124 iter->stamp = m_gtk_model->stamp;
4125 iter->user_data = (gpointer) node->GetItem().GetID();
4126
4127 return TRUE;
4128 }
4129 }
4130
4131 // item can be deleted already in the model
4132 int wxDataViewCtrlInternal::GetIndexOf( const wxDataViewItem &parent, const wxDataViewItem &item )
4133 {
4134 if (m_wx_model->IsVirtualListModel())
4135 {
4136 return wxPtrToUInt(item.GetID()) - 1;
4137 }
4138 else
4139 {
4140 wxGtkTreeModelNode *parent_node = FindNode( parent );
4141 wxGtkTreeModelChildren &children = parent_node->GetChildren();
4142 size_t j;
4143 for (j = 0; j < children.GetCount(); j++)
4144 {
4145 if (children[j] == item.GetID())
4146 return j;
4147 }
4148 }
4149 return -1;
4150 }
4151
4152
4153 static wxGtkTreeModelNode*
4154 wxDataViewCtrlInternal_FindNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item )
4155 {
4156 if( model == NULL )
4157 return NULL;
4158
4159 ItemList list;
4160 list.DeleteContents( true );
4161 wxDataViewItem it( item );
4162
4163 while( it.IsOk() )
4164 {
4165 wxDataViewItem * pItem = new wxDataViewItem( it );
4166 list.Insert( pItem );
4167 it = model->GetParent( it );
4168 }
4169
4170 wxGtkTreeModelNode * node = treeNode;
4171 for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
4172 {
4173 if( node && node->GetNodes().GetCount() != 0 )
4174 {
4175 int len = node->GetNodes().GetCount();
4176 wxGtkTreeModelNodes &nodes = node->GetNodes();
4177 int j = 0;
4178 for( ; j < len; j ++)
4179 {
4180 if( nodes[j]->GetItem() == *(n->GetData()))
4181 {
4182 node = nodes[j];
4183 break;
4184 }
4185 }
4186
4187 if( j == len )
4188 {
4189 return NULL;
4190 }
4191 }
4192 else
4193 return NULL;
4194 }
4195 return node;
4196
4197 }
4198
4199 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
4200 {
4201 if (!iter)
4202 return m_root;
4203
4204 wxDataViewItem item( (void*) iter->user_data );
4205 if (!item.IsOk())
4206 return m_root;
4207
4208 wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
4209
4210 /*
4211 if (!result)
4212 {
4213 wxLogDebug( "Not found %p", iter->user_data );
4214 char *crash = NULL;
4215 *crash = 0;
4216 }
4217 // TODO: remove this code
4218 */
4219
4220 return result;
4221 }
4222
4223 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item )
4224 {
4225 if (!item.IsOk())
4226 return m_root;
4227
4228 wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
4229
4230 /*
4231 if (!result)
4232 {
4233 wxLogDebug( "Not found %p", item.GetID() );
4234 char *crash = NULL;
4235 *crash = 0;
4236 }
4237 // TODO: remove this code
4238 */
4239
4240 return result;
4241 }
4242
4243 static wxGtkTreeModelNode*
4244 wxDataViewCtrlInternal_FindParentNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item )
4245 {
4246 if( model == NULL )
4247 return NULL;
4248
4249 ItemList list;
4250 list.DeleteContents( true );
4251 if( !item.IsOk() )
4252 return NULL;
4253
4254 wxDataViewItem it( model->GetParent( item ) );
4255 while( it.IsOk() )
4256 {
4257 wxDataViewItem * pItem = new wxDataViewItem( it );
4258 list.Insert( pItem );
4259 it = model->GetParent( it );
4260 }
4261
4262 wxGtkTreeModelNode * node = treeNode;
4263 for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
4264 {
4265 if( node && node->GetNodes().GetCount() != 0 )
4266 {
4267 int len = node->GetNodes().GetCount();
4268 wxGtkTreeModelNodes nodes = node->GetNodes();
4269 int j = 0;
4270 for( ; j < len; j ++)
4271 {
4272 if( nodes[j]->GetItem() == *(n->GetData()))
4273 {
4274 node = nodes[j];
4275 break;
4276 }
4277 }
4278
4279 if( j == len )
4280 {
4281 return NULL;
4282 }
4283 }
4284 else
4285 return NULL;
4286 }
4287 //Examine whether the node is item's parent node
4288 int len = node->GetChildCount();
4289 for( int i = 0; i < len ; i ++ )
4290 {
4291 if( node->GetChildren().Item( i ) == item.GetID() )
4292 return node;
4293 }
4294 return NULL;
4295 }
4296
4297 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( GtkTreeIter *iter )
4298 {
4299 if (!iter)
4300 return NULL;
4301
4302 wxDataViewItem item( (void*) iter->user_data );
4303 if (!item.IsOk())
4304 return NULL;
4305
4306 return wxDataViewCtrlInternal_FindParentNode( m_wx_model, m_root, item );
4307 }
4308
4309 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( const wxDataViewItem &item )
4310 {
4311 if (!item.IsOk())
4312 return NULL;
4313
4314 return wxDataViewCtrlInternal_FindParentNode( m_wx_model, m_root, item );
4315 }
4316
4317 //-----------------------------------------------------------------------------
4318 // wxDataViewCtrl signal callbacks
4319 //-----------------------------------------------------------------------------
4320
4321 static void
4322 wxdataview_selection_changed_callback( GtkTreeSelection* WXUNUSED(selection), wxDataViewCtrl *dv )
4323 {
4324 if (!gtk_widget_get_realized(dv->m_widget))
4325 return;
4326
4327 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, dv->GetId() );
4328 event.SetItem( dv->GetSelection() );
4329 event.SetModel( dv->GetModel() );
4330 dv->HandleWindowEvent( event );
4331 }
4332
4333 static void
4334 wxdataview_row_activated_callback( GtkTreeView* WXUNUSED(treeview), GtkTreePath *path,
4335 GtkTreeViewColumn *WXUNUSED(column), wxDataViewCtrl *dv )
4336 {
4337 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, dv->GetId() );
4338
4339 wxDataViewItem item(dv->GTKPathToItem(path));
4340 event.SetItem( item );
4341 event.SetModel( dv->GetModel() );
4342 dv->HandleWindowEvent( event );
4343 }
4344
4345 static gboolean
4346 wxdataview_test_expand_row_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
4347 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
4348 {
4349 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING, dv->GetId() );
4350
4351 wxDataViewItem item( (void*) iter->user_data );;
4352 event.SetItem( item );
4353 event.SetModel( dv->GetModel() );
4354 dv->HandleWindowEvent( event );
4355
4356 return !event.IsAllowed();
4357 }
4358
4359 static void
4360 wxdataview_row_expanded_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
4361 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
4362 {
4363 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED, dv->GetId() );
4364
4365 wxDataViewItem item( (void*) iter->user_data );;
4366 event.SetItem( item );
4367 event.SetModel( dv->GetModel() );
4368 dv->HandleWindowEvent( event );
4369 }
4370
4371 static gboolean
4372 wxdataview_test_collapse_row_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
4373 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
4374 {
4375 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING, dv->GetId() );
4376
4377 wxDataViewItem item( (void*) iter->user_data );;
4378 event.SetItem( item );
4379 event.SetModel( dv->GetModel() );
4380 dv->HandleWindowEvent( event );
4381
4382 return !event.IsAllowed();
4383 }
4384
4385 static void
4386 wxdataview_row_collapsed_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
4387 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
4388 {
4389 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED, dv->GetId() );
4390
4391 wxDataViewItem item( (void*) iter->user_data );;
4392 event.SetItem( item );
4393 event.SetModel( dv->GetModel() );
4394 dv->HandleWindowEvent( event );
4395 }
4396
4397 //-----------------------------------------------------------------------------
4398 // wxDataViewCtrl
4399 //-----------------------------------------------------------------------------
4400
4401 void wxDataViewCtrl::AddChildGTK(wxWindowGTK* child)
4402 {
4403 GtkWidget* treeview = GtkGetTreeView();
4404
4405 // Insert widget in GtkTreeView
4406 if (gtk_widget_get_realized(treeview))
4407 gtk_widget_set_parent_window( child->m_widget,
4408 gtk_tree_view_get_bin_window( GTK_TREE_VIEW(treeview) ) );
4409 gtk_widget_set_parent( child->m_widget, treeview );
4410 }
4411
4412 static
4413 void gtk_dataviewctrl_size_callback( GtkWidget *WXUNUSED(widget),
4414 GtkAllocation *WXUNUSED(gtk_alloc),
4415 wxDataViewCtrl *win )
4416 {
4417 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
4418 while (node)
4419 {
4420 wxWindow *child = node->GetData();
4421
4422 GtkRequisition req;
4423 gtk_widget_size_request( child->m_widget, &req );
4424
4425 GtkAllocation alloc;
4426 alloc.x = child->m_x;
4427 alloc.y = child->m_y;
4428 alloc.width = child->m_width;
4429 alloc.height = child->m_height;
4430 gtk_widget_size_allocate( child->m_widget, &alloc );
4431
4432 node = node->GetNext();
4433 }
4434 }
4435
4436
4437 //-----------------------------------------------------------------------------
4438 // "motion_notify_event"
4439 //-----------------------------------------------------------------------------
4440
4441 static gboolean
4442 gtk_dataview_motion_notify_callback( GtkWidget *WXUNUSED(widget),
4443 GdkEventMotion *gdk_event,
4444 wxDataViewCtrl *dv )
4445 {
4446 if (gdk_event->is_hint)
4447 {
4448 int x = 0;
4449 int y = 0;
4450 GdkModifierType state;
4451 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
4452 gdk_event->x = x;
4453 gdk_event->y = y;
4454 }
4455
4456 wxGtkTreePath path;
4457 GtkTreeViewColumn *column = NULL;
4458 gint cell_x = 0;
4459 gint cell_y = 0;
4460 if (gtk_tree_view_get_path_at_pos(
4461 GTK_TREE_VIEW(dv->GtkGetTreeView()),
4462 (int) gdk_event->x, (int) gdk_event->y,
4463 path.ByRef(),
4464 &column,
4465 &cell_x,
4466 &cell_y))
4467 {
4468 if (path)
4469 {
4470 GtkTreeIter iter;
4471 dv->GtkGetInternal()->get_iter( &iter, path );
4472 }
4473 }
4474
4475
4476 return FALSE;
4477 }
4478
4479 //-----------------------------------------------------------------------------
4480 // "button_press_event"
4481 //-----------------------------------------------------------------------------
4482
4483 static gboolean
4484 gtk_dataview_button_press_callback( GtkWidget *WXUNUSED(widget),
4485 GdkEventButton *gdk_event,
4486 wxDataViewCtrl *dv )
4487 {
4488 if ((gdk_event->button == 3) && (gdk_event->type == GDK_BUTTON_PRESS))
4489 {
4490 wxGtkTreePath path;
4491 GtkTreeViewColumn *column = NULL;
4492 gint cell_x = 0;
4493 gint cell_y = 0;
4494 if (gtk_tree_view_get_path_at_pos(
4495 GTK_TREE_VIEW(dv->GtkGetTreeView()),
4496 (int) gdk_event->x, (int) gdk_event->y,
4497 path.ByRef(),
4498 &column,
4499 &cell_x,
4500 &cell_y))
4501 {
4502 if (path)
4503 {
4504 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, dv->GetId() );
4505 event.SetItem(dv->GTKPathToItem(path));
4506 event.SetModel( dv->GetModel() );
4507 return dv->HandleWindowEvent( event );
4508 }
4509 }
4510 }
4511
4512 return FALSE;
4513 }
4514
4515 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
4516
4517 wxDataViewCtrl::~wxDataViewCtrl()
4518 {
4519 // Stop editing before destroying the control to remove any event handlers
4520 // which are added when editing started: if we didn't do this, the base
4521 // class dtor would assert as it checks for any leftover handlers.
4522 if ( m_treeview )
4523 {
4524 GtkTreeViewColumn *col;
4525 gtk_tree_view_get_cursor(GTK_TREE_VIEW(m_treeview), NULL, &col);
4526
4527 wxDataViewColumn * const wxcol = FromGTKColumn(col);
4528 if ( wxcol )
4529 {
4530 // This won't do anything if we're not editing it
4531 wxcol->GetRenderer()->CancelEditing();
4532 }
4533 }
4534
4535 m_cols.Clear();
4536
4537 delete m_internal;
4538 }
4539
4540 void wxDataViewCtrl::Init()
4541 {
4542 m_internal = NULL;
4543
4544 m_cols.DeleteContents( true );
4545
4546 m_uniformRowHeight = -1;
4547 }
4548
4549 bool wxDataViewCtrl::Create(wxWindow *parent,
4550 wxWindowID id,
4551 const wxPoint& pos,
4552 const wxSize& size,
4553 long style,
4554 const wxValidator& validator,
4555 const wxString& name)
4556 {
4557 if (!PreCreation( parent, pos, size ) ||
4558 !CreateBase( parent, id, pos, size, style, validator, name ))
4559 {
4560 wxFAIL_MSG( wxT("wxDataViewCtrl creation failed") );
4561 return false;
4562 }
4563
4564 m_widget = gtk_scrolled_window_new (NULL, NULL);
4565 g_object_ref(m_widget);
4566
4567 GTKScrolledWindowSetBorder(m_widget, style);
4568
4569 m_treeview = gtk_tree_view_new();
4570 gtk_container_add (GTK_CONTAINER (m_widget), m_treeview);
4571
4572 g_signal_connect (m_treeview, "size_allocate",
4573 G_CALLBACK (gtk_dataviewctrl_size_callback), this);
4574
4575 #ifdef __WXGTK26__
4576 if (!gtk_check_version(2,6,0))
4577 {
4578 bool fixed = (style & wxDV_VARIABLE_LINE_HEIGHT) == 0;
4579 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), fixed );
4580 }
4581 #endif
4582
4583 if (style & wxDV_MULTIPLE)
4584 {
4585 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4586 gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
4587 }
4588
4589 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(m_treeview), (style & wxDV_NO_HEADER) == 0 );
4590
4591 #ifdef __WXGTK210__
4592 if (!gtk_check_version(2,10,0))
4593 {
4594 GtkTreeViewGridLines grid = GTK_TREE_VIEW_GRID_LINES_NONE;
4595
4596 if ((style & wxDV_HORIZ_RULES) != 0 &&
4597 (style & wxDV_VERT_RULES) != 0)
4598 grid = GTK_TREE_VIEW_GRID_LINES_BOTH;
4599 else if (style & wxDV_VERT_RULES)
4600 grid = GTK_TREE_VIEW_GRID_LINES_VERTICAL;
4601 else if (style & wxDV_HORIZ_RULES)
4602 grid = GTK_TREE_VIEW_GRID_LINES_HORIZONTAL;
4603
4604 if (grid != GTK_TREE_VIEW_GRID_LINES_NONE)
4605 gtk_tree_view_set_grid_lines( GTK_TREE_VIEW(m_treeview), grid );
4606 }
4607 #endif
4608
4609 gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(m_treeview), (style & wxDV_ROW_LINES) != 0 );
4610
4611 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_widget),
4612 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
4613 gtk_widget_show (m_treeview);
4614
4615 m_parent->DoAddChild( this );
4616
4617 PostCreation(size);
4618
4619 GtkEnableSelectionEvents();
4620
4621 g_signal_connect_after (m_treeview, "row-activated",
4622 G_CALLBACK (wxdataview_row_activated_callback), this);
4623
4624 g_signal_connect (m_treeview, "test-collapse-row",
4625 G_CALLBACK (wxdataview_test_collapse_row_callback), this);
4626
4627 g_signal_connect_after (m_treeview, "row-collapsed",
4628 G_CALLBACK (wxdataview_row_collapsed_callback), this);
4629
4630 g_signal_connect (m_treeview, "test-expand-row",
4631 G_CALLBACK (wxdataview_test_expand_row_callback), this);
4632
4633 g_signal_connect_after (m_treeview, "row-expanded",
4634 G_CALLBACK (wxdataview_row_expanded_callback), this);
4635
4636 g_signal_connect (m_treeview, "motion_notify_event",
4637 G_CALLBACK (gtk_dataview_motion_notify_callback), this);
4638
4639 g_signal_connect (m_treeview, "button_press_event",
4640 G_CALLBACK (gtk_dataview_button_press_callback), this);
4641
4642 return true;
4643 }
4644
4645 wxDataViewItem wxDataViewCtrl::GTKPathToItem(GtkTreePath *path) const
4646 {
4647 GtkTreeIter iter;
4648 return wxDataViewItem(path && m_internal->get_iter(&iter, path)
4649 ? iter.user_data
4650 : NULL);
4651 }
4652
4653 void wxDataViewCtrl::OnInternalIdle()
4654 {
4655 wxWindow::OnInternalIdle();
4656
4657 m_internal->OnInternalIdle();
4658
4659 unsigned int cols = GetColumnCount();
4660 unsigned int i;
4661 for (i = 0; i < cols; i++)
4662 {
4663 wxDataViewColumn *col = GetColumn( i );
4664 col->OnInternalIdle();
4665 }
4666
4667 if (m_ensureVisibleDefered.IsOk())
4668 {
4669 ExpandAncestors(m_ensureVisibleDefered);
4670 GtkTreeIter iter;
4671 iter.user_data = (gpointer) m_ensureVisibleDefered.GetID();
4672 wxGtkTreePath path(m_internal->get_path( &iter ));
4673 gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW(m_treeview), path, NULL, false, 0.0, 0.0 );
4674 m_ensureVisibleDefered = wxDataViewItem(0);
4675 }
4676 }
4677
4678 bool wxDataViewCtrl::AssociateModel( wxDataViewModel *model )
4679 {
4680 wxDELETE(m_internal);
4681
4682 if (!wxDataViewCtrlBase::AssociateModel( model ))
4683 return false;
4684
4685 #ifdef __WXGTK26__
4686 if (!gtk_check_version(2,6,0))
4687 {
4688 bool fixed = (((GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT) == 0) || (model->IsVirtualListModel()));
4689 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), fixed );
4690 }
4691 #endif
4692
4693 m_internal = new wxDataViewCtrlInternal( this, model );
4694
4695 return true;
4696 }
4697
4698 bool wxDataViewCtrl::EnableDragSource( const wxDataFormat &format )
4699 {
4700 return m_internal->EnableDragSource( format );
4701 }
4702
4703 bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat &format )
4704 {
4705 return m_internal->EnableDropTarget( format );
4706 }
4707
4708 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
4709 {
4710 if (!wxDataViewCtrlBase::AppendColumn(col))
4711 return false;
4712
4713 m_cols.Append( col );
4714
4715 #ifdef __WXGTK26__
4716 if (!gtk_check_version(2,6,0))
4717 {
4718 if (gtk_tree_view_column_get_sizing( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) ) !=
4719 GTK_TREE_VIEW_COLUMN_FIXED)
4720 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), FALSE );
4721 }
4722 #endif
4723
4724 gtk_tree_view_append_column( GTK_TREE_VIEW(m_treeview),
4725 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) );
4726
4727 return true;
4728 }
4729
4730 bool wxDataViewCtrl::PrependColumn( wxDataViewColumn *col )
4731 {
4732 if (!wxDataViewCtrlBase::PrependColumn(col))
4733 return false;
4734
4735 m_cols.Insert( col );
4736
4737 #ifdef __WXGTK26__
4738 if (!gtk_check_version(2,6,0))
4739 {
4740 if (gtk_tree_view_column_get_sizing( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) ) !=
4741 GTK_TREE_VIEW_COLUMN_FIXED)
4742 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), FALSE );
4743 }
4744 #endif
4745
4746 gtk_tree_view_insert_column( GTK_TREE_VIEW(m_treeview),
4747 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()), 0 );
4748
4749 return true;
4750 }
4751
4752 bool wxDataViewCtrl::InsertColumn( unsigned int pos, wxDataViewColumn *col )
4753 {
4754 if (!wxDataViewCtrlBase::InsertColumn(pos,col))
4755 return false;
4756
4757 m_cols.Insert( pos, col );
4758
4759 #ifdef __WXGTK26__
4760 if (!gtk_check_version(2,6,0))
4761 {
4762 if (gtk_tree_view_column_get_sizing( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) ) !=
4763 GTK_TREE_VIEW_COLUMN_FIXED)
4764 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), FALSE );
4765 }
4766 #endif
4767
4768 gtk_tree_view_insert_column( GTK_TREE_VIEW(m_treeview),
4769 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()), pos );
4770
4771 return true;
4772 }
4773
4774 unsigned int wxDataViewCtrl::GetColumnCount() const
4775 {
4776 return m_cols.GetCount();
4777 }
4778
4779 wxDataViewColumn* wxDataViewCtrl::FromGTKColumn(GtkTreeViewColumn *gtk_col) const
4780 {
4781 if ( !gtk_col )
4782 return NULL;
4783
4784 wxDataViewColumnList::const_iterator iter;
4785 for (iter = m_cols.begin(); iter != m_cols.end(); ++iter)
4786 {
4787 wxDataViewColumn *col = *iter;
4788 if (GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) == gtk_col)
4789 {
4790 return col;
4791 }
4792 }
4793
4794 wxFAIL_MSG( "No matching column?" );
4795
4796 return NULL;
4797 }
4798
4799 wxDataViewColumn* wxDataViewCtrl::GetColumn( unsigned int pos ) const
4800 {
4801 GtkTreeViewColumn *gtk_col = gtk_tree_view_get_column( GTK_TREE_VIEW(m_treeview), pos );
4802
4803 return FromGTKColumn(gtk_col);
4804 }
4805
4806 bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column )
4807 {
4808 gtk_tree_view_remove_column( GTK_TREE_VIEW(m_treeview),
4809 GTK_TREE_VIEW_COLUMN(column->GetGtkHandle()) );
4810
4811 m_cols.DeleteObject( column );
4812
4813 return true;
4814 }
4815
4816 bool wxDataViewCtrl::ClearColumns()
4817 {
4818 wxDataViewColumnList::iterator iter;
4819 for (iter = m_cols.begin(); iter != m_cols.end(); ++iter)
4820 {
4821 wxDataViewColumn *col = *iter;
4822 gtk_tree_view_remove_column( GTK_TREE_VIEW(m_treeview),
4823 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) );
4824 }
4825
4826 m_cols.Clear();
4827
4828 return true;
4829 }
4830
4831 int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const
4832 {
4833 GtkTreeViewColumn *gtk_column = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle());
4834
4835 wxGtkList list(gtk_tree_view_get_columns(GTK_TREE_VIEW(m_treeview)));
4836
4837 return g_list_index( list, (gconstpointer) gtk_column );
4838 }
4839
4840 wxDataViewColumn *wxDataViewCtrl::GetSortingColumn() const
4841 {
4842 return m_internal->GetDataViewSortColumn();
4843 }
4844
4845 void wxDataViewCtrl::Expand( const wxDataViewItem & item )
4846 {
4847 GtkTreeIter iter;
4848 iter.user_data = item.GetID();
4849 wxGtkTreePath path(m_internal->get_path( &iter ));
4850 gtk_tree_view_expand_row( GTK_TREE_VIEW(m_treeview), path, false );
4851 }
4852
4853 void wxDataViewCtrl::Collapse( const wxDataViewItem & item )
4854 {
4855 GtkTreeIter iter;
4856 iter.user_data = item.GetID();
4857 wxGtkTreePath path(m_internal->get_path( &iter ));
4858 gtk_tree_view_collapse_row( GTK_TREE_VIEW(m_treeview), path );
4859 }
4860
4861 bool wxDataViewCtrl::IsExpanded( const wxDataViewItem & item ) const
4862 {
4863 GtkTreeIter iter;
4864 iter.user_data = item.GetID();
4865 wxGtkTreePath path(m_internal->get_path( &iter ));
4866 return gtk_tree_view_row_expanded( GTK_TREE_VIEW(m_treeview), path );
4867 }
4868
4869 wxDataViewItem wxDataViewCtrl::DoGetCurrentItem() const
4870 {
4871 // The tree doesn't have any current item if it hadn't been created yet but
4872 // it's arguably not an error to call this function in this case so just
4873 // return an invalid item without asserting.
4874 if ( !m_treeview )
4875 return wxDataViewItem();
4876
4877 wxGtkTreePath path;
4878 gtk_tree_view_get_cursor(GTK_TREE_VIEW(m_treeview), path.ByRef(), NULL);
4879
4880 return GTKPathToItem(path);
4881 }
4882
4883 void wxDataViewCtrl::DoSetCurrentItem(const wxDataViewItem& item)
4884 {
4885 wxCHECK_RET( m_treeview,
4886 "Current item can't be set before creating the control." );
4887
4888 // We need to make sure the model knows about this item or the path would
4889 // be invalid and gtk_tree_view_set_cursor() would silently do nothing.
4890 ExpandAncestors(item);
4891
4892 // We also need to preserve the existing selection from changing.
4893 // Unfortunately the only way to do it seems to use our own selection
4894 // function and forbid any selection changes during set cursor call.
4895 wxGtkTreeSelectionLock
4896 lock(gtk_tree_view_get_selection(GTK_TREE_VIEW(m_treeview)));
4897
4898 // Do move the cursor now.
4899 GtkTreeIter iter;
4900 iter.user_data = item.GetID();
4901 wxGtkTreePath path(m_internal->get_path( &iter ));
4902
4903 gtk_tree_view_set_cursor(GTK_TREE_VIEW(m_treeview), path, NULL, FALSE);
4904 }
4905
4906 void wxDataViewCtrl::StartEditor(const wxDataViewItem& item, unsigned int column)
4907 {
4908 wxCHECK_RET( m_treeview,
4909 "Current item can't be set before creating the control." );
4910
4911 // We need to make sure the model knows about this item or the path would
4912 // be invalid and gtk_tree_view_set_cursor() would silently do nothing.
4913 ExpandAncestors(item);
4914
4915 wxDataViewColumn *dvcolumn = GetColumn(column);
4916 wxASSERT_MSG(dvcolumn, "Could not retrieve column");
4917 GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(dvcolumn->GetGtkHandle());
4918
4919 // We also need to preserve the existing selection from changing.
4920 // Unfortunately the only way to do it seems to use our own selection
4921 // function and forbid any selection changes during set cursor call.
4922 wxGtkTreeSelectionLock
4923 lock(gtk_tree_view_get_selection(GTK_TREE_VIEW(m_treeview)));
4924
4925 // Do move the cursor now.
4926 GtkTreeIter iter;
4927 iter.user_data = item.GetID();
4928 wxGtkTreePath path(m_internal->get_path( &iter ));
4929
4930 gtk_tree_view_set_cursor(GTK_TREE_VIEW(m_treeview), path, gcolumn, TRUE);
4931 }
4932
4933 wxDataViewItem wxDataViewCtrl::GetSelection() const
4934 {
4935 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4936
4937 if (m_windowStyle & wxDV_MULTIPLE)
4938 {
4939 // Report the first one
4940 GtkTreeModel *model;
4941 GList *list = gtk_tree_selection_get_selected_rows( selection, &model );
4942
4943 if (list)
4944 {
4945 GtkTreePath *path = (GtkTreePath*) list->data;
4946 wxDataViewItem item(GTKPathToItem(path));
4947
4948 // delete list
4949 g_list_foreach( list, (GFunc) gtk_tree_path_free, NULL );
4950 g_list_free( list );
4951
4952 return item;
4953 }
4954 }
4955 else
4956 {
4957 GtkTreeIter iter;
4958 if (gtk_tree_selection_get_selected( selection, NULL, &iter ))
4959 {
4960 wxDataViewItem item( iter.user_data );
4961 return item;
4962 }
4963 }
4964
4965 return wxDataViewItem(0);
4966 }
4967
4968 int wxDataViewCtrl::GetSelections( wxDataViewItemArray & sel ) const
4969 {
4970 sel.Clear();
4971
4972 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4973 if (HasFlag(wxDV_MULTIPLE))
4974 {
4975 GtkTreeModel *model;
4976 wxGtkTreePathList list(gtk_tree_selection_get_selected_rows(selection, &model));
4977
4978 int count = 0;
4979 for ( GList* current = list; current; current = g_list_next(current) )
4980 {
4981 GtkTreePath *path = (GtkTreePath*) list->data;
4982
4983 sel.Add(GTKPathToItem(path));
4984 count++;
4985 }
4986
4987 return count;
4988 }
4989 else
4990 {
4991 GtkTreeModel *model;
4992 GtkTreeIter iter;
4993 gboolean has_selection = gtk_tree_selection_get_selected( selection, &model, &iter );
4994 if (has_selection)
4995 {
4996 sel.Add( wxDataViewItem( (void*) iter.user_data) );
4997 return 1;
4998 }
4999 }
5000
5001 return 0;
5002 }
5003
5004 void wxDataViewCtrl::SetSelections( const wxDataViewItemArray & sel )
5005 {
5006 GtkDisableSelectionEvents();
5007
5008 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5009
5010 gtk_tree_selection_unselect_all( selection );
5011
5012 wxDataViewItem last_parent;
5013
5014 size_t i;
5015 for (i = 0; i < sel.GetCount(); i++)
5016 {
5017 wxDataViewItem item = sel[i];
5018 wxDataViewItem parent = GetModel()->GetParent( item );
5019 if (parent)
5020 {
5021 if (parent != last_parent)
5022 ExpandAncestors(item);
5023 }
5024 last_parent = parent;
5025
5026 GtkTreeIter iter;
5027 iter.stamp = m_internal->GetGtkModel()->stamp;
5028 iter.user_data = (gpointer) item.GetID();
5029 gtk_tree_selection_select_iter( selection, &iter );
5030 }
5031
5032 GtkEnableSelectionEvents();
5033 }
5034
5035 void wxDataViewCtrl::Select( const wxDataViewItem & item )
5036 {
5037 ExpandAncestors(item);
5038
5039 GtkDisableSelectionEvents();
5040
5041 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5042
5043 GtkTreeIter iter;
5044 iter.stamp = m_internal->GetGtkModel()->stamp;
5045 iter.user_data = (gpointer) item.GetID();
5046 gtk_tree_selection_select_iter( selection, &iter );
5047
5048 GtkEnableSelectionEvents();
5049 }
5050
5051 void wxDataViewCtrl::Unselect( const wxDataViewItem & item )
5052 {
5053 GtkDisableSelectionEvents();
5054
5055 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5056
5057 GtkTreeIter iter;
5058 iter.stamp = m_internal->GetGtkModel()->stamp;
5059 iter.user_data = (gpointer) item.GetID();
5060 gtk_tree_selection_unselect_iter( selection, &iter );
5061
5062 GtkEnableSelectionEvents();
5063 }
5064
5065 bool wxDataViewCtrl::IsSelected( const wxDataViewItem & item ) const
5066 {
5067 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5068
5069 GtkTreeIter iter;
5070 iter.stamp = m_internal->GetGtkModel()->stamp;
5071 iter.user_data = (gpointer) item.GetID();
5072
5073 return gtk_tree_selection_iter_is_selected( selection, &iter );
5074 }
5075
5076 void wxDataViewCtrl::SelectAll()
5077 {
5078 GtkDisableSelectionEvents();
5079
5080 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5081
5082 gtk_tree_selection_select_all( selection );
5083
5084 GtkEnableSelectionEvents();
5085 }
5086
5087 void wxDataViewCtrl::UnselectAll()
5088 {
5089 GtkDisableSelectionEvents();
5090
5091 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5092
5093 gtk_tree_selection_unselect_all( selection );
5094
5095 GtkEnableSelectionEvents();
5096 }
5097
5098 void wxDataViewCtrl::EnsureVisible(const wxDataViewItem& item,
5099 const wxDataViewColumn *WXUNUSED(column))
5100 {
5101 m_ensureVisibleDefered = item;
5102 ExpandAncestors(item);
5103
5104 GtkTreeIter iter;
5105 iter.user_data = (gpointer) item.GetID();
5106 wxGtkTreePath path(m_internal->get_path( &iter ));
5107 gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW(m_treeview), path, NULL, false, 0.0, 0.0 );
5108 }
5109
5110 void wxDataViewCtrl::HitTest(const wxPoint& point,
5111 wxDataViewItem& item,
5112 wxDataViewColumn *& column) const
5113 {
5114 // gtk_tree_view_get_dest_row_at_pos() is the right one. But it does not tell the column.
5115 // gtk_tree_view_get_path_at_pos() is the wrong function. It doesn't mind the header but returns column.
5116 // See http://mail.gnome.org/archives/gtkmm-list/2005-January/msg00080.html
5117 // So we have to use both of them.
5118 // Friedrich Haase 2010-9-20
5119 wxGtkTreePath path, pathScratch;
5120 GtkTreeViewColumn* GtkColumn = NULL;
5121 GtkTreeViewDropPosition pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
5122 gint cell_x = 0;
5123 gint cell_y = 0;
5124
5125 // cannot directly call GtkGetTreeView(), HitTest is const and so is this pointer
5126 wxDataViewCtrl* ctrl = (wxDataViewCtrl*)this; // ugly workaround, ctrl is NOT const
5127 GtkTreeView* treeView = GTK_TREE_VIEW(ctrl->GtkGetTreeView());
5128
5129 // is there possibly a better suited function to get the column?
5130 gtk_tree_view_get_path_at_pos( // and this is the wrong call but it delivers the column
5131 treeView,
5132 (int) point.x, (int) point.y,
5133 pathScratch.ByRef(),
5134 &GtkColumn, // here we get the GtkColumn
5135 &cell_x,
5136 &cell_y );
5137
5138 if ( GtkColumn != NULL )
5139 {
5140 // we got GTK column
5141 // the right call now which takes the header into account
5142 gtk_tree_view_get_dest_row_at_pos( treeView, (int) point.x, (int) point.y, path.ByRef(), &pos);
5143
5144 if (path)
5145 item = wxDataViewItem(GTKPathToItem(path));
5146 // else we got a GTK column but the position is not over an item, e.g. below last item
5147 for ( unsigned int i=0, cols=GetColumnCount(); i<cols; ++i ) // search the wx column
5148 {
5149 wxDataViewColumn* col = GetColumn(i);
5150 if ( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) == GtkColumn )
5151 {
5152 column = col; // here we get the wx column
5153 break;
5154 }
5155 }
5156 }
5157 // else no column and thus no item, both null
5158 }
5159
5160 wxRect
5161 wxDataViewCtrl::GetItemRect(const wxDataViewItem& WXUNUSED(item),
5162 const wxDataViewColumn *WXUNUSED(column)) const
5163 {
5164 return wxRect();
5165 }
5166
5167 bool wxDataViewCtrl::SetRowHeight(int rowHeight)
5168 {
5169 m_uniformRowHeight = rowHeight;
5170 return true;
5171 }
5172
5173 void wxDataViewCtrl::DoSetExpanderColumn()
5174 {
5175 gtk_tree_view_set_expander_column( GTK_TREE_VIEW(m_treeview),
5176 GTK_TREE_VIEW_COLUMN( GetExpanderColumn()->GetGtkHandle() ) );
5177 }
5178
5179 void wxDataViewCtrl::DoSetIndent()
5180 {
5181 }
5182
5183 void wxDataViewCtrl::GtkDisableSelectionEvents()
5184 {
5185 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5186 g_signal_handlers_disconnect_by_func( selection,
5187 (gpointer) (wxdataview_selection_changed_callback), this);
5188 }
5189
5190 void wxDataViewCtrl::GtkEnableSelectionEvents()
5191 {
5192 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5193 g_signal_connect_after (selection, "changed",
5194 G_CALLBACK (wxdataview_selection_changed_callback), this);
5195 }
5196
5197 // ----------------------------------------------------------------------------
5198 // visual attributes stuff
5199 // ----------------------------------------------------------------------------
5200
5201 // static
5202 wxVisualAttributes
5203 wxDataViewCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
5204 {
5205 return GetDefaultAttributesFromGTKWidget(gtk_tree_view_new);
5206 }
5207
5208 void wxDataViewCtrl::DoApplyWidgetStyle(GtkRcStyle *style)
5209 {
5210 wxDataViewCtrlBase::DoApplyWidgetStyle(style);
5211 gtk_widget_modify_style(m_treeview, style);
5212 }
5213
5214 #endif // !wxUSE_GENERICDATAVIEWCTRL
5215
5216 #endif // wxUSE_DATAVIEWCTRL