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