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