]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/dataview.cpp
support underlined fonts (patch 1448089)
[wxWidgets.git] / src / gtk / dataview.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #include "wx/defs.h"
14
15 #if wxUSE_DATAVIEWCTRL
16
17 #include "wx/dataview.h"
18 #include "wx/stockitem.h"
19 #include "wx/dcclient.h"
20 #include "wx/calctrl.h"
21 #include "wx/popupwin.h"
22 #include "wx/sizer.h"
23 #include "wx/log.h"
24
25 #include "wx/gtk/private.h"
26 #include "wx/gtk/win_gtk.h"
27
28 #include <gobject/gvaluecollector.h>
29 #include <gtk/gtktreemodel.h>
30 #include <gtk/gtktreednd.h>
31
32 #include <gdk/gdkkeysyms.h>
33
34 //-----------------------------------------------------------------------------
35 // classes
36 //-----------------------------------------------------------------------------
37
38 class wxDataViewCtrl;
39
40 //-----------------------------------------------------------------------------
41 // data
42 //-----------------------------------------------------------------------------
43
44 extern bool g_blockEventsOnDrag;
45
46 //-----------------------------------------------------------------------------
47 // define new GTK+ class wxGtkListStore
48 //-----------------------------------------------------------------------------
49
50 extern "C" {
51
52 #define GTK_TYPE_WX_LIST_STORE (gtk_wx_list_store_get_type ())
53 #define GTK_WX_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_LIST_STORE, GtkWxListStore))
54 #define GTK_WX_LIST_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_LIST_STORE, GtkWxListStoreClass))
55 #define GTK_IS_WX_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_LIST_STORE))
56 #define GTK_IS_WX_LIST_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_LIST_STORE))
57 #define GTK_WX_LIST_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_LIST_STORE, GtkWxListStoreClass))
58
59 GType gtk_wx_list_store_get_type (void);
60
61 typedef struct _GtkWxListStore GtkWxListStore;
62 typedef struct _GtkWxListStoreClass GtkWxListStoreClass;
63
64 struct _GtkWxListStore
65 {
66 GObject parent;
67
68 /*< private >*/
69 gint stamp;
70 wxDataViewListModel *model;
71 };
72
73 struct _GtkWxListStoreClass
74 {
75 GObjectClass list_parent_class;
76
77 };
78
79 static GtkWxListStore *wxgtk_list_store_new (void);
80 static void wxgtk_list_store_init (GtkWxListStore *list_store);
81 static void wxgtk_list_store_class_init (GtkWxListStoreClass *klass);
82 static void wxgtk_list_store_tree_model_init (GtkTreeModelIface *iface);
83 static void wxgtk_list_store_finalize (GObject *object);
84 static GtkTreeModelFlags wxgtk_list_store_get_flags (GtkTreeModel *tree_model);
85 static gint wxgtk_list_store_get_n_columns (GtkTreeModel *tree_model);
86 static GType wxgtk_list_store_get_column_type (GtkTreeModel *tree_model,
87 gint index);
88 static gboolean wxgtk_list_store_get_iter (GtkTreeModel *tree_model,
89 GtkTreeIter *iter,
90 GtkTreePath *path);
91 static GtkTreePath *wxgtk_list_store_get_path (GtkTreeModel *tree_model,
92 GtkTreeIter *iter);
93 static void wxgtk_list_store_get_value (GtkTreeModel *tree_model,
94 GtkTreeIter *iter,
95 gint column,
96 GValue *value);
97 static gboolean wxgtk_list_store_iter_next (GtkTreeModel *tree_model,
98 GtkTreeIter *iter);
99 static gboolean wxgtk_list_store_iter_children (GtkTreeModel *tree_model,
100 GtkTreeIter *iter,
101 GtkTreeIter *parent);
102 static gboolean wxgtk_list_store_iter_has_child (GtkTreeModel *tree_model,
103 GtkTreeIter *iter);
104 static gint wxgtk_list_store_iter_n_children (GtkTreeModel *tree_model,
105 GtkTreeIter *iter);
106 static gboolean wxgtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
107 GtkTreeIter *iter,
108 GtkTreeIter *parent,
109 gint n);
110 static gboolean wxgtk_list_store_iter_parent (GtkTreeModel *tree_model,
111 GtkTreeIter *iter,
112 GtkTreeIter *child);
113
114 static GObjectClass *list_parent_class = NULL;
115
116 GType
117 gtk_wx_list_store_get_type (void)
118 {
119 static GType list_store_type = 0;
120
121 if (!list_store_type)
122 {
123 static const GTypeInfo list_store_info =
124 {
125 sizeof (GtkWxListStoreClass),
126 NULL, /* base_init */
127 NULL, /* base_finalize */
128 (GClassInitFunc) wxgtk_list_store_class_init,
129 NULL, /* class_finalize */
130 NULL, /* class_data */
131 sizeof (GtkWxListStore),
132 0,
133 (GInstanceInitFunc) wxgtk_list_store_init,
134 };
135
136 static const GInterfaceInfo tree_model_info =
137 {
138 (GInterfaceInitFunc) wxgtk_list_store_tree_model_init,
139 NULL,
140 NULL
141 };
142
143 list_store_type = g_type_register_static (G_TYPE_OBJECT, "GtkWxListStore",
144 &list_store_info, (GTypeFlags)0 );
145
146 g_type_add_interface_static (list_store_type,
147 GTK_TYPE_TREE_MODEL,
148 &tree_model_info);
149 }
150
151 return list_store_type;
152 }
153
154 static GtkWxListStore *
155 wxgtk_list_store_new(void)
156 {
157 GtkWxListStore *retval = (GtkWxListStore *) g_object_new (GTK_TYPE_WX_LIST_STORE, NULL);
158 return retval;
159 }
160
161 static void
162 wxgtk_list_store_class_init (GtkWxListStoreClass *klass)
163 {
164 list_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
165 GObjectClass *object_class = (GObjectClass*) klass;
166 object_class->finalize = wxgtk_list_store_finalize;
167 }
168
169 static void
170 wxgtk_list_store_tree_model_init (GtkTreeModelIface *iface)
171 {
172 iface->get_flags = wxgtk_list_store_get_flags;
173 iface->get_n_columns = wxgtk_list_store_get_n_columns;
174 iface->get_column_type = wxgtk_list_store_get_column_type;
175 iface->get_iter = wxgtk_list_store_get_iter;
176 iface->get_path = wxgtk_list_store_get_path;
177 iface->get_value = wxgtk_list_store_get_value;
178 iface->iter_next = wxgtk_list_store_iter_next;
179 iface->iter_children = wxgtk_list_store_iter_children;
180 iface->iter_has_child = wxgtk_list_store_iter_has_child;
181 iface->iter_n_children = wxgtk_list_store_iter_n_children;
182 iface->iter_nth_child = wxgtk_list_store_iter_nth_child;
183 iface->iter_parent = wxgtk_list_store_iter_parent;
184 }
185
186 static void
187 wxgtk_list_store_init (GtkWxListStore *list_store)
188 {
189 list_store->model = NULL;
190 list_store->stamp = g_random_int();
191 }
192
193 static void
194 wxgtk_list_store_finalize (GObject *object)
195 {
196 /* GtkWxListStore *list_store = GTK_WX_LIST_STORE (object); */
197
198 /* we need to sort out, which class deletes what */
199 /* delete list_store->model; */
200
201 /* must chain up */
202 (* list_parent_class->finalize) (object);
203 }
204
205 } // extern "C"
206
207 //-----------------------------------------------------------------------------
208 // implement callbacks from wxGtkListStore class by letting
209 // them call the methods of wxWidgets' wxDataViewListModel
210 //-----------------------------------------------------------------------------
211
212 static GtkTreeModelFlags
213 wxgtk_list_store_get_flags (GtkTreeModel *tree_model)
214 {
215 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), (GtkTreeModelFlags)0 );
216
217 // GTK+ list store uses a linked list for storing the
218 // items and a pointer to a child is used as the member
219 // field of a GtkTreeIter. This means that the iter is
220 // valid in the GtkListStore as long as the child exists.
221 // We use the index of the row and since the index of a
222 // specific row will change if a row above is deleted,
223 // the iter does not persist
224 return /* GTK_TREE_MODEL_ITERS_PERSIST | */ GTK_TREE_MODEL_LIST_ONLY;
225 }
226
227 static gint
228 wxgtk_list_store_get_n_columns (GtkTreeModel *tree_model)
229 {
230 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
231 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), 0);
232
233 return list_store->model->GetNumberOfCols();
234 }
235
236 static GType
237 wxgtk_list_store_get_column_type (GtkTreeModel *tree_model,
238 gint index)
239 {
240 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
241 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), G_TYPE_INVALID);
242
243 GType gtype = G_TYPE_INVALID;
244
245 wxString wxtype = list_store->model->GetColType( (size_t) index );
246
247 if (wxtype == wxT("string"))
248 gtype = G_TYPE_STRING;
249
250 return gtype;
251 }
252
253 static gboolean
254 wxgtk_list_store_get_iter (GtkTreeModel *tree_model,
255 GtkTreeIter *iter,
256 GtkTreePath *path)
257 {
258 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
259 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
260 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
261
262 size_t i = (size_t)gtk_tree_path_get_indices (path)[0];
263
264 if (i >= list_store->model->GetNumberOfRows())
265 return FALSE;
266
267 iter->stamp = list_store->stamp;
268 // user_data is just the index
269 iter->user_data = (gpointer) i;
270
271 return TRUE;
272 }
273
274 static GtkTreePath *
275 wxgtk_list_store_get_path (GtkTreeModel *tree_model,
276 GtkTreeIter *iter)
277 {
278 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), NULL);
279 g_return_val_if_fail (iter->stamp == GTK_WX_LIST_STORE (tree_model)->stamp, NULL);
280
281 GtkTreePath *retval = gtk_tree_path_new ();
282 // user_data is just the index
283 int i = (int) iter->user_data;
284 gtk_tree_path_append_index (retval, i);
285 return retval;
286 }
287
288 static void
289 wxgtk_list_store_get_value (GtkTreeModel *tree_model,
290 GtkTreeIter *iter,
291 gint column,
292 GValue *value)
293 {
294 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
295 g_return_if_fail (GTK_IS_WX_LIST_STORE (tree_model) );
296
297 wxDataViewListModel *model = list_store->model;
298 wxString mtype = model->GetColType( (size_t) column );
299 if (mtype == wxT("string"))
300 {
301 wxVariant variant;
302 g_value_init( value, G_TYPE_STRING );
303 model->GetValue( variant, (size_t) column, (size_t) iter->user_data );
304 g_value_set_string( value, wxGTK_CONV(variant.GetString()) );
305 }
306 else
307 {
308 }
309
310 #if 0
311 GtkTreeDataList *list;
312 gint tmp_column = column;
313
314 g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
315 g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
316
317 list = G_SLIST (iter->user_data)->data;
318
319 while (tmp_column-- > 0 && list)
320 list = list->next;
321
322 if (list == NULL)
323 g_value_init (value, GTK_LIST_STORE (tree_model)->column_headers[column]);
324 else
325 _gtk_tree_data_list_node_to_value (list,
326 GTK_LIST_STORE (tree_model)->column_headers[column],
327 value);
328 #endif
329
330 }
331
332 static gboolean
333 wxgtk_list_store_iter_next (GtkTreeModel *tree_model,
334 GtkTreeIter *iter)
335 {
336 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
337 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
338
339 g_return_val_if_fail (list_store->stamp == iter->stamp, FALSE);
340
341 int n = (int) iter->user_data;
342
343 if (n == -1)
344 return FALSE;
345
346 if (n >= (int) list_store->model->GetNumberOfRows()-1)
347 return FALSE;
348
349 iter->user_data = (gpointer) ++n;
350
351 return TRUE;
352 }
353
354 static gboolean
355 wxgtk_list_store_iter_children (GtkTreeModel *tree_model,
356 GtkTreeIter *iter,
357 GtkTreeIter *parent)
358 {
359 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
360 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
361
362 // this is a list, nodes have no children
363 if (parent)
364 return FALSE;
365
366 iter->stamp = list_store->stamp;
367 iter->user_data = (gpointer) -1;
368
369 return TRUE;
370 }
371
372 static gboolean
373 wxgtk_list_store_iter_has_child (GtkTreeModel *tree_model,
374 GtkTreeIter *iter)
375 {
376 return FALSE;
377 }
378
379 static gint
380 wxgtk_list_store_iter_n_children (GtkTreeModel *tree_model,
381 GtkTreeIter *iter)
382 {
383 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), -1);
384 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
385
386 if (iter == NULL)
387 return (gint) list_store->model->GetNumberOfRows();
388
389 g_return_val_if_fail (list_store->stamp == iter->stamp, -1);
390
391 return 0;
392 }
393
394 static gboolean
395 wxgtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
396 GtkTreeIter *iter,
397 GtkTreeIter *parent,
398 gint n)
399 {
400 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
401 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
402
403 if (parent)
404 return FALSE;
405
406 if (n < 0)
407 return FALSE;
408
409 if (n >= (gint) list_store->model->GetNumberOfRows())
410 return FALSE;
411
412 iter->stamp = list_store->stamp;
413 iter->user_data = (gpointer) n;
414
415 return TRUE;
416 }
417
418 static gboolean
419 wxgtk_list_store_iter_parent (GtkTreeModel *tree_model,
420 GtkTreeIter *iter,
421 GtkTreeIter *child)
422 {
423 return FALSE;
424 }
425
426 //-----------------------------------------------------------------------------
427 // define new GTK+ class wxGtkCellRenderer
428 //-----------------------------------------------------------------------------
429
430 extern "C" {
431
432 #define GTK_TYPE_WX_CELL_RENDERER (gtk_wx_cell_renderer_get_type ())
433 #define GTK_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRenderer))
434 #define GTK_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
435 #define GTK_IS_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_CELL_RENDERER))
436 #define GTK_IS_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_CELL_RENDERER))
437 #define GTK_WX_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
438
439 GType gtk_wx_cell_renderer_get_type (void);
440
441 typedef struct _GtkWxCellRenderer GtkWxCellRenderer;
442 typedef struct _GtkWxCellRendererClass GtkWxCellRendererClass;
443
444 struct _GtkWxCellRenderer
445 {
446 GtkCellRenderer parent;
447
448 /*< private >*/
449 wxDataViewCustomCell *cell;
450 guint32 last_click;
451 };
452
453 struct _GtkWxCellRendererClass
454 {
455 GtkCellRendererClass cell_parent_class;
456 };
457
458
459 static GtkCellRenderer *gtk_wx_cell_renderer_new (void);
460 static void gtk_wx_cell_renderer_init (
461 GtkWxCellRenderer *cell );
462 static void gtk_wx_cell_renderer_class_init(
463 GtkWxCellRendererClass *klass );
464 static void gtk_wx_cell_renderer_finalize (
465 GObject *object );
466 static void gtk_wx_cell_renderer_get_size (
467 GtkCellRenderer *cell,
468 GtkWidget *widget,
469 GdkRectangle *rectangle,
470 gint *x_offset,
471 gint *y_offset,
472 gint *width,
473 gint *height );
474 static void gtk_wx_cell_renderer_render (
475 GtkCellRenderer *cell,
476 GdkWindow *window,
477 GtkWidget *widget,
478 GdkRectangle *background_area,
479 GdkRectangle *cell_area,
480 GdkRectangle *expose_area,
481 GtkCellRendererState flags );
482 static gboolean gtk_wx_cell_renderer_activate(
483 GtkCellRenderer *cell,
484 GdkEvent *event,
485 GtkWidget *widget,
486 const gchar *path,
487 GdkRectangle *background_area,
488 GdkRectangle *cell_area,
489 GtkCellRendererState flags );
490
491 static GObjectClass *cell_parent_class = NULL;
492
493 } // extern "C"
494
495 GType
496 gtk_wx_cell_renderer_get_type (void)
497 {
498 static GType cell_wx_type = 0;
499
500 if (!cell_wx_type)
501 {
502 static const GTypeInfo cell_wx_info =
503 {
504 sizeof (GtkWxCellRendererClass),
505 NULL, /* base_init */
506 NULL, /* base_finalize */
507 (GClassInitFunc) gtk_wx_cell_renderer_class_init,
508 NULL, /* class_finalize */
509 NULL, /* class_data */
510 sizeof (GtkWxCellRenderer),
511 0, /* n_preallocs */
512 (GInstanceInitFunc) gtk_wx_cell_renderer_init,
513 };
514
515 cell_wx_type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
516 "GtkWxCellRenderer", &cell_wx_info, (GTypeFlags)0 );
517 }
518
519 return cell_wx_type;
520 }
521
522 static void
523 gtk_wx_cell_renderer_init (GtkWxCellRenderer *cell)
524 {
525 cell->cell = NULL;
526 cell->last_click = 0;
527 }
528
529 static void
530 gtk_wx_cell_renderer_class_init (GtkWxCellRendererClass *klass)
531 {
532 GObjectClass *object_class = G_OBJECT_CLASS (klass);
533 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
534
535 cell_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
536
537 object_class->finalize = gtk_wx_cell_renderer_finalize;
538
539 cell_class->get_size = gtk_wx_cell_renderer_get_size;
540 cell_class->render = gtk_wx_cell_renderer_render;
541 cell_class->activate = gtk_wx_cell_renderer_activate;
542 }
543
544 static void
545 gtk_wx_cell_renderer_finalize (GObject *object)
546 {
547 /* must chain up */
548 (* G_OBJECT_CLASS (cell_parent_class)->finalize) (object);
549 }
550
551 GtkCellRenderer*
552 gtk_wx_cell_renderer_new (void)
553 {
554 return (GtkCellRenderer*) g_object_new (GTK_TYPE_WX_CELL_RENDERER, NULL);
555 }
556
557 static void
558 gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer,
559 GtkWidget *widget,
560 GdkRectangle *cell_area,
561 gint *x_offset,
562 gint *y_offset,
563 gint *width,
564 gint *height)
565 {
566 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
567 wxDataViewCustomCell *cell = wxrenderer->cell;
568
569 wxSize size = cell->GetSize();
570
571 gint calc_width = (gint) renderer->xpad * 2 + size.x;
572 gint calc_height = (gint) renderer->ypad * 2 + size.y;
573
574 if (x_offset)
575 *x_offset = 0;
576 if (y_offset)
577 *y_offset = 0;
578
579 if (cell_area && size.x > 0 && size.y > 0)
580 {
581 if (x_offset)
582 {
583 *x_offset = (gint)((renderer->xalign *
584 (cell_area->width - calc_width - 2 * renderer->xpad)));
585 *x_offset = MAX (*x_offset, 0) + renderer->xpad;
586 }
587 if (y_offset)
588 {
589 *y_offset = (gint)((renderer->yalign *
590 (cell_area->height - calc_height - 2 * renderer->ypad)));
591 *y_offset = MAX (*y_offset, 0) + renderer->ypad;
592 }
593 }
594
595 if (width)
596 *width = calc_width;
597
598 if (height)
599 *height = calc_height;
600 }
601
602 static void
603 gtk_wx_cell_renderer_render (GtkCellRenderer *renderer,
604 GdkWindow *window,
605 GtkWidget *widget,
606 GdkRectangle *background_area,
607 GdkRectangle *cell_area,
608 GdkRectangle *expose_area,
609 GtkCellRendererState flags)
610
611 {
612 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
613 wxDataViewCustomCell *cell = wxrenderer->cell;
614
615 GdkRectangle rect;
616 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
617 &rect.x,
618 &rect.y,
619 &rect.width,
620 &rect.height);
621
622 rect.x += cell_area->x;
623 rect.y += cell_area->y;
624 rect.width -= renderer->xpad * 2;
625 rect.height -= renderer->ypad * 2;
626
627 GdkRectangle dummy;
628 if (gdk_rectangle_intersect (expose_area, &rect, &dummy))
629 {
630 wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
631 wxWindowDC* dc = (wxWindowDC*) cell->GetDC();
632 if (dc->m_window == NULL)
633 {
634 dc->m_window = window;
635 dc->SetUpDC();
636 }
637
638 int state = 0;
639 if (flags & GTK_CELL_RENDERER_SELECTED)
640 state |= wxDATAVIEW_CELL_SELECTED;
641 if (flags & GTK_CELL_RENDERER_PRELIT)
642 state |= wxDATAVIEW_CELL_PRELIT;
643 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
644 state |= wxDATAVIEW_CELL_INSENSITIVE;
645 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
646 state |= wxDATAVIEW_CELL_INSENSITIVE;
647 if (flags & GTK_CELL_RENDERER_FOCUSED)
648 state |= wxDATAVIEW_CELL_FOCUSED;
649 cell->Render( renderrect, dc, state );
650 }
651 }
652
653 static gboolean
654 gtk_wx_cell_renderer_activate(
655 GtkCellRenderer *renderer,
656 GdkEvent *event,
657 GtkWidget *widget,
658 const gchar *path,
659 GdkRectangle *background_area,
660 GdkRectangle *cell_area,
661 GtkCellRendererState flags )
662 {
663 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
664 wxDataViewCustomCell *cell = wxrenderer->cell;
665
666 GdkRectangle rect;
667 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
668 &rect.x,
669 &rect.y,
670 &rect.width,
671 &rect.height);
672
673 rect.x += cell_area->x;
674 rect.y += cell_area->y;
675 rect.width -= renderer->xpad * 2;
676 rect.height -= renderer->ypad * 2;
677
678 wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
679
680 wxDataViewListModel *model = cell->GetOwner()->GetOwner()->GetModel();
681
682 GtkTreePath *treepath = gtk_tree_path_new_from_string( path );
683 size_t model_row = (size_t)gtk_tree_path_get_indices (treepath)[0];
684 gtk_tree_path_free( treepath );
685
686 size_t model_col = cell->GetOwner()->GetModelColumn();
687
688 if (event->type == GDK_BUTTON_PRESS)
689 {
690 GdkEventButton *button_event = (GdkEventButton*) event;
691 wxPoint pt( ((int) button_event->x) - renderrect.x,
692 ((int) button_event->y) - renderrect.y );
693
694 bool ret = false;
695 if (button_event->button == 1)
696 {
697 if (cell->LeftClick( pt, renderrect, model, model_col, model_row ))
698 ret = true;
699 // TODO: query system double-click time
700 if (button_event->time - wxrenderer->last_click < 400)
701 if (cell->Activate( renderrect, model, model_col, model_row ))
702 ret = true;
703 }
704 if (button_event->button == 3)
705 {
706 if (cell->RightClick( pt, renderrect, model, model_col, model_row ))
707 ret = true;
708 }
709
710 wxrenderer->last_click = button_event->time;
711
712 return ret;
713 }
714
715 return false;
716 }
717
718 // ---------------------------------------------------------
719 // wxGtkDataViewListModelNotifier
720 // ---------------------------------------------------------
721
722 class wxGtkDataViewListModelNotifier: public wxDataViewListModelNotifier
723 {
724 public:
725 wxGtkDataViewListModelNotifier( GtkWxListStore* gtk_store, wxDataViewListModel *wx_model );
726
727 virtual bool RowAppended();
728 virtual bool RowPrepended();
729 virtual bool RowInserted( size_t before );
730 virtual bool RowDeleted( size_t row );
731 virtual bool RowChanged( size_t row );
732 virtual bool ValueChanged( size_t col, size_t row );
733 virtual bool RowsReordered( size_t *new_order );
734 virtual bool Cleared();
735
736 GtkWxListStore *m_gtk_store;
737 wxDataViewListModel *m_wx_model;
738 };
739
740 // ---------------------------------------------------------
741 // wxGtkDataViewListModelNotifier
742 // ---------------------------------------------------------
743
744 wxGtkDataViewListModelNotifier::wxGtkDataViewListModelNotifier(
745 GtkWxListStore* gtk_store, wxDataViewListModel *wx_model )
746 {
747 m_gtk_store = gtk_store;
748 m_wx_model = wx_model;
749 }
750
751 bool wxGtkDataViewListModelNotifier::RowAppended()
752 {
753 size_t pos = m_wx_model->GetNumberOfRows()-1;
754
755 GtkTreeIter iter;
756 iter.stamp = m_gtk_store->stamp;
757 iter.user_data = (gpointer) pos;
758
759 GtkTreePath *path = gtk_tree_path_new ();
760 gtk_tree_path_append_index (path, (gint) pos);
761 gtk_tree_model_row_inserted (GTK_TREE_MODEL (m_gtk_store), path, &iter);
762 gtk_tree_path_free (path);
763
764 return true;
765 }
766
767 bool wxGtkDataViewListModelNotifier::RowPrepended()
768 {
769 GtkTreeIter iter;
770 iter.stamp = m_gtk_store->stamp;
771 iter.user_data = (gpointer) 0;
772
773 GtkTreePath *path = gtk_tree_path_new ();
774 gtk_tree_path_append_index (path, (gint) 0);
775 gtk_tree_model_row_inserted (GTK_TREE_MODEL (m_gtk_store), path, &iter);
776 gtk_tree_path_free (path);
777
778 return true;
779 }
780
781 bool wxGtkDataViewListModelNotifier::RowInserted( size_t before )
782 {
783 return false;
784 }
785
786 bool wxGtkDataViewListModelNotifier::RowDeleted( size_t row )
787 {
788 return false;
789 }
790
791 bool wxGtkDataViewListModelNotifier::RowChanged( size_t row )
792 {
793 GtkTreeIter iter;
794 iter.stamp = m_gtk_store->stamp;
795 iter.user_data = (gpointer) row;
796 GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (m_gtk_store), &iter);
797 gtk_tree_model_row_changed (GTK_TREE_MODEL (m_gtk_store), path, &iter);
798 gtk_tree_path_free (path);
799
800 return true;
801 }
802
803 bool wxGtkDataViewListModelNotifier::ValueChanged( size_t model_col, size_t model_row )
804 {
805 // This adds GTK+'s missing MVC logic for ValueChanged
806 wxNode *node = GetOwner()->m_viewingColumns.GetFirst();
807 while (node)
808 {
809 wxDataViewViewingColumn* viewing_column = (wxDataViewViewingColumn*) node->GetData();
810 if (viewing_column->m_modelColumn == model_col)
811 {
812 GtkTreeView *widget = GTK_TREE_VIEW(viewing_column->m_viewColumn->GetOwner()->m_treeview);
813 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(viewing_column->m_viewColumn->GetGtkHandle());
814
815 // Get cell area
816 GtkTreePath *path = gtk_tree_path_new();
817 gtk_tree_path_append_index( path, model_row );
818 GdkRectangle cell_area;
819 gtk_tree_view_get_cell_area( widget, path, column, &cell_area );
820 gtk_tree_path_free( path );
821
822 int ydiff = column->button->allocation.height;
823 // Redraw
824 gtk_widget_queue_draw_area( GTK_WIDGET(widget),
825 cell_area.x, ydiff + cell_area.y, cell_area.width, cell_area.height );
826 }
827
828 node = node->GetNext();
829 }
830
831 return true;
832 }
833
834 bool wxGtkDataViewListModelNotifier::RowsReordered( size_t *new_order )
835 {
836 // Assume sizeof(size_t)= == sizeof(gint)
837
838 GtkTreePath *path = gtk_tree_path_new ();
839 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (m_gtk_store), path, NULL, (gint*)new_order);
840 gtk_tree_path_free (path);
841
842 // This adds GTK+'s missing MVC logic for RowsReordered
843 wxNode *node = GetOwner()->m_viewingColumns.GetFirst();
844 while (node)
845 {
846 wxDataViewViewingColumn* viewing_column = (wxDataViewViewingColumn*) node->GetData();
847 GtkTreeView *widget = GTK_TREE_VIEW(viewing_column->m_viewColumn->GetOwner()->m_treeview);
848 // Doesn't work yet...
849 gtk_widget_queue_draw( GTK_WIDGET(widget) );
850
851 node = node->GetNext();
852 }
853
854 return true;
855 }
856
857 bool wxGtkDataViewListModelNotifier::Cleared()
858 {
859 return false;
860 }
861
862 // ---------------------------------------------------------
863 // wxDataViewCell
864 // ---------------------------------------------------------
865
866 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCell, wxDataViewCellBase)
867
868 wxDataViewCell::wxDataViewCell( const wxString &varianttype, wxDataViewCellMode mode ) :
869 wxDataViewCellBase( varianttype, mode )
870 {
871 m_renderer = NULL;
872 }
873
874 // ---------------------------------------------------------
875 // wxDataViewTextCell
876 // ---------------------------------------------------------
877
878 extern "C" {
879 static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer,
880 gchar *arg1, gchar *arg2, gpointer user_data );
881 }
882
883 static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer,
884 gchar *arg1, gchar *arg2, gpointer user_data )
885 {
886 wxDataViewTextCell *cell = (wxDataViewTextCell*) user_data;
887
888 wxString tmp = wxGTK_CONV_BACK( arg2 );
889 wxVariant value = tmp;
890 if (!cell->Validate( value ))
891 return;
892
893 wxDataViewListModel *model = cell->GetOwner()->GetOwner()->GetModel();
894
895 GtkTreePath *path = gtk_tree_path_new_from_string( arg1 );
896 size_t model_row = (size_t)gtk_tree_path_get_indices (path)[0];
897 gtk_tree_path_free( path );
898
899 size_t model_col = cell->GetOwner()->GetModelColumn();
900
901 model->SetValue( value, model_col, model_row );
902 model->ValueChanged( model_col, model_row );
903 }
904
905 IMPLEMENT_ABSTRACT_CLASS(wxDataViewTextCell, wxDataViewCell)
906
907 wxDataViewTextCell::wxDataViewTextCell( const wxString &varianttype, wxDataViewCellMode mode ) :
908 wxDataViewCell( varianttype, mode )
909 {
910 m_renderer = (void*) gtk_cell_renderer_text_new();
911
912 if (m_mode & wxDATAVIEW_CELL_EDITABLE)
913 {
914 GValue gvalue = { 0, };
915 g_value_init( &gvalue, G_TYPE_BOOLEAN );
916 g_value_set_boolean( &gvalue, true );
917 g_object_set_property( G_OBJECT(m_renderer), "editable", &gvalue );
918 g_value_unset( &gvalue );
919
920 g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
921 }
922 }
923
924 bool wxDataViewTextCell::SetValue( const wxVariant &value )
925 {
926 wxString tmp = value;
927
928 GValue gvalue = { 0, };
929 g_value_init( &gvalue, G_TYPE_STRING );
930 g_value_set_string( &gvalue, wxGTK_CONV( tmp ) );
931 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
932 g_value_unset( &gvalue );
933
934 return true;
935 }
936
937 bool wxDataViewTextCell::GetValue( wxVariant &value )
938 {
939 GValue gvalue = { 0, };
940 g_value_init( &gvalue, G_TYPE_STRING );
941 g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
942 wxString tmp = wxGTK_CONV_BACK( g_value_get_string( &gvalue ) );
943 g_value_unset( &gvalue );
944
945 value = tmp;
946
947 return true;
948 }
949
950 // ---------------------------------------------------------
951 // wxDataViewToggleCell
952 // ---------------------------------------------------------
953
954 extern "C" {
955 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
956 gchar *path, gpointer user_data );
957 }
958
959 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
960 gchar *path, gpointer user_data )
961 {
962 wxDataViewToggleCell *cell = (wxDataViewToggleCell*) user_data;
963
964 // get old value
965 GValue gvalue = { 0, };
966 g_value_init( &gvalue, G_TYPE_BOOLEAN );
967 g_object_get_property( G_OBJECT(renderer), "active", &gvalue );
968 bool tmp = g_value_get_boolean( &gvalue );
969 g_value_unset( &gvalue );
970 // invert it
971 tmp = !tmp;
972
973 wxVariant value = tmp;
974 if (!cell->Validate( value ))
975 return;
976
977 wxDataViewListModel *model = cell->GetOwner()->GetOwner()->GetModel();
978
979 GtkTreePath *gtk_path = gtk_tree_path_new_from_string( path );
980 size_t model_row = (size_t)gtk_tree_path_get_indices (gtk_path)[0];
981 gtk_tree_path_free( gtk_path );
982
983 size_t model_col = cell->GetOwner()->GetModelColumn();
984
985 model->SetValue( value, model_col, model_row );
986 model->ValueChanged( model_col, model_row );
987 }
988
989 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleCell, wxDataViewCell)
990
991 wxDataViewToggleCell::wxDataViewToggleCell( const wxString &varianttype,
992 wxDataViewCellMode mode ) :
993 wxDataViewCell( varianttype, mode )
994 {
995 m_renderer = (void*) gtk_cell_renderer_toggle_new();
996
997 if (m_mode & wxDATAVIEW_CELL_EDITABLE)
998 {
999 g_signal_connect_after( m_renderer, "toggled", G_CALLBACK(wxGtkToggleRendererToggledCallback), this );
1000 }
1001 else
1002 {
1003
1004 GValue gvalue = { 0, };
1005 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1006 g_value_set_boolean( &gvalue, false );
1007 g_object_set_property( G_OBJECT(m_renderer), "activatable", &gvalue );
1008 g_value_unset( &gvalue );
1009
1010 GValue gvalue2 = { 0, };
1011 g_value_init( &gvalue2, gtk_cell_renderer_mode_get_type() );
1012 g_value_set_enum( &gvalue2, GTK_CELL_RENDERER_MODE_INERT );
1013 g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue2 );
1014 g_value_unset( &gvalue2 );
1015
1016 }
1017 }
1018
1019 bool wxDataViewToggleCell::SetValue( const wxVariant &value )
1020 {
1021 bool tmp = value;
1022
1023 GValue gvalue = { 0, };
1024 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1025 g_value_set_boolean( &gvalue, tmp );
1026 g_object_set_property( G_OBJECT(m_renderer), "active", &gvalue );
1027 g_value_unset( &gvalue );
1028
1029 return true;
1030 }
1031
1032 bool wxDataViewToggleCell::GetValue( wxVariant &value )
1033 {
1034 GValue gvalue = { 0, };
1035 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1036 g_object_get_property( G_OBJECT(m_renderer), "active", &gvalue );
1037 bool tmp = g_value_get_boolean( &gvalue );
1038 g_value_unset( &gvalue );
1039
1040 value = tmp;
1041
1042 return true;
1043 }
1044
1045 // ---------------------------------------------------------
1046 // wxDataViewCustomCell
1047 // ---------------------------------------------------------
1048
1049 class wxDataViewCtrlDC: public wxWindowDC
1050 {
1051 public:
1052 wxDataViewCtrlDC( wxDataViewCtrl *window )
1053 {
1054 GtkWidget *widget = window->m_treeview;
1055 // Set later
1056 m_window = NULL;
1057
1058 m_context = window->GtkGetPangoDefaultContext();
1059 m_layout = pango_layout_new( m_context );
1060 m_fontdesc = pango_font_description_copy( widget->style->font_desc );
1061
1062 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
1063
1064 // Set m_window later
1065 // SetUpDC();
1066 // m_owner = window;
1067 }
1068 };
1069
1070 // ---------------------------------------------------------
1071 // wxDataViewCustomCell
1072 // ---------------------------------------------------------
1073
1074 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomCell, wxDataViewCell)
1075
1076 wxDataViewCustomCell::wxDataViewCustomCell( const wxString &varianttype,
1077 wxDataViewCellMode mode, bool no_init ) :
1078 wxDataViewCell( varianttype, mode )
1079 {
1080 m_dc = NULL;
1081
1082 if (no_init)
1083 m_renderer = NULL;
1084 else
1085 Init();
1086 }
1087
1088 bool wxDataViewCustomCell::Init()
1089 {
1090 GtkWxCellRenderer *renderer = (GtkWxCellRenderer *) gtk_wx_cell_renderer_new();
1091 renderer->cell = this;
1092
1093 m_renderer = (void*) renderer;
1094
1095 if (m_mode & wxDATAVIEW_CELL_ACTIVATABLE)
1096 {
1097 GValue gvalue = { 0, };
1098 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
1099 g_value_set_enum( &gvalue, GTK_CELL_RENDERER_MODE_ACTIVATABLE );
1100 g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue );
1101 g_value_unset( &gvalue );
1102 }
1103
1104 return true;
1105 }
1106
1107 wxDataViewCustomCell::~wxDataViewCustomCell()
1108 {
1109 if (m_dc)
1110 delete m_dc;
1111 }
1112
1113 wxDC *wxDataViewCustomCell::GetDC()
1114 {
1115 if (m_dc == NULL)
1116 {
1117 if (GetOwner() == NULL)
1118 return NULL;
1119 if (GetOwner()->GetOwner() == NULL)
1120 return NULL;
1121 m_dc = new wxDataViewCtrlDC( GetOwner()->GetOwner() );
1122 }
1123
1124 return m_dc;
1125 }
1126
1127 // ---------------------------------------------------------
1128 // wxDataViewProgressCell
1129 // ---------------------------------------------------------
1130
1131 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressCell, wxDataViewCustomCell)
1132
1133 wxDataViewProgressCell::wxDataViewProgressCell( const wxString &label,
1134 const wxString &varianttype, wxDataViewCellMode mode ) :
1135 wxDataViewCustomCell( varianttype, mode, true )
1136 {
1137 m_label = label;
1138 m_value = 0;
1139
1140 #ifdef __WXGTK26__
1141 if (!gtk_check_version(2,6,0))
1142 {
1143 m_renderer = (void*) gtk_cell_renderer_progress_new();
1144
1145 GValue gvalue = { 0, };
1146 g_value_init( &gvalue, G_TYPE_STRING );
1147 g_value_set_boolean( &gvalue, wxGTK_CONV(m_label) );
1148 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
1149 g_value_unset( &gvalue );
1150 }
1151 else
1152 #endif
1153 {
1154 // Use custom cell code
1155 wxDataViewCustomCell::Init();
1156 }
1157 }
1158
1159 wxDataViewProgressCell::~wxDataViewProgressCell()
1160 {
1161 }
1162
1163 bool wxDataViewProgressCell::SetValue( const wxVariant &value )
1164 {
1165 #ifdef __WXGTK26__
1166 if (!gtk_check_version(2,6,0))
1167 {
1168 gint tmp = (int) value;
1169 GValue gvalue = { 0, };
1170 g_value_init( &gvalue, G_TYPE_INT );
1171 g_value_set_boolean( &gvalue, tmp );
1172 g_object_set_property( G_OBJECT(m_renderer), "value", &gvalue );
1173 g_value_unset( &gvalue );
1174 }
1175 else
1176 #endif
1177 {
1178 m_value = (long) value;
1179
1180 if (m_value < 0) m_value = 0;
1181 if (m_value > 100) m_value = 100;
1182 }
1183
1184 return true;
1185 }
1186
1187 bool wxDataViewProgressCell::Render( wxRect cell, wxDC *dc, int state )
1188 {
1189 double pct = (double)m_value / 100.0;
1190 wxRect bar = cell;
1191 bar.width = (int)(cell.width * pct);
1192 dc->SetPen( *wxTRANSPARENT_PEN );
1193 dc->SetBrush( *wxBLUE_BRUSH );
1194 dc->DrawRectangle( bar );
1195
1196 dc->SetBrush( *wxTRANSPARENT_BRUSH );
1197 dc->SetPen( *wxBLACK_PEN );
1198 dc->DrawRectangle( cell );
1199
1200 return true;
1201 }
1202
1203 wxSize wxDataViewProgressCell::GetSize()
1204 {
1205 return wxSize(40,12);
1206 }
1207
1208 // ---------------------------------------------------------
1209 // wxDataViewDateCell
1210 // ---------------------------------------------------------
1211
1212 class wxDataViewDateCellPopupTransient: public wxPopupTransientWindow
1213 {
1214 public:
1215 wxDataViewDateCellPopupTransient( wxWindow* parent, wxDateTime *value,
1216 wxDataViewListModel *model, size_t col, size_t row ) :
1217 wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
1218 {
1219 m_model = model;
1220 m_col = col;
1221 m_row = row;
1222 m_cal = new wxCalendarCtrl( this, -1, *value );
1223 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
1224 sizer->Add( m_cal, 1, wxGROW );
1225 SetSizer( sizer );
1226 sizer->Fit( this );
1227 }
1228
1229 virtual void OnDismiss()
1230 {
1231 }
1232
1233 void OnCalendar( wxCalendarEvent &event );
1234
1235 wxCalendarCtrl *m_cal;
1236 wxDataViewListModel *m_model;
1237 size_t m_col;
1238 size_t m_row;
1239
1240 private:
1241 DECLARE_EVENT_TABLE()
1242 };
1243
1244 BEGIN_EVENT_TABLE(wxDataViewDateCellPopupTransient,wxPopupTransientWindow)
1245 EVT_CALENDAR( -1, wxDataViewDateCellPopupTransient::OnCalendar )
1246 END_EVENT_TABLE()
1247
1248 void wxDataViewDateCellPopupTransient::OnCalendar( wxCalendarEvent &event )
1249 {
1250 wxDateTime date = event.GetDate();
1251 wxVariant value = date;
1252 m_model->SetValue( value, m_col, m_row );
1253 m_model->ValueChanged( m_col, m_row );
1254 DismissAndNotify();
1255 }
1256
1257 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateCell, wxDataViewCustomCell)
1258
1259 wxDataViewDateCell::wxDataViewDateCell( const wxString &varianttype,
1260 wxDataViewCellMode mode ) :
1261 wxDataViewCustomCell( varianttype, mode )
1262 {
1263 }
1264
1265 bool wxDataViewDateCell::SetValue( const wxVariant &value )
1266 {
1267 m_date = value.GetDateTime();
1268
1269 return true;
1270 }
1271
1272 bool wxDataViewDateCell::Render( wxRect cell, wxDC *dc, int state )
1273 {
1274 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
1275 wxString tmp = m_date.FormatDate();
1276 dc->DrawText( tmp, cell.x, cell.y );
1277
1278 return true;
1279 }
1280
1281 wxSize wxDataViewDateCell::GetSize()
1282 {
1283 wxDataViewCtrl* view = GetOwner()->GetOwner();
1284 wxString tmp = m_date.FormatDate();
1285 wxCoord x,y,d;
1286 view->GetTextExtent( tmp, &x, &y, &d );
1287 return wxSize(x,y+d);
1288 }
1289
1290 bool wxDataViewDateCell::Activate( wxRect cell, wxDataViewListModel *model, size_t col, size_t row )
1291 {
1292 wxVariant variant;
1293 model->GetValue( variant, col, row );
1294 wxDateTime value = variant.GetDateTime();
1295
1296 wxDataViewDateCellPopupTransient *popup = new wxDataViewDateCellPopupTransient(
1297 GetOwner()->GetOwner()->GetParent(), &value, model, col, row );
1298 wxPoint pos = wxGetMousePosition();
1299 popup->Move( pos );
1300 popup->Layout();
1301 popup->Popup( popup->m_cal );
1302
1303 return true;
1304 }
1305
1306 // ---------------------------------------------------------
1307 // wxDataViewColumn
1308 // ---------------------------------------------------------
1309
1310 extern "C" {
1311 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
1312 GtkCellRenderer *cell,
1313 GtkTreeModel *model,
1314 GtkTreeIter *iter,
1315 gpointer data );
1316 }
1317
1318
1319 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
1320 GtkCellRenderer *renderer,
1321 GtkTreeModel *model,
1322 GtkTreeIter *iter,
1323 gpointer data )
1324 {
1325 g_return_if_fail (GTK_IS_WX_LIST_STORE (model));
1326 GtkWxListStore *list_store = (GtkWxListStore *) model;
1327
1328 wxDataViewCell *cell = (wxDataViewCell*) data;
1329
1330 size_t model_row = (size_t) iter->user_data;
1331
1332 wxVariant value;
1333 list_store->model->GetValue( value, cell->GetOwner()->GetModelColumn(), model_row );
1334
1335 if (value.GetType() != cell->GetVariantType())
1336 wxLogError( wxT("Wrong type\n") );
1337
1338 cell->SetValue( value );
1339 }
1340
1341 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
1342
1343 wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewCell *cell,
1344 size_t model_column, int flags ) :
1345 wxDataViewColumnBase( title, cell, model_column, flags )
1346 {
1347 GtkCellRenderer *renderer = (GtkCellRenderer *) cell->GetGtkHandle();
1348
1349 GtkTreeViewColumn *column = gtk_tree_view_column_new();
1350
1351 gtk_tree_view_column_set_title( column, wxGTK_CONV(title) );
1352
1353 gtk_tree_view_column_pack_start( column, renderer, TRUE );
1354
1355 gtk_tree_view_column_set_cell_data_func( column, renderer,
1356 wxGtkTreeCellDataFunc, (gpointer) cell, NULL );
1357
1358 m_column = (void*) column;
1359 }
1360
1361 wxDataViewColumn::~wxDataViewColumn()
1362 {
1363 }
1364
1365 void wxDataViewColumn::SetTitle( const wxString &title )
1366 {
1367 wxDataViewColumnBase::SetTitle( title );
1368
1369 GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column;
1370 gtk_tree_view_column_set_title( column, wxGTK_CONV(title) );
1371 }
1372
1373 //-----------------------------------------------------------------------------
1374 // wxDataViewCtrl
1375 //-----------------------------------------------------------------------------
1376
1377 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
1378
1379 wxDataViewCtrl::~wxDataViewCtrl()
1380 {
1381 if (m_notifier)
1382 GetModel()->RemoveNotifier( m_notifier );
1383 }
1384
1385 void wxDataViewCtrl::Init()
1386 {
1387 m_notifier = NULL;
1388 }
1389
1390 bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
1391 const wxPoint& pos, const wxSize& size,
1392 long style, const wxValidator& validator )
1393 {
1394 Init();
1395
1396 m_needParent = TRUE;
1397 m_acceptsFocus = TRUE;
1398
1399 if (!PreCreation( parent, pos, size ) ||
1400 !CreateBase( parent, id, pos, size, style, validator ))
1401 {
1402 wxFAIL_MSG( wxT("wxDataViewCtrl creation failed") );
1403 return FALSE;
1404 }
1405
1406 m_widget = gtk_scrolled_window_new (NULL, NULL);
1407 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (m_widget), GTK_SHADOW_IN);
1408
1409 m_treeview = gtk_tree_view_new();
1410 gtk_container_add (GTK_CONTAINER (m_widget), m_treeview);
1411
1412 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_widget),
1413 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1414 gtk_widget_show (m_treeview);
1415
1416 m_parent->DoAddChild( this );
1417
1418 PostCreation(size);
1419
1420 return true;
1421 }
1422
1423 bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model )
1424 {
1425 if (!wxDataViewCtrlBase::AssociateModel( model ))
1426 return false;
1427
1428 GtkWxListStore *gtk_store = wxgtk_list_store_new();
1429 gtk_store->model = model;
1430
1431 m_notifier = new wxGtkDataViewListModelNotifier( gtk_store, model );
1432
1433 model->AddNotifier( m_notifier );
1434
1435 gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview), GTK_TREE_MODEL(gtk_store) );
1436 g_object_unref( gtk_store );
1437
1438 return true;
1439 }
1440
1441 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
1442 {
1443 if (!wxDataViewCtrlBase::AppendColumn(col))
1444 return false;
1445
1446 GtkTreeViewColumn *column = (GtkTreeViewColumn *)col->GetGtkHandle();
1447
1448 gtk_tree_view_append_column( GTK_TREE_VIEW(m_treeview), column );
1449
1450 return true;
1451 }
1452
1453
1454 #endif // wxUSE_DATAVIEWCTRL
1455