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