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