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