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