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