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