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