]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/dataview.cpp
Implemented and tested EXPANDED etc events for wxGTK and in the sample
[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 #include "wx/list.h"
30 #include "wx/listimpl.cpp"
31
32
33 #include "wx/gtk/private.h"
34 #include "wx/gtk/win_gtk.h"
35
36 #include <gobject/gvaluecollector.h>
37 #include <gtk/gtktreemodel.h>
38 #include <gtk/gtktreesortable.h>
39 #include <gtk/gtktreednd.h>
40
41 #include <gdk/gdkkeysyms.h>
42
43 //-----------------------------------------------------------------------------
44 //-----------------------------------------------------------------------------
45
46 class wxDataViewCtrlInternal;
47
48 wxDataViewCtrlInternal *g_internal = NULL;
49
50 class wxGtkTreeModelNode;
51
52 extern "C" {
53 typedef struct _GtkWxTreeModel GtkWxTreeModel;
54 }
55
56 //-----------------------------------------------------------------------------
57 // wxDataViewCtrlInternal
58 //-----------------------------------------------------------------------------
59
60 WX_DECLARE_LIST(wxDataViewItem, ItemList);
61 WX_DEFINE_LIST(ItemList);
62
63 class wxDataViewCtrlInternal
64 {
65 public:
66 wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataViewModel *wx_model, GtkWxTreeModel *owner );
67 ~wxDataViewCtrlInternal();
68
69 gboolean get_iter( GtkTreeIter *iter, GtkTreePath *path );
70 GtkTreePath *get_path( GtkTreeIter *iter);
71 GtkTreePath *get_path_safe( GtkTreeIter *iter);
72 gboolean iter_next( GtkTreeIter *iter );
73 gboolean iter_children( GtkTreeIter *iter, GtkTreeIter *parent);
74 gboolean iter_has_child( GtkTreeIter *iter );
75 gint iter_n_children( GtkTreeIter *iter );
76 gboolean iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n );
77 gboolean iter_parent( GtkTreeIter *iter, GtkTreeIter *child );
78
79 wxDataViewModel* GetDataViewModel() { return m_wx_model; }
80 wxDataViewCtrl* GetOwner() { return m_owner; }
81 GtkWxTreeModel* GetGtkModel() { return m_gtk_model; }
82
83 bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
84 bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
85 bool ItemChanged( const wxDataViewItem &item );
86 bool ValueChanged( const wxDataViewItem &item, unsigned int col );
87 bool Cleared();
88 void Resort();
89
90 void SetSortOrder( GtkSortType sort_order ) { m_sort_order = sort_order; }
91 GtkSortType GetSortOrder() { return m_sort_order; }
92
93 void SetSortColumn( unsigned int column ) { m_sort_column = column; }
94 unsigned int GetSortColumn() { return m_sort_column; }
95
96 protected:
97 void InitTree();
98 wxGtkTreeModelNode *FindNode( const wxDataViewItem &item );
99 wxGtkTreeModelNode *FindNode( GtkTreeIter *iter );
100 wxGtkTreeModelNode *FindParentNode( const wxDataViewItem &item );
101 wxGtkTreeModelNode *FindParentNode( GtkTreeIter *iter );
102 void BuildBranch( wxGtkTreeModelNode *branch );
103
104 private:
105 wxGtkTreeModelNode *m_root;
106 wxDataViewModel *m_wx_model;
107 GtkWxTreeModel *m_gtk_model;
108 wxDataViewCtrl *m_owner;
109 GtkSortType m_sort_order;
110 unsigned int m_sort_column;
111 };
112
113
114 //-----------------------------------------------------------------------------
115 // wxGtkTreeModelNode
116 //-----------------------------------------------------------------------------
117
118 int LINKAGEMODE wxGtkTreeModelNodeCmp( void *id1, void *id2 );
119
120 WX_DEFINE_ARRAY_PTR( wxGtkTreeModelNode*, wxGtkTreeModelNodes );
121 WX_DEFINE_SORTED_ARRAY( void* , wxGtkTreeModelChildren );
122
123 class wxGtkTreeModelNode
124 {
125 public:
126 wxGtkTreeModelNode( wxGtkTreeModelNode* parent, const wxDataViewItem &item,
127 wxDataViewCtrlInternal *internal )
128 {
129 m_parent = parent;
130 m_item = item;
131 m_internal = internal;
132 g_internal = internal;
133 m_children = new wxGtkTreeModelChildren( wxGtkTreeModelNodeCmp );
134 }
135
136 ~wxGtkTreeModelNode()
137 {
138 g_internal = m_internal;
139 size_t count = m_children->GetCount();
140 size_t i;
141 for (i = 0; i < count; i++)
142 {
143 wxGtkTreeModelNode *child = m_nodes.Item( i );
144 delete child;
145 }
146 delete m_children;
147 }
148
149 unsigned int AddNode( wxGtkTreeModelNode* child )
150 {
151 g_internal = m_internal;
152 m_nodes.Add( child );
153 return m_children->Add( child->GetItem().GetID() );
154 }
155
156 unsigned int AddLeave( void* id )
157 {
158 g_internal = m_internal;
159 return m_children->Add( id );
160 }
161
162 void DeleteChild( void* id )
163 {
164 g_internal = m_internal;
165 size_t pos;
166 size_t count = m_children->GetCount();
167 for (pos = 0; pos < count; pos++)
168 {
169 if (m_children->Item( pos ) == id)
170 {
171 m_children->RemoveAt( pos );
172 break;
173 }
174 }
175 count = m_nodes.GetCount();
176 for (pos = 0; pos < count; pos++)
177 {
178 wxGtkTreeModelNode *node = m_nodes.Item( pos );
179 if (node->GetItem().GetID() == id)
180 {
181 m_nodes.RemoveAt( pos );
182 delete node;
183 break;
184 }
185 }
186
187 }
188
189 wxGtkTreeModelNode* GetParent()
190 { return m_parent; }
191 wxGtkTreeModelNodes &GetNodes()
192 { return m_nodes; }
193 wxGtkTreeModelChildren &GetChildren()
194 { return *m_children; }
195
196 unsigned int GetChildCount() { return m_children->GetCount(); }
197 unsigned int GetNodesCount() { return m_nodes.GetCount(); }
198
199 wxDataViewItem &GetItem() { return m_item; }
200 wxDataViewCtrlInternal *GetInternal() { return m_internal; }
201
202 void Resort();
203
204 private:
205 wxGtkTreeModelNode *m_parent;
206 wxGtkTreeModelNodes m_nodes;
207 wxGtkTreeModelChildren *m_children;
208 wxDataViewItem m_item;
209 wxDataViewCtrlInternal *m_internal;
210 };
211
212
213 int LINKAGEMODE wxGtkTreeModelNodeCmp( void* id1, void* id2 )
214 {
215 int ret = g_internal->GetDataViewModel()->Compare( id1, id2,
216 g_internal->GetSortColumn(), (g_internal->GetSortOrder() == GTK_SORT_ASCENDING) );
217
218 return ret;
219 }
220
221 //-----------------------------------------------------------------------------
222 // data
223 //-----------------------------------------------------------------------------
224
225 extern bool g_blockEventsOnDrag;
226
227 //-----------------------------------------------------------------------------
228 // define new GTK+ class wxGtkTreeModel
229 //-----------------------------------------------------------------------------
230
231 extern "C" {
232
233 #define GTK_TYPE_WX_TREE_MODEL (gtk_wx_tree_model_get_type ())
234 #define GTK_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModel))
235 #define GTK_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
236 #define GTK_IS_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_TREE_MODEL))
237 #define GTK_IS_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_TREE_MODEL))
238 #define GTK_WX_TREE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
239
240 GType gtk_wx_tree_model_get_type (void);
241
242 typedef struct _GtkWxTreeModelClass GtkWxTreeModelClass;
243
244 struct _GtkWxTreeModel
245 {
246 GObject parent;
247
248 /*< private >*/
249 gint stamp;
250 wxDataViewCtrlInternal *internal;
251 };
252
253 struct _GtkWxTreeModelClass
254 {
255 GObjectClass list_parent_class;
256 };
257
258 static GtkWxTreeModel *wxgtk_tree_model_new (void);
259 static void wxgtk_tree_model_init (GtkWxTreeModel *tree_model);
260 static void wxgtk_tree_model_class_init (GtkWxTreeModelClass *klass);
261 static void wxgtk_tree_model_tree_model_init (GtkTreeModelIface *iface);
262 static void wxgtk_tree_model_sortable_init (GtkTreeSortableIface *iface);
263 static void wxgtk_tree_model_finalize (GObject *object);
264 static GtkTreeModelFlags wxgtk_tree_model_get_flags (GtkTreeModel *tree_model);
265 static gint wxgtk_tree_model_get_n_columns (GtkTreeModel *tree_model);
266 static GType wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model,
267 gint index);
268 static gboolean wxgtk_tree_model_get_iter (GtkTreeModel *tree_model,
269 GtkTreeIter *iter,
270 GtkTreePath *path);
271 static GtkTreePath *wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
272 GtkTreeIter *iter);
273 static GtkTreePath *wxgtk_tree_model_get_path_safe (GtkTreeModel *tree_model,
274 GtkTreeIter *iter);
275 static void wxgtk_tree_model_get_value (GtkTreeModel *tree_model,
276 GtkTreeIter *iter,
277 gint column,
278 GValue *value);
279 static gboolean wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
280 GtkTreeIter *iter);
281 static gboolean wxgtk_tree_model_iter_children (GtkTreeModel *tree_model,
282 GtkTreeIter *iter,
283 GtkTreeIter *parent);
284 static gboolean wxgtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
285 GtkTreeIter *iter);
286 static gint wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
287 GtkTreeIter *iter);
288 static gboolean wxgtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
289 GtkTreeIter *iter,
290 GtkTreeIter *parent,
291 gint n);
292 static gboolean wxgtk_tree_model_iter_parent (GtkTreeModel *tree_model,
293 GtkTreeIter *iter,
294 GtkTreeIter *child);
295
296 /* sortable */
297 static gboolean wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
298 gint *sort_column_id,
299 GtkSortType *order);
300 static void wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
301 gint sort_column_id,
302 GtkSortType order);
303 static void wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable,
304 gint sort_column_id,
305 GtkTreeIterCompareFunc func,
306 gpointer data,
307 GtkDestroyNotify destroy);
308 static void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable,
309 GtkTreeIterCompareFunc func,
310 gpointer data,
311 GtkDestroyNotify destroy);
312 static gboolean wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable);
313
314
315
316 static GObjectClass *list_parent_class = NULL;
317
318 GType
319 gtk_wx_tree_model_get_type (void)
320 {
321 static GType tree_model_type = 0;
322
323 if (!tree_model_type)
324 {
325 const GTypeInfo tree_model_info =
326 {
327 sizeof (GtkWxTreeModelClass),
328 NULL, /* base_init */
329 NULL, /* base_finalize */
330 (GClassInitFunc) wxgtk_tree_model_class_init,
331 NULL, /* class_finalize */
332 NULL, /* class_data */
333 sizeof (GtkWxTreeModel),
334 0,
335 (GInstanceInitFunc) wxgtk_tree_model_init,
336 };
337
338 static const GInterfaceInfo tree_model_iface_info =
339 {
340 (GInterfaceInitFunc) wxgtk_tree_model_tree_model_init,
341 NULL,
342 NULL
343 };
344
345 static const GInterfaceInfo sortable_iface_info =
346 {
347 (GInterfaceInitFunc) wxgtk_tree_model_sortable_init,
348 NULL,
349 NULL
350 };
351
352 tree_model_type = g_type_register_static (G_TYPE_OBJECT, "GtkWxTreeModel",
353 &tree_model_info, (GTypeFlags)0 );
354
355 g_type_add_interface_static (tree_model_type,
356 GTK_TYPE_TREE_MODEL,
357 &tree_model_iface_info);
358 g_type_add_interface_static (tree_model_type,
359 GTK_TYPE_TREE_SORTABLE,
360 &sortable_iface_info);
361 }
362
363 return tree_model_type;
364 }
365
366 static GtkWxTreeModel *
367 wxgtk_tree_model_new(void)
368 {
369 GtkWxTreeModel *retval = (GtkWxTreeModel *) g_object_new (GTK_TYPE_WX_TREE_MODEL, NULL);
370 return retval;
371 }
372
373 static void
374 wxgtk_tree_model_class_init (GtkWxTreeModelClass *klass)
375 {
376 list_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
377 GObjectClass *object_class = (GObjectClass*) klass;
378 object_class->finalize = wxgtk_tree_model_finalize;
379 }
380
381 static void
382 wxgtk_tree_model_tree_model_init (GtkTreeModelIface *iface)
383 {
384 iface->get_flags = wxgtk_tree_model_get_flags;
385 iface->get_n_columns = wxgtk_tree_model_get_n_columns;
386 iface->get_column_type = wxgtk_tree_model_get_column_type;
387 iface->get_iter = wxgtk_tree_model_get_iter;
388 iface->get_path = wxgtk_tree_model_get_path;
389 iface->get_value = wxgtk_tree_model_get_value;
390 iface->iter_next = wxgtk_tree_model_iter_next;
391 iface->iter_children = wxgtk_tree_model_iter_children;
392 iface->iter_has_child = wxgtk_tree_model_iter_has_child;
393 iface->iter_n_children = wxgtk_tree_model_iter_n_children;
394 iface->iter_nth_child = wxgtk_tree_model_iter_nth_child;
395 iface->iter_parent = wxgtk_tree_model_iter_parent;
396 }
397
398 static void
399 wxgtk_tree_model_sortable_init (GtkTreeSortableIface *iface)
400 {
401 iface->get_sort_column_id = wxgtk_tree_model_get_sort_column_id;
402 iface->set_sort_column_id = wxgtk_tree_model_set_sort_column_id;
403 iface->set_sort_func = wxgtk_tree_model_set_sort_func;
404 iface->set_default_sort_func = wxgtk_tree_model_set_default_sort_func;
405 iface->has_default_sort_func = wxgtk_tree_model_has_default_sort_func;
406 }
407
408 static void
409 wxgtk_tree_model_init (GtkWxTreeModel *tree_model)
410 {
411 tree_model->internal = NULL;
412 tree_model->stamp = g_random_int();
413 }
414
415 static void
416 wxgtk_tree_model_finalize (GObject *object)
417 {
418 /* must chain up */
419 (* list_parent_class->finalize) (object);
420 }
421
422 } // extern "C"
423
424 //-----------------------------------------------------------------------------
425 // implement callbacks from wxGtkTreeModel class by letting
426 // them call the methods of wxWidgets' wxDataViewModel
427 //-----------------------------------------------------------------------------
428
429 static GtkTreeModelFlags
430 wxgtk_tree_model_get_flags (GtkTreeModel *tree_model)
431 {
432 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (tree_model), (GtkTreeModelFlags)0 );
433
434 return GTK_TREE_MODEL_ITERS_PERSIST;
435 }
436
437 static gint
438 wxgtk_tree_model_get_n_columns (GtkTreeModel *tree_model)
439 {
440 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
441 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), 0);
442
443 return wxtree_model->internal->GetDataViewModel()->GetColumnCount();
444 }
445
446 static GType
447 wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model,
448 gint index)
449 {
450 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
451 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), G_TYPE_INVALID);
452
453 GType gtype = G_TYPE_INVALID;
454
455 wxString wxtype = wxtree_model->internal->GetDataViewModel()->GetColumnType( (unsigned int) index );
456
457 if (wxtype == wxT("string"))
458 gtype = G_TYPE_STRING;
459 else
460 {
461 wxFAIL_MSG( _T("non-string columns not supported yet") );
462 }
463
464 return gtype;
465 }
466
467 static gboolean
468 wxgtk_tree_model_get_iter (GtkTreeModel *tree_model,
469 GtkTreeIter *iter,
470 GtkTreePath *path)
471 {
472 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
473 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
474 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
475
476 return wxtree_model->internal->get_iter( iter, path );
477 }
478
479 static GtkTreePath *
480 wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
481 GtkTreeIter *iter)
482 {
483 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
484 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), NULL);
485 g_return_val_if_fail (iter->stamp == GTK_WX_TREE_MODEL (wxtree_model)->stamp, NULL);
486
487 return wxtree_model->internal->get_path( iter );
488 }
489
490 static GtkTreePath *
491 wxgtk_tree_model_get_path_safe (GtkTreeModel *tree_model,
492 GtkTreeIter *iter)
493 {
494 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
495 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), NULL);
496 g_return_val_if_fail (iter->stamp == GTK_WX_TREE_MODEL (wxtree_model)->stamp, NULL);
497
498 return wxtree_model->internal->get_path_safe( iter );
499 }
500
501 static void
502 wxgtk_tree_model_get_value (GtkTreeModel *tree_model,
503 GtkTreeIter *iter,
504 gint column,
505 GValue *value)
506 {
507 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
508 g_return_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model) );
509
510 wxDataViewModel *model = wxtree_model->internal->GetDataViewModel();
511 wxString mtype = model->GetColumnType( (unsigned int) column );
512 if (mtype == wxT("string"))
513 {
514 wxVariant variant;
515 g_value_init( value, G_TYPE_STRING );
516 wxDataViewItem item( (void*) iter->user_data );
517 model->GetValue( variant, item, (unsigned int) column );
518
519 g_value_set_string( value, variant.GetString().utf8_str() );
520 }
521 else
522 {
523 wxFAIL_MSG( _T("non-string columns not supported yet") );
524 }
525 }
526
527 static gboolean
528 wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
529 GtkTreeIter *iter)
530 {
531 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
532 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
533 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
534
535 return wxtree_model->internal->iter_next( iter );
536 }
537
538 static gboolean
539 wxgtk_tree_model_iter_children (GtkTreeModel *tree_model,
540 GtkTreeIter *iter,
541 GtkTreeIter *parent)
542 {
543 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
544 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
545 g_return_val_if_fail (wxtree_model->stamp == parent->stamp, FALSE);
546
547 return wxtree_model->internal->iter_children( iter, parent );
548 }
549
550 static gboolean
551 wxgtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
552 GtkTreeIter *iter)
553 {
554 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
555 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
556 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
557
558 return wxtree_model->internal->iter_has_child( iter );
559 }
560
561 static gint
562 wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
563 GtkTreeIter *iter)
564 {
565 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
566 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
567 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, 0);
568
569 return wxtree_model->internal->iter_n_children( iter );
570 }
571
572 static gboolean
573 wxgtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
574 GtkTreeIter *iter,
575 GtkTreeIter *parent,
576 gint n)
577 {
578 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
579 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
580
581 return wxtree_model->internal->iter_nth_child( iter, parent, n );
582 }
583
584 static gboolean
585 wxgtk_tree_model_iter_parent (GtkTreeModel *tree_model,
586 GtkTreeIter *iter,
587 GtkTreeIter *child)
588 {
589 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
590 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
591 g_return_val_if_fail (wxtree_model->stamp == child->stamp, FALSE);
592
593 return wxtree_model->internal->iter_parent( iter, child );
594 }
595
596 /* sortable */
597 gboolean wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
598 gint *sort_column_id,
599 GtkSortType *order)
600 {
601 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) sortable;
602
603 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (sortable), FALSE);
604
605 if (sort_column_id)
606 *sort_column_id = tree_model->internal->GetSortColumn();
607
608 if (order)
609 *order = tree_model->internal->GetSortOrder();
610
611 return TRUE;
612 }
613
614 void wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
615 gint sort_column_id,
616 GtkSortType order)
617 {
618 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) sortable;
619 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
620
621 if ((sort_column_id == (gint) tree_model->internal->GetSortColumn()) &&
622 (order == tree_model->internal->GetSortOrder()))
623 return;
624
625 tree_model->internal->SetSortColumn( sort_column_id );
626
627 tree_model->internal->SetSortOrder( order );
628
629 gtk_tree_sortable_sort_column_changed (sortable);
630
631 tree_model->internal->GetDataViewModel()->Resort();
632 }
633
634 void wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable,
635 gint sort_column_id,
636 GtkTreeIterCompareFunc func,
637 gpointer data,
638 GtkDestroyNotify destroy)
639 {
640 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
641 g_return_if_fail (func != NULL);
642 }
643
644 void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable,
645 GtkTreeIterCompareFunc func,
646 gpointer data,
647 GtkDestroyNotify destroy)
648 {
649 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
650 g_return_if_fail (func != NULL);
651
652 wxPrintf( "wxgtk_tree_model_set_default_sort_func\n" );
653 }
654
655 gboolean wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable)
656 {
657 return FALSE;
658 }
659
660 //-----------------------------------------------------------------------------
661 // define new GTK+ class wxGtkRendererRenderer
662 //-----------------------------------------------------------------------------
663
664 extern "C" {
665
666 #define GTK_TYPE_WX_CELL_RENDERER (gtk_wx_cell_renderer_get_type ())
667 #define GTK_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRenderer))
668 #define GTK_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
669 #define GTK_IS_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_CELL_RENDERER))
670 #define GTK_IS_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_CELL_RENDERER))
671 #define GTK_WX_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
672
673 GType gtk_wx_cell_renderer_get_type (void);
674
675 typedef struct _GtkWxCellRenderer GtkWxCellRenderer;
676 typedef struct _GtkWxCellRendererClass GtkWxCellRendererClass;
677
678 struct _GtkWxCellRenderer
679 {
680 GtkCellRenderer parent;
681
682 /*< private >*/
683 wxDataViewCustomRenderer *cell;
684 guint32 last_click;
685 };
686
687 struct _GtkWxCellRendererClass
688 {
689 GtkCellRendererClass cell_parent_class;
690 };
691
692
693 static GtkCellRenderer *gtk_wx_cell_renderer_new (void);
694 static void gtk_wx_cell_renderer_init (
695 GtkWxCellRenderer *cell );
696 static void gtk_wx_cell_renderer_class_init(
697 GtkWxCellRendererClass *klass );
698 static void gtk_wx_cell_renderer_finalize (
699 GObject *object );
700 static void gtk_wx_cell_renderer_get_size (
701 GtkCellRenderer *cell,
702 GtkWidget *widget,
703 GdkRectangle *rectangle,
704 gint *x_offset,
705 gint *y_offset,
706 gint *width,
707 gint *height );
708 static void gtk_wx_cell_renderer_render (
709 GtkCellRenderer *cell,
710 GdkWindow *window,
711 GtkWidget *widget,
712 GdkRectangle *background_area,
713 GdkRectangle *cell_area,
714 GdkRectangle *expose_area,
715 GtkCellRendererState flags );
716 static gboolean gtk_wx_cell_renderer_activate(
717 GtkCellRenderer *cell,
718 GdkEvent *event,
719 GtkWidget *widget,
720 const gchar *path,
721 GdkRectangle *background_area,
722 GdkRectangle *cell_area,
723 GtkCellRendererState flags );
724 static GtkCellEditable *gtk_wx_cell_renderer_start_editing(
725 GtkCellRenderer *cell,
726 GdkEvent *event,
727 GtkWidget *widget,
728 const gchar *path,
729 GdkRectangle *background_area,
730 GdkRectangle *cell_area,
731 GtkCellRendererState flags );
732
733
734 static GObjectClass *cell_parent_class = NULL;
735
736 } // extern "C"
737
738 GType
739 gtk_wx_cell_renderer_get_type (void)
740 {
741 static GType cell_wx_type = 0;
742
743 if (!cell_wx_type)
744 {
745 const GTypeInfo cell_wx_info =
746 {
747 sizeof (GtkWxCellRendererClass),
748 NULL, /* base_init */
749 NULL, /* base_finalize */
750 (GClassInitFunc) gtk_wx_cell_renderer_class_init,
751 NULL, /* class_finalize */
752 NULL, /* class_data */
753 sizeof (GtkWxCellRenderer),
754 0, /* n_preallocs */
755 (GInstanceInitFunc) gtk_wx_cell_renderer_init,
756 };
757
758 cell_wx_type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
759 "GtkWxCellRenderer", &cell_wx_info, (GTypeFlags)0 );
760 }
761
762 return cell_wx_type;
763 }
764
765 static void
766 gtk_wx_cell_renderer_init (GtkWxCellRenderer *cell)
767 {
768 cell->cell = NULL;
769 cell->last_click = 0;
770 }
771
772 static void
773 gtk_wx_cell_renderer_class_init (GtkWxCellRendererClass *klass)
774 {
775 GObjectClass *object_class = G_OBJECT_CLASS (klass);
776 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
777
778 cell_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
779
780 object_class->finalize = gtk_wx_cell_renderer_finalize;
781
782 cell_class->get_size = gtk_wx_cell_renderer_get_size;
783 cell_class->render = gtk_wx_cell_renderer_render;
784 cell_class->activate = gtk_wx_cell_renderer_activate;
785 cell_class->start_editing = gtk_wx_cell_renderer_start_editing;
786 }
787
788 static void
789 gtk_wx_cell_renderer_finalize (GObject *object)
790 {
791 /* must chain up */
792 (* G_OBJECT_CLASS (cell_parent_class)->finalize) (object);
793 }
794
795 GtkCellRenderer*
796 gtk_wx_cell_renderer_new (void)
797 {
798 return (GtkCellRenderer*) g_object_new (GTK_TYPE_WX_CELL_RENDERER, NULL);
799 }
800
801
802
803 static GtkCellEditable *gtk_wx_cell_renderer_start_editing(
804 GtkCellRenderer *renderer,
805 GdkEvent *event,
806 GtkWidget *widget,
807 const gchar *path,
808 GdkRectangle *background_area,
809 GdkRectangle *cell_area,
810 GtkCellRendererState flags )
811 {
812 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
813 wxDataViewCustomRenderer *cell = wxrenderer->cell;
814 if (!cell->HasEditorCtrl())
815 return NULL;
816
817 GdkRectangle rect;
818 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
819 &rect.x,
820 &rect.y,
821 &rect.width,
822 &rect.height);
823
824 rect.x += cell_area->x;
825 rect.y += cell_area->y;
826 // rect.width -= renderer->xpad * 2;
827 // rect.height -= renderer->ypad * 2;
828
829 // wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
830 wxRect renderrect( cell_area->x, cell_area->y, cell_area->width, cell_area->height );
831
832 GtkTreePath *treepath = gtk_tree_path_new_from_string( path );
833 GtkTreeIter iter;
834 cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, treepath );
835 wxDataViewItem item( (void*) iter.user_data );
836 gtk_tree_path_free( treepath );
837
838 cell->StartEditing( item, renderrect );
839
840 return NULL;
841 }
842
843 static void
844 gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer,
845 GtkWidget *widget,
846 GdkRectangle *cell_area,
847 gint *x_offset,
848 gint *y_offset,
849 gint *width,
850 gint *height)
851 {
852 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
853 wxDataViewCustomRenderer *cell = wxrenderer->cell;
854
855 wxSize size = cell->GetSize();
856
857 gint calc_width = (gint) renderer->xpad * 2 + size.x;
858 gint calc_height = (gint) renderer->ypad * 2 + size.y;
859
860 if (x_offset)
861 *x_offset = 0;
862 if (y_offset)
863 *y_offset = 0;
864
865 if (cell_area && size.x > 0 && size.y > 0)
866 {
867 if (x_offset)
868 {
869 *x_offset = (gint)((renderer->xalign *
870 (cell_area->width - calc_width - 2 * renderer->xpad)));
871 *x_offset = MAX (*x_offset, 0) + renderer->xpad;
872 }
873 if (y_offset)
874 {
875 *y_offset = (gint)((renderer->yalign *
876 (cell_area->height - calc_height - 2 * renderer->ypad)));
877 *y_offset = MAX (*y_offset, 0) + renderer->ypad;
878 }
879 }
880
881 if (width)
882 *width = calc_width;
883
884 if (height)
885 *height = calc_height;
886 }
887
888 static void
889 gtk_wx_cell_renderer_render (GtkCellRenderer *renderer,
890 GdkWindow *window,
891 GtkWidget *widget,
892 GdkRectangle *background_area,
893 GdkRectangle *cell_area,
894 GdkRectangle *expose_area,
895 GtkCellRendererState flags)
896
897 {
898 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
899 wxDataViewCustomRenderer *cell = wxrenderer->cell;
900
901 GdkRectangle rect;
902 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
903 &rect.x,
904 &rect.y,
905 &rect.width,
906 &rect.height);
907
908 rect.x += cell_area->x;
909 rect.y += cell_area->y;
910 rect.width -= renderer->xpad * 2;
911 rect.height -= renderer->ypad * 2;
912
913 GdkRectangle dummy;
914 if (gdk_rectangle_intersect (expose_area, &rect, &dummy))
915 {
916 wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
917 wxWindowDC* dc = (wxWindowDC*) cell->GetDC();
918 if (dc->m_window == NULL)
919 {
920 dc->m_window = window;
921 dc->SetUpDC();
922 }
923
924 int state = 0;
925 if (flags & GTK_CELL_RENDERER_SELECTED)
926 state |= wxDATAVIEW_CELL_SELECTED;
927 if (flags & GTK_CELL_RENDERER_PRELIT)
928 state |= wxDATAVIEW_CELL_PRELIT;
929 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
930 state |= wxDATAVIEW_CELL_INSENSITIVE;
931 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
932 state |= wxDATAVIEW_CELL_INSENSITIVE;
933 if (flags & GTK_CELL_RENDERER_FOCUSED)
934 state |= wxDATAVIEW_CELL_FOCUSED;
935 cell->Render( renderrect, dc, state );
936 }
937 }
938
939 static gboolean
940 gtk_wx_cell_renderer_activate(
941 GtkCellRenderer *renderer,
942 GdkEvent *event,
943 GtkWidget *widget,
944 const gchar *path,
945 GdkRectangle *background_area,
946 GdkRectangle *cell_area,
947 GtkCellRendererState flags )
948 {
949 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
950 wxDataViewCustomRenderer *cell = wxrenderer->cell;
951
952 GdkRectangle rect;
953 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
954 &rect.x,
955 &rect.y,
956 &rect.width,
957 &rect.height);
958
959 rect.x += cell_area->x;
960 rect.y += cell_area->y;
961 rect.width -= renderer->xpad * 2;
962 rect.height -= renderer->ypad * 2;
963
964 wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
965
966 wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel();
967
968 GtkTreePath *treepath = gtk_tree_path_new_from_string( path );
969 // TODO
970 wxDataViewItem item;
971 gtk_tree_path_free( treepath );
972
973 unsigned int model_col = cell->GetOwner()->GetModelColumn();
974
975 if (!event)
976 {
977 bool ret = false;
978
979 // activated by <ENTER>
980 if (cell->Activate( renderrect, model, item, model_col ))
981 ret = true;
982
983 return ret;
984 }
985 else if (event->type == GDK_BUTTON_PRESS)
986 {
987 GdkEventButton *button_event = (GdkEventButton*) event;
988 wxPoint pt( ((int) button_event->x) - renderrect.x,
989 ((int) button_event->y) - renderrect.y );
990
991 bool ret = false;
992 if (button_event->button == 1)
993 {
994 if (cell->LeftClick( pt, renderrect, model, item, model_col ))
995 ret = true;
996 // TODO: query system double-click time
997 if (button_event->time - wxrenderer->last_click < 400)
998 if (cell->Activate( renderrect, model, item, model_col ))
999 ret = true;
1000 }
1001 if (button_event->button == 3)
1002 {
1003 if (cell->RightClick( pt, renderrect, model, item, model_col ))
1004 ret = true;
1005 }
1006
1007 wxrenderer->last_click = button_event->time;
1008
1009 return ret;
1010 }
1011
1012 return false;
1013 }
1014
1015 // ---------------------------------------------------------
1016 // wxGtkDataViewModelNotifier
1017 // ---------------------------------------------------------
1018
1019 class wxGtkDataViewModelNotifier: public wxDataViewModelNotifier
1020 {
1021 public:
1022 wxGtkDataViewModelNotifier( GtkWxTreeModel *wxgtk_model,
1023 wxDataViewModel *wx_model,
1024 wxDataViewCtrl *ctrl );
1025 ~wxGtkDataViewModelNotifier();
1026
1027 virtual bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
1028 virtual bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
1029 virtual bool ItemChanged( const wxDataViewItem &item );
1030 virtual bool ValueChanged( const wxDataViewItem &item, unsigned int col );
1031 virtual bool Cleared();
1032 virtual void Resort();
1033
1034 GtkWxTreeModel *m_wxgtk_model;
1035 wxDataViewModel *m_wx_model;
1036 wxDataViewCtrl *m_owner;
1037 };
1038
1039 // ---------------------------------------------------------
1040 // wxGtkDataViewListModelNotifier
1041 // ---------------------------------------------------------
1042
1043 wxGtkDataViewModelNotifier::wxGtkDataViewModelNotifier(
1044 GtkWxTreeModel* wxgtk_model, wxDataViewModel *wx_model,
1045 wxDataViewCtrl *ctrl )
1046 {
1047 m_wxgtk_model = wxgtk_model;
1048 m_wx_model = wx_model;
1049 m_owner = ctrl;
1050 }
1051
1052 wxGtkDataViewModelNotifier::~wxGtkDataViewModelNotifier()
1053 {
1054 m_wx_model = NULL;
1055 m_wxgtk_model = NULL;
1056 }
1057
1058 bool wxGtkDataViewModelNotifier::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
1059 {
1060 m_owner->GtkGetInternal()->ItemAdded( parent, item );
1061
1062 GtkTreeIter iter;
1063 iter.stamp = m_wxgtk_model->stamp;
1064 iter.user_data = (gpointer) item.GetID();
1065
1066 GtkTreePath *path = wxgtk_tree_model_get_path(
1067 GTK_TREE_MODEL(m_wxgtk_model), &iter );
1068 gtk_tree_model_row_inserted(
1069 GTK_TREE_MODEL(m_wxgtk_model), path, &iter);
1070 gtk_tree_path_free (path);
1071
1072 return true;
1073 }
1074
1075 bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
1076 {
1077 GtkTreeIter iter;
1078 iter.stamp = m_wxgtk_model->stamp;
1079 iter.user_data = (gpointer) item.GetID();
1080
1081 GtkTreePath *path = wxgtk_tree_model_get_path_safe(
1082 GTK_TREE_MODEL(m_wxgtk_model), &iter );
1083 gtk_tree_model_row_deleted(
1084 GTK_TREE_MODEL(m_wxgtk_model), path );
1085 gtk_tree_path_free (path);
1086
1087 m_owner->GtkGetInternal()->ItemDeleted( parent, item );
1088
1089 return true;
1090 }
1091
1092 void wxGtkDataViewModelNotifier::Resort()
1093 {
1094 m_owner->GtkGetInternal()->Resort();
1095 }
1096
1097 bool wxGtkDataViewModelNotifier::ItemChanged( const wxDataViewItem &item )
1098 {
1099 GtkTreeIter iter;
1100 iter.stamp = m_wxgtk_model->stamp;
1101 iter.user_data = (gpointer) item.GetID();
1102
1103 GtkTreePath *path = wxgtk_tree_model_get_path(
1104 GTK_TREE_MODEL(m_wxgtk_model), &iter );
1105 gtk_tree_model_row_changed(
1106 GTK_TREE_MODEL(m_wxgtk_model), path, &iter );
1107 gtk_tree_path_free (path);
1108
1109 m_owner->GtkGetInternal()->ItemChanged( item );
1110
1111 return true;
1112 }
1113
1114 bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsigned int model_col )
1115 {
1116 // This adds GTK+'s missing MVC logic for ValueChanged
1117 unsigned int index;
1118 for (index = 0; index < m_owner->GetColumnCount(); index++)
1119 {
1120 wxDataViewColumn *column = m_owner->GetColumn( index );
1121 if (column->GetModelColumn() == model_col)
1122 {
1123 GtkTreeView *widget = GTK_TREE_VIEW(m_owner->m_treeview);
1124 GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle());
1125
1126 // Get cell area
1127 GtkTreeIter iter;
1128 iter.stamp = m_wxgtk_model->stamp;
1129 iter.user_data = (gpointer) item.GetID();
1130 GtkTreePath *path = wxgtk_tree_model_get_path(
1131 GTK_TREE_MODEL(m_wxgtk_model), &iter );
1132 GdkRectangle cell_area;
1133 gtk_tree_view_get_cell_area( widget, path, gcolumn, &cell_area );
1134 gtk_tree_path_free( path );
1135
1136 GtkAdjustment* hadjust = gtk_tree_view_get_hadjustment( widget );
1137 double d = gtk_adjustment_get_value( hadjust );
1138 int xdiff = (int) d;
1139
1140 int ydiff = gcolumn->button->allocation.height;
1141 // Redraw
1142 gtk_widget_queue_draw_area( GTK_WIDGET(widget),
1143 cell_area.x - xdiff, ydiff + cell_area.y, cell_area.width, cell_area.height );
1144
1145 m_owner->GtkGetInternal()->ValueChanged( item, model_col );
1146
1147 return true;
1148 }
1149 }
1150
1151 return false;
1152 }
1153
1154 bool wxGtkDataViewModelNotifier::Cleared()
1155 {
1156 // TODO: delete everything
1157
1158 m_owner->GtkGetInternal()->Cleared();
1159
1160 return false;
1161 }
1162
1163 // ---------------------------------------------------------
1164 // wxDataViewRenderer
1165 // ---------------------------------------------------------
1166
1167 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
1168
1169 wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1170 int align ) :
1171 wxDataViewRendererBase( varianttype, mode, align )
1172 {
1173 m_renderer = NULL;
1174
1175 // NOTE: SetMode() and SetAlignment() needs to be called in the renderer's ctor,
1176 // after the m_renderer pointer has been initialized
1177 }
1178
1179 void wxDataViewRenderer::SetMode( wxDataViewCellMode mode )
1180 {
1181 GtkCellRendererMode gtkMode;
1182 switch (mode)
1183 {
1184 case wxDATAVIEW_CELL_INERT:
1185 gtkMode = GTK_CELL_RENDERER_MODE_INERT;
1186 break;
1187 case wxDATAVIEW_CELL_ACTIVATABLE:
1188 gtkMode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
1189 break;
1190 case wxDATAVIEW_CELL_EDITABLE:
1191 gtkMode = GTK_CELL_RENDERER_MODE_EDITABLE;
1192 break;
1193 }
1194
1195 GValue gvalue = { 0, };
1196 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
1197 g_value_set_enum( &gvalue, gtkMode );
1198 g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue );
1199 g_value_unset( &gvalue );
1200 }
1201
1202 wxDataViewCellMode wxDataViewRenderer::GetMode() const
1203 {
1204 wxDataViewCellMode ret;
1205
1206 GValue gvalue;
1207 g_object_get( G_OBJECT(m_renderer), "mode", &gvalue, NULL);
1208
1209 switch (g_value_get_enum(&gvalue))
1210 {
1211 case GTK_CELL_RENDERER_MODE_INERT:
1212 ret = wxDATAVIEW_CELL_INERT;
1213 break;
1214 case GTK_CELL_RENDERER_MODE_ACTIVATABLE:
1215 ret = wxDATAVIEW_CELL_ACTIVATABLE;
1216 break;
1217 case GTK_CELL_RENDERER_MODE_EDITABLE:
1218 ret = wxDATAVIEW_CELL_EDITABLE;
1219 break;
1220 }
1221
1222 g_value_unset( &gvalue );
1223
1224 return ret;
1225 }
1226
1227 void wxDataViewRenderer::SetAlignment( int align )
1228 {
1229 // horizontal alignment:
1230
1231 gfloat xalign = 0.0;
1232 if (align & wxALIGN_RIGHT)
1233 xalign = 1.0;
1234 else if (align & wxALIGN_CENTER_HORIZONTAL)
1235 xalign = 0.5;
1236
1237 GValue gvalue = { 0, };
1238 g_value_init( &gvalue, G_TYPE_FLOAT );
1239 g_value_set_float( &gvalue, xalign );
1240 g_object_set_property( G_OBJECT(m_renderer), "xalign", &gvalue );
1241 g_value_unset( &gvalue );
1242
1243 // vertical alignment:
1244
1245 gfloat yalign = 0.0;
1246 if (align & wxALIGN_BOTTOM)
1247 yalign = 1.0;
1248 else if (align & wxALIGN_CENTER_VERTICAL)
1249 yalign = 0.5;
1250
1251 GValue gvalue2 = { 0, };
1252 g_value_init( &gvalue2, G_TYPE_FLOAT );
1253 g_value_set_float( &gvalue2, yalign );
1254 g_object_set_property( G_OBJECT(m_renderer), "yalign", &gvalue2 );
1255 g_value_unset( &gvalue2 );
1256 }
1257
1258 int wxDataViewRenderer::GetAlignment() const
1259 {
1260 int ret = 0;
1261 GValue gvalue;
1262
1263 // horizontal alignment:
1264
1265 g_object_get( G_OBJECT(m_renderer), "xalign", &gvalue, NULL );
1266 float xalign = g_value_get_float( &gvalue );
1267 if (xalign < 0.5)
1268 ret |= wxALIGN_LEFT;
1269 else if (xalign == 0.5)
1270 ret |= wxALIGN_CENTER_HORIZONTAL;
1271 else
1272 ret |= wxALIGN_RIGHT;
1273 g_value_unset( &gvalue );
1274
1275
1276 // vertical alignment:
1277
1278 g_object_get( G_OBJECT(m_renderer), "yalign", &gvalue, NULL );
1279 float yalign = g_value_get_float( &gvalue );
1280 if (yalign < 0.5)
1281 ret |= wxALIGN_TOP;
1282 else if (yalign == 0.5)
1283 ret |= wxALIGN_CENTER_VERTICAL;
1284 else
1285 ret |= wxALIGN_BOTTOM;
1286 g_value_unset( &gvalue );
1287
1288 return ret;
1289 }
1290
1291
1292
1293 // ---------------------------------------------------------
1294 // wxDataViewTextRenderer
1295 // ---------------------------------------------------------
1296
1297 extern "C" {
1298 static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer,
1299 gchar *arg1, gchar *arg2, gpointer user_data );
1300 }
1301
1302 static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer,
1303 gchar *arg1, gchar *arg2, gpointer user_data )
1304 {
1305 wxDataViewTextRenderer *cell = (wxDataViewTextRenderer*) user_data;
1306
1307 wxString tmp = wxGTK_CONV_BACK_FONT(arg2, cell->GetOwner()->GetOwner()->GetFont());
1308 wxVariant value = tmp;
1309 if (!cell->Validate( value ))
1310 return;
1311
1312 wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel();
1313
1314 GtkTreePath *path = gtk_tree_path_new_from_string( arg1 );
1315 GtkTreeIter iter;
1316 cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, path );
1317 wxDataViewItem item( (void*) iter.user_data );;
1318 gtk_tree_path_free( path );
1319
1320 unsigned int model_col = cell->GetOwner()->GetModelColumn();
1321
1322 model->SetValue( value, item, model_col );
1323 model->ValueChanged( item, model_col );
1324 }
1325
1326 IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewRenderer)
1327
1328 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1329 int align ) :
1330 wxDataViewRenderer( varianttype, mode, align )
1331 {
1332 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_text_new();
1333
1334 if (mode & wxDATAVIEW_CELL_EDITABLE)
1335 {
1336 GValue gvalue = { 0, };
1337 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1338 g_value_set_boolean( &gvalue, true );
1339 g_object_set_property( G_OBJECT(m_renderer), "editable", &gvalue );
1340 g_value_unset( &gvalue );
1341
1342 g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
1343 }
1344
1345 SetMode(mode);
1346 SetAlignment(align);
1347 }
1348
1349 bool wxDataViewTextRenderer::SetValue( const wxVariant &value )
1350 {
1351 wxString tmp = value;
1352
1353 GValue gvalue = { 0, };
1354 g_value_init( &gvalue, G_TYPE_STRING );
1355 g_value_set_string( &gvalue, wxGTK_CONV_FONT( tmp, GetOwner()->GetOwner()->GetFont() ) );
1356 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
1357 g_value_unset( &gvalue );
1358
1359 return true;
1360 }
1361
1362 bool wxDataViewTextRenderer::GetValue( wxVariant &value ) const
1363 {
1364 GValue gvalue = { 0, };
1365 g_value_init( &gvalue, G_TYPE_STRING );
1366 g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
1367 wxString tmp = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ),
1368 wx_const_cast(wxDataViewTextRenderer*, this)->GetOwner()->GetOwner()->GetFont() );
1369 g_value_unset( &gvalue );
1370
1371 value = tmp;
1372
1373 return true;
1374 }
1375
1376 void wxDataViewTextRenderer::SetAlignment( int align )
1377 {
1378 wxDataViewRenderer::SetAlignment(align);
1379
1380 if (gtk_check_version(2,10,0))
1381 return;
1382
1383 // horizontal alignment:
1384 PangoAlignment pangoAlign = PANGO_ALIGN_LEFT;
1385 if (align & wxALIGN_RIGHT)
1386 pangoAlign = PANGO_ALIGN_RIGHT;
1387 else if (align & wxALIGN_CENTER_HORIZONTAL)
1388 pangoAlign = PANGO_ALIGN_CENTER;
1389
1390 GValue gvalue = { 0, };
1391 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
1392 g_value_set_enum( &gvalue, pangoAlign );
1393 g_object_set_property( G_OBJECT(m_renderer), "alignment", &gvalue );
1394 g_value_unset( &gvalue );
1395 }
1396
1397 // ---------------------------------------------------------
1398 // wxDataViewBitmapRenderer
1399 // ---------------------------------------------------------
1400
1401 IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewRenderer)
1402
1403 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1404 int align ) :
1405 wxDataViewRenderer( varianttype, mode, align )
1406 {
1407 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_pixbuf_new();
1408
1409 SetMode(mode);
1410 SetAlignment(align);
1411 }
1412
1413 bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
1414 {
1415 if (value.GetType() == wxT("wxBitmap"))
1416 {
1417 wxBitmap bitmap;
1418 bitmap << value;
1419
1420 // This may create a Pixbuf representation in the
1421 // wxBitmap object (and it will stay there)
1422 GdkPixbuf *pixbuf = bitmap.GetPixbuf();
1423
1424 GValue gvalue = { 0, };
1425 g_value_init( &gvalue, G_TYPE_OBJECT );
1426 g_value_set_object( &gvalue, pixbuf );
1427 g_object_set_property( G_OBJECT(m_renderer), "pixbuf", &gvalue );
1428 g_value_unset( &gvalue );
1429
1430 return true;
1431 }
1432
1433 if (value.GetType() == wxT("wxIcon"))
1434 {
1435 wxIcon bitmap;
1436 bitmap << value;
1437
1438 // This may create a Pixbuf representation in the
1439 // wxBitmap object (and it will stay there)
1440 GdkPixbuf *pixbuf = bitmap.GetPixbuf();
1441
1442 GValue gvalue = { 0, };
1443 g_value_init( &gvalue, G_TYPE_OBJECT );
1444 g_value_set_object( &gvalue, pixbuf );
1445 g_object_set_property( G_OBJECT(m_renderer), "pixbuf", &gvalue );
1446 g_value_unset( &gvalue );
1447
1448 return true;
1449 }
1450
1451 return false;
1452 }
1453
1454 bool wxDataViewBitmapRenderer::GetValue( wxVariant &value ) const
1455 {
1456 return false;
1457 }
1458
1459 // ---------------------------------------------------------
1460 // wxDataViewToggleRenderer
1461 // ---------------------------------------------------------
1462
1463 extern "C" {
1464 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
1465 gchar *path, gpointer user_data );
1466 }
1467
1468 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
1469 gchar *path, gpointer user_data )
1470 {
1471 wxDataViewToggleRenderer *cell = (wxDataViewToggleRenderer*) user_data;
1472
1473 // get old value
1474 GValue gvalue = { 0, };
1475 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1476 g_object_get_property( G_OBJECT(renderer), "active", &gvalue );
1477 bool tmp = g_value_get_boolean( &gvalue );
1478 g_value_unset( &gvalue );
1479 // invert it
1480 tmp = !tmp;
1481
1482 wxVariant value = tmp;
1483 if (!cell->Validate( value ))
1484 return;
1485
1486 wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel();
1487
1488 GtkTreePath *gtk_path = gtk_tree_path_new_from_string( path );
1489 GtkTreeIter iter;
1490 cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, gtk_path );
1491 wxDataViewItem item( (void*) iter.user_data );;
1492 gtk_tree_path_free( gtk_path );
1493
1494 unsigned int model_col = cell->GetOwner()->GetModelColumn();
1495
1496 model->SetValue( value, item, model_col );
1497 model->ValueChanged( item, model_col );
1498 }
1499
1500 IMPLEMENT_CLASS(wxDataViewToggleRenderer, wxDataViewRenderer)
1501
1502 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
1503 wxDataViewCellMode mode, int align ) :
1504 wxDataViewRenderer( varianttype, mode, align )
1505 {
1506 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_toggle_new();
1507
1508 if (mode & wxDATAVIEW_CELL_ACTIVATABLE)
1509 {
1510 g_signal_connect_after( m_renderer, "toggled",
1511 G_CALLBACK(wxGtkToggleRendererToggledCallback), this );
1512 }
1513 else
1514 {
1515 GValue gvalue = { 0, };
1516 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1517 g_value_set_boolean( &gvalue, false );
1518 g_object_set_property( G_OBJECT(m_renderer), "activatable", &gvalue );
1519 g_value_unset( &gvalue );
1520 }
1521
1522 SetMode(mode);
1523 SetAlignment(align);
1524 }
1525
1526 bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
1527 {
1528 bool tmp = value;
1529
1530 GValue gvalue = { 0, };
1531 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1532 g_value_set_boolean( &gvalue, tmp );
1533 g_object_set_property( G_OBJECT(m_renderer), "active", &gvalue );
1534 g_value_unset( &gvalue );
1535
1536 return true;
1537 }
1538
1539 bool wxDataViewToggleRenderer::GetValue( wxVariant &value ) const
1540 {
1541 GValue gvalue = { 0, };
1542 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1543 g_object_get_property( G_OBJECT(m_renderer), "active", &gvalue );
1544 bool tmp = g_value_get_boolean( &gvalue );
1545 g_value_unset( &gvalue );
1546
1547 value = tmp;
1548
1549 return true;
1550 }
1551
1552 // ---------------------------------------------------------
1553 // wxDataViewCustomRenderer
1554 // ---------------------------------------------------------
1555
1556 class wxDataViewCtrlDC: public wxWindowDC
1557 {
1558 public:
1559 wxDataViewCtrlDC( wxDataViewCtrl *window )
1560 {
1561 GtkWidget *widget = window->m_treeview;
1562 // Set later
1563 m_window = NULL;
1564
1565 m_context = window->GtkGetPangoDefaultContext();
1566 m_layout = pango_layout_new( m_context );
1567 m_fontdesc = pango_font_description_copy( widget->style->font_desc );
1568
1569 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
1570
1571 // Set m_window later
1572 // SetUpDC();
1573 // m_owner = window;
1574 }
1575 };
1576
1577 // ---------------------------------------------------------
1578 // wxDataViewCustomRenderer
1579 // ---------------------------------------------------------
1580
1581 IMPLEMENT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
1582
1583 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
1584 wxDataViewCellMode mode, int align,
1585 bool no_init ) :
1586 wxDataViewRenderer( varianttype, mode, align )
1587 {
1588 m_dc = NULL;
1589
1590 if (no_init)
1591 m_renderer = NULL;
1592 else
1593 Init(mode, align);
1594 }
1595
1596 bool wxDataViewCustomRenderer::Init(wxDataViewCellMode mode, int align)
1597 {
1598 GtkWxCellRenderer *renderer = (GtkWxCellRenderer *) gtk_wx_cell_renderer_new();
1599 renderer->cell = this;
1600
1601 m_renderer = (GtkCellRenderer*) renderer;
1602
1603 SetMode(mode);
1604 SetAlignment(align);
1605
1606 return true;
1607 }
1608
1609 wxDataViewCustomRenderer::~wxDataViewCustomRenderer()
1610 {
1611 if (m_dc)
1612 delete m_dc;
1613 }
1614
1615 wxDC *wxDataViewCustomRenderer::GetDC()
1616 {
1617 if (m_dc == NULL)
1618 {
1619 if (GetOwner() == NULL)
1620 return NULL;
1621 if (GetOwner()->GetOwner() == NULL)
1622 return NULL;
1623 m_dc = new wxDataViewCtrlDC( GetOwner()->GetOwner() );
1624 }
1625
1626 return m_dc;
1627 }
1628
1629 // ---------------------------------------------------------
1630 // wxDataViewProgressRenderer
1631 // ---------------------------------------------------------
1632
1633 IMPLEMENT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
1634
1635 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
1636 const wxString &varianttype, wxDataViewCellMode mode, int align ) :
1637 wxDataViewCustomRenderer( varianttype, mode, align, true )
1638 {
1639 m_label = label;
1640 m_value = 0;
1641
1642 #ifdef __WXGTK26__
1643 if (!gtk_check_version(2,6,0))
1644 {
1645 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_progress_new();
1646
1647 GValue gvalue = { 0, };
1648 g_value_init( &gvalue, G_TYPE_STRING );
1649
1650 // FIXME: font encoding support
1651 g_value_set_string( &gvalue, wxGTK_CONV_SYS(m_label) );
1652 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
1653 g_value_unset( &gvalue );
1654
1655 SetMode(mode);
1656 SetAlignment(align);
1657 }
1658 else
1659 #endif
1660 {
1661 // Use custom cell code
1662 wxDataViewCustomRenderer::Init(mode, align);
1663 }
1664 }
1665
1666 wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
1667 {
1668 }
1669
1670 bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
1671 {
1672 #ifdef __WXGTK26__
1673 if (!gtk_check_version(2,6,0))
1674 {
1675 gint tmp = (long) value;
1676 GValue gvalue = { 0, };
1677 g_value_init( &gvalue, G_TYPE_INT );
1678 g_value_set_int( &gvalue, tmp );
1679 g_object_set_property( G_OBJECT(m_renderer), "value", &gvalue );
1680 g_value_unset( &gvalue );
1681 }
1682 else
1683 #endif
1684 {
1685 m_value = (long) value;
1686
1687 if (m_value < 0) m_value = 0;
1688 if (m_value > 100) m_value = 100;
1689 }
1690
1691 return true;
1692 }
1693
1694 bool wxDataViewProgressRenderer::GetValue( wxVariant &value ) const
1695 {
1696 return false;
1697 }
1698
1699 bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int state )
1700 {
1701 double pct = (double)m_value / 100.0;
1702 wxRect bar = cell;
1703 bar.width = (int)(cell.width * pct);
1704 dc->SetPen( *wxTRANSPARENT_PEN );
1705 dc->SetBrush( *wxBLUE_BRUSH );
1706 dc->DrawRectangle( bar );
1707
1708 dc->SetBrush( *wxTRANSPARENT_BRUSH );
1709 dc->SetPen( *wxBLACK_PEN );
1710 dc->DrawRectangle( cell );
1711
1712 return true;
1713 }
1714
1715 wxSize wxDataViewProgressRenderer::GetSize() const
1716 {
1717 return wxSize(40,12);
1718 }
1719
1720 // ---------------------------------------------------------
1721 // wxDataViewDateRenderer
1722 // ---------------------------------------------------------
1723
1724 class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
1725 {
1726 public:
1727 wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
1728 wxDataViewModel *model, const wxDataViewItem &item, unsigned int col ) :
1729 wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
1730 {
1731 m_model = model;
1732 m_item = item;
1733 m_col = col;
1734 m_cal = new wxCalendarCtrl( this, -1, *value );
1735 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
1736 sizer->Add( m_cal, 1, wxGROW );
1737 SetSizer( sizer );
1738 sizer->Fit( this );
1739 }
1740
1741 virtual void OnDismiss()
1742 {
1743 }
1744
1745 void OnCalendar( wxCalendarEvent &event );
1746
1747 wxCalendarCtrl *m_cal;
1748 wxDataViewModel *m_model;
1749 wxDataViewItem m_item;
1750 unsigned int m_col;
1751
1752 private:
1753 DECLARE_EVENT_TABLE()
1754 };
1755
1756 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
1757 EVT_CALENDAR( -1, wxDataViewDateRendererPopupTransient::OnCalendar )
1758 END_EVENT_TABLE()
1759
1760 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
1761 {
1762 wxDateTime date = event.GetDate();
1763 wxVariant value = date;
1764 m_model->SetValue( value, m_item, m_col );
1765 m_model->ValueChanged( m_item, m_col );
1766 DismissAndNotify();
1767 }
1768
1769 IMPLEMENT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
1770
1771 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
1772 wxDataViewCellMode mode, int align ) :
1773 wxDataViewCustomRenderer( varianttype, mode, align )
1774 {
1775 SetMode(mode);
1776 SetAlignment(align);
1777 }
1778
1779 bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
1780 {
1781 m_date = value.GetDateTime();
1782
1783 return true;
1784 }
1785
1786 bool wxDataViewDateRenderer::GetValue( wxVariant &value ) const
1787 {
1788 return false;
1789 }
1790
1791 bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state )
1792 {
1793 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
1794 wxString tmp = m_date.FormatDate();
1795 dc->DrawText( tmp, cell.x, cell.y );
1796
1797 return true;
1798 }
1799
1800 wxSize wxDataViewDateRenderer::GetSize() const
1801 {
1802 wxString tmp = m_date.FormatDate();
1803 wxCoord x,y,d;
1804 GetView()->GetTextExtent( tmp, &x, &y, &d );
1805 return wxSize(x,y+d);
1806 }
1807
1808 bool wxDataViewDateRenderer::Activate( wxRect cell, wxDataViewModel *model,
1809 const wxDataViewItem &item, unsigned int col )
1810 {
1811 wxVariant variant;
1812 model->GetValue( variant, item, col );
1813 wxDateTime value = variant.GetDateTime();
1814
1815 wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
1816 GetOwner()->GetOwner()->GetParent(), &value, model, item, col );
1817 wxPoint pos = wxGetMousePosition();
1818 popup->Move( pos );
1819 popup->Layout();
1820 popup->Popup( popup->m_cal );
1821
1822 return true;
1823 }
1824
1825 // ---------------------------------------------------------
1826 // wxDataViewColumn
1827 // ---------------------------------------------------------
1828
1829
1830 static gboolean
1831 gtk_dataview_header_button_press_callback( GtkWidget *widget,
1832 GdkEventButton *gdk_event,
1833 wxDataViewColumn *column )
1834 {
1835 if (gdk_event->type != GDK_BUTTON_PRESS)
1836 return FALSE;
1837
1838 if (gdk_event->button == 1)
1839 {
1840 wxDataViewCtrl *dv = column->GetOwner();
1841 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, dv->GetId() );
1842 event.SetDataViewColumn( column );
1843 event.SetModel( dv->GetModel() );
1844 if (dv->GetEventHandler()->ProcessEvent( event ))
1845 return TRUE;
1846 }
1847
1848 return FALSE;
1849 }
1850
1851 extern "C" {
1852 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
1853 GtkCellRenderer *cell,
1854 GtkTreeModel *model,
1855 GtkTreeIter *iter,
1856 gpointer data );
1857 }
1858
1859
1860 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
1861 GtkCellRenderer *renderer,
1862 GtkTreeModel *model,
1863 GtkTreeIter *iter,
1864 gpointer data )
1865 {
1866 g_return_if_fail (GTK_IS_WX_TREE_MODEL (model));
1867 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) model;
1868
1869 wxDataViewRenderer *cell = (wxDataViewRenderer*) data;
1870
1871 wxDataViewItem item( (void*) iter->user_data );
1872
1873 wxVariant value;
1874 tree_model->internal->GetDataViewModel()->GetValue( value, item, cell->GetOwner()->GetModelColumn() );
1875
1876 if (value.GetType() != cell->GetVariantType())
1877 wxLogError( wxT("Wrong type, required: %s but: %s"),
1878 value.GetType().c_str(),
1879 cell->GetVariantType().c_str() );
1880
1881 cell->SetValue( value );
1882
1883 #if 0
1884 wxListItemAttr attr;
1885 tree_model->model->GetAttr( attr, cell->GetOwner()->GetModelColumn(), model_row );
1886
1887 if (attr.HasBackgroundColour())
1888 {
1889 wxColour colour = attr.GetBackgroundColour();
1890 const GdkColor * const gcol = colour.GetColor();
1891
1892 GValue gvalue = { 0, };
1893 g_value_init( &gvalue, GDK_TYPE_COLOR );
1894 g_value_set_boxed( &gvalue, gcol );
1895 g_object_set_property( G_OBJECT(renderer), "cell-background_gdk", &gvalue );
1896 g_value_unset( &gvalue );
1897 }
1898 else
1899 {
1900 GValue gvalue = { 0, };
1901 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1902 g_value_set_boolean( &gvalue, FALSE );
1903 g_object_set_property( G_OBJECT(renderer), "cell-background-set", &gvalue );
1904 g_value_unset( &gvalue );
1905 }
1906 #endif
1907
1908 }
1909
1910 IMPLEMENT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
1911
1912 wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell,
1913 unsigned int model_column, int width,
1914 wxAlignment align, int flags ) :
1915 wxDataViewColumnBase( title, cell, model_column, width, align, flags )
1916 {
1917 Init( align, flags, width );
1918
1919 gtk_tree_view_column_set_clickable( GTK_TREE_VIEW_COLUMN(m_column), TRUE );
1920 SetTitle( title );
1921 }
1922
1923 wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell,
1924 unsigned int model_column, int width,
1925 wxAlignment align, int flags ) :
1926 wxDataViewColumnBase( bitmap, cell, model_column, width, align, flags )
1927 {
1928 Init( align, flags, width );
1929
1930 SetBitmap( bitmap );
1931 }
1932
1933 void wxDataViewColumn::Init(wxAlignment align, int flags, int width)
1934 {
1935 m_isConnected = false;
1936
1937 GtkCellRenderer *renderer = (GtkCellRenderer *) GetRenderer()->GetGtkHandle();
1938 GtkTreeViewColumn *column = gtk_tree_view_column_new();
1939 m_column = (GtkWidget*) column;
1940
1941 SetFlags( flags );
1942 SetAlignment( align );
1943
1944 // NOTE: we prefer not to call SetMinWidth(wxDVC_DEFAULT_MINWIDTH);
1945 // as GTK+ is smart and unless explicitely told, will set the minimal
1946 // width to the title's lenght, which is a better default
1947
1948 // the GTK_TREE_VIEW_COLUMN_FIXED is required by the "fixed height" mode
1949 // that we use for the wxDataViewCtrl
1950 gtk_tree_view_column_set_fixed_width( column, width < 0 ? wxDVC_DEFAULT_WIDTH : width );
1951 gtk_tree_view_column_set_sizing( column, GTK_TREE_VIEW_COLUMN_FIXED );
1952
1953 gtk_tree_view_column_pack_end( column, renderer, TRUE );
1954
1955 gtk_tree_view_column_set_cell_data_func( column, renderer,
1956 wxGtkTreeCellDataFunc, (gpointer) GetRenderer(), NULL );
1957 }
1958
1959 wxDataViewColumn::~wxDataViewColumn()
1960 {
1961 }
1962
1963 void wxDataViewColumn::OnInternalIdle()
1964 {
1965 if (m_isConnected)
1966 return;
1967
1968 if (GTK_WIDGET_REALIZED(GetOwner()->m_treeview))
1969 {
1970 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
1971 if (column->button)
1972 {
1973 g_signal_connect(column->button, "button_press_event",
1974 G_CALLBACK (gtk_dataview_header_button_press_callback), this);
1975
1976 m_isConnected = true;
1977 }
1978 }
1979 }
1980
1981 void wxDataViewColumn::SetOwner( wxDataViewCtrl *owner )
1982 {
1983 wxDataViewColumnBase::SetOwner( owner );
1984
1985 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
1986
1987 gtk_tree_view_column_set_title( column, wxGTK_CONV_FONT(GetTitle(), GetOwner()->GetFont() ) );
1988 }
1989
1990 void wxDataViewColumn::SetTitle( const wxString &title )
1991 {
1992 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
1993
1994 if (m_isConnected)
1995 {
1996 // disconnect before column->button gets recreated
1997 g_signal_handlers_disconnect_by_func( column->button,
1998 (GtkWidget*) gtk_dataview_header_button_press_callback, this);
1999
2000 m_isConnected = false;
2001 }
2002
2003 // FIXME: can it really happen that we don't have the owner here??
2004 wxDataViewCtrl *ctrl = GetOwner();
2005 gtk_tree_view_column_set_title( column, ctrl ? wxGTK_CONV_FONT(title, ctrl->GetFont())
2006 : wxGTK_CONV_SYS(title) );
2007
2008 gtk_tree_view_column_set_widget( column, NULL );
2009 }
2010
2011 wxString wxDataViewColumn::GetTitle() const
2012 {
2013 const gchar *str = gtk_tree_view_column_get_title( GTK_TREE_VIEW_COLUMN(m_column) );
2014 return wxConvFileName->cMB2WX(str);
2015 }
2016
2017 void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap )
2018 {
2019 wxDataViewColumnBase::SetBitmap( bitmap );
2020
2021 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2022 if (bitmap.Ok())
2023 {
2024 GtkImage *gtk_image = GTK_IMAGE( gtk_image_new() );
2025
2026 GdkBitmap *mask = (GdkBitmap *) NULL;
2027 if (bitmap.GetMask())
2028 mask = bitmap.GetMask()->GetBitmap();
2029
2030 if (bitmap.HasPixbuf())
2031 {
2032 gtk_image_set_from_pixbuf(GTK_IMAGE(gtk_image),
2033 bitmap.GetPixbuf());
2034 }
2035 else
2036 {
2037 gtk_image_set_from_pixmap(GTK_IMAGE(gtk_image),
2038 bitmap.GetPixmap(), mask);
2039 }
2040 gtk_widget_show( GTK_WIDGET(gtk_image) );
2041
2042 gtk_tree_view_column_set_widget( column, GTK_WIDGET(gtk_image) );
2043 }
2044 else
2045 {
2046 gtk_tree_view_column_set_widget( column, NULL );
2047 }
2048 }
2049
2050 void wxDataViewColumn::SetHidden( bool hidden )
2051 {
2052 gtk_tree_view_column_set_visible( GTK_TREE_VIEW_COLUMN(m_column), !hidden );
2053 }
2054
2055 void wxDataViewColumn::SetResizeable( bool resizeable )
2056 {
2057 gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizeable );
2058 }
2059
2060 void wxDataViewColumn::SetAlignment( wxAlignment align )
2061 {
2062 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2063
2064 gfloat xalign = 0.0;
2065 if (align == wxALIGN_RIGHT)
2066 xalign = 1.0;
2067 if (align == wxALIGN_CENTER_HORIZONTAL ||
2068 align == wxALIGN_CENTER)
2069 xalign = 0.5;
2070
2071 gtk_tree_view_column_set_alignment( column, xalign );
2072 }
2073
2074 wxAlignment wxDataViewColumn::GetAlignment() const
2075 {
2076 gfloat xalign = gtk_tree_view_column_get_alignment( GTK_TREE_VIEW_COLUMN(m_column) );
2077
2078 if (xalign == 1.0)
2079 return wxALIGN_RIGHT;
2080 if (xalign == 0.5)
2081 return wxALIGN_CENTER_HORIZONTAL;
2082
2083 return wxALIGN_LEFT;
2084 }
2085
2086 void wxDataViewColumn::SetSortable( bool sortable )
2087 {
2088 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2089
2090 if (sortable)
2091 gtk_tree_view_column_set_sort_column_id( column, GetModelColumn() );
2092 else
2093 gtk_tree_view_column_set_sort_column_id( column, -1 );
2094 }
2095
2096 bool wxDataViewColumn::IsSortable() const
2097 {
2098 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2099 return (gtk_tree_view_column_get_sort_column_id( column ) != -1);
2100 }
2101
2102 bool wxDataViewColumn::IsResizeable() const
2103 {
2104 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2105 return gtk_tree_view_column_get_resizable( column );
2106 }
2107
2108 bool wxDataViewColumn::IsHidden() const
2109 {
2110 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2111 return !gtk_tree_view_column_get_visible( column );
2112 }
2113
2114 void wxDataViewColumn::SetSortOrder( bool ascending )
2115 {
2116 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2117
2118 if (ascending)
2119 gtk_tree_view_column_set_sort_order( column, GTK_SORT_ASCENDING );
2120 else
2121 gtk_tree_view_column_set_sort_order( column, GTK_SORT_DESCENDING );
2122 }
2123
2124 bool wxDataViewColumn::IsSortOrderAscending() const
2125 {
2126 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2127
2128 return (gtk_tree_view_column_get_sort_order( column ) != GTK_SORT_DESCENDING);
2129 }
2130
2131 void wxDataViewColumn::SetMinWidth( int width )
2132 {
2133 gtk_tree_view_column_set_min_width( GTK_TREE_VIEW_COLUMN(m_column), width );
2134 }
2135
2136 int wxDataViewColumn::GetMinWidth() const
2137 {
2138 return gtk_tree_view_column_get_min_width( GTK_TREE_VIEW_COLUMN(m_column) );
2139 }
2140
2141 int wxDataViewColumn::GetWidth() const
2142 {
2143 return gtk_tree_view_column_get_width( GTK_TREE_VIEW_COLUMN(m_column) );
2144 }
2145
2146 void wxDataViewColumn::SetWidth( int width )
2147 {
2148 gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), width );
2149 }
2150
2151
2152 //-----------------------------------------------------------------------------
2153 // wxGtkTreeModelNode
2154 //-----------------------------------------------------------------------------
2155
2156 void wxGtkTreeModelNode::Resort()
2157 {
2158 g_internal = m_internal;
2159
2160 size_t child_count = GetChildCount();
2161 if (child_count == 0)
2162 return;
2163
2164 size_t node_count = GetNodesCount();
2165
2166 if (child_count == 1)
2167 {
2168 if (node_count == 1)
2169 {
2170 wxGtkTreeModelNode *node = m_nodes.Item( 0 );
2171 node->Resort();
2172 }
2173 return;
2174 }
2175
2176 wxGtkTreeModelChildren *new_array = new wxGtkTreeModelChildren( wxGtkTreeModelNodeCmp );
2177
2178 size_t pos;
2179 for (pos = 0; pos < child_count; pos++)
2180 new_array->Add( m_children->Item( pos ) );
2181
2182 gint *new_order = new gint[child_count];
2183
2184 for (pos = 0; pos < child_count; pos++)
2185 {
2186 void *id = new_array->Item( pos );
2187 size_t old_pos;
2188 for (old_pos = 0; old_pos < child_count; old_pos++)
2189 {
2190 if (id == m_children->Item(old_pos))
2191 {
2192 new_order[pos] = old_pos;
2193 break;
2194 }
2195 }
2196 }
2197
2198 // for (pos = 0; pos < count; pos++)
2199 // m_children->Clear();
2200 delete m_children;
2201
2202 m_children = new_array;
2203
2204 GtkTreeModel *gtk_tree_model = GTK_TREE_MODEL( m_internal->GetGtkModel() );
2205
2206 GtkTreePath *path = gtk_tree_path_new ();
2207 wxGtkTreeModelNode *parent = GetParent();
2208 void *id = GetItem().GetID();
2209
2210 while (parent)
2211 {
2212 int pos = parent->GetChildren().Index( id );
2213 gtk_tree_path_prepend_index( path, pos );
2214 id = parent->GetItem().GetID();
2215 parent = parent->GetParent();
2216 }
2217
2218 GtkTreeIter iter;
2219 iter.user_data = id;
2220 iter.stamp = m_internal->GetGtkModel()->stamp;
2221 gtk_tree_model_rows_reordered( gtk_tree_model, path, &iter, new_order );
2222
2223 gtk_tree_path_free (path);
2224
2225 delete [] new_order;
2226
2227 for (pos = 0; pos < node_count; pos++)
2228 {
2229 wxGtkTreeModelNode *node = m_nodes.Item( pos );
2230 node->Resort();
2231 }
2232 }
2233
2234 //-----------------------------------------------------------------------------
2235 // wxDataViewCtrlInternal
2236 //-----------------------------------------------------------------------------
2237
2238 wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner,
2239 wxDataViewModel *wx_model, GtkWxTreeModel *gtk_model )
2240 {
2241 m_owner = owner;
2242 m_wx_model = wx_model;
2243 m_gtk_model = gtk_model;
2244 m_root = NULL;
2245 m_sort_order = GTK_SORT_ASCENDING;
2246 m_sort_column = 0;
2247 InitTree();
2248 }
2249
2250 wxDataViewCtrlInternal::~wxDataViewCtrlInternal()
2251 {
2252 g_object_unref( m_gtk_model );
2253 }
2254
2255 void wxDataViewCtrlInternal::InitTree()
2256 {
2257 wxDataViewItem item;
2258 m_root = new wxGtkTreeModelNode( NULL, item, this );
2259
2260 BuildBranch( m_root );
2261 }
2262
2263 void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node )
2264 {
2265 if (node->GetChildCount() == 0)
2266 {
2267 wxDataViewItem child = m_wx_model->GetFirstChild( node->GetItem() );
2268 while (child.IsOk())
2269 {
2270 if (m_wx_model->IsContainer( child ))
2271 node->AddNode( new wxGtkTreeModelNode( node, child, this ) );
2272 else
2273 node->AddLeave( child.GetID() );
2274
2275 // Don't send any events here
2276
2277 child = m_wx_model->GetNextSibling( child );
2278 }
2279 }
2280 }
2281
2282 void wxDataViewCtrlInternal::Resort()
2283 {
2284 m_root->Resort();
2285 }
2286
2287 bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
2288 {
2289 wxGtkTreeModelNode *parent_node = FindNode( parent );
2290 if (m_wx_model->IsContainer( item ))
2291 parent_node->AddNode( new wxGtkTreeModelNode( parent_node, item, this ) );
2292 else
2293 parent_node->AddLeave( item.GetID() );
2294
2295 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED, m_owner->GetId() );
2296 event.SetEventObject( m_owner );
2297 event.SetModel( m_owner->GetModel() );
2298 event.SetItem( item );
2299 m_owner->GetEventHandler()->ProcessEvent( event );
2300
2301 return true;
2302 }
2303
2304 bool wxDataViewCtrlInternal::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
2305 {
2306 wxGtkTreeModelNode *parent_node = FindNode( parent );
2307 parent_node->DeleteChild( item.GetID() );
2308
2309 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_DELETED, m_owner->GetId() );
2310 event.SetEventObject( m_owner );
2311 event.SetModel( m_owner->GetModel() );
2312 event.SetItem( item );
2313 m_owner->GetEventHandler()->ProcessEvent( event );
2314
2315 return true;
2316 }
2317
2318 bool wxDataViewCtrlInternal::ItemChanged( const wxDataViewItem &item )
2319 {
2320 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_CHANGED, m_owner->GetId() );
2321 event.SetEventObject( m_owner );
2322 event.SetModel( m_owner->GetModel() );
2323 event.SetItem( item );
2324 m_owner->GetEventHandler()->ProcessEvent( event );
2325
2326 return true;
2327 }
2328
2329 bool wxDataViewCtrlInternal::ValueChanged( const wxDataViewItem &item, unsigned int col )
2330 {
2331 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_VALUE_CHANGED, m_owner->GetId() );
2332 event.SetEventObject( m_owner );
2333 event.SetModel( m_owner->GetModel() );
2334 event.SetColumn( col );
2335 event.SetItem( item );
2336 m_owner->GetEventHandler()->ProcessEvent( event );
2337
2338 return true;
2339 }
2340
2341 bool wxDataViewCtrlInternal::Cleared()
2342 {
2343 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_CLEARED, m_owner->GetId() );
2344 event.SetEventObject( m_owner );
2345 event.SetModel( m_owner->GetModel() );
2346 m_owner->GetEventHandler()->ProcessEvent( event );
2347
2348 return true;
2349 }
2350
2351 gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path )
2352 {
2353 g_internal = this;
2354
2355 int depth = gtk_tree_path_get_depth( path );
2356
2357 wxGtkTreeModelNode *node = m_root;
2358
2359 int i;
2360 for (i = 0; i < depth; i++)
2361 {
2362 BuildBranch( node );
2363
2364 gint pos = gtk_tree_path_get_indices (path)[i];
2365 if (pos < 0) return FALSE;
2366 if ((size_t)pos >= node->GetChildCount()) return FALSE;
2367
2368 void* id = node->GetChildren().Item( (size_t) pos );
2369
2370 if (i == depth-1)
2371 {
2372 iter->stamp = m_gtk_model->stamp;
2373 iter->user_data = id;
2374 return TRUE;
2375 }
2376
2377 size_t count = node->GetNodes().GetCount();
2378 size_t pos2;
2379 for (pos2 = 0; pos2 < count; pos2++)
2380 {
2381 wxGtkTreeModelNode *child_node = node->GetNodes().Item( pos2 );
2382 if (child_node->GetItem().GetID() == id)
2383 {
2384 node = child_node;
2385 break;
2386 }
2387 }
2388 }
2389
2390 return FALSE;
2391 }
2392
2393 GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter )
2394 {
2395 g_internal = this;
2396
2397 GtkTreePath *retval = gtk_tree_path_new ();
2398 void *id = iter->user_data;
2399
2400 wxGtkTreeModelNode *node = FindParentNode( iter );
2401 while (node)
2402 {
2403 int pos = node->GetChildren().Index( id );
2404 gtk_tree_path_prepend_index( retval, pos );
2405
2406 id = node->GetItem().GetID();
2407 node = node->GetParent();
2408 }
2409
2410 return retval;
2411 }
2412
2413 GtkTreePath *wxDataViewCtrlInternal::get_path_safe( GtkTreeIter *iter )
2414 {
2415 g_internal = this;
2416
2417 GtkTreePath *retval = gtk_tree_path_new ();
2418 void *id = iter->user_data;
2419
2420 wxGtkTreeModelNode *node = FindParentNode( iter );
2421 while (node)
2422 {
2423 size_t pos;
2424 for (pos = 0; pos < node->GetChildren().GetCount(); pos++)
2425 {
2426 if (id == node->GetChildren().Item( pos ))
2427 {
2428 gtk_tree_path_prepend_index( retval, (int) pos );
2429 continue;
2430 }
2431 }
2432
2433 id = node->GetItem().GetID();
2434 node = node->GetParent();
2435 }
2436
2437 return retval;
2438 }
2439
2440 gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter )
2441 {
2442 g_internal = this;
2443
2444 wxGtkTreeModelNode *parent = FindParentNode( iter );
2445 if( parent == NULL )
2446 return FALSE;
2447
2448 unsigned int pos = parent->GetChildren().Index( iter->user_data );
2449
2450 if (pos == parent->GetChildCount()-1)
2451 return FALSE;
2452
2453 iter->stamp = m_gtk_model->stamp;
2454 iter->user_data = parent->GetChildren().Item( pos+1 );
2455
2456 return TRUE;
2457 }
2458
2459 gboolean wxDataViewCtrlInternal::iter_children( GtkTreeIter *iter, GtkTreeIter *parent )
2460 {
2461 g_internal = this;
2462
2463 wxDataViewItem item( (void*) parent->user_data );
2464
2465 if (!m_wx_model->IsContainer( item ))
2466 return FALSE;
2467
2468 wxGtkTreeModelNode *parent_node = FindNode( parent );
2469 BuildBranch( parent_node );
2470
2471 if (parent_node->GetChildCount() == 0)
2472 return FALSE;
2473
2474 iter->stamp = m_gtk_model->stamp;
2475 iter->user_data = (gpointer) parent_node->GetChildren().Item( 0 );
2476
2477 return TRUE;
2478 }
2479
2480 gboolean wxDataViewCtrlInternal::iter_has_child( GtkTreeIter *iter )
2481 {
2482 g_internal = this;
2483
2484 wxDataViewItem item( (void*) iter->user_data );
2485 bool is_container = m_wx_model->IsContainer( item );
2486
2487 if (!is_container)
2488 return FALSE;
2489
2490 wxGtkTreeModelNode *node = FindNode( iter );
2491 BuildBranch( node );
2492
2493 return (node->GetChildCount() > 0);
2494 }
2495
2496 gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter )
2497 {
2498 g_internal = this;
2499
2500 wxDataViewItem item( (void*) iter->user_data );
2501
2502 if (!m_wx_model->IsContainer( item ))
2503 return 0;
2504
2505 wxGtkTreeModelNode *parent_node = FindNode( iter );
2506 BuildBranch( parent_node );
2507
2508 // wxPrintf( "iter_n_children %d\n", parent_node->GetChildCount() );
2509
2510 return parent_node->GetChildCount();
2511 }
2512
2513 gboolean wxDataViewCtrlInternal::iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n )
2514 {
2515 g_internal = this;
2516
2517 void* id = NULL;
2518 if (parent) id = (void*) parent->user_data;
2519 wxDataViewItem item( id );
2520
2521 if (!m_wx_model->IsContainer( item ))
2522 return FALSE;
2523
2524 wxGtkTreeModelNode *parent_node = FindNode( parent );
2525 BuildBranch( parent_node );
2526
2527 // wxPrintf( "iter_nth_child %d\n", n );
2528
2529 iter->stamp = m_gtk_model->stamp;
2530 iter->user_data = parent_node->GetChildren().Item( n );
2531
2532 return TRUE;
2533 }
2534
2535 gboolean wxDataViewCtrlInternal::iter_parent( GtkTreeIter *iter, GtkTreeIter *child )
2536 {
2537 g_internal = this;
2538
2539 wxGtkTreeModelNode *node = FindParentNode( child );
2540 if (!node)
2541 return FALSE;
2542
2543 iter->stamp = m_gtk_model->stamp;
2544 iter->user_data = (gpointer) node->GetItem().GetID();
2545
2546 return TRUE;
2547 }
2548
2549 static wxGtkTreeModelNode*
2550 wxDataViewCtrlInternal_FindNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item )
2551 {
2552 if( model == NULL )
2553 return NULL;
2554
2555 ItemList list;
2556 list.DeleteContents( true );
2557 wxDataViewItem it( item );
2558 while( it.IsOk() )
2559 {
2560 wxDataViewItem * pItem = new wxDataViewItem( it );
2561 list.Insert( pItem );
2562 it = model->GetParent( it );
2563 }
2564
2565 wxGtkTreeModelNode * node = treeNode;
2566 for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
2567 {
2568 if( node && node->GetNodes().GetCount() != 0 )
2569 {
2570 int len = node->GetNodes().GetCount();
2571 wxGtkTreeModelNodes nodes = node->GetNodes();
2572 int j = 0;
2573 for( ; j < len; j ++)
2574 {
2575 if( nodes[j]->GetItem() == *(n->GetData()))
2576 {
2577 node = nodes[j];
2578 break;
2579 }
2580 }
2581
2582 if( j == len )
2583 {
2584 return NULL;
2585 }
2586 }
2587 else
2588 return NULL;
2589 }
2590 return node;
2591
2592 }
2593
2594 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
2595 {
2596 if (!iter)
2597 return m_root;
2598
2599 wxDataViewItem item( (void*) iter->user_data );
2600 if (!item.IsOk())
2601 return m_root;
2602
2603 wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
2604
2605 if (!result)
2606 {
2607 wxPrintf( "Not found %d\n", (int) iter->user_data );
2608 char *crash = NULL;
2609 *crash = 0;
2610 }
2611
2612 return result;
2613 }
2614
2615 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item )
2616 {
2617 if (!item.IsOk())
2618 return m_root;
2619
2620 wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
2621
2622 if (!result)
2623 {
2624 wxPrintf( "Not found %d\n", (int) item.GetID() );
2625 char *crash = NULL;
2626 *crash = 0;
2627 }
2628
2629 return result;
2630 }
2631
2632 static wxGtkTreeModelNode*
2633 wxDataViewCtrlInternal_FindParentNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item )
2634 {
2635 if( model == NULL )
2636 return NULL;
2637
2638 ItemList list;
2639 list.DeleteContents( true );
2640 if( !item.IsOk() )
2641 return NULL;
2642
2643 wxDataViewItem it( model->GetParent( item ) );
2644 while( it.IsOk() )
2645 {
2646 wxDataViewItem * pItem = new wxDataViewItem( it );
2647 list.Insert( pItem );
2648 it = model->GetParent( it );
2649 }
2650
2651 wxGtkTreeModelNode * node = treeNode;
2652 for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
2653 {
2654 if( node && node->GetNodes().GetCount() != 0 )
2655 {
2656 int len = node->GetNodes().GetCount();
2657 wxGtkTreeModelNodes nodes = node->GetNodes();
2658 int j = 0;
2659 for( ; j < len; j ++)
2660 {
2661 if( nodes[j]->GetItem() == *(n->GetData()))
2662 {
2663 node = nodes[j];
2664 break;
2665 }
2666 }
2667
2668 if( j == len )
2669 {
2670 return NULL;
2671 }
2672 }
2673 else
2674 return NULL;
2675 }
2676 //Examine whether the node is item's parent node
2677 int len = node->GetChildCount();
2678 for( int i = 0; i < len ; i ++ )
2679 {
2680 if( node->GetChildren().Item( i ) == item.GetID() )
2681 return node;
2682 }
2683 return NULL;
2684 }
2685
2686 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( GtkTreeIter *iter )
2687 {
2688 if (!iter)
2689 return NULL;
2690
2691 wxDataViewItem item( (void*) iter->user_data );
2692 if (!item.IsOk())
2693 return NULL;
2694
2695 return wxDataViewCtrlInternal_FindParentNode( m_wx_model, m_root, item );
2696 }
2697
2698 wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( const wxDataViewItem &item )
2699 {
2700 if (!item.IsOk())
2701 return NULL;
2702
2703 return wxDataViewCtrlInternal_FindParentNode( m_wx_model, m_root, item );
2704 }
2705
2706 //-----------------------------------------------------------------------------
2707 // wxDataViewCtrl signal callbacks
2708 //-----------------------------------------------------------------------------
2709
2710 static void
2711 wxdataview_selection_changed_callback( GtkTreeSelection* selection, wxDataViewCtrl *dv )
2712 {
2713 if (!GTK_WIDGET_REALIZED(dv->m_widget))
2714 return;
2715
2716 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_SELECTED, dv->GetId() );
2717 // TODO: item
2718 event.SetModel( dv->GetModel() );
2719 dv->GetEventHandler()->ProcessEvent( event );
2720 }
2721
2722 static void
2723 wxdataview_row_activated_callback( GtkTreeView* treeview, GtkTreePath *path,
2724 GtkTreeViewColumn *column, wxDataViewCtrl *dv )
2725 {
2726 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, dv->GetId() );
2727
2728 GtkTreeIter iter;
2729 dv->GtkGetInternal()->get_iter( &iter, path );
2730 wxDataViewItem item( (void*) iter.user_data );;
2731 event.SetItem( item );
2732 event.SetModel( dv->GetModel() );
2733 dv->GetEventHandler()->ProcessEvent( event );
2734 }
2735
2736 static gboolean
2737 wxdataview_test_expand_row_callback( GtkTreeView* treeview, GtkTreeIter* iter,
2738 GtkTreePath *path, wxDataViewCtrl *dv )
2739 {
2740 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING, dv->GetId() );
2741
2742 wxDataViewItem item( (void*) iter->user_data );;
2743 event.SetItem( item );
2744 event.SetModel( dv->GetModel() );
2745 dv->GetEventHandler()->ProcessEvent( event );
2746
2747 return !event.IsAllowed();
2748 }
2749
2750 static void
2751 wxdataview_row_expanded_callback( GtkTreeView* treeview, GtkTreeIter* iter,
2752 GtkTreePath *path, wxDataViewCtrl *dv )
2753 {
2754 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED, dv->GetId() );
2755
2756 wxDataViewItem item( (void*) iter->user_data );;
2757 event.SetItem( item );
2758 event.SetModel( dv->GetModel() );
2759 dv->GetEventHandler()->ProcessEvent( event );
2760 }
2761
2762 static gboolean
2763 wxdataview_test_collapse_row_callback( GtkTreeView* treeview, GtkTreeIter* iter,
2764 GtkTreePath *path, wxDataViewCtrl *dv )
2765 {
2766 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING, dv->GetId() );
2767
2768 wxDataViewItem item( (void*) iter->user_data );;
2769 event.SetItem( item );
2770 event.SetModel( dv->GetModel() );
2771 dv->GetEventHandler()->ProcessEvent( event );
2772
2773 return !event.IsAllowed();
2774 }
2775
2776 static void
2777 wxdataview_row_collapsed_callback( GtkTreeView* treeview, GtkTreeIter* iter,
2778 GtkTreePath *path, wxDataViewCtrl *dv )
2779 {
2780 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED, dv->GetId() );
2781
2782 wxDataViewItem item( (void*) iter->user_data );;
2783 event.SetItem( item );
2784 event.SetModel( dv->GetModel() );
2785 dv->GetEventHandler()->ProcessEvent( event );
2786 }
2787
2788 //-----------------------------------------------------------------------------
2789 // wxDataViewCtrl
2790 //-----------------------------------------------------------------------------
2791
2792 //-----------------------------------------------------------------------------
2793 // InsertChild for wxDataViewCtrl
2794 //-----------------------------------------------------------------------------
2795
2796 static void wxInsertChildInDataViewCtrl( wxWindowGTK* parent, wxWindowGTK* child )
2797 {
2798 wxDataViewCtrl * dvc = (wxDataViewCtrl*) parent;
2799 GtkWidget *treeview = dvc->GtkGetTreeView();
2800
2801 // Insert widget in GtkTreeView
2802 if (GTK_WIDGET_REALIZED(treeview))
2803 gtk_widget_set_parent_window( child->m_widget,
2804 gtk_tree_view_get_bin_window( GTK_TREE_VIEW(treeview) ) );
2805 gtk_widget_set_parent( child->m_widget, treeview );
2806 }
2807
2808 static
2809 void gtk_dataviewctrl_size_callback( GtkWidget *WXUNUSED(widget),
2810 GtkAllocation *alloc,
2811 wxDataViewCtrl *win )
2812 {
2813 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
2814 while (node)
2815 {
2816 wxWindow *child = node->GetData();
2817
2818 GtkRequisition req;
2819 gtk_widget_size_request( child->m_widget, &req );
2820
2821 GtkAllocation alloc;
2822 alloc.x = child->m_x;
2823 alloc.y = child->m_y;
2824 alloc.width = child->m_width;
2825 alloc.height = child->m_height;
2826 gtk_widget_size_allocate( child->m_widget, &alloc );
2827
2828 node = node->GetNext();
2829 }
2830 }
2831
2832
2833
2834 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
2835
2836 wxDataViewCtrl::~wxDataViewCtrl()
2837 {
2838 if (m_notifier)
2839 GetModel()->RemoveNotifier( m_notifier );
2840
2841 // remove the model from the GtkTreeView before it gets destroyed by the
2842 // wxDataViewCtrlBase's dtor
2843 gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview), NULL );
2844
2845 delete m_internal;
2846 }
2847
2848 void wxDataViewCtrl::Init()
2849 {
2850 m_notifier = NULL;
2851 }
2852
2853 bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
2854 const wxPoint& pos, const wxSize& size,
2855 long style, const wxValidator& validator )
2856 {
2857 Init();
2858
2859 if (!PreCreation( parent, pos, size ) ||
2860 !CreateBase( parent, id, pos, size, style, validator ))
2861 {
2862 wxFAIL_MSG( wxT("wxDataViewCtrl creation failed") );
2863 return false;
2864 }
2865
2866 m_insertCallback = wxInsertChildInDataViewCtrl;
2867
2868 m_widget = gtk_scrolled_window_new (NULL, NULL);
2869
2870 GtkScrolledWindowSetBorder(m_widget, style);
2871
2872 m_treeview = gtk_tree_view_new();
2873 gtk_container_add (GTK_CONTAINER (m_widget), m_treeview);
2874
2875 g_signal_connect (m_treeview, "size_allocate",
2876 G_CALLBACK (gtk_dataviewctrl_size_callback), this);
2877
2878 #ifdef __WXGTK26__
2879 if (!gtk_check_version(2,6,0))
2880 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), TRUE );
2881 #endif
2882
2883 if (style & wxDV_MULTIPLE)
2884 {
2885 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
2886 gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
2887 }
2888
2889 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(m_treeview), (style & wxDV_NO_HEADER) == 0 );
2890
2891 #ifdef __WXGTK210__
2892 if (!gtk_check_version(2,10,0))
2893 {
2894 GtkTreeViewGridLines grid = GTK_TREE_VIEW_GRID_LINES_NONE;
2895
2896 if ((style & wxDV_HORIZ_RULES) != 0 &&
2897 (style & wxDV_VERT_RULES) != 0)
2898 grid = GTK_TREE_VIEW_GRID_LINES_BOTH;
2899 else if (style & wxDV_VERT_RULES)
2900 grid = GTK_TREE_VIEW_GRID_LINES_VERTICAL;
2901 else if (style & wxDV_HORIZ_RULES)
2902 grid = GTK_TREE_VIEW_GRID_LINES_HORIZONTAL;
2903
2904 gtk_tree_view_set_grid_lines( GTK_TREE_VIEW(m_treeview), grid );
2905 }
2906 else
2907 #endif
2908 {
2909 gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(m_treeview), (style & wxDV_HORIZ_RULES) != 0 );
2910 }
2911
2912 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_widget),
2913 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2914 gtk_widget_show (m_treeview);
2915
2916 m_parent->DoAddChild( this );
2917
2918 PostCreation(size);
2919
2920 GtkEnableSelectionEvents();
2921
2922 g_signal_connect_after (m_treeview, "row-activated",
2923 G_CALLBACK (wxdataview_row_activated_callback), this);
2924
2925 g_signal_connect (m_treeview, "test-collapse-row",
2926 G_CALLBACK (wxdataview_test_collapse_row_callback), this);
2927
2928 g_signal_connect_after (m_treeview, "row-collapsed",
2929 G_CALLBACK (wxdataview_row_collapsed_callback), this);
2930
2931 g_signal_connect (m_treeview, "test-expand-row",
2932 G_CALLBACK (wxdataview_test_expand_row_callback), this);
2933
2934 g_signal_connect_after (m_treeview, "row-expanded",
2935 G_CALLBACK (wxdataview_row_expanded_callback), this);
2936
2937 return true;
2938 }
2939
2940 void wxDataViewCtrl::OnInternalIdle()
2941 {
2942 wxWindow::OnInternalIdle();
2943
2944 unsigned int cols = GetColumnCount();
2945 unsigned int i;
2946 for (i = 0; i < cols; i++)
2947 {
2948 wxDataViewColumn *col = GetColumn( i );
2949 col->OnInternalIdle();
2950 }
2951 }
2952
2953 bool wxDataViewCtrl::AssociateModel( wxDataViewModel *model )
2954 {
2955 if (!wxDataViewCtrlBase::AssociateModel( model ))
2956 return false;
2957
2958 GtkWxTreeModel *gtk_model = wxgtk_tree_model_new();
2959 m_internal = new wxDataViewCtrlInternal( this, model, gtk_model );
2960 gtk_model->internal = m_internal;
2961
2962 m_notifier = new wxGtkDataViewModelNotifier( gtk_model, model, this );
2963
2964 model->AddNotifier( m_notifier );
2965
2966 gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview), GTK_TREE_MODEL(gtk_model) );
2967
2968 // unref in wxDataViewCtrlInternal
2969 // g_object_unref( gtk_model );
2970
2971 return true;
2972 }
2973
2974 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
2975 {
2976 if (!wxDataViewCtrlBase::AppendColumn(col))
2977 return false;
2978
2979 GtkTreeViewColumn *column = (GtkTreeViewColumn *)col->GetGtkHandle();
2980
2981 gtk_tree_view_append_column( GTK_TREE_VIEW(m_treeview), column );
2982
2983 return true;
2984 }
2985
2986 wxDataViewItem wxDataViewCtrl::GetSelection()
2987 {
2988 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
2989
2990 if (m_windowStyle & wxDV_MULTIPLE)
2991 {
2992 }
2993 else
2994 {
2995 GtkTreeIter iter;
2996 if (gtk_tree_selection_get_selected( selection, NULL, &iter ))
2997 {
2998 wxDataViewItem item( (void*) iter.user_data );
2999 return item;
3000 }
3001 }
3002
3003 return wxDataViewItem(0);
3004 }
3005
3006 int wxDataViewCtrl::GetSelections( wxDataViewItemArray & sel ) const
3007 {
3008 return 0;
3009 }
3010
3011 void wxDataViewCtrl::SetSelections( const wxDataViewItemArray & sel )
3012 {
3013 }
3014
3015 void wxDataViewCtrl::Select( const wxDataViewItem & item )
3016 {
3017 }
3018
3019 void wxDataViewCtrl::Unselect( const wxDataViewItem & item )
3020 {
3021 }
3022
3023 bool wxDataViewCtrl::IsSelected( const wxDataViewItem & item ) const
3024 {
3025 return false;
3026 }
3027
3028 void wxDataViewCtrl::SelectAll()
3029 {
3030 }
3031
3032 void wxDataViewCtrl::UnselectAll()
3033 {
3034 }
3035
3036 void wxDataViewCtrl::EnsureVisible( const wxDataViewItem & item )
3037 {
3038 }
3039
3040 void wxDataViewCtrl::DoSetExpanderColumn()
3041 {
3042 }
3043
3044 void wxDataViewCtrl::DoSetIndent()
3045 {
3046 }
3047
3048 void wxDataViewCtrl::GtkDisableSelectionEvents()
3049 {
3050 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
3051 g_signal_connect_after (selection, "changed",
3052 G_CALLBACK (wxdataview_selection_changed_callback), this);
3053 }
3054
3055 void wxDataViewCtrl::GtkEnableSelectionEvents()
3056 {
3057 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
3058 g_signal_handlers_disconnect_by_func( selection,
3059 (gpointer) (wxdataview_selection_changed_callback), this);
3060 }
3061
3062 // static
3063 wxVisualAttributes
3064 wxDataViewCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
3065 {
3066 return GetDefaultAttributesFromGTKWidget(gtk_tree_view_new);
3067 }
3068
3069
3070 #endif
3071 // !wxUSE_GENERICDATAVIEWCTRL
3072
3073 #endif
3074 // wxUSE_DATAVIEWCTRL