]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dataview.cpp
Use wxGtkString here to clean up code, and not leak in debug builds
[wxWidgets.git] / src / gtk / dataview.cpp
CommitLineData
790b137e
RR
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"
e152afc3 19#include "wx/dcclient.h"
7ea3a0de
RR
20#include "wx/calctrl.h"
21#include "wx/popupwin.h"
22#include "wx/sizer.h"
3f3af7e7 23#include "wx/log.h"
790b137e
RR
24
25#include "wx/gtk/private.h"
26#include "wx/gtk/win_gtk.h"
27
28#include <gobject/gvaluecollector.h>
1557c77b
RR
29#include <gtk/gtktreemodel.h>
30#include <gtk/gtktreednd.h>
790b137e 31
4d496ecb
RR
32#include <gdk/gdkkeysyms.h>
33
790b137e
RR
34//-----------------------------------------------------------------------------
35// classes
36//-----------------------------------------------------------------------------
37
38class wxDataViewCtrl;
39
790b137e
RR
40//-----------------------------------------------------------------------------
41// data
42//-----------------------------------------------------------------------------
43
44extern bool g_blockEventsOnDrag;
45
46//-----------------------------------------------------------------------------
47// define new GTK+ class wxGtkListStore
48//-----------------------------------------------------------------------------
49
50extern "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
59GType gtk_wx_list_store_get_type (void);
60
61typedef struct _GtkWxListStore GtkWxListStore;
62typedef struct _GtkWxListStoreClass GtkWxListStoreClass;
63
64struct _GtkWxListStore
65{
66 GObject parent;
67
68 /*< private >*/
69 gint stamp;
70 wxDataViewListModel *model;
71};
72
73struct _GtkWxListStoreClass
74{
e152afc3 75 GObjectClass list_parent_class;
790b137e
RR
76
77};
78
e152afc3 79static GtkWxListStore *wxgtk_list_store_new (void);
790b137e 80static void wxgtk_list_store_init (GtkWxListStore *list_store);
1557c77b 81static void wxgtk_list_store_class_init (GtkWxListStoreClass *klass);
790b137e
RR
82static void wxgtk_list_store_tree_model_init (GtkTreeModelIface *iface);
83static void wxgtk_list_store_finalize (GObject *object);
84static GtkTreeModelFlags wxgtk_list_store_get_flags (GtkTreeModel *tree_model);
85static gint wxgtk_list_store_get_n_columns (GtkTreeModel *tree_model);
86static GType wxgtk_list_store_get_column_type (GtkTreeModel *tree_model,
87 gint index);
88static gboolean wxgtk_list_store_get_iter (GtkTreeModel *tree_model,
89 GtkTreeIter *iter,
90 GtkTreePath *path);
91static GtkTreePath *wxgtk_list_store_get_path (GtkTreeModel *tree_model,
92 GtkTreeIter *iter);
93static void wxgtk_list_store_get_value (GtkTreeModel *tree_model,
94 GtkTreeIter *iter,
95 gint column,
96 GValue *value);
97static gboolean wxgtk_list_store_iter_next (GtkTreeModel *tree_model,
98 GtkTreeIter *iter);
99static gboolean wxgtk_list_store_iter_children (GtkTreeModel *tree_model,
100 GtkTreeIter *iter,
101 GtkTreeIter *parent);
102static gboolean wxgtk_list_store_iter_has_child (GtkTreeModel *tree_model,
103 GtkTreeIter *iter);
104static gint wxgtk_list_store_iter_n_children (GtkTreeModel *tree_model,
105 GtkTreeIter *iter);
106static gboolean wxgtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
107 GtkTreeIter *iter,
108 GtkTreeIter *parent,
109 gint n);
110static gboolean wxgtk_list_store_iter_parent (GtkTreeModel *tree_model,
111 GtkTreeIter *iter,
112 GtkTreeIter *child);
113
e152afc3 114static GObjectClass *list_parent_class = NULL;
790b137e
RR
115
116GType
111f83c4 117gtk_wx_list_store_get_type (void)
790b137e
RR
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",
1557c77b 144 &list_store_info, (GTypeFlags)0 );
790b137e
RR
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
1557c77b 154static GtkWxListStore *
e152afc3 155wxgtk_list_store_new(void)
1557c77b 156{
e152afc3
RR
157 GtkWxListStore *retval = (GtkWxListStore *) g_object_new (GTK_TYPE_WX_LIST_STORE, NULL);
158 return retval;
1557c77b
RR
159}
160
790b137e 161static void
1557c77b 162wxgtk_list_store_class_init (GtkWxListStoreClass *klass)
790b137e 163{
e152afc3
RR
164 list_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
165 GObjectClass *object_class = (GObjectClass*) klass;
790b137e
RR
166 object_class->finalize = wxgtk_list_store_finalize;
167}
168
169static void
170wxgtk_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
186static void
187wxgtk_list_store_init (GtkWxListStore *list_store)
188{
189 list_store->model = NULL;
1557c77b 190 list_store->stamp = g_random_int();
790b137e
RR
191}
192
193static void
194wxgtk_list_store_finalize (GObject *object)
195{
1557c77b 196 /* GtkWxListStore *list_store = GTK_WX_LIST_STORE (object); */
790b137e
RR
197
198 /* we need to sort out, which class deletes what */
111f83c4 199 /* delete list_store->model; */
790b137e
RR
200
201 /* must chain up */
e152afc3 202 (* list_parent_class->finalize) (object);
790b137e
RR
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
212static GtkTreeModelFlags
213wxgtk_list_store_get_flags (GtkTreeModel *tree_model)
214{
1557c77b 215 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), (GtkTreeModelFlags)0 );
790b137e 216
67cbdfc1
RR
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;
790b137e
RR
225}
226
227static gint
228wxgtk_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
239eaa41 233 return list_store->model->GetNumberOfCols();
790b137e
RR
234}
235
236static GType
237wxgtk_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
1557c77b 243 GType gtype = G_TYPE_INVALID;
239eaa41 244
1557c77b
RR
245 wxString wxtype = list_store->model->GetColType( (size_t) index );
246
247 if (wxtype == wxT("string"))
248 gtype = G_TYPE_STRING;
790b137e
RR
249
250 return gtype;
251}
252
253static gboolean
254wxgtk_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
1557c77b 262 size_t i = (size_t)gtk_tree_path_get_indices (path)[0];
790b137e 263
1557c77b 264 if (i >= list_store->model->GetNumberOfRows())
239eaa41 265 return FALSE;
790b137e 266
239eaa41
RR
267 iter->stamp = list_store->stamp;
268 // user_data is just the index
269 iter->user_data = (gpointer) i;
790b137e
RR
270
271 return TRUE;
272}
273
274static GtkTreePath *
275wxgtk_list_store_get_path (GtkTreeModel *tree_model,
276 GtkTreeIter *iter)
277{
790b137e 278 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), NULL);
239eaa41 279 g_return_val_if_fail (iter->stamp == GTK_WX_LIST_STORE (tree_model)->stamp, NULL);
790b137e 280
239eaa41
RR
281 GtkTreePath *retval = gtk_tree_path_new ();
282 // user_data is just the index
1557c77b 283 int i = (int) iter->user_data;
239eaa41
RR
284 gtk_tree_path_append_index (retval, i);
285 return retval;
790b137e
RR
286}
287
288static void
289wxgtk_list_store_get_value (GtkTreeModel *tree_model,
290 GtkTreeIter *iter,
291 gint column,
292 GValue *value)
293{
1557c77b 294 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
790b137e 295 g_return_if_fail (GTK_IS_WX_LIST_STORE (tree_model) );
239eaa41 296
1557c77b
RR
297 wxDataViewListModel *model = list_store->model;
298 wxString mtype = model->GetColType( (size_t) column );
299 if (mtype == wxT("string"))
300 {
3f3af7e7 301 wxVariant variant;
1557c77b 302 g_value_init( value, G_TYPE_STRING );
3f3af7e7 303 model->GetValue( variant, (size_t) column, (size_t) iter->user_data );
1557c77b
RR
304 g_value_set_string( value, wxGTK_CONV(variant.GetString()) );
305 }
306 else
307 {
308 }
790b137e
RR
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
332static gboolean
333wxgtk_list_store_iter_next (GtkTreeModel *tree_model,
334 GtkTreeIter *iter)
335{
790b137e 336 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
1557c77b 337 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
790b137e 338
67cbdfc1 339 g_return_val_if_fail (list_store->stamp == iter->stamp, FALSE);
790b137e 340
67cbdfc1
RR
341 int n = (int) iter->user_data;
342
343 if (n == -1)
344 return FALSE;
345
1a367564 346 if (n >= (int) list_store->model->GetNumberOfRows()-1)
67cbdfc1
RR
347 return FALSE;
348
111f83c4 349 iter->user_data = (gpointer) ++n;
790b137e 350
67cbdfc1 351 return TRUE;
790b137e
RR
352}
353
354static gboolean
355wxgtk_list_store_iter_children (GtkTreeModel *tree_model,
356 GtkTreeIter *iter,
357 GtkTreeIter *parent)
358{
67cbdfc1 359 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
1557c77b 360 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
67cbdfc1
RR
361
362 // this is a list, nodes have no children
790b137e
RR
363 if (parent)
364 return FALSE;
365
67cbdfc1
RR
366 iter->stamp = list_store->stamp;
367 iter->user_data = (gpointer) -1;
368
369 return TRUE;
790b137e
RR
370}
371
372static gboolean
373wxgtk_list_store_iter_has_child (GtkTreeModel *tree_model,
374 GtkTreeIter *iter)
375{
376 return FALSE;
377}
378
379static gint
380wxgtk_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);
1557c77b 384 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
790b137e
RR
385
386 if (iter == NULL)
1557c77b 387 return (gint) list_store->model->GetNumberOfRows();
790b137e 388
67cbdfc1 389 g_return_val_if_fail (list_store->stamp == iter->stamp, -1);
790b137e
RR
390
391 return 0;
392}
393
394static gboolean
395wxgtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
396 GtkTreeIter *iter,
397 GtkTreeIter *parent,
398 gint n)
399{
67cbdfc1 400 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
1557c77b 401 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
67cbdfc1
RR
402
403 if (parent)
404 return FALSE;
790b137e 405
67cbdfc1
RR
406 if (n < 0)
407 return FALSE;
408
1557c77b 409 if (n >= (gint) list_store->model->GetNumberOfRows())
67cbdfc1 410 return FALSE;
790b137e 411
67cbdfc1
RR
412 iter->stamp = list_store->stamp;
413 iter->user_data = (gpointer) n;
414
415 return TRUE;
790b137e
RR
416}
417
418static gboolean
419wxgtk_list_store_iter_parent (GtkTreeModel *tree_model,
420 GtkTreeIter *iter,
421 GtkTreeIter *child)
422{
423 return FALSE;
424}
425
e152afc3
RR
426//-----------------------------------------------------------------------------
427// define new GTK+ class wxGtkCellRenderer
428//-----------------------------------------------------------------------------
429
430extern "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
439GType gtk_wx_cell_renderer_get_type (void);
440
441typedef struct _GtkWxCellRenderer GtkWxCellRenderer;
442typedef struct _GtkWxCellRendererClass GtkWxCellRendererClass;
443
444struct _GtkWxCellRenderer
445{
446 GtkCellRenderer parent;
447
448 /*< private >*/
449 wxDataViewCustomCell *cell;
4d496ecb 450 guint32 last_click;
e152afc3
RR
451};
452
453struct _GtkWxCellRendererClass
454{
455 GtkCellRendererClass cell_parent_class;
e152afc3
RR
456};
457
458
459static GtkCellRenderer *gtk_wx_cell_renderer_new (void);
553f7d8f
RR
460static void gtk_wx_cell_renderer_init (
461 GtkWxCellRenderer *cell );
462static void gtk_wx_cell_renderer_class_init(
463 GtkWxCellRendererClass *klass );
464static void gtk_wx_cell_renderer_finalize (
465 GObject *object );
466static 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 );
474static 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 );
482static 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 );
e152afc3
RR
490
491static GObjectClass *cell_parent_class = NULL;
492
493} // extern "C"
494
495GType
496gtk_wx_cell_renderer_get_type (void)
497{
553f7d8f 498 static GType cell_wx_type = 0;
e152afc3 499
553f7d8f 500 if (!cell_wx_type)
e152afc3 501 {
553f7d8f
RR
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 );
e152afc3
RR
517 }
518
553f7d8f 519 return cell_wx_type;
e152afc3
RR
520}
521
522static void
523gtk_wx_cell_renderer_init (GtkWxCellRenderer *cell)
524{
525 cell->cell = NULL;
4d496ecb 526 cell->last_click = 0;
e152afc3
RR
527}
528
529static void
530gtk_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;
553f7d8f 541 cell_class->activate = gtk_wx_cell_renderer_activate;
e152afc3
RR
542}
543
544static void
545gtk_wx_cell_renderer_finalize (GObject *object)
546{
547 /* must chain up */
548 (* G_OBJECT_CLASS (cell_parent_class)->finalize) (object);
549}
550
551GtkCellRenderer*
552gtk_wx_cell_renderer_new (void)
553{
554 return (GtkCellRenderer*) g_object_new (GTK_TYPE_WX_CELL_RENDERER, NULL);
555}
556
557static void
558gtk_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
602static void
603gtk_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();
4d496ecb
RR
632 if (dc->m_window == NULL)
633 {
634 dc->m_window = window;
635 dc->SetUpDC();
636 }
e152afc3
RR
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
553f7d8f
RR
653static gboolean
654gtk_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 );
4d496ecb
RR
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 );
553f7d8f 693
4d496ecb
RR
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;
7ea3a0de 699 // TODO: query system double-click time
4d496ecb
RR
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
4d496ecb 715 return false;
553f7d8f
RR
716}
717
6e2e590f
RR
718// ---------------------------------------------------------
719// wxGtkDataViewListModelNotifier
720// ---------------------------------------------------------
721
722class wxGtkDataViewListModelNotifier: public wxDataViewListModelNotifier
723{
724public:
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 );
a7f61f76 732 virtual bool ValueChanged( size_t col, size_t row );
4eccd3a1 733 virtual bool RowsReordered( size_t *new_order );
6e2e590f
RR
734 virtual bool Cleared();
735
736 GtkWxListStore *m_gtk_store;
737 wxDataViewListModel *m_wx_model;
738};
739
740// ---------------------------------------------------------
741// wxGtkDataViewListModelNotifier
742// ---------------------------------------------------------
743
744wxGtkDataViewListModelNotifier::wxGtkDataViewListModelNotifier(
745 GtkWxListStore* gtk_store, wxDataViewListModel *wx_model )
746{
747 m_gtk_store = gtk_store;
748 m_wx_model = wx_model;
749}
750
751bool 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
767bool wxGtkDataViewListModelNotifier::RowPrepended()
768{
605c2c4a
RR
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;
6e2e590f
RR
779}
780
781bool wxGtkDataViewListModelNotifier::RowInserted( size_t before )
782{
783 return false;
784}
785
786bool wxGtkDataViewListModelNotifier::RowDeleted( size_t row )
787{
788 return false;
789}
790
791bool wxGtkDataViewListModelNotifier::RowChanged( size_t row )
792{
a7f61f76
RR
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;
6e2e590f
RR
801}
802
8f850e28 803bool wxGtkDataViewListModelNotifier::ValueChanged( size_t model_col, size_t model_row )
6e2e590f 804{
4eccd3a1 805 // This adds GTK+'s missing MVC logic for ValueChanged
8f850e28
RR
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;
6e2e590f
RR
832}
833
4eccd3a1
RR
834bool 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 }
4eccd3a1
RR
853
854 return true;
855}
856
6e2e590f
RR
857bool wxGtkDataViewListModelNotifier::Cleared()
858{
859 return false;
860}
861
6842a71a
RR
862// ---------------------------------------------------------
863// wxDataViewCell
864// ---------------------------------------------------------
865
866IMPLEMENT_ABSTRACT_CLASS(wxDataViewCell, wxDataViewCellBase)
867
868wxDataViewCell::wxDataViewCell( const wxString &varianttype, wxDataViewCellMode mode ) :
869 wxDataViewCellBase( varianttype, mode )
870{
871 m_renderer = NULL;
872}
873
874// ---------------------------------------------------------
875// wxDataViewTextCell
876// ---------------------------------------------------------
877
a7f61f76
RR
878extern "C" {
879static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer,
880 gchar *arg1, gchar *arg2, gpointer user_data );
881}
882
883static 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
6842a71a
RR
905IMPLEMENT_ABSTRACT_CLASS(wxDataViewTextCell, wxDataViewCell)
906
907wxDataViewTextCell::wxDataViewTextCell( const wxString &varianttype, wxDataViewCellMode mode ) :
908 wxDataViewCell( varianttype, mode )
909{
910 m_renderer = (void*) gtk_cell_renderer_text_new();
a7f61f76
RR
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 }
6842a71a 922}
790b137e 923
7b4fde82
RR
924bool 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
a7f61f76
RR
937bool 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
fa28826d 950// ---------------------------------------------------------
605c2c4a 951// wxDataViewToggleCell
fa28826d
RR
952// ---------------------------------------------------------
953
605c2c4a
RR
954extern "C" {
955static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
956 gchar *path, gpointer user_data );
957}
958
959static 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
989IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleCell, wxDataViewCell)
990
991wxDataViewToggleCell::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 {
553f7d8f
RR
999 g_signal_connect_after( m_renderer, "toggled", G_CALLBACK(wxGtkToggleRendererToggledCallback), this );
1000 }
1001 else
1002 {
1003
605c2c4a
RR
1004 GValue gvalue = { 0, };
1005 g_value_init( &gvalue, G_TYPE_BOOLEAN );
553f7d8f 1006 g_value_set_boolean( &gvalue, false );
605c2c4a
RR
1007 g_object_set_property( G_OBJECT(m_renderer), "activatable", &gvalue );
1008 g_value_unset( &gvalue );
553f7d8f
RR
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
605c2c4a
RR
1016 }
1017}
1018
1019bool 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
1032bool 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
e152afc3
RR
1045// ---------------------------------------------------------
1046// wxDataViewCustomCell
1047// ---------------------------------------------------------
1048
1049class wxDataViewCtrlDC: public wxWindowDC
1050{
1051public:
1052 wxDataViewCtrlDC( wxDataViewCtrl *window )
1053 {
1a367564 1054 GtkWidget *widget = window->m_treeview;
e152afc3
RR
1055 // Set later
1056 m_window = NULL;
4d496ecb 1057
e152afc3
RR
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
4d496ecb
RR
1064 // Set m_window later
1065 // SetUpDC();
1066 // m_owner = window;
e152afc3
RR
1067 }
1068};
1069
1070// ---------------------------------------------------------
1071// wxDataViewCustomCell
1072// ---------------------------------------------------------
1073
1074IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomCell, wxDataViewCell)
1075
1076wxDataViewCustomCell::wxDataViewCustomCell( const wxString &varianttype,
ad63bf41 1077 wxDataViewCellMode mode, bool no_init ) :
e152afc3
RR
1078 wxDataViewCell( varianttype, mode )
1079{
1080 m_dc = NULL;
1081
ad63bf41
RR
1082 if (no_init)
1083 m_renderer = NULL;
1084 else
1085 Init();
1086}
1087
1088bool wxDataViewCustomCell::Init()
1089{
e152afc3
RR
1090 GtkWxCellRenderer *renderer = (GtkWxCellRenderer *) gtk_wx_cell_renderer_new();
1091 renderer->cell = this;
1092
1093 m_renderer = (void*) renderer;
ad63bf41 1094
553f7d8f
RR
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
ad63bf41 1104 return true;
e152afc3
RR
1105}
1106
1107wxDataViewCustomCell::~wxDataViewCustomCell()
1108{
1109 if (m_dc)
1110 delete m_dc;
1111}
1112
1113wxDC *wxDataViewCustomCell::GetDC()
1114{
1115 if (m_dc == NULL)
4d496ecb
RR
1116 {
1117 if (GetOwner() == NULL)
1118 return NULL;
1119 if (GetOwner()->GetOwner() == NULL)
1120 return NULL;
e152afc3 1121 m_dc = new wxDataViewCtrlDC( GetOwner()->GetOwner() );
4d496ecb 1122 }
e152afc3
RR
1123
1124 return m_dc;
1125}
1126
ad63bf41
RR
1127// ---------------------------------------------------------
1128// wxDataViewProgressCell
1129// ---------------------------------------------------------
1130
1131IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressCell, wxDataViewCustomCell)
1132
1133wxDataViewProgressCell::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
1159wxDataViewProgressCell::~wxDataViewProgressCell()
1160{
1161}
1162
1163bool 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
1187bool 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
1203wxSize wxDataViewProgressCell::GetSize()
1204{
1205 return wxSize(40,12);
1206}
1207
4d496ecb
RR
1208// ---------------------------------------------------------
1209// wxDataViewDateCell
1210// ---------------------------------------------------------
1211
7ea3a0de
RR
1212class wxDataViewDateCellPopupTransient: public wxPopupTransientWindow
1213{
1214public:
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
1240private:
1241 DECLARE_EVENT_TABLE()
1242};
1243
1244BEGIN_EVENT_TABLE(wxDataViewDateCellPopupTransient,wxPopupTransientWindow)
1245 EVT_CALENDAR( -1, wxDataViewDateCellPopupTransient::OnCalendar )
1246END_EVENT_TABLE()
1247
1248void 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
4d496ecb
RR
1257IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateCell, wxDataViewCustomCell)
1258
1259wxDataViewDateCell::wxDataViewDateCell( const wxString &varianttype,
1260 wxDataViewCellMode mode ) :
1261 wxDataViewCustomCell( varianttype, mode )
1262{
1263}
1264
1265bool wxDataViewDateCell::SetValue( const wxVariant &value )
1266{
1267 m_date = value.GetDateTime();
1268
1269 return true;
1270}
1271
1272bool 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
1281wxSize 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
1290bool wxDataViewDateCell::Activate( wxRect cell, wxDataViewListModel *model, size_t col, size_t row )
1291{
3f3af7e7
RR
1292 wxVariant variant;
1293 model->GetValue( variant, col, row );
7ea3a0de
RR
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 );
4d496ecb
RR
1302
1303 return true;
1304}
1305
605c2c4a
RR
1306// ---------------------------------------------------------
1307// wxDataViewColumn
1308// ---------------------------------------------------------
7b4fde82
RR
1309
1310extern "C" {
1311static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
1312 GtkCellRenderer *cell,
1313 GtkTreeModel *model,
1314 GtkTreeIter *iter,
1315 gpointer data );
1316}
1317
1318
1319static 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;
a7f61f76
RR
1329
1330 size_t model_row = (size_t) iter->user_data;
7b4fde82 1331
3f3af7e7
RR
1332 wxVariant value;
1333 list_store->model->GetValue( value, cell->GetOwner()->GetModelColumn(), model_row );
7b4fde82
RR
1334
1335 if (value.GetType() != cell->GetVariantType())
3f3af7e7 1336 wxLogError( wxT("Wrong type\n") );
7b4fde82
RR
1337
1338 cell->SetValue( value );
1339}
1340
fa28826d
RR
1341IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
1342
6842a71a
RR
1343wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewCell *cell,
1344 size_t model_column, int flags ) :
1345 wxDataViewColumnBase( title, cell, model_column, flags )
fa28826d 1346{
6842a71a 1347 GtkCellRenderer *renderer = (GtkCellRenderer *) cell->GetGtkHandle();
fa28826d 1348
6842a71a
RR
1349 GtkTreeViewColumn *column = gtk_tree_view_column_new();
1350
1351 gtk_tree_view_column_set_title( column, wxGTK_CONV(title) );
fa28826d 1352
6842a71a
RR
1353 gtk_tree_view_column_pack_start( column, renderer, TRUE );
1354
7b4fde82
RR
1355 gtk_tree_view_column_set_cell_data_func( column, renderer,
1356 wxGtkTreeCellDataFunc, (gpointer) cell, NULL );
6842a71a 1357
fa28826d
RR
1358 m_column = (void*) column;
1359}
1360
1361wxDataViewColumn::~wxDataViewColumn()
1362{
1363}
1364
1365void 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
790b137e
RR
1373//-----------------------------------------------------------------------------
1374// wxDataViewCtrl
1375//-----------------------------------------------------------------------------
1376
239eaa41
RR
1377IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
1378
1379wxDataViewCtrl::~wxDataViewCtrl()
1380{
8f850e28
RR
1381 if (m_notifier)
1382 GetModel()->RemoveNotifier( m_notifier );
239eaa41
RR
1383}
1384
1385void wxDataViewCtrl::Init()
1386{
8f850e28 1387 m_notifier = NULL;
239eaa41
RR
1388}
1389
1390bool 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 }
1a367564
RR
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);
239eaa41 1411
1a367564
RR
1412 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_widget),
1413 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1414 gtk_widget_show (m_treeview);
239eaa41
RR
1415
1416 m_parent->DoAddChild( this );
1417
1418 PostCreation(size);
1419
1420 return true;
1421}
1422
6e2e590f 1423bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model )
239eaa41
RR
1424{
1425 if (!wxDataViewCtrlBase::AssociateModel( model ))
1426 return false;
1427
6e2e590f
RR
1428 GtkWxListStore *gtk_store = wxgtk_list_store_new();
1429 gtk_store->model = model;
1430
8f850e28 1431 m_notifier = new wxGtkDataViewListModelNotifier( gtk_store, model );
6e2e590f 1432
8f850e28 1433 model->AddNotifier( m_notifier );
1557c77b 1434
1a367564
RR
1435 gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview), GTK_TREE_MODEL(gtk_store) );
1436 g_object_unref( gtk_store );
239eaa41
RR
1437
1438 return true;
1439}
790b137e 1440
fa28826d
RR
1441bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
1442{
1443 if (!wxDataViewCtrlBase::AppendColumn(col))
1444 return false;
1445
1446 GtkTreeViewColumn *column = (GtkTreeViewColumn *)col->GetGtkHandle();
1447
1a367564 1448 gtk_tree_view_append_column( GTK_TREE_VIEW(m_treeview), column );
fa28826d
RR
1449
1450 return true;
1451}
1452
790b137e
RR
1453
1454#endif // wxUSE_DATAVIEWCTRL
1455