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