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