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