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