]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/dataview.cpp
fixing utf32 native conversion
[wxWidgets.git] / src / gtk / dataview.cpp
... / ...
CommitLineData
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 #include "wx/settings.h"
24 #include "wx/crt.h"
25#endif
26
27#include "wx/stockitem.h"
28#include "wx/calctrl.h"
29#include "wx/popupwin.h"
30#include "wx/listimpl.cpp"
31
32#include "wx/gtk/private.h"
33#include "wx/gtk/dc.h"
34#include "wx/gtk/dcclient.h"
35
36//-----------------------------------------------------------------------------
37//-----------------------------------------------------------------------------
38
39static wxDataViewCtrlInternal *gs_internal = NULL;
40
41class wxGtkTreeModelNode;
42
43extern "C" {
44typedef struct _GtkWxTreeModel GtkWxTreeModel;
45}
46
47//-----------------------------------------------------------------------------
48// wxDataViewCtrlInternal
49//-----------------------------------------------------------------------------
50
51WX_DECLARE_LIST(wxDataViewItem, ItemList);
52WX_DEFINE_LIST(ItemList)
53
54class WXDLLIMPEXP_ADV wxDataViewCtrlInternal
55{
56public:
57 wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataViewModel *wx_model, GtkWxTreeModel *gtk_model );
58 ~wxDataViewCtrlInternal();
59
60 // model iface
61 GtkTreeModelFlags get_flags();
62 gboolean get_iter( GtkTreeIter *iter, GtkTreePath *path );
63 GtkTreePath *get_path( GtkTreeIter *iter);
64 gboolean iter_next( GtkTreeIter *iter );
65 gboolean iter_children( GtkTreeIter *iter, GtkTreeIter *parent);
66 gboolean iter_has_child( GtkTreeIter *iter );
67 gint iter_n_children( GtkTreeIter *iter );
68 gboolean iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n );
69 gboolean iter_parent( GtkTreeIter *iter, GtkTreeIter *child );
70
71 // dnd iface
72
73 bool EnableDragSource( const wxDataFormat &format );
74 bool EnableDropTarget( const wxDataFormat &format );
75
76 gboolean row_draggable( GtkTreeDragSource *drag_source, GtkTreePath *path );
77 gboolean drag_data_delete( GtkTreeDragSource *drag_source, GtkTreePath* path );
78 gboolean drag_data_get( GtkTreeDragSource *drag_source, GtkTreePath *path,
79 GtkSelectionData *selection_data );
80 gboolean drag_data_received( GtkTreeDragDest *drag_dest, GtkTreePath *dest,
81 GtkSelectionData *selection_data );
82 gboolean row_drop_possible( GtkTreeDragDest *drag_dest, GtkTreePath *dest_path,
83 GtkSelectionData *selection_data );
84
85 // notifactions from wxDataViewModel
86 bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
87 bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
88 bool ItemChanged( const wxDataViewItem &item );
89 bool ValueChanged( const wxDataViewItem &item, unsigned int col );
90 bool Cleared();
91 void Resort();
92
93 // sorting interface
94 void SetSortOrder( GtkSortType sort_order ) { m_sort_order = sort_order; }
95 GtkSortType GetSortOrder() { return m_sort_order; }
96
97 void SetSortColumn( int column ) { m_sort_column = column; }
98 int GetSortColumn() { return m_sort_column; }
99
100 void SetDataViewSortColumn( wxDataViewColumn *column ) { m_dataview_sort_column = column; }
101 wxDataViewColumn *GetDataViewSortColumn() { return m_dataview_sort_column; }
102
103 bool IsSorted() { return (m_sort_column >= 0); }
104
105 // accessors
106 wxDataViewModel* GetDataViewModel() { return m_wx_model; }
107 wxDataViewCtrl* GetOwner() { return m_owner; }
108 GtkWxTreeModel* GetGtkModel() { return m_gtk_model; }
109
110protected:
111 void InitTree();
112 wxGtkTreeModelNode *FindNode( const wxDataViewItem &item );
113 wxGtkTreeModelNode *FindNode( GtkTreeIter *iter );
114 wxGtkTreeModelNode *FindParentNode( const wxDataViewItem &item );
115 wxGtkTreeModelNode *FindParentNode( GtkTreeIter *iter );
116 void BuildBranch( wxGtkTreeModelNode *branch );
117
118private:
119 wxGtkTreeModelNode *m_root;
120 wxDataViewModel *m_wx_model;
121 GtkWxTreeModel *m_gtk_model;
122 wxDataViewCtrl *m_owner;
123 GtkSortType m_sort_order;
124 wxDataViewColumn *m_dataview_sort_column;
125 int m_sort_column;
126
127 GtkTargetEntry m_dragSourceTargetEntry;
128 wxCharBuffer m_dragSourceTargetEntryTarget;
129 wxDataObject *m_dragDataObject;
130
131 GtkTargetEntry m_dropTargetTargetEntry;
132 wxCharBuffer m_dropTargetTargetEntryTarget;
133 wxDataObject *m_dropDataObject;
134};
135
136
137//-----------------------------------------------------------------------------
138// wxGtkTreeModelNode
139//-----------------------------------------------------------------------------
140
141static
142int LINKAGEMODE wxGtkTreeModelChildCmp( void** id1, void** id2 )
143{
144 int ret = gs_internal->GetDataViewModel()->Compare( *id1, *id2,
145 gs_internal->GetSortColumn(), (gs_internal->GetSortOrder() == GTK_SORT_ASCENDING) );
146
147 return ret;
148}
149
150WX_DEFINE_ARRAY_PTR( wxGtkTreeModelNode*, wxGtkTreeModelNodes );
151WX_DEFINE_ARRAY_PTR( void*, wxGtkTreeModelChildren );
152
153class wxGtkTreeModelNode
154{
155public:
156 wxGtkTreeModelNode( wxGtkTreeModelNode* parent, const wxDataViewItem &item,
157 wxDataViewCtrlInternal *internal )
158 {
159 m_parent = parent;
160 m_item = item;
161 m_internal = internal;
162 }
163
164 ~wxGtkTreeModelNode()
165 {
166 size_t count = m_nodes.GetCount();
167 size_t i;
168 for (i = 0; i < count; i++)
169 {
170 wxGtkTreeModelNode *child = m_nodes.Item( i );
171 delete child;
172 }
173 }
174
175 unsigned int AddNode( wxGtkTreeModelNode* child )
176 {
177 m_nodes.Add( child );
178
179 void *id = child->GetItem().GetID();
180
181 m_children.Add( id );
182
183 if (m_internal->IsSorted() || m_internal->GetDataViewModel()->HasDefaultCompare())
184 {
185 gs_internal = m_internal;
186 m_children.Sort( &wxGtkTreeModelChildCmp );
187 return m_children.Index( id );
188 }
189
190 return m_children.GetCount()-1;
191 }
192
193 unsigned int AddLeave( void* id )
194 {
195 m_children.Add( id );
196
197 if (m_internal->IsSorted() || m_internal->GetDataViewModel()->HasDefaultCompare())
198 {
199 gs_internal = m_internal;
200 m_children.Sort( &wxGtkTreeModelChildCmp );
201 return m_children.Index( id );
202 }
203
204 return m_children.GetCount()-1;
205 }
206
207 void DeleteChild( void* id )
208 {
209 m_children.Remove( id );
210
211 unsigned int count = m_nodes.GetCount();
212 unsigned int pos;
213 for (pos = 0; pos < count; pos++)
214 {
215 wxGtkTreeModelNode *node = m_nodes.Item( pos );
216 if (node->GetItem().GetID() == id)
217 {
218 m_nodes.RemoveAt( pos );
219 delete node;
220 break;
221 }
222 }
223
224 }
225
226 wxGtkTreeModelNode* GetParent()
227 { return m_parent; }
228 wxGtkTreeModelNodes &GetNodes()
229 { return m_nodes; }
230 wxGtkTreeModelChildren &GetChildren()
231 { return m_children; }
232
233 unsigned int GetChildCount() { return m_children.GetCount(); }
234 unsigned int GetNodesCount() { return m_nodes.GetCount(); }
235
236 wxDataViewItem &GetItem() { return m_item; }
237 wxDataViewCtrlInternal *GetInternal() { return m_internal; }
238
239 void Resort();
240
241private:
242 wxGtkTreeModelNode *m_parent;
243 wxGtkTreeModelNodes m_nodes;
244 wxGtkTreeModelChildren m_children;
245 wxDataViewItem m_item;
246 wxDataViewCtrlInternal *m_internal;
247};
248
249
250//-----------------------------------------------------------------------------
251// data
252//-----------------------------------------------------------------------------
253
254extern bool g_blockEventsOnDrag;
255
256//-----------------------------------------------------------------------------
257// define new GTK+ class wxGtkTreeModel
258//-----------------------------------------------------------------------------
259
260extern "C" {
261
262#define GTK_TYPE_WX_TREE_MODEL (gtk_wx_tree_model_get_type ())
263#define GTK_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModel))
264#define GTK_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
265#define GTK_IS_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_TREE_MODEL))
266#define GTK_IS_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_TREE_MODEL))
267#define GTK_WX_TREE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
268
269GType gtk_wx_tree_model_get_type (void);
270
271typedef struct _GtkWxTreeModelClass GtkWxTreeModelClass;
272
273struct _GtkWxTreeModel
274{
275 GObject parent;
276
277 /*< private >*/
278 gint stamp;
279 wxDataViewCtrlInternal *internal;
280};
281
282struct _GtkWxTreeModelClass
283{
284 GObjectClass list_parent_class;
285};
286
287static GtkWxTreeModel *wxgtk_tree_model_new (void);
288static void wxgtk_tree_model_init (GtkWxTreeModel *tree_model);
289static void wxgtk_tree_model_class_init (GtkWxTreeModelClass *klass);
290
291static void wxgtk_tree_model_tree_model_init (GtkTreeModelIface *iface);
292static void wxgtk_tree_model_sortable_init (GtkTreeSortableIface *iface);
293static void wxgtk_tree_model_drag_source_init(GtkTreeDragSourceIface *iface);
294static void wxgtk_tree_model_drag_dest_init (GtkTreeDragDestIface *iface);
295
296static void wxgtk_tree_model_finalize (GObject *object);
297static GtkTreeModelFlags wxgtk_tree_model_get_flags (GtkTreeModel *tree_model);
298static gint wxgtk_tree_model_get_n_columns (GtkTreeModel *tree_model);
299static GType wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model,
300 gint index);
301static gboolean wxgtk_tree_model_get_iter (GtkTreeModel *tree_model,
302 GtkTreeIter *iter,
303 GtkTreePath *path);
304static GtkTreePath *wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
305 GtkTreeIter *iter);
306static void wxgtk_tree_model_get_value (GtkTreeModel *tree_model,
307 GtkTreeIter *iter,
308 gint column,
309 GValue *value);
310static gboolean wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
311 GtkTreeIter *iter);
312static gboolean wxgtk_tree_model_iter_children (GtkTreeModel *tree_model,
313 GtkTreeIter *iter,
314 GtkTreeIter *parent);
315static gboolean wxgtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
316 GtkTreeIter *iter);
317static gint wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
318 GtkTreeIter *iter);
319static gboolean wxgtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
320 GtkTreeIter *iter,
321 GtkTreeIter *parent,
322 gint n);
323static gboolean wxgtk_tree_model_iter_parent (GtkTreeModel *tree_model,
324 GtkTreeIter *iter,
325 GtkTreeIter *child);
326
327/* sortable */
328static gboolean wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
329 gint *sort_column_id,
330 GtkSortType *order);
331static void wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
332 gint sort_column_id,
333 GtkSortType order);
334static void wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable,
335 gint sort_column_id,
336 GtkTreeIterCompareFunc func,
337 gpointer data,
338 GtkDestroyNotify destroy);
339static void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable,
340 GtkTreeIterCompareFunc func,
341 gpointer data,
342 GtkDestroyNotify destroy);
343static gboolean wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable);
344
345/* drag'n'drop */
346static gboolean wxgtk_tree_model_row_draggable (GtkTreeDragSource *drag_source,
347 GtkTreePath *path);
348static gboolean wxgtk_tree_model_drag_data_delete (GtkTreeDragSource *drag_source,
349 GtkTreePath *path);
350static gboolean wxgtk_tree_model_drag_data_get (GtkTreeDragSource *drag_source,
351 GtkTreePath *path,
352 GtkSelectionData *selection_data);
353static gboolean wxgtk_tree_model_drag_data_received (GtkTreeDragDest *drag_dest,
354 GtkTreePath *dest,
355 GtkSelectionData *selection_data);
356static gboolean wxgtk_tree_model_row_drop_possible (GtkTreeDragDest *drag_dest,
357 GtkTreePath *dest_path,
358 GtkSelectionData *selection_data);
359
360
361static GObjectClass *list_parent_class = NULL;
362
363GType
364gtk_wx_tree_model_get_type (void)
365{
366 static GType tree_model_type = 0;
367
368 if (!tree_model_type)
369 {
370 const GTypeInfo tree_model_info =
371 {
372 sizeof (GtkWxTreeModelClass),
373 NULL, /* base_init */
374 NULL, /* base_finalize */
375 (GClassInitFunc) wxgtk_tree_model_class_init,
376 NULL, /* class_finalize */
377 NULL, /* class_data */
378 sizeof (GtkWxTreeModel),
379 0,
380 (GInstanceInitFunc) wxgtk_tree_model_init,
381 };
382
383 static const GInterfaceInfo tree_model_iface_info =
384 {
385 (GInterfaceInitFunc) wxgtk_tree_model_tree_model_init,
386 NULL,
387 NULL
388 };
389
390 static const GInterfaceInfo sortable_iface_info =
391 {
392 (GInterfaceInitFunc) wxgtk_tree_model_sortable_init,
393 NULL,
394 NULL
395 };
396
397 static const GInterfaceInfo drag_source_iface_info =
398 {
399 (GInterfaceInitFunc) wxgtk_tree_model_drag_source_init,
400 NULL,
401 NULL
402 };
403
404 static const GInterfaceInfo drag_dest_iface_info =
405 {
406 (GInterfaceInitFunc) wxgtk_tree_model_drag_dest_init,
407 NULL,
408 NULL
409 };
410
411 tree_model_type = g_type_register_static (G_TYPE_OBJECT, "GtkWxTreeModel",
412 &tree_model_info, (GTypeFlags)0 );
413
414 g_type_add_interface_static (tree_model_type,
415 GTK_TYPE_TREE_MODEL,
416 &tree_model_iface_info);
417 g_type_add_interface_static (tree_model_type,
418 GTK_TYPE_TREE_SORTABLE,
419 &sortable_iface_info);
420 g_type_add_interface_static (tree_model_type,
421 GTK_TYPE_TREE_DRAG_DEST,
422 &drag_dest_iface_info);
423 g_type_add_interface_static (tree_model_type,
424 GTK_TYPE_TREE_DRAG_SOURCE,
425 &drag_source_iface_info);
426 }
427
428 return tree_model_type;
429}
430
431static GtkWxTreeModel *
432wxgtk_tree_model_new(void)
433{
434 GtkWxTreeModel *retval = (GtkWxTreeModel *) g_object_new (GTK_TYPE_WX_TREE_MODEL, NULL);
435 return retval;
436}
437
438static void
439wxgtk_tree_model_class_init (GtkWxTreeModelClass *klass)
440{
441 list_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
442 GObjectClass *object_class = (GObjectClass*) klass;
443 object_class->finalize = wxgtk_tree_model_finalize;
444}
445
446static void
447wxgtk_tree_model_tree_model_init (GtkTreeModelIface *iface)
448{
449 iface->get_flags = wxgtk_tree_model_get_flags;
450 iface->get_n_columns = wxgtk_tree_model_get_n_columns;
451 iface->get_column_type = wxgtk_tree_model_get_column_type;
452 iface->get_iter = wxgtk_tree_model_get_iter;
453 iface->get_path = wxgtk_tree_model_get_path;
454 iface->get_value = wxgtk_tree_model_get_value;
455 iface->iter_next = wxgtk_tree_model_iter_next;
456 iface->iter_children = wxgtk_tree_model_iter_children;
457 iface->iter_has_child = wxgtk_tree_model_iter_has_child;
458 iface->iter_n_children = wxgtk_tree_model_iter_n_children;
459 iface->iter_nth_child = wxgtk_tree_model_iter_nth_child;
460 iface->iter_parent = wxgtk_tree_model_iter_parent;
461}
462
463static void
464wxgtk_tree_model_sortable_init (GtkTreeSortableIface *iface)
465{
466 iface->get_sort_column_id = wxgtk_tree_model_get_sort_column_id;
467 iface->set_sort_column_id = wxgtk_tree_model_set_sort_column_id;
468 iface->set_sort_func = wxgtk_tree_model_set_sort_func;
469 iface->set_default_sort_func = wxgtk_tree_model_set_default_sort_func;
470 iface->has_default_sort_func = wxgtk_tree_model_has_default_sort_func;
471}
472
473static void
474wxgtk_tree_model_drag_source_init(GtkTreeDragSourceIface *iface)
475{
476 iface->row_draggable = wxgtk_tree_model_row_draggable;
477 iface->drag_data_delete = wxgtk_tree_model_drag_data_delete;
478 iface->drag_data_get = wxgtk_tree_model_drag_data_get;
479}
480
481static void
482wxgtk_tree_model_drag_dest_init (GtkTreeDragDestIface *iface)
483{
484 iface->drag_data_received = wxgtk_tree_model_drag_data_received;
485 iface->row_drop_possible = wxgtk_tree_model_row_drop_possible;
486}
487
488static void
489wxgtk_tree_model_init (GtkWxTreeModel *tree_model)
490{
491 tree_model->internal = NULL;
492 tree_model->stamp = g_random_int();
493}
494
495static void
496wxgtk_tree_model_finalize (GObject *object)
497{
498 /* must chain up */
499 (* list_parent_class->finalize) (object);
500}
501
502} // extern "C"
503
504//-----------------------------------------------------------------------------
505// implement callbacks from wxGtkTreeModel class by letting
506// them call the methods of wxWidgets' wxDataViewModel
507//-----------------------------------------------------------------------------
508
509static GtkTreeModelFlags
510wxgtk_tree_model_get_flags (GtkTreeModel *tree_model)
511{
512 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
513 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), (GtkTreeModelFlags)0 );
514
515 return wxtree_model->internal->get_flags();
516}
517
518static gint
519wxgtk_tree_model_get_n_columns (GtkTreeModel *tree_model)
520{
521 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
522 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), 0);
523
524 return wxtree_model->internal->GetDataViewModel()->GetColumnCount();
525}
526
527static GType
528wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model,
529 gint index)
530{
531 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
532 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), G_TYPE_INVALID);
533
534 GType gtype = G_TYPE_INVALID;
535
536 wxString wxtype = wxtree_model->internal->GetDataViewModel()->GetColumnType( (unsigned int) index );
537
538 wxPrintf( "get_column_type %s\n", wxtype );
539
540 if (wxtype == wxT("string"))
541 gtype = G_TYPE_STRING;
542 else
543 {
544 gtype = G_TYPE_STRING;
545 // wxFAIL_MSG( _T("non-string columns not supported yet") );
546 }
547
548 return gtype;
549}
550
551static gboolean
552wxgtk_tree_model_get_iter (GtkTreeModel *tree_model,
553 GtkTreeIter *iter,
554 GtkTreePath *path)
555{
556 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
557 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
558 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
559
560 return wxtree_model->internal->get_iter( iter, path );
561}
562
563static GtkTreePath *
564wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
565 GtkTreeIter *iter)
566{
567 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
568 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), NULL);
569 g_return_val_if_fail (iter->stamp == GTK_WX_TREE_MODEL (wxtree_model)->stamp, NULL);
570
571 return wxtree_model->internal->get_path( iter );
572}
573
574static void
575wxgtk_tree_model_get_value (GtkTreeModel *tree_model,
576 GtkTreeIter *iter,
577 gint column,
578 GValue *value)
579{
580 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
581 g_return_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model) );
582
583 wxDataViewModel *model = wxtree_model->internal->GetDataViewModel();
584 wxString mtype = model->GetColumnType( (unsigned int) column );
585 if (mtype == wxT("string"))
586 {
587 wxVariant variant;
588 g_value_init( value, G_TYPE_STRING );
589 wxDataViewItem item( (void*) iter->user_data );
590 model->GetValue( variant, item, (unsigned int) column );
591
592 g_value_set_string( value, variant.GetString().utf8_str() );
593 }
594 else
595 {
596 wxFAIL_MSG( _T("non-string columns not supported yet") );
597 }
598}
599
600static gboolean
601wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
602 GtkTreeIter *iter)
603{
604 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
605
606 if (wxtree_model->stamp != iter->stamp)
607 wxPrintf( "crash\n" );
608
609 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
610 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
611
612 return wxtree_model->internal->iter_next( iter );
613}
614
615static gboolean
616wxgtk_tree_model_iter_children (GtkTreeModel *tree_model,
617 GtkTreeIter *iter,
618 GtkTreeIter *parent)
619{
620 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
621 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
622 g_return_val_if_fail (wxtree_model->stamp == parent->stamp, FALSE);
623
624 return wxtree_model->internal->iter_children( iter, parent );
625}
626
627static gboolean
628wxgtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
629 GtkTreeIter *iter)
630{
631 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
632 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
633 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
634
635 return wxtree_model->internal->iter_has_child( iter );
636}
637
638static gint
639wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
640 GtkTreeIter *iter)
641{
642 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
643 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
644
645 if (iter != NULL)
646 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, 0);
647
648 return wxtree_model->internal->iter_n_children( iter );
649}
650
651static gboolean
652wxgtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
653 GtkTreeIter *iter,
654 GtkTreeIter *parent,
655 gint n)
656{
657 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
658 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
659
660 return wxtree_model->internal->iter_nth_child( iter, parent, n );
661}
662
663static gboolean
664wxgtk_tree_model_iter_parent (GtkTreeModel *tree_model,
665 GtkTreeIter *iter,
666 GtkTreeIter *child)
667{
668 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
669 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
670 g_return_val_if_fail (wxtree_model->stamp == child->stamp, FALSE);
671
672 return wxtree_model->internal->iter_parent( iter, child );
673}
674
675/* drag'n'drop iface */
676static gboolean
677wxgtk_tree_model_row_draggable (GtkTreeDragSource *drag_source,
678 GtkTreePath *path)
679{
680 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_source;
681 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
682
683 return wxtree_model->internal->row_draggable( drag_source, path );
684}
685
686static gboolean
687wxgtk_tree_model_drag_data_delete (GtkTreeDragSource *drag_source,
688 GtkTreePath *path)
689{
690 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_source;
691 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
692
693 return wxtree_model->internal->drag_data_delete( drag_source, path );
694}
695
696static gboolean
697wxgtk_tree_model_drag_data_get (GtkTreeDragSource *drag_source,
698 GtkTreePath *path,
699 GtkSelectionData *selection_data)
700{
701 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_source;
702 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
703
704#if 0
705 wxPrintf( "drag_get_data\n");
706
707 wxGtkString atom_selection(gdk_atom_name(selection_data->selection));
708 wxPrintf( "selection %s\n", wxString::FromAscii(atom_selection) );
709
710 wxGtkString atom_target(gdk_atom_name(selection_data->target));
711 wxPrintf( "target %s\n", wxString::FromAscii(atom_target) );
712
713 wxGtkString atom_type(gdk_atom_name(selection_data->type));
714 wxPrintf( "type %s\n", wxString::FromAscii(atom_type) );
715
716 wxPrintf( "format %d\n", selection_data->format );
717#endif
718
719 return wxtree_model->internal->drag_data_get( drag_source, path, selection_data );
720}
721
722static gboolean
723wxgtk_tree_model_drag_data_received (GtkTreeDragDest *drag_dest,
724 GtkTreePath *dest,
725 GtkSelectionData *selection_data)
726{
727 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_dest;
728 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
729
730 return wxtree_model->internal->drag_data_received( drag_dest, dest, selection_data );
731}
732
733static gboolean
734wxgtk_tree_model_row_drop_possible (GtkTreeDragDest *drag_dest,
735 GtkTreePath *dest_path,
736 GtkSelectionData *selection_data)
737{
738 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_dest;
739 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
740
741 return wxtree_model->internal->row_drop_possible( drag_dest, dest_path, selection_data );
742}
743
744/* sortable iface */
745static gboolean
746wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
747 gint *sort_column_id,
748 GtkSortType *order)
749{
750 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) sortable;
751
752 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (sortable), FALSE);
753
754 if (!wxtree_model->internal->IsSorted())
755 {
756 if (sort_column_id)
757 *sort_column_id = -1;
758
759 return TRUE;
760 }
761
762
763 if (sort_column_id)
764 *sort_column_id = wxtree_model->internal->GetSortColumn();
765
766 if (order)
767 *order = wxtree_model->internal->GetSortOrder();
768
769 return TRUE;
770}
771
772wxDataViewColumn *gs_lastLeftClickHeader = NULL;
773
774static void
775wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
776 gint sort_column_id,
777 GtkSortType order)
778{
779 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) sortable;
780 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
781
782 tree_model->internal->SetDataViewSortColumn( gs_lastLeftClickHeader );
783
784 if ((sort_column_id != (gint) tree_model->internal->GetSortColumn()) ||
785 (order != tree_model->internal->GetSortOrder()))
786 {
787 tree_model->internal->SetSortColumn( sort_column_id );
788 tree_model->internal->SetSortOrder( order );
789
790 gtk_tree_sortable_sort_column_changed (sortable);
791
792 tree_model->internal->GetDataViewModel()->Resort();
793 }
794
795 if (gs_lastLeftClickHeader)
796 {
797 wxDataViewCtrl *dv = tree_model->internal->GetOwner();
798 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, dv->GetId() );
799 event.SetDataViewColumn( gs_lastLeftClickHeader );
800 event.SetModel( dv->GetModel() );
801 dv->HandleWindowEvent( event );
802 }
803
804 gs_lastLeftClickHeader = NULL;
805}
806
807static void
808wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable,
809 gint WXUNUSED(sort_column_id),
810 GtkTreeIterCompareFunc func,
811 gpointer WXUNUSED(data),
812 GtkDestroyNotify WXUNUSED(destroy) )
813{
814 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
815 g_return_if_fail (func != NULL);
816}
817
818void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable,
819 GtkTreeIterCompareFunc func,
820 gpointer WXUNUSED(data),
821 GtkDestroyNotify WXUNUSED(destroy) )
822{
823 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
824 g_return_if_fail (func != NULL);
825
826 wxPrintf( "wxgtk_tree_model_set_default_sort_func\n" );
827}
828
829gboolean wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable)
830{
831 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (sortable), FALSE );
832
833 return FALSE;
834}
835
836//-----------------------------------------------------------------------------
837// define new GTK+ class wxGtkRendererRenderer
838//-----------------------------------------------------------------------------
839
840extern "C" {
841
842#define GTK_TYPE_WX_CELL_RENDERER (gtk_wx_cell_renderer_get_type ())
843#define GTK_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRenderer))
844#define GTK_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
845#define GTK_IS_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_CELL_RENDERER))
846#define GTK_IS_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_CELL_RENDERER))
847#define GTK_WX_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
848
849GType gtk_wx_cell_renderer_get_type (void);
850
851typedef struct _GtkWxCellRenderer GtkWxCellRenderer;
852typedef struct _GtkWxCellRendererClass GtkWxCellRendererClass;
853
854struct _GtkWxCellRenderer
855{
856 GtkCellRenderer parent;
857
858 /*< private >*/
859 wxDataViewCustomRenderer *cell;
860 guint32 last_click;
861};
862
863struct _GtkWxCellRendererClass
864{
865 GtkCellRendererClass cell_parent_class;
866};
867
868
869static GtkCellRenderer *gtk_wx_cell_renderer_new (void);
870static void gtk_wx_cell_renderer_init (
871 GtkWxCellRenderer *cell );
872static void gtk_wx_cell_renderer_class_init(
873 GtkWxCellRendererClass *klass );
874static void gtk_wx_cell_renderer_finalize (
875 GObject *object );
876static void gtk_wx_cell_renderer_get_size (
877 GtkCellRenderer *cell,
878 GtkWidget *widget,
879 GdkRectangle *rectangle,
880 gint *x_offset,
881 gint *y_offset,
882 gint *width,
883 gint *height );
884static void gtk_wx_cell_renderer_render (
885 GtkCellRenderer *cell,
886 GdkWindow *window,
887 GtkWidget *widget,
888 GdkRectangle *background_area,
889 GdkRectangle *cell_area,
890 GdkRectangle *expose_area,
891 GtkCellRendererState flags );
892static gboolean gtk_wx_cell_renderer_activate(
893 GtkCellRenderer *cell,
894 GdkEvent *event,
895 GtkWidget *widget,
896 const gchar *path,
897 GdkRectangle *background_area,
898 GdkRectangle *cell_area,
899 GtkCellRendererState flags );
900static GtkCellEditable *gtk_wx_cell_renderer_start_editing(
901 GtkCellRenderer *cell,
902 GdkEvent *event,
903 GtkWidget *widget,
904 const gchar *path,
905 GdkRectangle *background_area,
906 GdkRectangle *cell_area,
907 GtkCellRendererState flags );
908
909
910static GObjectClass *cell_parent_class = NULL;
911
912} // extern "C"
913
914GType
915gtk_wx_cell_renderer_get_type (void)
916{
917 static GType cell_wx_type = 0;
918
919 if (!cell_wx_type)
920 {
921 const GTypeInfo cell_wx_info =
922 {
923 sizeof (GtkWxCellRendererClass),
924 NULL, /* base_init */
925 NULL, /* base_finalize */
926 (GClassInitFunc) gtk_wx_cell_renderer_class_init,
927 NULL, /* class_finalize */
928 NULL, /* class_data */
929 sizeof (GtkWxCellRenderer),
930 0, /* n_preallocs */
931 (GInstanceInitFunc) gtk_wx_cell_renderer_init,
932 };
933
934 cell_wx_type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
935 "GtkWxCellRenderer", &cell_wx_info, (GTypeFlags)0 );
936 }
937
938 return cell_wx_type;
939}
940
941static void
942gtk_wx_cell_renderer_init (GtkWxCellRenderer *cell)
943{
944 cell->cell = NULL;
945 cell->last_click = 0;
946}
947
948static void
949gtk_wx_cell_renderer_class_init (GtkWxCellRendererClass *klass)
950{
951 GObjectClass *object_class = G_OBJECT_CLASS (klass);
952 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
953
954 cell_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
955
956 object_class->finalize = gtk_wx_cell_renderer_finalize;
957
958 cell_class->get_size = gtk_wx_cell_renderer_get_size;
959 cell_class->render = gtk_wx_cell_renderer_render;
960 cell_class->activate = gtk_wx_cell_renderer_activate;
961 cell_class->start_editing = gtk_wx_cell_renderer_start_editing;
962}
963
964static void
965gtk_wx_cell_renderer_finalize (GObject *object)
966{
967 /* must chain up */
968 (* G_OBJECT_CLASS (cell_parent_class)->finalize) (object);
969}
970
971GtkCellRenderer*
972gtk_wx_cell_renderer_new (void)
973{
974 return (GtkCellRenderer*) g_object_new (GTK_TYPE_WX_CELL_RENDERER, NULL);
975}
976
977
978
979static GtkCellEditable *gtk_wx_cell_renderer_start_editing(
980 GtkCellRenderer *renderer,
981 GdkEvent *WXUNUSED(event),
982 GtkWidget *widget,
983 const gchar *path,
984 GdkRectangle *WXUNUSED(background_area),
985 GdkRectangle *cell_area,
986 GtkCellRendererState WXUNUSED(flags) )
987{
988 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
989 wxDataViewCustomRenderer *cell = wxrenderer->cell;
990
991 // Renderer doesn't support in-place editing
992 if (!cell->HasEditorCtrl())
993 return NULL;
994
995 // An in-place editing control is still around
996 if (cell->GetEditorCtrl())
997 return NULL;
998
999 GdkRectangle rect;
1000 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
1001 &rect.x,
1002 &rect.y,
1003 &rect.width,
1004 &rect.height);
1005
1006 rect.x += cell_area->x;
1007 rect.y += cell_area->y;
1008// rect.width -= renderer->xpad * 2;
1009// rect.height -= renderer->ypad * 2;
1010
1011// wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
1012 wxRect renderrect( cell_area->x, cell_area->y, cell_area->width, cell_area->height );
1013
1014 GtkTreePath *treepath = gtk_tree_path_new_from_string( path );
1015 GtkTreeIter iter;
1016 cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, treepath );
1017 wxDataViewItem item( (void*) iter.user_data );
1018 gtk_tree_path_free( treepath );
1019
1020 cell->StartEditing( item, renderrect );
1021
1022 return NULL;
1023}
1024
1025static void
1026gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer,
1027 GtkWidget *WXUNUSED(widget),
1028 GdkRectangle *cell_area,
1029 gint *x_offset,
1030 gint *y_offset,
1031 gint *width,
1032 gint *height)
1033{
1034 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
1035 wxDataViewCustomRenderer *cell = wxrenderer->cell;
1036
1037 wxSize size = cell->GetSize();
1038
1039 gint calc_width = (gint) renderer->xpad * 2 + size.x;
1040 gint calc_height = (gint) renderer->ypad * 2 + size.y;
1041
1042 if (x_offset)
1043 *x_offset = 0;
1044 if (y_offset)
1045 *y_offset = 0;
1046
1047 if (cell_area && size.x > 0 && size.y > 0)
1048 {
1049 if (x_offset)
1050 {
1051 *x_offset = (gint)((renderer->xalign *
1052 (cell_area->width - calc_width - 2 * renderer->xpad)));
1053 *x_offset = MAX (*x_offset, 0) + renderer->xpad;
1054 }
1055 if (y_offset)
1056 {
1057 *y_offset = (gint)((renderer->yalign *
1058 (cell_area->height - calc_height - 2 * renderer->ypad)));
1059 *y_offset = MAX (*y_offset, 0) + renderer->ypad;
1060 }
1061 }
1062
1063 if (width)
1064 *width = calc_width;
1065
1066 if (height)
1067 *height = calc_height;
1068}
1069
1070static void
1071gtk_wx_cell_renderer_render (GtkCellRenderer *renderer,
1072 GdkWindow *window,
1073 GtkWidget *widget,
1074 GdkRectangle *background_area,
1075 GdkRectangle *cell_area,
1076 GdkRectangle *expose_area,
1077 GtkCellRendererState flags)
1078
1079{
1080 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
1081 wxDataViewCustomRenderer *cell = wxrenderer->cell;
1082
1083 cell->window = window;
1084 cell->widget = widget;
1085 cell->background_area = (void*) background_area;
1086 cell->cell_area = (void*) cell_area;
1087 cell->expose_area = (void*) expose_area;
1088 cell->flags = (int) flags;
1089
1090 GdkRectangle rect;
1091 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
1092 &rect.x,
1093 &rect.y,
1094 &rect.width,
1095 &rect.height);
1096
1097 rect.x += cell_area->x;
1098 rect.y += cell_area->y;
1099 rect.width -= renderer->xpad * 2;
1100 rect.height -= renderer->ypad * 2;
1101
1102 GdkRectangle dummy;
1103 if (gdk_rectangle_intersect (expose_area, &rect, &dummy))
1104 {
1105 wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
1106 wxWindowDC* dc = (wxWindowDC*) cell->GetDC();
1107 wxWindowDCImpl *impl = (wxWindowDCImpl *) dc->GetImpl();
1108 // Reinitilise GDK window everytime as drawing can also
1109 // be done into DnD drop window.
1110 impl->m_gdkwindow = window;
1111 impl->SetUpDC();
1112
1113 int state = 0;
1114 if (flags & GTK_CELL_RENDERER_SELECTED)
1115 state |= wxDATAVIEW_CELL_SELECTED;
1116 if (flags & GTK_CELL_RENDERER_PRELIT)
1117 state |= wxDATAVIEW_CELL_PRELIT;
1118 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
1119 state |= wxDATAVIEW_CELL_INSENSITIVE;
1120 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
1121 state |= wxDATAVIEW_CELL_INSENSITIVE;
1122 if (flags & GTK_CELL_RENDERER_FOCUSED)
1123 state |= wxDATAVIEW_CELL_FOCUSED;
1124 cell->Render( renderrect, dc, state );
1125 }
1126}
1127
1128static gboolean
1129gtk_wx_cell_renderer_activate(
1130 GtkCellRenderer *renderer,
1131 GdkEvent *event,
1132 GtkWidget *widget,
1133 const gchar *path,
1134 GdkRectangle *WXUNUSED(background_area),
1135 GdkRectangle *cell_area,
1136 GtkCellRendererState WXUNUSED(flags) )
1137{
1138 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
1139 wxDataViewCustomRenderer *cell = wxrenderer->cell;
1140
1141 GdkRectangle rect;
1142 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
1143 &rect.x,
1144 &rect.y,
1145 &rect.width,
1146 &rect.height);
1147
1148 rect.x += cell_area->x;
1149 rect.y += cell_area->y;
1150 rect.width -= renderer->xpad * 2;
1151 rect.height -= renderer->ypad * 2;
1152
1153 wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
1154
1155 wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel();
1156
1157 GtkTreePath *treepath = gtk_tree_path_new_from_string( path );
1158
1159 GtkTreeIter iter;
1160 cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, treepath );
1161 wxDataViewItem item( iter.user_data );
1162 gtk_tree_path_free( treepath );
1163
1164 unsigned int model_col = cell->GetOwner()->GetModelColumn();
1165
1166 if (!event)
1167 {
1168 bool ret = false;
1169
1170 // activated by <ENTER>
1171 if (cell->Activate( renderrect, model, item, model_col ))
1172 ret = true;
1173
1174 return ret;
1175 }
1176 else if (event->type == GDK_BUTTON_PRESS)
1177 {
1178 GdkEventButton *button_event = (GdkEventButton*) event;
1179 wxPoint pt( ((int) button_event->x) - renderrect.x,
1180 ((int) button_event->y) - renderrect.y );
1181
1182 bool ret = false;
1183 if (button_event->button == 1)
1184 {
1185 if (cell->LeftClick( pt, renderrect, model, item, model_col ))
1186 ret = true;
1187 // TODO: query system double-click time
1188 if (button_event->time - wxrenderer->last_click < 400)
1189 if (cell->Activate( renderrect, model, item, model_col ))
1190 ret = true;
1191 }
1192 wxrenderer->last_click = button_event->time;
1193
1194 return ret;
1195 }
1196
1197 return false;
1198}
1199
1200// ---------------------------------------------------------
1201// wxGtkDataViewModelNotifier
1202// ---------------------------------------------------------
1203
1204class wxGtkDataViewModelNotifier: public wxDataViewModelNotifier
1205{
1206public:
1207 wxGtkDataViewModelNotifier( GtkWxTreeModel *wxgtk_model,
1208 wxDataViewModel *wx_model,
1209 wxDataViewCtrl *ctrl );
1210 ~wxGtkDataViewModelNotifier();
1211
1212 virtual bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
1213 virtual bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
1214 virtual bool ItemChanged( const wxDataViewItem &item );
1215 virtual bool ValueChanged( const wxDataViewItem &item, unsigned int col );
1216 virtual bool Cleared();
1217 virtual void Resort();
1218
1219 void SetGtkModel( GtkWxTreeModel *model ) { m_wxgtk_model = model; }
1220
1221private:
1222 GtkWxTreeModel *m_wxgtk_model;
1223 wxDataViewModel *m_wx_model;
1224 wxDataViewCtrl *m_owner;
1225};
1226
1227// ---------------------------------------------------------
1228// wxGtkDataViewListModelNotifier
1229// ---------------------------------------------------------
1230
1231wxGtkDataViewModelNotifier::wxGtkDataViewModelNotifier(
1232 GtkWxTreeModel* wxgtk_model, wxDataViewModel *wx_model,
1233 wxDataViewCtrl *ctrl )
1234{
1235 m_wxgtk_model = wxgtk_model;
1236 m_wx_model = wx_model;
1237 m_owner = ctrl;
1238}
1239
1240wxGtkDataViewModelNotifier::~wxGtkDataViewModelNotifier()
1241{
1242 m_wx_model = NULL;
1243 m_wxgtk_model = NULL;
1244}
1245
1246bool wxGtkDataViewModelNotifier::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
1247{
1248 m_owner->GtkGetInternal()->ItemAdded( parent, item );
1249
1250 GtkTreeIter iter;
1251 iter.stamp = m_wxgtk_model->stamp;
1252 iter.user_data = (gpointer) item.GetID();
1253
1254 GtkTreePath *path = wxgtk_tree_model_get_path(
1255 GTK_TREE_MODEL(m_wxgtk_model), &iter );
1256 gtk_tree_model_row_inserted(
1257 GTK_TREE_MODEL(m_wxgtk_model), path, &iter);
1258 gtk_tree_path_free (path);
1259
1260 return true;
1261}
1262
1263bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
1264{
1265 GtkTreeIter iter;
1266 iter.stamp = m_wxgtk_model->stamp;
1267 iter.user_data = (gpointer) item.GetID();
1268
1269 GtkTreePath *path = wxgtk_tree_model_get_path(
1270 GTK_TREE_MODEL(m_wxgtk_model), &iter );
1271 gtk_tree_model_row_deleted(
1272 GTK_TREE_MODEL(m_wxgtk_model), path );
1273 gtk_tree_path_free (path);
1274
1275 m_owner->GtkGetInternal()->ItemDeleted( parent, item );
1276
1277 return true;
1278}
1279
1280void wxGtkDataViewModelNotifier::Resort()
1281{
1282 m_owner->GtkGetInternal()->Resort();
1283}
1284
1285bool wxGtkDataViewModelNotifier::ItemChanged( const wxDataViewItem &item )
1286{
1287 GtkTreeIter iter;
1288 iter.stamp = m_wxgtk_model->stamp;
1289 iter.user_data = (gpointer) item.GetID();
1290
1291 GtkTreePath *path = wxgtk_tree_model_get_path(
1292 GTK_TREE_MODEL(m_wxgtk_model), &iter );
1293 gtk_tree_model_row_changed(
1294 GTK_TREE_MODEL(m_wxgtk_model), path, &iter );
1295 gtk_tree_path_free (path);
1296
1297 m_owner->GtkGetInternal()->ItemChanged( item );
1298
1299 return true;
1300}
1301
1302bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsigned int model_col )
1303{
1304 // This adds GTK+'s missing MVC logic for ValueChanged
1305 unsigned int index;
1306 for (index = 0; index < m_owner->GetColumnCount(); index++)
1307 {
1308 wxDataViewColumn *column = m_owner->GetColumn( index );
1309 if (column->GetModelColumn() == model_col)
1310 {
1311 GtkTreeView *widget = GTK_TREE_VIEW(m_owner->m_treeview);
1312 GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle());
1313
1314 // Get cell area
1315 GtkTreeIter iter;
1316 iter.stamp = m_wxgtk_model->stamp;
1317 iter.user_data = (gpointer) item.GetID();
1318 GtkTreePath *path = wxgtk_tree_model_get_path(
1319 GTK_TREE_MODEL(m_wxgtk_model), &iter );
1320 GdkRectangle cell_area;
1321 gtk_tree_view_get_cell_area( widget, path, gcolumn, &cell_area );
1322 gtk_tree_path_free( path );
1323
1324 GtkAdjustment* hadjust = gtk_tree_view_get_hadjustment( widget );
1325 double d = gtk_adjustment_get_value( hadjust );
1326 int xdiff = (int) d;
1327
1328 int ydiff = gcolumn->button->allocation.height;
1329 // Redraw
1330 gtk_widget_queue_draw_area( GTK_WIDGET(widget),
1331 cell_area.x - xdiff, ydiff + cell_area.y, cell_area.width, cell_area.height );
1332
1333 m_owner->GtkGetInternal()->ValueChanged( item, model_col );
1334
1335 return true;
1336 }
1337 }
1338
1339 return false;
1340}
1341
1342bool wxGtkDataViewModelNotifier::Cleared()
1343{
1344 gtk_tree_view_set_model( GTK_TREE_VIEW(m_owner->m_treeview), NULL );
1345
1346 // this will create a new GTK model
1347 m_owner->GtkGetInternal()->Cleared();
1348
1349 SetGtkModel( m_owner->GtkGetInternal()->GetGtkModel() );
1350
1351 gtk_tree_view_set_model( GTK_TREE_VIEW(m_owner->m_treeview), GTK_TREE_MODEL(m_wxgtk_model) );
1352
1353 return false;
1354}
1355
1356// ---------------------------------------------------------
1357// wxDataViewRenderer
1358// ---------------------------------------------------------
1359
1360static gpointer s_user_data = NULL;
1361
1362static void
1363wxgtk_cell_editable_editing_done( GtkCellEditable *WXUNUSED(editable),
1364 wxDataViewRenderer *wxrenderer )
1365{
1366 wxDataViewColumn *column = wxrenderer->GetOwner();
1367 wxDataViewCtrl *dv = column->GetOwner();
1368 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE, dv->GetId() );
1369 event.SetDataViewColumn( column );
1370 event.SetModel( dv->GetModel() );
1371 wxDataViewItem item( s_user_data );
1372 event.SetItem( item );
1373 dv->HandleWindowEvent( event );
1374}
1375
1376static void
1377wxgtk_renderer_editing_started( GtkCellRenderer *WXUNUSED(cell), GtkCellEditable *editable,
1378 gchar *path, wxDataViewRenderer *wxrenderer )
1379{
1380 wxDataViewColumn *column = wxrenderer->GetOwner();
1381 wxDataViewCtrl *dv = column->GetOwner();
1382 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED, dv->GetId() );
1383 event.SetDataViewColumn( column );
1384 event.SetModel( dv->GetModel() );
1385 GtkTreePath *tree_path = gtk_tree_path_new_from_string( path );
1386 GtkTreeIter iter;
1387 dv->GtkGetInternal()->get_iter( &iter, tree_path );
1388 gtk_tree_path_free( tree_path );
1389 wxDataViewItem item( iter.user_data );
1390 event.SetItem( item );
1391 dv->HandleWindowEvent( event );
1392
1393 if (GTK_IS_CELL_EDITABLE(editable))
1394 {
1395 s_user_data = iter.user_data;
1396
1397 g_signal_connect (GTK_CELL_EDITABLE (editable), "editing_done",
1398 G_CALLBACK (wxgtk_cell_editable_editing_done),
1399 (gpointer) wxrenderer );
1400
1401 }
1402}
1403
1404
1405IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
1406
1407wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1408 int align ) :
1409 wxDataViewRendererBase( varianttype, mode, align )
1410{
1411 m_renderer = NULL;
1412
1413 // NOTE: SetMode() and SetAlignment() needs to be called in the renderer's ctor,
1414 // after the m_renderer pointer has been initialized
1415}
1416
1417void wxDataViewRenderer::GtkInitHandlers()
1418{
1419 if (!gtk_check_version(2,6,0))
1420 {
1421 g_signal_connect (GTK_CELL_RENDERER(m_renderer), "editing_started",
1422 G_CALLBACK (wxgtk_renderer_editing_started),
1423 this);
1424 }
1425}
1426
1427void wxDataViewRenderer::SetMode( wxDataViewCellMode mode )
1428{
1429 GtkCellRendererMode gtkMode;
1430 switch (mode)
1431 {
1432 case wxDATAVIEW_CELL_INERT:
1433 gtkMode = GTK_CELL_RENDERER_MODE_INERT;
1434 break;
1435
1436 case wxDATAVIEW_CELL_ACTIVATABLE:
1437 gtkMode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
1438 break;
1439
1440 case wxDATAVIEW_CELL_EDITABLE:
1441 gtkMode = GTK_CELL_RENDERER_MODE_EDITABLE;
1442 break;
1443
1444 default:
1445 wxFAIL_MSG( "unknown wxDataViewCellMode value" );
1446 return;
1447 }
1448
1449 // This value is most often ignored in GtkTreeView
1450 GValue gvalue = { 0, };
1451 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
1452 g_value_set_enum( &gvalue, gtkMode );
1453 g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue );
1454 g_value_unset( &gvalue );
1455}
1456
1457wxDataViewCellMode wxDataViewRenderer::GetMode() const
1458{
1459 wxDataViewCellMode ret;
1460
1461 GValue gvalue;
1462 g_object_get( G_OBJECT(m_renderer), "mode", &gvalue, NULL);
1463
1464 switch (g_value_get_enum(&gvalue))
1465 {
1466 default:
1467 wxFAIL_MSG( "unknown GtkCellRendererMode value" );
1468 // fall through (we have to return something)
1469
1470 case GTK_CELL_RENDERER_MODE_INERT:
1471 ret = wxDATAVIEW_CELL_INERT;
1472 break;
1473
1474 case GTK_CELL_RENDERER_MODE_ACTIVATABLE:
1475 ret = wxDATAVIEW_CELL_ACTIVATABLE;
1476 break;
1477
1478 case GTK_CELL_RENDERER_MODE_EDITABLE:
1479 ret = wxDATAVIEW_CELL_EDITABLE;
1480 break;
1481 }
1482
1483 g_value_unset( &gvalue );
1484
1485 return ret;
1486}
1487
1488void wxDataViewRenderer::GtkUpdateAlignment()
1489{
1490 int align = m_alignment;
1491
1492 // query alignment from column ?
1493 if (align == -1)
1494 {
1495 // None there yet
1496 if (GetOwner() == NULL)
1497 return;
1498
1499 align = GetOwner()->GetAlignment();
1500 align |= wxALIGN_CENTRE_VERTICAL;
1501 }
1502
1503 // horizontal alignment:
1504
1505 gfloat xalign = 0.0;
1506 if (align & wxALIGN_RIGHT)
1507 xalign = 1.0;
1508 else if (align & wxALIGN_CENTER_HORIZONTAL)
1509 xalign = 0.5;
1510
1511 GValue gvalue = { 0, };
1512 g_value_init( &gvalue, G_TYPE_FLOAT );
1513 g_value_set_float( &gvalue, xalign );
1514 g_object_set_property( G_OBJECT(m_renderer), "xalign", &gvalue );
1515 g_value_unset( &gvalue );
1516
1517 // vertical alignment:
1518
1519 gfloat yalign = 0.0;
1520 if (align & wxALIGN_BOTTOM)
1521 yalign = 1.0;
1522 else if (align & wxALIGN_CENTER_VERTICAL)
1523 yalign = 0.5;
1524
1525 GValue gvalue2 = { 0, };
1526 g_value_init( &gvalue2, G_TYPE_FLOAT );
1527 g_value_set_float( &gvalue2, yalign );
1528 g_object_set_property( G_OBJECT(m_renderer), "yalign", &gvalue2 );
1529 g_value_unset( &gvalue2 );
1530}
1531
1532void wxDataViewRenderer::SetAlignment( int align )
1533{
1534 m_alignment = align;
1535 GtkUpdateAlignment();
1536}
1537
1538int wxDataViewRenderer::GetAlignment() const
1539{
1540 return m_alignment;
1541}
1542
1543// ---------------------------------------------------------
1544// wxDataViewTextRenderer
1545// ---------------------------------------------------------
1546
1547extern "C" {
1548static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer,
1549 gchar *arg1, gchar *arg2, gpointer user_data );
1550}
1551
1552static void wxGtkTextRendererEditedCallback( GtkCellRendererText *WXUNUSED(renderer),
1553 gchar *arg1, gchar *arg2, gpointer user_data )
1554{
1555 wxDataViewRenderer *cell = (wxDataViewRenderer*) user_data;
1556
1557 wxString tmp = wxGTK_CONV_BACK_FONT(arg2, cell->GetOwner()->GetOwner()->GetFont());
1558 wxVariant value = tmp;
1559 if (!cell->Validate( value ))
1560 return;
1561
1562 wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel();
1563
1564 GtkTreePath *path = gtk_tree_path_new_from_string( arg1 );
1565 GtkTreeIter iter;
1566 cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, path );
1567 wxDataViewItem item( (void*) iter.user_data );;
1568 gtk_tree_path_free( path );
1569
1570 unsigned int model_col = cell->GetOwner()->GetModelColumn();
1571
1572 model->SetValue( value, item, model_col );
1573 model->ValueChanged( item, model_col );
1574}
1575
1576IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewRenderer)
1577
1578wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1579 int align ) :
1580 wxDataViewRenderer( varianttype, mode, align )
1581{
1582 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_text_new();
1583
1584 if (mode & wxDATAVIEW_CELL_EDITABLE)
1585 {
1586 GValue gvalue = { 0, };
1587 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1588 g_value_set_boolean( &gvalue, true );
1589 g_object_set_property( G_OBJECT(m_renderer), "editable", &gvalue );
1590 g_value_unset( &gvalue );
1591
1592 g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
1593
1594 GtkInitHandlers();
1595 }
1596
1597 SetMode(mode);
1598 SetAlignment(align);
1599}
1600
1601bool wxDataViewTextRenderer::SetValue( const wxVariant &value )
1602{
1603 wxString tmp = value;
1604
1605 GValue gvalue = { 0, };
1606 g_value_init( &gvalue, G_TYPE_STRING );
1607 g_value_set_string( &gvalue, wxGTK_CONV_FONT( tmp, GetOwner()->GetOwner()->GetFont() ) );
1608 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
1609 g_value_unset( &gvalue );
1610
1611 return true;
1612}
1613
1614bool wxDataViewTextRenderer::GetValue( wxVariant &value ) const
1615{
1616 GValue gvalue = { 0, };
1617 g_value_init( &gvalue, G_TYPE_STRING );
1618 g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
1619 wxString tmp = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ), const_cast<wxDataViewTextRenderer*>(this)->GetOwner()->GetOwner()->GetFont() );
1620 g_value_unset( &gvalue );
1621
1622 value = tmp;
1623
1624 return true;
1625}
1626
1627void wxDataViewTextRenderer::SetAlignment( int align )
1628{
1629 wxDataViewRenderer::SetAlignment(align);
1630
1631 if (gtk_check_version(2,10,0))
1632 return;
1633
1634 // horizontal alignment:
1635 PangoAlignment pangoAlign = PANGO_ALIGN_LEFT;
1636 if (align & wxALIGN_RIGHT)
1637 pangoAlign = PANGO_ALIGN_RIGHT;
1638 else if (align & wxALIGN_CENTER_HORIZONTAL)
1639 pangoAlign = PANGO_ALIGN_CENTER;
1640
1641 GValue gvalue = { 0, };
1642 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
1643 g_value_set_enum( &gvalue, pangoAlign );
1644 g_object_set_property( G_OBJECT(m_renderer), "alignment", &gvalue );
1645 g_value_unset( &gvalue );
1646}
1647
1648// ---------------------------------------------------------
1649// wxDataViewTextRendererAttr
1650// ---------------------------------------------------------
1651
1652IMPLEMENT_CLASS(wxDataViewTextRendererAttr,wxDataViewTextRenderer)
1653
1654wxDataViewTextRendererAttr::wxDataViewTextRendererAttr( const wxString &varianttype,
1655 wxDataViewCellMode mode, int align ) :
1656 wxDataViewTextRenderer( varianttype, mode, align )
1657{
1658}
1659
1660// ---------------------------------------------------------
1661// wxDataViewBitmapRenderer
1662// ---------------------------------------------------------
1663
1664IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewRenderer)
1665
1666wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1667 int align ) :
1668 wxDataViewRenderer( varianttype, mode, align )
1669{
1670 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_pixbuf_new();
1671
1672 SetMode(mode);
1673 SetAlignment(align);
1674}
1675
1676bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
1677{
1678 if (value.GetType() == wxT("wxBitmap"))
1679 {
1680 wxBitmap bitmap;
1681 bitmap << value;
1682
1683 // This may create a Pixbuf representation in the
1684 // wxBitmap object (and it will stay there)
1685 GdkPixbuf *pixbuf = bitmap.GetPixbuf();
1686
1687 GValue gvalue = { 0, };
1688 g_value_init( &gvalue, G_TYPE_OBJECT );
1689 g_value_set_object( &gvalue, pixbuf );
1690 g_object_set_property( G_OBJECT(m_renderer), "pixbuf", &gvalue );
1691 g_value_unset( &gvalue );
1692
1693 return true;
1694 }
1695
1696 if (value.GetType() == wxT("wxIcon"))
1697 {
1698 wxIcon bitmap;
1699 bitmap << value;
1700
1701 // This may create a Pixbuf representation in the
1702 // wxBitmap object (and it will stay there)
1703 GdkPixbuf *pixbuf = bitmap.GetPixbuf();
1704
1705 GValue gvalue = { 0, };
1706 g_value_init( &gvalue, G_TYPE_OBJECT );
1707 g_value_set_object( &gvalue, pixbuf );
1708 g_object_set_property( G_OBJECT(m_renderer), "pixbuf", &gvalue );
1709 g_value_unset( &gvalue );
1710
1711 return true;
1712 }
1713
1714 return false;
1715}
1716
1717bool wxDataViewBitmapRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
1718{
1719 return false;
1720}
1721
1722// ---------------------------------------------------------
1723// wxDataViewToggleRenderer
1724// ---------------------------------------------------------
1725
1726extern "C" {
1727static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
1728 gchar *path, gpointer user_data );
1729}
1730
1731static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
1732 gchar *path, gpointer user_data )
1733{
1734 wxDataViewToggleRenderer *cell = (wxDataViewToggleRenderer*) user_data;
1735
1736 // get old value
1737 GValue gvalue = { 0, };
1738 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1739 g_object_get_property( G_OBJECT(renderer), "active", &gvalue );
1740 bool tmp = g_value_get_boolean( &gvalue );
1741 g_value_unset( &gvalue );
1742 // invert it
1743 tmp = !tmp;
1744
1745 wxVariant value = tmp;
1746 if (!cell->Validate( value ))
1747 return;
1748
1749 wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel();
1750
1751 GtkTreePath *gtk_path = gtk_tree_path_new_from_string( path );
1752 GtkTreeIter iter;
1753 cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, gtk_path );
1754 wxDataViewItem item( (void*) iter.user_data );;
1755 gtk_tree_path_free( gtk_path );
1756
1757 unsigned int model_col = cell->GetOwner()->GetModelColumn();
1758
1759 model->SetValue( value, item, model_col );
1760 model->ValueChanged( item, model_col );
1761}
1762
1763IMPLEMENT_CLASS(wxDataViewToggleRenderer, wxDataViewRenderer)
1764
1765wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
1766 wxDataViewCellMode mode, int align ) :
1767 wxDataViewRenderer( varianttype, mode, align )
1768{
1769 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_toggle_new();
1770
1771 if (mode & wxDATAVIEW_CELL_ACTIVATABLE)
1772 {
1773 g_signal_connect_after( m_renderer, "toggled",
1774 G_CALLBACK(wxGtkToggleRendererToggledCallback), this );
1775 }
1776 else
1777 {
1778 GValue gvalue = { 0, };
1779 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1780 g_value_set_boolean( &gvalue, false );
1781 g_object_set_property( G_OBJECT(m_renderer), "activatable", &gvalue );
1782 g_value_unset( &gvalue );
1783 }
1784
1785 SetMode(mode);
1786 SetAlignment(align);
1787}
1788
1789bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
1790{
1791 bool tmp = value;
1792
1793 GValue gvalue = { 0, };
1794 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1795 g_value_set_boolean( &gvalue, tmp );
1796 g_object_set_property( G_OBJECT(m_renderer), "active", &gvalue );
1797 g_value_unset( &gvalue );
1798
1799 return true;
1800}
1801
1802bool wxDataViewToggleRenderer::GetValue( wxVariant &value ) const
1803{
1804 GValue gvalue = { 0, };
1805 g_value_init( &gvalue, G_TYPE_BOOLEAN );
1806 g_object_get_property( G_OBJECT(m_renderer), "active", &gvalue );
1807 bool tmp = g_value_get_boolean( &gvalue );
1808 g_value_unset( &gvalue );
1809
1810 value = tmp;
1811
1812 return true;
1813}
1814
1815// ---------------------------------------------------------
1816// wxDataViewCustomRenderer
1817// ---------------------------------------------------------
1818
1819class wxDataViewCtrlDCImpl: public wxWindowDCImpl
1820{
1821public:
1822 wxDataViewCtrlDCImpl( wxDC *owner, wxDataViewCtrl *window ) :
1823 wxWindowDCImpl( owner )
1824 {
1825 GtkWidget *widget = window->m_treeview;
1826 // Set later
1827 m_gdkwindow = NULL;
1828
1829 m_window = window;
1830
1831 m_context = window->GtkGetPangoDefaultContext();
1832 m_layout = pango_layout_new( m_context );
1833 m_fontdesc = pango_font_description_copy( widget->style->font_desc );
1834
1835 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
1836
1837 // Set m_gdkwindow later
1838 // SetUpDC();
1839 }
1840};
1841
1842class wxDataViewCtrlDC: public wxWindowDC
1843{
1844public:
1845 wxDataViewCtrlDC( wxDataViewCtrl *window ) :
1846 wxWindowDC( new wxDataViewCtrlDCImpl( this, window ) )
1847 { }
1848};
1849
1850
1851// ---------------------------------------------------------
1852// wxDataViewCustomRenderer
1853// ---------------------------------------------------------
1854
1855IMPLEMENT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
1856
1857wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
1858 wxDataViewCellMode mode, int align,
1859 bool no_init ) :
1860 wxDataViewRenderer( varianttype, mode, align )
1861{
1862 m_dc = NULL;
1863 m_text_renderer = NULL;
1864
1865 if (no_init)
1866 m_renderer = NULL;
1867 else
1868 Init(mode, align);
1869}
1870
1871void wxDataViewCustomRenderer::RenderText( const wxString &text, int xoffset,
1872 wxRect WXUNUSED(cell), wxDC *WXUNUSED(dc), int WXUNUSED(state) )
1873{
1874#if 0
1875 wxDataViewCtrl *view = GetOwner()->GetOwner();
1876 wxColour col = (state & wxDATAVIEW_CELL_SELECTED) ?
1877 wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) :
1878 view->GetForegroundColour();
1879 dc->SetTextForeground(col);
1880 dc->DrawText( text, cell.x + xoffset, cell.y + ((cell.height - dc->GetCharHeight()) / 2));
1881#else
1882 if (!m_text_renderer)
1883 m_text_renderer = gtk_cell_renderer_text_new();
1884
1885 GValue gvalue = { 0, };
1886 g_value_init( &gvalue, G_TYPE_STRING );
1887 g_value_set_string( &gvalue, wxGTK_CONV_FONT( text, GetOwner()->GetOwner()->GetFont() ) );
1888 g_object_set_property( G_OBJECT(m_text_renderer), "text", &gvalue );
1889 g_value_unset( &gvalue );
1890
1891 ((GdkRectangle*) cell_area)->x += xoffset;
1892 ((GdkRectangle*) cell_area)->width -= xoffset;
1893
1894 gtk_cell_renderer_render( m_text_renderer,
1895 window,
1896 widget,
1897 (GdkRectangle*) background_area,
1898 (GdkRectangle*) cell_area,
1899 (GdkRectangle*) expose_area,
1900 (GtkCellRendererState) flags );
1901
1902 ((GdkRectangle*) cell_area)->x -= xoffset;
1903 ((GdkRectangle*) cell_area)->width += xoffset;
1904#endif
1905}
1906
1907bool wxDataViewCustomRenderer::Init(wxDataViewCellMode mode, int align)
1908{
1909 GtkWxCellRenderer *renderer = (GtkWxCellRenderer *) gtk_wx_cell_renderer_new();
1910 renderer->cell = this;
1911
1912 m_renderer = (GtkCellRenderer*) renderer;
1913
1914 SetMode(mode);
1915 SetAlignment(align);
1916
1917 GtkInitHandlers();
1918
1919 return true;
1920}
1921
1922wxDataViewCustomRenderer::~wxDataViewCustomRenderer()
1923{
1924 if (m_dc)
1925 delete m_dc;
1926
1927 if (m_text_renderer)
1928 gtk_object_sink( GTK_OBJECT(m_text_renderer) );
1929}
1930
1931wxDC *wxDataViewCustomRenderer::GetDC()
1932{
1933 if (m_dc == NULL)
1934 {
1935 if (GetOwner() == NULL)
1936 return NULL;
1937 if (GetOwner()->GetOwner() == NULL)
1938 return NULL;
1939 m_dc = new wxDataViewCtrlDC( GetOwner()->GetOwner() );
1940 }
1941
1942 return m_dc;
1943}
1944
1945// ---------------------------------------------------------
1946// wxDataViewProgressRenderer
1947// ---------------------------------------------------------
1948
1949IMPLEMENT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
1950
1951wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
1952 const wxString &varianttype, wxDataViewCellMode mode, int align ) :
1953 wxDataViewCustomRenderer( varianttype, mode, align, true )
1954{
1955 m_label = label;
1956 m_value = 0;
1957
1958#ifdef __WXGTK26__
1959 if (!gtk_check_version(2,6,0))
1960 {
1961 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_progress_new();
1962
1963 GValue gvalue = { 0, };
1964 g_value_init( &gvalue, G_TYPE_STRING );
1965
1966 g_value_set_string( &gvalue, wxGTK_CONV_FONT( m_label, GetOwner()->GetOwner()->GetFont() ) );
1967 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
1968 g_value_unset( &gvalue );
1969
1970 SetMode(mode);
1971 SetAlignment(align);
1972 }
1973 else
1974#endif
1975 {
1976 // Use custom cell code
1977 wxDataViewCustomRenderer::Init(mode, align);
1978 }
1979}
1980
1981wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
1982{
1983}
1984
1985bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
1986{
1987#ifdef __WXGTK26__
1988 if (!gtk_check_version(2,6,0))
1989 {
1990 gint tmp = (long) value;
1991 GValue gvalue = { 0, };
1992 g_value_init( &gvalue, G_TYPE_INT );
1993 g_value_set_int( &gvalue, tmp );
1994 g_object_set_property( G_OBJECT(m_renderer), "value", &gvalue );
1995 g_value_unset( &gvalue );
1996 }
1997 else
1998#endif
1999 {
2000 m_value = (long) value;
2001
2002 if (m_value < 0) m_value = 0;
2003 if (m_value > 100) m_value = 100;
2004 }
2005
2006 return true;
2007}
2008
2009bool wxDataViewProgressRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
2010{
2011 return false;
2012}
2013
2014bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
2015{
2016 double pct = (double)m_value / 100.0;
2017 wxRect bar = cell;
2018 bar.width = (int)(cell.width * pct);
2019 dc->SetPen( *wxTRANSPARENT_PEN );
2020 dc->SetBrush( *wxBLUE_BRUSH );
2021 dc->DrawRectangle( bar );
2022
2023 dc->SetBrush( *wxTRANSPARENT_BRUSH );
2024 dc->SetPen( *wxBLACK_PEN );
2025 dc->DrawRectangle( cell );
2026
2027 return true;
2028}
2029
2030wxSize wxDataViewProgressRenderer::GetSize() const
2031{
2032 return wxSize(40,12);
2033}
2034
2035// -------------------------------------
2036// wxDataViewChoiceRenderer
2037// -------------------------------------
2038
2039wxDataViewChoiceRenderer::wxDataViewChoiceRenderer( const wxArrayString &choices,
2040 wxDataViewCellMode mode, int alignment ) :
2041 wxDataViewCustomRenderer( "string", mode, alignment, true )
2042{
2043 m_choices = choices;
2044
2045#ifdef __WXGTK26__
2046 if (!gtk_check_version(2,6,0))
2047 {
2048 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_combo_new();
2049
2050 GtkListStore *store = gtk_list_store_new( 1, G_TYPE_STRING );
2051 size_t n;
2052 for (n = 0; n < m_choices.GetCount(); n++)
2053 gtk_list_store_insert_with_values( store, NULL, n, 0, m_choices[n].utf8_str(), -1 );
2054
2055 g_object_set (m_renderer,
2056 "model", store,
2057 "text-column", 0,
2058 "has-entry", FALSE,
2059 NULL);
2060
2061 bool editable = (mode & wxDATAVIEW_CELL_EDITABLE);
2062 g_object_set (m_renderer, "editable", editable, NULL);
2063
2064 SetAlignment(alignment);
2065
2066 g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
2067
2068 GtkInitHandlers();
2069 }
2070 else
2071#endif
2072 {
2073 // Use custom cell code
2074 wxDataViewCustomRenderer::Init(mode, alignment);
2075 }
2076}
2077
2078bool wxDataViewChoiceRenderer::Render( wxRect rect, wxDC *dc, int state )
2079{
2080 RenderText( m_data, 0, rect, dc, state );
2081 return true;
2082}
2083
2084wxSize wxDataViewChoiceRenderer::GetSize() const
2085{
2086 return wxSize(70,20);
2087}
2088
2089bool wxDataViewChoiceRenderer::SetValue( const wxVariant &value )
2090{
2091
2092#ifdef __WXGTK26__
2093 if (!gtk_check_version(2,6,0))
2094 {
2095 GValue gvalue = { 0, };
2096 g_value_init( &gvalue, G_TYPE_STRING );
2097 g_value_set_string( &gvalue, wxGTK_CONV_FONT( value.GetString(), GetOwner()->GetOwner()->GetFont() ) );
2098 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
2099 g_value_unset( &gvalue );
2100 }
2101 else
2102#endif
2103 m_data = value.GetString();
2104
2105 return true;
2106}
2107
2108bool wxDataViewChoiceRenderer::GetValue( wxVariant &value ) const
2109{
2110#ifdef __WXGTK26__
2111 if (!gtk_check_version(2,6,0))
2112 {
2113 GValue gvalue = { 0, };
2114 g_value_init( &gvalue, G_TYPE_STRING );
2115 g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
2116 wxString temp = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ), const_cast<wxDataViewTextRenderer*>(this)->GetOwner()->GetOwner()->GetFont() );
2117 g_value_unset( &gvalue );
2118 value = temp;
2119 wxPrintf( "temp %s\n", temp );
2120 }
2121 else
2122#endif
2123 value = m_data;
2124
2125 return true;
2126}
2127
2128void wxDataViewChoiceRenderer::SetAlignment( int align )
2129{
2130 wxDataViewCustomRenderer::SetAlignment(align);
2131
2132 if (gtk_check_version(2,10,0))
2133 return;
2134
2135 // horizontal alignment:
2136 PangoAlignment pangoAlign = PANGO_ALIGN_LEFT;
2137 if (align & wxALIGN_RIGHT)
2138 pangoAlign = PANGO_ALIGN_RIGHT;
2139 else if (align & wxALIGN_CENTER_HORIZONTAL)
2140 pangoAlign = PANGO_ALIGN_CENTER;
2141
2142 GValue gvalue = { 0, };
2143 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
2144 g_value_set_enum( &gvalue, pangoAlign );
2145 g_object_set_property( G_OBJECT(m_renderer), "alignment", &gvalue );
2146 g_value_unset( &gvalue );
2147}
2148
2149// ---------------------------------------------------------
2150// wxDataViewDateRenderer
2151// ---------------------------------------------------------
2152
2153class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
2154{
2155public:
2156 wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
2157 wxDataViewModel *model, const wxDataViewItem &item, unsigned int col ) :
2158 wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
2159 {
2160 m_model = model;
2161 m_item = item;
2162 m_col = col;
2163 m_cal = new wxCalendarCtrl( this, -1, *value );
2164 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
2165 sizer->Add( m_cal, 1, wxGROW );
2166 SetSizer( sizer );
2167 sizer->Fit( this );
2168 }
2169
2170 virtual void OnDismiss()
2171 {
2172 }
2173
2174 void OnCalendar( wxCalendarEvent &event );
2175
2176 wxCalendarCtrl *m_cal;
2177 wxDataViewModel *m_model;
2178 wxDataViewItem m_item;
2179 unsigned int m_col;
2180
2181private:
2182 DECLARE_EVENT_TABLE()
2183};
2184
2185BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
2186 EVT_CALENDAR( -1, wxDataViewDateRendererPopupTransient::OnCalendar )
2187END_EVENT_TABLE()
2188
2189void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
2190{
2191 wxDateTime date = event.GetDate();
2192 wxVariant value = date;
2193 m_model->SetValue( value, m_item, m_col );
2194 m_model->ValueChanged( m_item, m_col );
2195 DismissAndNotify();
2196}
2197
2198IMPLEMENT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
2199
2200wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
2201 wxDataViewCellMode mode, int align ) :
2202 wxDataViewCustomRenderer( varianttype, mode, align )
2203{
2204 SetMode(mode);
2205 SetAlignment(align);
2206}
2207
2208bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
2209{
2210 m_date = value.GetDateTime();
2211
2212 return true;
2213}
2214
2215bool wxDataViewDateRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
2216{
2217 return false;
2218}
2219
2220bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state )
2221{
2222 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
2223 wxString tmp = m_date.FormatDate();
2224 RenderText( tmp, 0, cell, dc, state );
2225 return true;
2226}
2227
2228wxSize wxDataViewDateRenderer::GetSize() const
2229{
2230 wxString tmp = m_date.FormatDate();
2231 wxCoord x,y,d;
2232 GetView()->GetTextExtent( tmp, &x, &y, &d );
2233 return wxSize(x,y+d);
2234}
2235
2236bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewModel *model,
2237 const wxDataViewItem &item, unsigned int col )
2238{
2239 wxVariant variant;
2240 model->GetValue( variant, item, col );
2241 wxDateTime value = variant.GetDateTime();
2242
2243 wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
2244 GetOwner()->GetOwner()->GetParent(), &value, model, item, col );
2245 wxPoint pos = wxGetMousePosition();
2246 popup->Move( pos );
2247 popup->Layout();
2248 popup->Popup( popup->m_cal );
2249
2250 return true;
2251}
2252
2253
2254// ---------------------------------------------------------
2255// wxDataViewIconTextRenderer
2256// ---------------------------------------------------------
2257
2258IMPLEMENT_CLASS(wxDataViewIconTextRenderer, wxDataViewCustomRenderer)
2259
2260wxDataViewIconTextRenderer::wxDataViewIconTextRenderer(
2261 const wxString &varianttype, wxDataViewCellMode mode, int align ) :
2262 wxDataViewCustomRenderer( varianttype, mode, align )
2263{
2264 SetMode(mode);
2265 SetAlignment(align);
2266}
2267
2268wxDataViewIconTextRenderer::~wxDataViewIconTextRenderer()
2269{
2270}
2271
2272bool wxDataViewIconTextRenderer::SetValue( const wxVariant &value )
2273{
2274 m_value << value;
2275 return true;
2276}
2277
2278bool wxDataViewIconTextRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
2279{
2280 return false;
2281}
2282
2283bool wxDataViewIconTextRenderer::Render( wxRect cell, wxDC *dc, int state )
2284{
2285 const wxIcon &icon = m_value.GetIcon();
2286 int offset = 0;
2287 if (icon.IsOk())
2288 {
2289 int yoffset = wxMax( 0, (cell.height - icon.GetHeight()) / 2 );
2290 dc->DrawIcon( icon, cell.x, cell.y + yoffset );
2291 offset = icon.GetWidth() + 4;
2292 }
2293
2294 RenderText( m_value.GetText(), offset, cell, dc, state );
2295
2296 return true;
2297}
2298
2299wxSize wxDataViewIconTextRenderer::GetSize() const
2300{
2301 wxSize size;
2302 if (m_value.GetIcon().IsOk())
2303 size.x = 4 + m_value.GetIcon().GetWidth();
2304 wxCoord x,y,d;
2305 GetView()->GetTextExtent( m_value.GetText(), &x, &y, &d );
2306 size.x += x;
2307 size.y = y+d;
2308 return size;
2309}
2310
2311wxControl* wxDataViewIconTextRenderer::CreateEditorCtrl(
2312 wxWindow *WXUNUSED(parent), wxRect WXUNUSED(labelRect), const wxVariant &WXUNUSED(value) )
2313{
2314 return NULL;
2315}
2316
2317bool wxDataViewIconTextRenderer::GetValueFromEditorCtrl(
2318 wxControl* WXUNUSED(editor), wxVariant &WXUNUSED(value) )
2319{
2320 return false;
2321}
2322
2323// ---------------------------------------------------------
2324// wxDataViewColumn
2325// ---------------------------------------------------------
2326
2327
2328static gboolean
2329gtk_dataview_header_button_press_callback( GtkWidget *WXUNUSED(widget),
2330 GdkEventButton *gdk_event,
2331 wxDataViewColumn *column )
2332{
2333 if (gdk_event->type != GDK_BUTTON_PRESS)
2334 return FALSE;
2335
2336 if (gdk_event->button == 1)
2337 {
2338 gs_lastLeftClickHeader = column;
2339
2340 wxDataViewCtrl *dv = column->GetOwner();
2341 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, dv->GetId() );
2342 event.SetDataViewColumn( column );
2343 event.SetModel( dv->GetModel() );
2344 if (dv->HandleWindowEvent( event ))
2345 return FALSE;
2346 }
2347
2348 if (gdk_event->button == 3)
2349 {
2350 wxDataViewCtrl *dv = column->GetOwner();
2351 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, dv->GetId() );
2352 event.SetDataViewColumn( column );
2353 event.SetModel( dv->GetModel() );
2354 if (dv->HandleWindowEvent( event ))
2355 return FALSE;
2356 }
2357
2358 return FALSE;
2359}
2360
2361extern "C" {
2362static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
2363 GtkCellRenderer *cell,
2364 GtkTreeModel *model,
2365 GtkTreeIter *iter,
2366 gpointer data );
2367}
2368
2369
2370static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column),
2371 GtkCellRenderer *renderer,
2372 GtkTreeModel *model,
2373 GtkTreeIter *iter,
2374 gpointer data )
2375{
2376 g_return_if_fail (GTK_IS_WX_TREE_MODEL (model));
2377 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) model;
2378
2379 wxDataViewRenderer *cell = (wxDataViewRenderer*) data;
2380
2381 wxDataViewItem item( (void*) iter->user_data );
2382
2383 wxDataViewModel *wx_model = tree_model->internal->GetDataViewModel();
2384
2385 if (!wx_model->IsVirtualListModel())
2386 {
2387
2388 if (wx_model->IsContainer( item ))
2389 {
2390 if (wx_model->HasContainerColumns( item ) || (cell->GetOwner()->GetModelColumn() == 0))
2391 {
2392 GValue gvalue = { 0, };
2393 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2394 g_value_set_boolean( &gvalue, TRUE );
2395 g_object_set_property( G_OBJECT(renderer), "visible", &gvalue );
2396 g_value_unset( &gvalue );
2397 }
2398 else
2399 {
2400 GValue gvalue = { 0, };
2401 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2402 g_value_set_boolean( &gvalue, FALSE );
2403 g_object_set_property( G_OBJECT(renderer), "visible", &gvalue );
2404 g_value_unset( &gvalue );
2405
2406 return;
2407 }
2408 }
2409 else
2410 {
2411 GValue gvalue = { 0, };
2412 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2413 g_value_set_boolean( &gvalue, TRUE );
2414 g_object_set_property( G_OBJECT(renderer), "visible", &gvalue );
2415 g_value_unset( &gvalue );
2416 }
2417
2418 }
2419
2420 wxVariant value;
2421 wx_model->GetValue( value, item, cell->GetOwner()->GetModelColumn() );
2422
2423 if (value.GetType() != cell->GetVariantType())
2424 wxLogError( wxT("Wrong type, required: %s but: %s"),
2425 value.GetType().c_str(),
2426 cell->GetVariantType().c_str() );
2427
2428 cell->SetValue( value );
2429
2430 if (cell->GtkHasAttributes())
2431 {
2432 wxDataViewItemAttr attr;
2433 bool colour_set = false;
2434 bool style_set = false;
2435 bool weight_set = false;
2436
2437 if (wx_model->GetAttr( item, cell->GetOwner()->GetModelColumn(), attr ))
2438 {
2439 // this must be a GtkCellRendererText
2440 wxColour colour = attr.GetColour();
2441 if (colour.IsOk())
2442 {
2443 const GdkColor * const gcol = colour.GetColor();
2444
2445 GValue gvalue = { 0, };
2446 g_value_init( &gvalue, GDK_TYPE_COLOR );
2447 g_value_set_boxed( &gvalue, gcol );
2448 g_object_set_property( G_OBJECT(renderer), "foreground_gdk", &gvalue );
2449 g_value_unset( &gvalue );
2450
2451 colour_set = true;
2452 }
2453
2454 if (attr.GetItalic())
2455 {
2456 GValue gvalue = { 0, };
2457 g_value_init( &gvalue, PANGO_TYPE_STYLE );
2458 g_value_set_enum( &gvalue, PANGO_STYLE_ITALIC );
2459 g_object_set_property( G_OBJECT(renderer), "style", &gvalue );
2460 g_value_unset( &gvalue );
2461
2462 style_set = true;
2463 }
2464
2465 if (attr.GetBold())
2466 {
2467 GValue gvalue = { 0, };
2468 g_value_init( &gvalue, PANGO_TYPE_WEIGHT );
2469 g_value_set_enum( &gvalue, PANGO_WEIGHT_BOLD );
2470 g_object_set_property( G_OBJECT(renderer), "weight", &gvalue );
2471 g_value_unset( &gvalue );
2472
2473 weight_set = true;
2474 }
2475 }
2476
2477 if (!style_set)
2478 {
2479 GValue gvalue = { 0, };
2480 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2481 g_value_set_boolean( &gvalue, FALSE );
2482 g_object_set_property( G_OBJECT(renderer), "style-set", &gvalue );
2483 g_value_unset( &gvalue );
2484 }
2485
2486 if (!weight_set)
2487 {
2488 GValue gvalue = { 0, };
2489 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2490 g_value_set_boolean( &gvalue, FALSE );
2491 g_object_set_property( G_OBJECT(renderer), "weight-set", &gvalue );
2492 g_value_unset( &gvalue );
2493 }
2494
2495 if (!colour_set)
2496 {
2497 GValue gvalue = { 0, };
2498 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2499 g_value_set_boolean( &gvalue, FALSE );
2500 g_object_set_property( G_OBJECT(renderer), "foreground-set", &gvalue );
2501 g_value_unset( &gvalue );
2502 }
2503 }
2504
2505#if 0
2506 if (attr.HasBackgroundColour())
2507 {
2508 wxColour colour = attr.GetBackgroundColour();
2509 const GdkColor * const gcol = colour.GetColor();
2510
2511 GValue gvalue = { 0, };
2512 g_value_init( &gvalue, GDK_TYPE_COLOR );
2513 g_value_set_boxed( &gvalue, gcol );
2514 g_object_set_property( G_OBJECT(renderer), "cell-background_gdk", &gvalue );
2515 g_value_unset( &gvalue );
2516 }
2517 else
2518 {
2519 GValue gvalue = { 0, };
2520 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2521 g_value_set_boolean( &gvalue, FALSE );
2522 g_object_set_property( G_OBJECT(renderer), "cell-background-set", &gvalue );
2523 g_value_unset( &gvalue );
2524 }
2525#endif
2526
2527}
2528
2529#include <wx/listimpl.cpp>
2530WX_DEFINE_LIST(wxDataViewColumnList)
2531
2532wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell,
2533 unsigned int model_column, int width,
2534 wxAlignment align, int flags )
2535 : wxDataViewColumnBase( cell, model_column )
2536{
2537 Init( align, flags, width );
2538
2539 SetTitle( title );
2540}
2541
2542wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell,
2543 unsigned int model_column, int width,
2544 wxAlignment align, int flags )
2545 : wxDataViewColumnBase( bitmap, cell, model_column )
2546{
2547 Init( align, flags, width );
2548
2549 SetBitmap( bitmap );
2550}
2551
2552void wxDataViewColumn::Init(wxAlignment align, int flags, int width)
2553{
2554 m_isConnected = false;
2555
2556 GtkCellRenderer *renderer = (GtkCellRenderer *) GetRenderer()->GetGtkHandle();
2557 GtkTreeViewColumn *column = gtk_tree_view_column_new();
2558 m_column = (GtkWidget*) column;
2559
2560 SetFlags( flags );
2561 SetAlignment( align );
2562
2563 SetWidth( width );
2564
2565 // Create container for icon and label
2566 GtkWidget *box = gtk_hbox_new( FALSE, 1 );
2567 gtk_widget_show( box );
2568 // gtk_container_set_border_width((GtkContainer*)box, 2);
2569 m_image = gtk_image_new();
2570 gtk_box_pack_start(GTK_BOX(box), m_image, FALSE, FALSE, 1);
2571 m_label = gtk_label_new("");
2572 gtk_box_pack_end( GTK_BOX(box), GTK_WIDGET(m_label), FALSE, FALSE, 1 );
2573 gtk_tree_view_column_set_widget( column, box );
2574
2575 gtk_tree_view_column_pack_end( column, renderer, TRUE );
2576
2577 gtk_tree_view_column_set_cell_data_func( column, renderer,
2578 wxGtkTreeCellDataFunc, (gpointer) GetRenderer(), NULL );
2579}
2580
2581void wxDataViewColumn::OnInternalIdle()
2582{
2583 if (m_isConnected)
2584 return;
2585
2586 if (GTK_WIDGET_REALIZED(GetOwner()->m_treeview))
2587 {
2588 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2589 if (column->button)
2590 {
2591 g_signal_connect(column->button, "button_press_event",
2592 G_CALLBACK (gtk_dataview_header_button_press_callback), this);
2593
2594 m_isConnected = true;
2595 }
2596 }
2597}
2598
2599void wxDataViewColumn::SetOwner( wxDataViewCtrl *owner )
2600{
2601 wxDataViewColumnBase::SetOwner( owner );
2602
2603 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2604
2605 gtk_tree_view_column_set_title( column, wxGTK_CONV_FONT(GetTitle(), GetOwner()->GetFont() ) );
2606}
2607
2608void wxDataViewColumn::SetTitle( const wxString &title )
2609{
2610 wxDataViewCtrl *ctrl = GetOwner();
2611 gtk_label_set_text( GTK_LABEL(m_label), ctrl ? wxGTK_CONV_FONT(title, ctrl->GetFont())
2612 : wxGTK_CONV_SYS(title) );
2613 if (title.empty())
2614 gtk_widget_hide( m_label );
2615 else
2616 gtk_widget_show( m_label );
2617}
2618
2619wxString wxDataViewColumn::GetTitle() const
2620{
2621 return wxGTK_CONV_BACK_FONT(
2622 gtk_label_get_text( GTK_LABEL(m_label) ),
2623 GetOwner()->GetFont()
2624 );
2625}
2626
2627void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap )
2628{
2629 wxDataViewColumnBase::SetBitmap( bitmap );
2630
2631 if (bitmap.Ok())
2632 {
2633 GtkImage *gtk_image = GTK_IMAGE(m_image);
2634
2635 GdkBitmap *mask = NULL;
2636 if (bitmap.GetMask())
2637 mask = bitmap.GetMask()->GetBitmap();
2638
2639 if (bitmap.HasPixbuf())
2640 {
2641 gtk_image_set_from_pixbuf(GTK_IMAGE(gtk_image),
2642 bitmap.GetPixbuf());
2643 }
2644 else
2645 {
2646 gtk_image_set_from_pixmap(GTK_IMAGE(gtk_image),
2647 bitmap.GetPixmap(), mask);
2648 }
2649 gtk_widget_show( m_image );
2650 }
2651 else
2652 {
2653 gtk_widget_hide( m_image );
2654 }
2655}
2656
2657void wxDataViewColumn::SetHidden( bool hidden )
2658{
2659 gtk_tree_view_column_set_visible( GTK_TREE_VIEW_COLUMN(m_column), !hidden );
2660}
2661
2662void wxDataViewColumn::SetResizeable( bool resizeable )
2663{
2664 gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizeable );
2665}
2666
2667void wxDataViewColumn::SetAlignment( wxAlignment align )
2668{
2669 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2670
2671 gfloat xalign = 0.0;
2672 if (align == wxALIGN_RIGHT)
2673 xalign = 1.0;
2674 if (align == wxALIGN_CENTER_HORIZONTAL ||
2675 align == wxALIGN_CENTER)
2676 xalign = 0.5;
2677
2678 gtk_tree_view_column_set_alignment( column, xalign );
2679
2680 if (m_renderer && m_renderer->GetAlignment() == -1)
2681 m_renderer->GtkUpdateAlignment();
2682}
2683
2684wxAlignment wxDataViewColumn::GetAlignment() const
2685{
2686 gfloat xalign = gtk_tree_view_column_get_alignment( GTK_TREE_VIEW_COLUMN(m_column) );
2687
2688 if (xalign == 1.0)
2689 return wxALIGN_RIGHT;
2690 if (xalign == 0.5)
2691 return wxALIGN_CENTER_HORIZONTAL;
2692
2693 return wxALIGN_LEFT;
2694}
2695
2696void wxDataViewColumn::SetSortable( bool sortable )
2697{
2698 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2699
2700 if ( sortable )
2701 {
2702 gtk_tree_view_column_set_sort_column_id( column, GetModelColumn() );
2703 }
2704 else
2705 {
2706 gtk_tree_view_column_set_sort_column_id( column, -1 );
2707 gtk_tree_view_column_set_sort_indicator( column, FALSE );
2708 gtk_tree_view_column_set_clickable( column, FALSE );
2709 }
2710}
2711
2712bool wxDataViewColumn::IsSortable() const
2713{
2714 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2715 return gtk_tree_view_column_get_clickable( column );
2716}
2717
2718void wxDataViewColumn::SetAsSortKey( bool WXUNUSED(sort) )
2719{
2720 // it might not make sense to have this function in wxHeaderColumn at
2721 // all in fact, changing of the sort order should only be done using the
2722 // associated control API
2723 wxFAIL_MSG( "not implemented" );
2724}
2725
2726bool wxDataViewColumn::IsSortKey() const
2727{
2728 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2729 return gtk_tree_view_column_get_sort_indicator( column );
2730}
2731
2732bool wxDataViewColumn::IsResizeable() const
2733{
2734 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2735 return gtk_tree_view_column_get_resizable( column );
2736}
2737
2738bool wxDataViewColumn::IsHidden() const
2739{
2740 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2741 return !gtk_tree_view_column_get_visible( column );
2742}
2743
2744void wxDataViewColumn::SetSortOrder( bool ascending )
2745{
2746 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2747
2748 if (ascending)
2749 gtk_tree_view_column_set_sort_order( column, GTK_SORT_ASCENDING );
2750 else
2751 gtk_tree_view_column_set_sort_order( column, GTK_SORT_DESCENDING );
2752
2753 gtk_tree_view_column_set_sort_indicator( column, TRUE );
2754}
2755
2756bool wxDataViewColumn::IsSortOrderAscending() const
2757{
2758 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
2759
2760 return (gtk_tree_view_column_get_sort_order( column ) != GTK_SORT_DESCENDING);
2761}
2762
2763void wxDataViewColumn::SetMinWidth( int width )
2764{
2765 gtk_tree_view_column_set_min_width( GTK_TREE_VIEW_COLUMN(m_column), width );
2766}
2767
2768int wxDataViewColumn::GetMinWidth() const
2769{
2770 return gtk_tree_view_column_get_min_width( GTK_TREE_VIEW_COLUMN(m_column) );
2771}
2772
2773int wxDataViewColumn::GetWidth() const
2774{
2775 return gtk_tree_view_column_get_width( GTK_TREE_VIEW_COLUMN(m_column) );
2776}
2777
2778void wxDataViewColumn::SetWidth( int width )
2779{
2780 if (width < 0)
2781 {
2782#if 1
2783 gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED );
2784
2785 // TODO find a better calculation
2786 gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), wxDVC_DEFAULT_WIDTH );
2787#else
2788 // this is unpractical for large numbers of items and disables
2789 // user resizing, which is totally unexpected
2790 gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_AUTOSIZE );
2791#endif
2792 }
2793 else
2794 {
2795 gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED );
2796
2797 gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), width );
2798 }
2799}
2800
2801void wxDataViewColumn::SetReorderable( bool reorderable )
2802{
2803 gtk_tree_view_column_set_reorderable( GTK_TREE_VIEW_COLUMN(m_column), reorderable );
2804}
2805
2806bool wxDataViewColumn::IsReorderable() const
2807{
2808 return gtk_tree_view_column_get_reorderable( GTK_TREE_VIEW_COLUMN(m_column) );
2809}
2810
2811//-----------------------------------------------------------------------------
2812// wxGtkTreeModelNode
2813//-----------------------------------------------------------------------------
2814
2815void wxGtkTreeModelNode::Resort()
2816{
2817 size_t child_count = GetChildCount();
2818 if (child_count == 0)
2819 return;
2820
2821 size_t node_count = GetNodesCount();
2822
2823 if (child_count == 1)
2824 {
2825 if (node_count == 1)
2826 {
2827 wxGtkTreeModelNode *node = m_nodes.Item( 0 );
2828 node->Resort();
2829 }
2830 return;
2831 }
2832
2833 wxGtkTreeModelChildren temp;
2834 WX_APPEND_ARRAY( temp, m_children );
2835
2836 gs_internal = m_internal;
2837 m_children.Sort( &wxGtkTreeModelChildCmp );
2838
2839 gint *new_order = new gint[child_count];
2840
2841 unsigned int pos;
2842 for (pos = 0; pos < child_count; pos++)
2843 {
2844 void *id = m_children.Item( pos );
2845 int old_pos = temp.Index( id );
2846 new_order[pos] = old_pos;
2847 }
2848
2849 GtkTreeModel *gtk_tree_model = GTK_TREE_MODEL( m_internal->GetGtkModel() );
2850
2851 GtkTreeIter iter;
2852 iter.user_data = GetItem().GetID();
2853 iter.stamp = m_internal->GetGtkModel()->stamp;
2854
2855 GtkTreePath *path = m_internal->get_path( &iter );
2856
2857 gtk_tree_model_rows_reordered( gtk_tree_model, path, &iter, new_order );
2858
2859 gtk_tree_path_free (path);
2860
2861 delete [] new_order;
2862
2863 for (pos = 0; pos < node_count; pos++)
2864 {
2865 wxGtkTreeModelNode *node = m_nodes.Item( pos );
2866 node->Resort();
2867 }
2868}
2869
2870//-----------------------------------------------------------------------------
2871// wxDataViewCtrlInternal
2872//-----------------------------------------------------------------------------
2873
2874wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner,
2875 wxDataViewModel *wx_model, GtkWxTreeModel *gtk_model )
2876{
2877 m_owner = owner;
2878 m_wx_model = wx_model;
2879 m_gtk_model = gtk_model;
2880 m_root = NULL;
2881 m_sort_order = GTK_SORT_ASCENDING;
2882 m_sort_column = -1;
2883 m_dataview_sort_column = NULL;
2884
2885 m_dragDataObject = NULL;
2886 m_dropDataObject = NULL;
2887
2888 if (!m_wx_model->IsVirtualListModel())
2889 InitTree();
2890}
2891
2892wxDataViewCtrlInternal::~wxDataViewCtrlInternal()
2893{
2894 g_object_unref( m_gtk_model );
2895
2896 delete m_dragDataObject;
2897 delete m_dropDataObject;
2898}
2899
2900void wxDataViewCtrlInternal::InitTree()
2901{
2902 wxDataViewItem item;
2903 m_root = new wxGtkTreeModelNode( NULL, item, this );
2904
2905 BuildBranch( m_root );
2906}
2907
2908void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node )
2909{
2910 if (node->GetChildCount() == 0)
2911 {
2912 wxDataViewItemArray children;
2913 unsigned int count = m_wx_model->GetChildren( node->GetItem(), children );
2914 unsigned int pos;
2915 for (pos = 0; pos < count; pos++)
2916 {
2917 wxDataViewItem child = children[pos];
2918
2919 if (m_wx_model->IsContainer( child ))
2920 node->AddNode( new wxGtkTreeModelNode( node, child, this ) );
2921 else
2922 node->AddLeave( child.GetID() );
2923
2924 // Don't send any events here
2925 }
2926 }
2927}
2928
2929// GTK+ dnd iface
2930
2931bool wxDataViewCtrlInternal::EnableDragSource( const wxDataFormat &format )
2932{
2933 wxGtkString atom_str( gdk_atom_name( format ) );
2934 m_dragSourceTargetEntryTarget = wxCharBuffer( atom_str );
2935
2936 m_dragSourceTargetEntry.target = m_dragSourceTargetEntryTarget.data();
2937 m_dragSourceTargetEntry.flags = 0;
2938 m_dragSourceTargetEntry.info = static_cast<guint>(-1);
2939
2940 gtk_tree_view_enable_model_drag_source( GTK_TREE_VIEW(m_owner->GtkGetTreeView() ),
2941 GDK_BUTTON1_MASK, &m_dragSourceTargetEntry, 1, (GdkDragAction) GDK_ACTION_COPY );
2942
2943 return true;
2944}
2945
2946bool wxDataViewCtrlInternal::EnableDropTarget( const wxDataFormat &format )
2947{
2948 wxGtkString atom_str( gdk_atom_name( format ) );
2949 m_dropTargetTargetEntryTarget = wxCharBuffer( atom_str );
2950
2951 m_dropTargetTargetEntry.target = m_dropTargetTargetEntryTarget.data();
2952 m_dropTargetTargetEntry.flags = 0;
2953 m_dropTargetTargetEntry.info = static_cast<guint>(-1);
2954
2955 gtk_tree_view_enable_model_drag_dest( GTK_TREE_VIEW(m_owner->GtkGetTreeView() ),
2956 &m_dropTargetTargetEntry, 1, (GdkDragAction) GDK_ACTION_COPY );
2957
2958 return true;
2959}
2960
2961gboolean wxDataViewCtrlInternal::row_draggable( GtkTreeDragSource *WXUNUSED(drag_source),
2962 GtkTreePath *path )
2963{
2964 delete m_dragDataObject;
2965
2966 GtkTreeIter iter;
2967 if (!get_iter( &iter, path )) return FALSE;
2968 wxDataViewItem item( (void*) iter.user_data );
2969
2970 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_BEGIN_DRAG, m_owner->GetId() );
2971 event.SetEventObject( m_owner );
2972 event.SetItem( item );
2973 event.SetModel( m_wx_model );
2974 if (!m_owner->HandleWindowEvent( event ))
2975 return FALSE;
2976
2977 if (!event.IsAllowed())
2978 return FALSE;
2979
2980 wxDataObject *obj = event.GetDataObject();
2981 if (!obj)
2982 return FALSE;
2983
2984 m_dragDataObject = obj;
2985
2986 return TRUE;
2987}
2988
2989gboolean
2990wxDataViewCtrlInternal::drag_data_delete(GtkTreeDragSource *WXUNUSED(drag_source),
2991 GtkTreePath *WXUNUSED(path))
2992{
2993 return FALSE;
2994}
2995
2996gboolean wxDataViewCtrlInternal::drag_data_get( GtkTreeDragSource *WXUNUSED(drag_source),
2997 GtkTreePath *path, GtkSelectionData *selection_data )
2998{
2999 GtkTreeIter iter;
3000 if (!get_iter( &iter, path )) return FALSE;
3001 wxDataViewItem item( (void*) iter.user_data );
3002
3003 if (!m_dragDataObject->IsSupported( selection_data->target ))
3004 return FALSE;
3005
3006 size_t size = m_dragDataObject->GetDataSize( selection_data->target );
3007 if (size == 0)
3008 return FALSE;
3009
3010 void *buf = malloc( size );
3011
3012 gboolean res = FALSE;
3013 if (m_dragDataObject->GetDataHere( selection_data->target, buf ))
3014 {
3015 res = TRUE;
3016
3017 gtk_selection_data_set( selection_data, selection_data->target,
3018 8, (const guchar*) buf, size );
3019 }
3020
3021 free( buf );
3022
3023 return res;
3024}
3025
3026gboolean
3027wxDataViewCtrlInternal::drag_data_received(GtkTreeDragDest *WXUNUSED(drag_dest),
3028 GtkTreePath *path,
3029 GtkSelectionData *selection_data)
3030{
3031 GtkTreeIter iter;
3032 if (!get_iter( &iter, path )) return FALSE;
3033 wxDataViewItem item( (void*) iter.user_data );
3034
3035 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP, m_owner->GetId() );
3036 event.SetEventObject( m_owner );
3037 event.SetItem( item );
3038 event.SetModel( m_wx_model );
3039 event.SetDataFormat( selection_data->target );
3040 event.SetDataSize( selection_data->length );
3041 event.SetDataBuffer( selection_data->data );
3042 if (!m_owner->HandleWindowEvent( event ))
3043 return FALSE;
3044
3045 if (!event.IsAllowed())
3046 return FALSE;
3047
3048 return TRUE;
3049}
3050
3051gboolean
3052wxDataViewCtrlInternal::row_drop_possible(GtkTreeDragDest *WXUNUSED(drag_dest),
3053 GtkTreePath *path,
3054 GtkSelectionData *selection_data)
3055{
3056 GtkTreeIter iter;
3057 if (!get_iter( &iter, path )) return FALSE;
3058 wxDataViewItem item( (void*) iter.user_data );
3059
3060 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP_POSSIBLE, m_owner->GetId() );
3061 event.SetEventObject( m_owner );
3062 event.SetItem( item );
3063 event.SetModel( m_wx_model );
3064 event.SetDataFormat( selection_data->target );
3065 if (!m_owner->HandleWindowEvent( event ))
3066 return FALSE;
3067
3068 if (!event.IsAllowed())
3069 return FALSE;
3070
3071 return TRUE;
3072}
3073
3074// notifications from wxDataViewModel
3075
3076bool wxDataViewCtrlInternal::Cleared()
3077{
3078 if (m_root)
3079 {
3080 delete m_root;
3081 InitTree();
3082 }
3083
3084 // Create new GTK model
3085 g_object_unref( m_gtk_model );
3086 m_gtk_model = wxgtk_tree_model_new();
3087 m_gtk_model->internal = this;
3088
3089 return true;
3090}
3091
3092void wxDataViewCtrlInternal::Resort()
3093{
3094 if (!m_wx_model->IsVirtualListModel())
3095 m_root->Resort();
3096}
3097
3098bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
3099{
3100 if (!m_wx_model->IsVirtualListModel())
3101 {
3102 wxGtkTreeModelNode *parent_node = FindNode( parent );
3103 if (m_wx_model->IsContainer( item ))
3104 parent_node->AddNode( new wxGtkTreeModelNode( parent_node, item, this ) );
3105 else
3106 parent_node->AddLeave( item.GetID() );
3107 }
3108
3109 return true;
3110}
3111
3112bool wxDataViewCtrlInternal::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
3113{
3114 if (!m_wx_model->IsVirtualListModel())
3115 {
3116 wxGtkTreeModelNode *parent_node = FindNode( parent );
3117 parent_node->DeleteChild( item.GetID() );
3118 }
3119
3120 return true;
3121}
3122
3123bool wxDataViewCtrlInternal::ItemChanged( const wxDataViewItem &item )
3124{
3125 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, m_owner->GetId() );
3126 event.SetEventObject( m_owner );
3127 event.SetModel( m_owner->GetModel() );
3128 event.SetItem( item );
3129 m_owner->HandleWindowEvent( event );
3130
3131 return true;
3132}
3133
3134bool wxDataViewCtrlInternal::ValueChanged( const wxDataViewItem &item, unsigned int col )
3135{
3136 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, m_owner->GetId() );
3137 event.SetEventObject( m_owner );
3138 event.SetModel( m_owner->GetModel() );
3139 event.SetColumn( col );
3140 event.SetDataViewColumn( GetOwner()->GetColumn(col) );
3141 event.SetItem( item );
3142 m_owner->HandleWindowEvent( event );
3143
3144 return true;
3145}
3146
3147// GTK+ model iface
3148
3149GtkTreeModelFlags wxDataViewCtrlInternal::get_flags()
3150{
3151 if (m_wx_model->IsVirtualListModel())
3152 return GTK_TREE_MODEL_LIST_ONLY;
3153 else
3154 return GTK_TREE_MODEL_ITERS_PERSIST;
3155}
3156
3157gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path )
3158{
3159 if (m_wx_model->IsVirtualListModel())
3160 {
3161 wxDataViewIndexListModel *wx_model = (wxDataViewIndexListModel*) m_wx_model;
3162
3163 unsigned int i = (unsigned int)gtk_tree_path_get_indices (path)[0];
3164
3165 if (i >= wx_model->GetLastIndex() + 1)
3166 return FALSE;
3167
3168 iter->stamp = m_gtk_model->stamp;
3169 // user_data is just the index
3170 iter->user_data = (gpointer) i;
3171
3172 return TRUE;
3173 }
3174 else
3175 {
3176 int depth = gtk_tree_path_get_depth( path );
3177
3178 wxGtkTreeModelNode *node = m_root;
3179
3180 int i;
3181 for (i = 0; i < depth; i++)
3182 {
3183 BuildBranch( node );
3184
3185 gint pos = gtk_tree_path_get_indices (path)[i];
3186 if (pos < 0) return FALSE;
3187 if ((size_t)pos >= node->GetChildCount()) return FALSE;
3188
3189 void* id = node->GetChildren().Item( (size_t) pos );
3190
3191 if (i == depth-1)
3192 {
3193 iter->stamp = m_gtk_model->stamp;
3194 iter->user_data = id;
3195 return TRUE;
3196 }
3197
3198 size_t count = node->GetNodes().GetCount();
3199 size_t pos2;
3200 for (pos2 = 0; pos2 < count; pos2++)
3201 {
3202 wxGtkTreeModelNode *child_node = node->GetNodes().Item( pos2 );
3203 if (child_node->GetItem().GetID() == id)
3204 {
3205 node = child_node;
3206 break;
3207 }
3208 }
3209 }
3210 }
3211
3212 return FALSE;
3213}
3214
3215GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter )
3216{
3217 GtkTreePath *retval = gtk_tree_path_new ();
3218
3219 if (m_wx_model->IsVirtualListModel())
3220 {
3221 // user_data is just the index
3222 int i = (wxUIntPtr) iter->user_data;
3223 gtk_tree_path_append_index (retval, i);
3224 }
3225 else
3226 {
3227 void *id = iter->user_data;
3228
3229 wxGtkTreeModelNode *node = FindParentNode( iter );
3230 while (node)
3231 {
3232 int pos = node->GetChildren().Index( id );
3233
3234 gtk_tree_path_prepend_index( retval, pos );
3235
3236 id = node->GetItem().GetID();
3237 node = node->GetParent();
3238 }
3239 }
3240
3241 return retval;
3242}
3243
3244gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter )
3245{
3246 if (m_wx_model->IsVirtualListModel())
3247 {
3248 wxDataViewIndexListModel *wx_model = (wxDataViewIndexListModel*) m_wx_model;
3249
3250 int n = (wxUIntPtr) iter->user_data;
3251
3252 if (n == -1)
3253 return FALSE;
3254
3255 if (n >= (int) wx_model->GetLastIndex())
3256 return FALSE;
3257
3258 iter->user_data = (gpointer) ++n;
3259 }
3260 else
3261 {
3262 wxGtkTreeModelNode *parent = FindParentNode( iter );
3263 if( parent == NULL )
3264 return FALSE;
3265
3266 int pos = parent->GetChildren().Index( iter->user_data );
3267
3268 if (pos == (int) parent->GetChildCount()-1)
3269 return FALSE;
3270
3271 iter->stamp = m_gtk_model->stamp;
3272 iter->user_data = parent->GetChildren().Item( pos+1 );
3273 }
3274
3275 return TRUE;
3276}
3277
3278gboolean wxDataViewCtrlInternal::iter_children( GtkTreeIter *iter, GtkTreeIter *parent )
3279{
3280 if (m_wx_model->IsVirtualListModel())
3281 {
3282 // this is a list, nodes have no children
3283 if (parent)
3284 return FALSE;
3285
3286 iter->stamp = m_gtk_model->stamp;
3287 iter->user_data = (gpointer) -1;
3288
3289 return TRUE;
3290 }
3291 else
3292 {
3293 wxDataViewItem item( (void*) parent->user_data );
3294
3295 if (!m_wx_model->IsContainer( item ))
3296 return FALSE;
3297
3298 wxGtkTreeModelNode *parent_node = FindNode( parent );
3299 BuildBranch( parent_node );
3300
3301 if (parent_node->GetChildCount() == 0)
3302 return FALSE;
3303
3304 iter->stamp = m_gtk_model->stamp;
3305 iter->user_data = (gpointer) parent_node->GetChildren().Item( 0 );
3306 }
3307
3308 return TRUE;
3309}
3310
3311gboolean wxDataViewCtrlInternal::iter_has_child( GtkTreeIter *iter )
3312{
3313 if (m_wx_model->IsVirtualListModel())
3314 {
3315 // this is a list, nodes have no children
3316 return FALSE;
3317 }
3318 else
3319 {
3320 wxDataViewItem item( (void*) iter->user_data );
3321
3322 bool is_container = m_wx_model->IsContainer( item );
3323
3324 if (!is_container)
3325 return FALSE;
3326
3327 wxGtkTreeModelNode *node = FindNode( iter );
3328 BuildBranch( node );
3329
3330 return (node->GetChildCount() > 0);
3331 }
3332}
3333
3334gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter )
3335{
3336 if (m_wx_model->IsVirtualListModel())
3337 {
3338 wxDataViewIndexListModel *wx_model = (wxDataViewIndexListModel*) m_wx_model;
3339
3340 if (iter == NULL)
3341 return (gint) wx_model->GetLastIndex() + 1;
3342
3343 return 0;
3344 }
3345 else
3346 {
3347 if (iter == NULL)
3348 return m_root->GetChildCount();
3349
3350 wxDataViewItem item( (void*) iter->user_data );
3351
3352 if (!m_wx_model->IsContainer( item ))
3353 return 0;
3354
3355 wxGtkTreeModelNode *parent_node = FindNode( iter );
3356 BuildBranch( parent_node );
3357
3358 // wxPrintf( "iter_n_children %d\n", parent_node->GetChildCount() );
3359
3360 return parent_node->GetChildCount();
3361 }
3362}
3363
3364gboolean wxDataViewCtrlInternal::iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n )
3365{
3366 if (m_wx_model->IsVirtualListModel())
3367 {
3368 wxDataViewIndexListModel *wx_model = (wxDataViewIndexListModel*) m_wx_model;
3369
3370 if (parent)
3371 return FALSE;
3372
3373 if (n < 0)
3374 return FALSE;
3375
3376 if (n >= (gint) wx_model->GetLastIndex() + 1)
3377 return FALSE;
3378
3379 iter->stamp = m_gtk_model->stamp;
3380 iter->user_data = (gpointer) n;
3381
3382 return TRUE;
3383 }
3384 else
3385 {
3386 void* id = NULL;
3387 if (parent) id = (void*) parent->user_data;
3388 wxDataViewItem item( id );
3389
3390 if (!m_wx_model->IsContainer( item ))
3391 return FALSE;
3392
3393 wxGtkTreeModelNode *parent_node = FindNode( parent );
3394 BuildBranch( parent_node );
3395
3396 // wxPrintf( "iter_nth_child %d\n", n );
3397
3398 iter->stamp = m_gtk_model->stamp;
3399 iter->user_data = parent_node->GetChildren().Item( n );
3400
3401 return TRUE;
3402 }
3403}
3404
3405gboolean wxDataViewCtrlInternal::iter_parent( GtkTreeIter *iter, GtkTreeIter *child )
3406{
3407 if (m_wx_model->IsVirtualListModel())
3408 {
3409 return FALSE;
3410 }
3411 else
3412 {
3413 wxGtkTreeModelNode *node = FindParentNode( child );
3414 if (!node)
3415 return FALSE;
3416
3417 iter->stamp = m_gtk_model->stamp;
3418 iter->user_data = (gpointer) node->GetItem().GetID();
3419
3420 return TRUE;
3421 }
3422}
3423
3424static wxGtkTreeModelNode*
3425wxDataViewCtrlInternal_FindNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item )
3426{
3427 if( model == NULL )
3428 return NULL;
3429
3430 ItemList list;
3431 list.DeleteContents( true );
3432 wxDataViewItem it( item );
3433
3434 while( it.IsOk() )
3435 {
3436 wxDataViewItem * pItem = new wxDataViewItem( it );
3437 list.Insert( pItem );
3438 it = model->GetParent( it );
3439 }
3440
3441 wxGtkTreeModelNode * node = treeNode;
3442 for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
3443 {
3444 if( node && node->GetNodes().GetCount() != 0 )
3445 {
3446 int len = node->GetNodes().GetCount();
3447 wxGtkTreeModelNodes nodes = node->GetNodes();
3448 int j = 0;
3449 for( ; j < len; j ++)
3450 {
3451 if( nodes[j]->GetItem() == *(n->GetData()))
3452 {
3453 node = nodes[j];
3454 break;
3455 }
3456 }
3457
3458 if( j == len )
3459 {
3460 return NULL;
3461 }
3462 }
3463 else
3464 return NULL;
3465 }
3466 return node;
3467
3468}
3469
3470wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
3471{
3472 if (!iter)
3473 return m_root;
3474
3475 wxDataViewItem item( (void*) iter->user_data );
3476 if (!item.IsOk())
3477 return m_root;
3478
3479 wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
3480
3481 if (!result)
3482 {
3483 wxLogDebug( "Not found %p", iter->user_data );
3484 char *crash = NULL;
3485 *crash = 0;
3486 }
3487
3488 return result;
3489}
3490
3491wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item )
3492{
3493 if (!item.IsOk())
3494 return m_root;
3495
3496 wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
3497
3498 if (!result)
3499 {
3500 wxLogDebug( "Not found %p", item.GetID() );
3501 char *crash = NULL;
3502 *crash = 0;
3503 }
3504
3505 return result;
3506}
3507
3508static wxGtkTreeModelNode*
3509wxDataViewCtrlInternal_FindParentNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item )
3510{
3511 if( model == NULL )
3512 return NULL;
3513
3514 ItemList list;
3515 list.DeleteContents( true );
3516 if( !item.IsOk() )
3517 return NULL;
3518
3519 wxDataViewItem it( model->GetParent( item ) );
3520 while( it.IsOk() )
3521 {
3522 wxDataViewItem * pItem = new wxDataViewItem( it );
3523 list.Insert( pItem );
3524 it = model->GetParent( it );
3525 }
3526
3527 wxGtkTreeModelNode * node = treeNode;
3528 for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
3529 {
3530 if( node && node->GetNodes().GetCount() != 0 )
3531 {
3532 int len = node->GetNodes().GetCount();
3533 wxGtkTreeModelNodes nodes = node->GetNodes();
3534 int j = 0;
3535 for( ; j < len; j ++)
3536 {
3537 if( nodes[j]->GetItem() == *(n->GetData()))
3538 {
3539 node = nodes[j];
3540 break;
3541 }
3542 }
3543
3544 if( j == len )
3545 {
3546 return NULL;
3547 }
3548 }
3549 else
3550 return NULL;
3551 }
3552 //Examine whether the node is item's parent node
3553 int len = node->GetChildCount();
3554 for( int i = 0; i < len ; i ++ )
3555 {
3556 if( node->GetChildren().Item( i ) == item.GetID() )
3557 return node;
3558 }
3559 return NULL;
3560}
3561
3562wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( GtkTreeIter *iter )
3563{
3564 if (!iter)
3565 return NULL;
3566
3567 wxDataViewItem item( (void*) iter->user_data );
3568 if (!item.IsOk())
3569 return NULL;
3570
3571 return wxDataViewCtrlInternal_FindParentNode( m_wx_model, m_root, item );
3572}
3573
3574wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( const wxDataViewItem &item )
3575{
3576 if (!item.IsOk())
3577 return NULL;
3578
3579 return wxDataViewCtrlInternal_FindParentNode( m_wx_model, m_root, item );
3580}
3581
3582//-----------------------------------------------------------------------------
3583// wxDataViewCtrl signal callbacks
3584//-----------------------------------------------------------------------------
3585
3586static void
3587wxdataview_selection_changed_callback( GtkTreeSelection* WXUNUSED(selection), wxDataViewCtrl *dv )
3588{
3589 if (!GTK_WIDGET_REALIZED(dv->m_widget))
3590 return;
3591
3592 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, dv->GetId() );
3593 event.SetItem( dv->GetSelection() );
3594 event.SetModel( dv->GetModel() );
3595 dv->HandleWindowEvent( event );
3596}
3597
3598static void
3599wxdataview_row_activated_callback( GtkTreeView* WXUNUSED(treeview), GtkTreePath *path,
3600 GtkTreeViewColumn *WXUNUSED(column), wxDataViewCtrl *dv )
3601{
3602 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, dv->GetId() );
3603
3604 GtkTreeIter iter;
3605 dv->GtkGetInternal()->get_iter( &iter, path );
3606 wxDataViewItem item( (void*) iter.user_data );;
3607 event.SetItem( item );
3608 event.SetModel( dv->GetModel() );
3609 dv->HandleWindowEvent( event );
3610}
3611
3612static gboolean
3613wxdataview_test_expand_row_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
3614 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
3615{
3616 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING, dv->GetId() );
3617
3618 wxDataViewItem item( (void*) iter->user_data );;
3619 event.SetItem( item );
3620 event.SetModel( dv->GetModel() );
3621 dv->HandleWindowEvent( event );
3622
3623 return !event.IsAllowed();
3624}
3625
3626static void
3627wxdataview_row_expanded_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
3628 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
3629{
3630 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED, dv->GetId() );
3631
3632 wxDataViewItem item( (void*) iter->user_data );;
3633 event.SetItem( item );
3634 event.SetModel( dv->GetModel() );
3635 dv->HandleWindowEvent( event );
3636}
3637
3638static gboolean
3639wxdataview_test_collapse_row_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
3640 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
3641{
3642 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING, dv->GetId() );
3643
3644 wxDataViewItem item( (void*) iter->user_data );;
3645 event.SetItem( item );
3646 event.SetModel( dv->GetModel() );
3647 dv->HandleWindowEvent( event );
3648
3649 return !event.IsAllowed();
3650}
3651
3652static void
3653wxdataview_row_collapsed_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
3654 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
3655{
3656 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED, dv->GetId() );
3657
3658 wxDataViewItem item( (void*) iter->user_data );;
3659 event.SetItem( item );
3660 event.SetModel( dv->GetModel() );
3661 dv->HandleWindowEvent( event );
3662}
3663
3664//-----------------------------------------------------------------------------
3665 // wxDataViewCtrl
3666//-----------------------------------------------------------------------------
3667
3668void wxDataViewCtrl::AddChildGTK(wxWindowGTK* child)
3669{
3670 GtkWidget* treeview = GtkGetTreeView();
3671
3672 // Insert widget in GtkTreeView
3673 if (GTK_WIDGET_REALIZED(treeview))
3674 gtk_widget_set_parent_window( child->m_widget,
3675 gtk_tree_view_get_bin_window( GTK_TREE_VIEW(treeview) ) );
3676 gtk_widget_set_parent( child->m_widget, treeview );
3677}
3678
3679static
3680void gtk_dataviewctrl_size_callback( GtkWidget *WXUNUSED(widget),
3681 GtkAllocation *WXUNUSED(gtk_alloc),
3682 wxDataViewCtrl *win )
3683{
3684 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
3685 while (node)
3686 {
3687 wxWindow *child = node->GetData();
3688
3689 GtkRequisition req;
3690 gtk_widget_size_request( child->m_widget, &req );
3691
3692 GtkAllocation alloc;
3693 alloc.x = child->m_x;
3694 alloc.y = child->m_y;
3695 alloc.width = child->m_width;
3696 alloc.height = child->m_height;
3697 gtk_widget_size_allocate( child->m_widget, &alloc );
3698
3699 node = node->GetNext();
3700 }
3701}
3702
3703
3704//-----------------------------------------------------------------------------
3705// "motion_notify_event"
3706//-----------------------------------------------------------------------------
3707
3708static gboolean
3709gtk_dataview_motion_notify_callback( GtkWidget *WXUNUSED(widget),
3710 GdkEventMotion *gdk_event,
3711 wxDataViewCtrl *dv )
3712{
3713 if (gdk_event->is_hint)
3714 {
3715 int x = 0;
3716 int y = 0;
3717 GdkModifierType state;
3718 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
3719 gdk_event->x = x;
3720 gdk_event->y = y;
3721 }
3722
3723 GtkTreePath *path = NULL;
3724 GtkTreeViewColumn *column = NULL;
3725 gint cell_x = 0;
3726 gint cell_y = 0;
3727 if (gtk_tree_view_get_path_at_pos(
3728 GTK_TREE_VIEW(dv->GtkGetTreeView()),
3729 (int) gdk_event->x, (int) gdk_event->y,
3730 &path,
3731 &column,
3732 &cell_x,
3733 &cell_y))
3734 {
3735 if (path)
3736 {
3737 GtkTreeIter iter;
3738 dv->GtkGetInternal()->get_iter( &iter, path );
3739
3740 // wxPrintf( "mouse %d %d\n", (int) gdk_event->x, (int) gdk_event->y );
3741
3742 gtk_tree_path_free( path );
3743 }
3744 }
3745
3746
3747 return FALSE;
3748}
3749
3750//-----------------------------------------------------------------------------
3751// "button_press_event"
3752//-----------------------------------------------------------------------------
3753
3754static gboolean
3755gtk_dataview_button_press_callback( GtkWidget *WXUNUSED(widget),
3756 GdkEventButton *gdk_event,
3757 wxDataViewCtrl *dv )
3758{
3759 if ((gdk_event->button == 3) && (gdk_event->type == GDK_BUTTON_PRESS))
3760 {
3761 GtkTreePath *path = NULL;
3762 GtkTreeViewColumn *column = NULL;
3763 gint cell_x = 0;
3764 gint cell_y = 0;
3765 if (gtk_tree_view_get_path_at_pos(
3766 GTK_TREE_VIEW(dv->GtkGetTreeView()),
3767 (int) gdk_event->x, (int) gdk_event->y,
3768 &path,
3769 &column,
3770 &cell_x,
3771 &cell_y))
3772 {
3773 if (path)
3774 {
3775 GtkTreeIter iter;
3776 dv->GtkGetInternal()->get_iter( &iter, path );
3777
3778 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, dv->GetId() );
3779 wxDataViewItem item( (void*) iter.user_data );;
3780 event.SetItem( item );
3781 event.SetModel( dv->GetModel() );
3782 bool ret = dv->HandleWindowEvent( event );
3783 gtk_tree_path_free( path );
3784 return ret;
3785 }
3786 }
3787 }
3788
3789 return FALSE;
3790}
3791
3792IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
3793
3794wxDataViewCtrl::~wxDataViewCtrl()
3795{
3796 if (m_notifier)
3797 GetModel()->RemoveNotifier( m_notifier );
3798
3799 m_cols.Clear();
3800
3801 // remove the model from the GtkTreeView before it gets destroyed by the
3802 // wxDataViewCtrlBase's dtor
3803 gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview), NULL );
3804
3805 delete m_internal;
3806}
3807
3808void wxDataViewCtrl::Init()
3809{
3810 m_notifier = NULL;
3811 m_internal = NULL;
3812
3813 m_cols.DeleteContents( true );
3814}
3815
3816bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
3817 const wxPoint& pos, const wxSize& size,
3818 long style, const wxValidator& validator )
3819{
3820 Init();
3821
3822 if (!PreCreation( parent, pos, size ) ||
3823 !CreateBase( parent, id, pos, size, style, validator ))
3824 {
3825 wxFAIL_MSG( wxT("wxDataViewCtrl creation failed") );
3826 return false;
3827 }
3828
3829 m_widget = gtk_scrolled_window_new (NULL, NULL);
3830 g_object_ref(m_widget);
3831
3832 GtkScrolledWindowSetBorder(m_widget, style);
3833
3834 m_treeview = gtk_tree_view_new();
3835 gtk_container_add (GTK_CONTAINER (m_widget), m_treeview);
3836
3837 g_signal_connect (m_treeview, "size_allocate",
3838 G_CALLBACK (gtk_dataviewctrl_size_callback), this);
3839
3840#ifdef __WXGTK26__
3841 if (!gtk_check_version(2,6,0))
3842 {
3843 bool fixed = (style & wxDV_VARIABLE_LINE_HEIGHT) == 0;
3844 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), fixed );
3845 }
3846#endif
3847
3848 if (style & wxDV_MULTIPLE)
3849 {
3850 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
3851 gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
3852 }
3853
3854 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(m_treeview), (style & wxDV_NO_HEADER) == 0 );
3855
3856#ifdef __WXGTK210__
3857 if (!gtk_check_version(2,10,0))
3858 {
3859 GtkTreeViewGridLines grid = GTK_TREE_VIEW_GRID_LINES_NONE;
3860
3861 if ((style & wxDV_HORIZ_RULES) != 0 &&
3862 (style & wxDV_VERT_RULES) != 0)
3863 grid = GTK_TREE_VIEW_GRID_LINES_BOTH;
3864 else if (style & wxDV_VERT_RULES)
3865 grid = GTK_TREE_VIEW_GRID_LINES_VERTICAL;
3866 else if (style & wxDV_HORIZ_RULES)
3867 grid = GTK_TREE_VIEW_GRID_LINES_HORIZONTAL;
3868
3869 if (grid != GTK_TREE_VIEW_GRID_LINES_NONE)
3870 gtk_tree_view_set_grid_lines( GTK_TREE_VIEW(m_treeview), grid );
3871 }
3872#endif
3873
3874 gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(m_treeview), (style & wxDV_ROW_LINES) != 0 );
3875
3876 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_widget),
3877 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3878 gtk_widget_show (m_treeview);
3879
3880 m_parent->DoAddChild( this );
3881
3882 PostCreation(size);
3883
3884 GtkEnableSelectionEvents();
3885
3886 g_signal_connect_after (m_treeview, "row-activated",
3887 G_CALLBACK (wxdataview_row_activated_callback), this);
3888
3889 g_signal_connect (m_treeview, "test-collapse-row",
3890 G_CALLBACK (wxdataview_test_collapse_row_callback), this);
3891
3892 g_signal_connect_after (m_treeview, "row-collapsed",
3893 G_CALLBACK (wxdataview_row_collapsed_callback), this);
3894
3895 g_signal_connect (m_treeview, "test-expand-row",
3896 G_CALLBACK (wxdataview_test_expand_row_callback), this);
3897
3898 g_signal_connect_after (m_treeview, "row-expanded",
3899 G_CALLBACK (wxdataview_row_expanded_callback), this);
3900
3901 g_signal_connect (m_treeview, "motion_notify_event",
3902 G_CALLBACK (gtk_dataview_motion_notify_callback), this);
3903
3904 g_signal_connect (m_treeview, "button_press_event",
3905 G_CALLBACK (gtk_dataview_button_press_callback), this);
3906
3907 return true;
3908}
3909
3910void wxDataViewCtrl::OnInternalIdle()
3911{
3912 wxWindow::OnInternalIdle();
3913
3914 unsigned int cols = GetColumnCount();
3915 unsigned int i;
3916 for (i = 0; i < cols; i++)
3917 {
3918 wxDataViewColumn *col = GetColumn( i );
3919 col->OnInternalIdle();
3920 }
3921}
3922
3923bool wxDataViewCtrl::AssociateModel( wxDataViewModel *model )
3924{
3925 if (GetModel())
3926 {
3927 delete m_internal;
3928 m_internal = NULL;
3929
3930 delete m_notifier;
3931 m_notifier = NULL;
3932 }
3933
3934 if (!wxDataViewCtrlBase::AssociateModel( model ))
3935 return false;
3936
3937#ifdef __WXGTK26__
3938 if (!gtk_check_version(2,6,0))
3939 {
3940 bool fixed = (((GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT) == 0) || (model->IsVirtualListModel()));
3941 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), fixed );
3942 }
3943#endif
3944
3945 GtkWxTreeModel *gtk_model = wxgtk_tree_model_new();
3946 m_internal = new wxDataViewCtrlInternal( this, model, gtk_model );
3947 gtk_model->internal = m_internal;
3948
3949 m_notifier = new wxGtkDataViewModelNotifier( gtk_model, model, this );
3950
3951 model->AddNotifier( m_notifier );
3952
3953 gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview), GTK_TREE_MODEL(gtk_model) );
3954
3955 // unref in wxDataViewCtrlInternal
3956 // g_object_unref( gtk_model );
3957
3958 return true;
3959}
3960
3961bool wxDataViewCtrl::EnableDragSource( const wxDataFormat &format )
3962{
3963 return m_internal->EnableDragSource( format );
3964}
3965
3966bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat &format )
3967{
3968 return m_internal->EnableDropTarget( format );
3969}
3970
3971bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
3972{
3973 if (!wxDataViewCtrlBase::AppendColumn(col))
3974 return false;
3975
3976 m_cols.Append( col );
3977
3978#ifdef __WXGTK26__
3979 if (!gtk_check_version(2,6,0))
3980 {
3981 if (gtk_tree_view_column_get_sizing( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) ) !=
3982 GTK_TREE_VIEW_COLUMN_FIXED)
3983 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), FALSE );
3984 }
3985#endif
3986
3987 gtk_tree_view_append_column( GTK_TREE_VIEW(m_treeview),
3988 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) );
3989
3990 return true;
3991}
3992
3993bool wxDataViewCtrl::PrependColumn( wxDataViewColumn *col )
3994{
3995 if (!wxDataViewCtrlBase::PrependColumn(col))
3996 return false;
3997
3998 m_cols.Insert( col );
3999
4000#ifdef __WXGTK26__
4001 if (!gtk_check_version(2,6,0))
4002 {
4003 if (gtk_tree_view_column_get_sizing( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) ) !=
4004 GTK_TREE_VIEW_COLUMN_FIXED)
4005 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), FALSE );
4006 }
4007#endif
4008
4009 gtk_tree_view_insert_column( GTK_TREE_VIEW(m_treeview),
4010 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()), 0 );
4011
4012 return true;
4013}
4014
4015bool wxDataViewCtrl::InsertColumn( unsigned int pos, wxDataViewColumn *col )
4016{
4017 if (!wxDataViewCtrlBase::InsertColumn(pos,col))
4018 return false;
4019
4020 m_cols.Insert( pos, col );
4021
4022#ifdef __WXGTK26__
4023 if (!gtk_check_version(2,6,0))
4024 {
4025 if (gtk_tree_view_column_get_sizing( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) ) !=
4026 GTK_TREE_VIEW_COLUMN_FIXED)
4027 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), FALSE );
4028 }
4029#endif
4030
4031 gtk_tree_view_insert_column( GTK_TREE_VIEW(m_treeview),
4032 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()), pos );
4033
4034 return true;
4035}
4036
4037unsigned int wxDataViewCtrl::GetColumnCount() const
4038{
4039 return m_cols.GetCount();
4040}
4041
4042wxDataViewColumn* wxDataViewCtrl::GetColumn( unsigned int pos ) const
4043{
4044 GtkTreeViewColumn *gtk_col = gtk_tree_view_get_column( GTK_TREE_VIEW(m_treeview), pos );
4045 if (!gtk_col)
4046 return NULL;
4047
4048 wxDataViewColumnList::const_iterator iter;
4049 for (iter = m_cols.begin(); iter != m_cols.end(); ++iter)
4050 {
4051 wxDataViewColumn *col = *iter;
4052 if (GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) == gtk_col)
4053 {
4054 return col;
4055 }
4056 }
4057
4058 return NULL;
4059}
4060
4061bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column )
4062{
4063 gtk_tree_view_remove_column( GTK_TREE_VIEW(m_treeview),
4064 GTK_TREE_VIEW_COLUMN(column->GetGtkHandle()) );
4065
4066 m_cols.DeleteObject( column );
4067
4068 return true;
4069}
4070
4071bool wxDataViewCtrl::ClearColumns()
4072{
4073 wxDataViewColumnList::iterator iter;
4074 for (iter = m_cols.begin(); iter != m_cols.end(); ++iter)
4075 {
4076 wxDataViewColumn *col = *iter;
4077 gtk_tree_view_remove_column( GTK_TREE_VIEW(m_treeview),
4078 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) );
4079 }
4080
4081 m_cols.Clear();
4082
4083 return true;
4084}
4085
4086int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const
4087{
4088 GtkTreeViewColumn *gtk_column = GTK_TREE_VIEW_COLUMN(column->GetConstGtkHandle());
4089
4090 GList *list = gtk_tree_view_get_columns( GTK_TREE_VIEW(m_treeview) );
4091
4092 gint pos = g_list_index( list, (gconstpointer) gtk_column );
4093
4094 g_list_free( list );
4095
4096 return pos;
4097}
4098
4099wxDataViewColumn *wxDataViewCtrl::GetSortingColumn() const
4100{
4101 return m_internal->GetDataViewSortColumn();
4102}
4103
4104void wxDataViewCtrl::Expand( const wxDataViewItem & item )
4105{
4106 GtkTreeIter iter;
4107 iter.user_data = item.GetID();
4108 GtkTreePath *path = m_internal->get_path( &iter );
4109 gtk_tree_view_expand_row( GTK_TREE_VIEW(m_treeview), path, false );
4110 gtk_tree_path_free( path );
4111}
4112
4113void wxDataViewCtrl::Collapse( const wxDataViewItem & item )
4114{
4115 GtkTreeIter iter;
4116 iter.user_data = item.GetID();
4117 GtkTreePath *path = m_internal->get_path( &iter );
4118 gtk_tree_view_collapse_row( GTK_TREE_VIEW(m_treeview), path );
4119 gtk_tree_path_free( path );
4120}
4121
4122bool wxDataViewCtrl::IsExpanded( const wxDataViewItem & item ) const
4123{
4124 GtkTreeIter iter;
4125 iter.user_data = item.GetID();
4126 GtkTreePath *path = m_internal->get_path( &iter );
4127 bool res = gtk_tree_view_row_expanded( GTK_TREE_VIEW(m_treeview), path );
4128 gtk_tree_path_free( path );
4129
4130 return res;
4131}
4132
4133wxDataViewItem wxDataViewCtrl::GetSelection() const
4134{
4135 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4136
4137 if (m_windowStyle & wxDV_MULTIPLE)
4138 {
4139 // Report the first one
4140 GtkTreeModel *model;
4141 GList *list = gtk_tree_selection_get_selected_rows( selection, &model );
4142
4143 if (list)
4144 {
4145 GtkTreePath *path = (GtkTreePath*) list->data;
4146 GtkTreeIter iter;
4147 m_internal->get_iter( &iter, path );
4148
4149 // delete list
4150 g_list_foreach( list, (GFunc) gtk_tree_path_free, NULL );
4151 g_list_free( list );
4152
4153 return wxDataViewItem( (void*) iter.user_data );
4154 }
4155 }
4156 else
4157 {
4158 GtkTreeIter iter;
4159 if (gtk_tree_selection_get_selected( selection, NULL, &iter ))
4160 {
4161 wxDataViewItem item( (void*) iter.user_data );
4162 return item;
4163 }
4164 }
4165
4166 return wxDataViewItem(0);
4167}
4168
4169int wxDataViewCtrl::GetSelections( wxDataViewItemArray & sel ) const
4170{
4171 sel.Clear();
4172
4173 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4174 if (HasFlag(wxDV_MULTIPLE))
4175 {
4176 GtkTreeModel *model;
4177 GList *list = gtk_tree_selection_get_selected_rows( selection, &model );
4178
4179 int count = 0;
4180 while (list)
4181 {
4182 GtkTreePath *path = (GtkTreePath*) list->data;
4183
4184 GtkTreeIter iter;
4185 m_internal->get_iter( &iter, path );
4186
4187 sel.Add( wxDataViewItem( (void*) iter.user_data ) );
4188
4189 list = g_list_next( list );
4190 count++;
4191 }
4192
4193 // delete list
4194 g_list_foreach( list, (GFunc) gtk_tree_path_free, NULL );
4195 g_list_free( list );
4196
4197 return count;
4198 }
4199 else
4200 {
4201 GtkTreeModel *model;
4202 GtkTreeIter iter;
4203 gboolean has_selection = gtk_tree_selection_get_selected( selection, &model, &iter );
4204 if (has_selection)
4205 {
4206 sel.Add( wxDataViewItem( (void*) iter.user_data) );
4207 return 1;
4208 }
4209 }
4210
4211 return 0;
4212}
4213
4214void wxDataViewCtrl::SetSelections( const wxDataViewItemArray & sel )
4215{
4216 GtkDisableSelectionEvents();
4217
4218 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4219
4220 gtk_tree_selection_unselect_all( selection );
4221
4222 wxDataViewItem last_parent;
4223
4224 size_t i;
4225 for (i = 0; i < sel.GetCount(); i++)
4226 {
4227 wxDataViewItem item = sel[i];
4228 wxDataViewItem parent = GetModel()->GetParent( item );
4229 if (parent)
4230 {
4231 if (parent != last_parent)
4232 ExpandAncestors(item);
4233 }
4234 last_parent = parent;
4235
4236 GtkTreeIter iter;
4237 iter.stamp = m_internal->GetGtkModel()->stamp;
4238 iter.user_data = (gpointer) item.GetID();
4239 gtk_tree_selection_select_iter( selection, &iter );
4240 }
4241
4242 GtkEnableSelectionEvents();
4243}
4244
4245void wxDataViewCtrl::Select( const wxDataViewItem & item )
4246{
4247 ExpandAncestors(item);
4248
4249 GtkDisableSelectionEvents();
4250
4251 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4252
4253 GtkTreeIter iter;
4254 iter.stamp = m_internal->GetGtkModel()->stamp;
4255 iter.user_data = (gpointer) item.GetID();
4256 gtk_tree_selection_select_iter( selection, &iter );
4257
4258 GtkEnableSelectionEvents();
4259}
4260
4261void wxDataViewCtrl::Unselect( const wxDataViewItem & item )
4262{
4263 GtkDisableSelectionEvents();
4264
4265 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4266
4267 GtkTreeIter iter;
4268 iter.stamp = m_internal->GetGtkModel()->stamp;
4269 iter.user_data = (gpointer) item.GetID();
4270 gtk_tree_selection_unselect_iter( selection, &iter );
4271
4272 GtkEnableSelectionEvents();
4273}
4274
4275bool wxDataViewCtrl::IsSelected( const wxDataViewItem & item ) const
4276{
4277 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4278
4279 GtkTreeIter iter;
4280 iter.stamp = m_internal->GetGtkModel()->stamp;
4281 iter.user_data = (gpointer) item.GetID();
4282
4283 return gtk_tree_selection_iter_is_selected( selection, &iter );
4284}
4285
4286void wxDataViewCtrl::SelectAll()
4287{
4288 GtkDisableSelectionEvents();
4289
4290 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4291
4292 gtk_tree_selection_select_all( selection );
4293
4294 GtkEnableSelectionEvents();
4295}
4296
4297void wxDataViewCtrl::UnselectAll()
4298{
4299 GtkDisableSelectionEvents();
4300
4301 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4302
4303 gtk_tree_selection_unselect_all( selection );
4304
4305 GtkEnableSelectionEvents();
4306}
4307
4308void wxDataViewCtrl::EnsureVisible(const wxDataViewItem& item,
4309 const wxDataViewColumn *WXUNUSED(column))
4310{
4311 ExpandAncestors(item);
4312
4313 GtkTreeIter iter;
4314 iter.user_data = (gpointer) item.GetID();
4315 GtkTreePath *path = m_internal->get_path( &iter );
4316 gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW(m_treeview), path, NULL, false, 0.0, 0.0 );
4317 gtk_tree_path_free( path );
4318}
4319
4320void wxDataViewCtrl::HitTest(const wxPoint& WXUNUSED(point),
4321 wxDataViewItem& item,
4322 wxDataViewColumn *& column) const
4323{
4324 item = wxDataViewItem(0);
4325 column = NULL;
4326}
4327
4328wxRect
4329wxDataViewCtrl::GetItemRect(const wxDataViewItem& WXUNUSED(item),
4330 const wxDataViewColumn *WXUNUSED(column)) const
4331{
4332 return wxRect();
4333}
4334
4335void wxDataViewCtrl::DoSetExpanderColumn()
4336{
4337 gtk_tree_view_set_expander_column( GTK_TREE_VIEW(m_treeview),
4338 GTK_TREE_VIEW_COLUMN( GetExpanderColumn()->GetGtkHandle() ) );
4339}
4340
4341void wxDataViewCtrl::DoSetIndent()
4342{
4343}
4344
4345void wxDataViewCtrl::GtkDisableSelectionEvents()
4346{
4347 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4348 g_signal_handlers_disconnect_by_func( selection,
4349 (gpointer) (wxdataview_selection_changed_callback), this);
4350}
4351
4352void wxDataViewCtrl::GtkEnableSelectionEvents()
4353{
4354 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4355 g_signal_connect_after (selection, "changed",
4356 G_CALLBACK (wxdataview_selection_changed_callback), this);
4357}
4358
4359// static
4360wxVisualAttributes
4361wxDataViewCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
4362{
4363 return GetDefaultAttributesFromGTKWidget(gtk_tree_view_new);
4364}
4365
4366
4367#endif
4368 // !wxUSE_GENERICDATAVIEWCTRL
4369
4370#endif
4371 // wxUSE_DATAVIEWCTRL