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