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