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