]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dataview.cpp
Don't warn about wxMetaFile in configure by default.
[wxWidgets.git] / src / gtk / dataview.cpp
CommitLineData
790b137e 1/////////////////////////////////////////////////////////////////////////////
93763ad5 2// Name: src/gtk/dataview.cpp
790b137e
RR
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
790b137e
RR
13#if wxUSE_DATAVIEWCTRL
14
15#include "wx/dataview.h"
4ed7af08
RR
16
17#ifndef wxUSE_GENERICDATAVIEWCTRL
18
e4db172a
WS
19#ifndef WX_PRECOMP
20 #include "wx/log.h"
ed4b0fdc 21 #include "wx/dcclient.h"
ed2fbeb8 22 #include "wx/sizer.h"
c3c62822
PC
23 #include "wx/settings.h"
24 #include "wx/crt.h"
e4db172a
WS
25#endif
26
790b137e 27#include "wx/stockitem.h"
7ea3a0de
RR
28#include "wx/calctrl.h"
29#include "wx/popupwin.h"
69892729 30#include "wx/listimpl.cpp"
790b137e
RR
31
32#include "wx/gtk/private.h"
888dde65
RR
33#include "wx/gtk/dc.h"
34#include "wx/gtk/dcclient.h"
4d496ecb 35
9d02e494 36#include "wx/gtk/private/gdkconv.h"
0eec47e4 37#include "wx/gtk/private/list.h"
9d02e494
VZ
38using namespace wxGTKImpl;
39
673810ee
RR
40class wxGtkDataViewModelNotifier;
41
790b137e 42//-----------------------------------------------------------------------------
790b137e
RR
43//-----------------------------------------------------------------------------
44
8c2654ce 45static wxDataViewCtrlInternal *gs_internal = NULL;
3b6280be
RR
46
47class wxGtkTreeModelNode;
ef427989 48
0be79c8a
RR
49extern "C" {
50typedef struct _GtkWxTreeModel GtkWxTreeModel;
51}
52
0c2a7270
VZ
53// ----------------------------------------------------------------------------
54// wxGtkTreePath: self-destroying GtkTreePath
55// ----------------------------------------------------------------------------
56
57// Usually this object is initialized with the associated GtkTreePath
58// immediately when it's constructed but it can also be changed later either by
59// using Assign() or by getting the pointer to the internally stored pointer
60// value using ByRef(). The latter should be avoided but is very convenient
61// when using GTK functions with GtkTreePath output parameters.
62class wxGtkTreePath
63{
64public:
65 // Ctor takes ownership of the given path and will free it if non-NULL.
66 wxGtkTreePath(GtkTreePath *path = NULL) : m_path(path) { }
67
68 // Creates a tree path for the given string path.
69 wxGtkTreePath(const gchar *strpath)
70 : m_path(gtk_tree_path_new_from_string(strpath))
71 {
72 }
73
74 // Set the stored pointer if not done by ctor.
75 void Assign(GtkTreePath *path)
76 {
77 wxASSERT_MSG( !m_path, "shouldn't be already initialized" );
78
79 m_path = path;
80 }
81
82 // Return the pointer to the internally stored pointer. This should only be
83 // used to initialize the object by passing it to some GTK function.
84 GtkTreePath **ByRef()
85 {
86 wxASSERT_MSG( !m_path, "shouldn't be already initialized" );
87
88 return &m_path;
89 }
90
91
92 operator GtkTreePath *() const { return m_path; }
93
94 ~wxGtkTreePath() { if ( m_path ) gtk_tree_path_free(m_path); }
95
96private:
97 GtkTreePath *m_path;
98
99 wxDECLARE_NO_COPY_CLASS(wxGtkTreePath);
100};
101
0eec47e4
VZ
102// ----------------------------------------------------------------------------
103// wxGtkTreePathList: self-destroying list of GtkTreePath objects.
104// ----------------------------------------------------------------------------
105
106class wxGtkTreePathList : public wxGtkList
107{
108public:
109 // Ctor takes ownership of the list.
110 explicit wxGtkTreePathList(GList* list)
111 : wxGtkList(list)
112 {
113 }
114
115 ~wxGtkTreePathList()
116 {
117 // Delete the list contents, wxGtkList will delete the list itself.
118 g_list_foreach(m_list, (GFunc)gtk_tree_path_free, NULL);
119 }
120};
121
80ce465c
VZ
122// ----------------------------------------------------------------------------
123// wxGtkTreeSelectionLock: prevent selection from changing during the
124// lifetime of this object
125// ----------------------------------------------------------------------------
126
127// Implementation note: it could be expected that setting the selection
128// function in this class ctor and resetting it back to the old value in its
129// dtor would work. However currently gtk_tree_selection_get_select_function()
130// can't be passed NULL (see https://bugzilla.gnome.org/show_bug.cgi?id=626276)
131// so we can't do this. Instead, we always use the selection function (which
132// imposes extra overhead, albeit minimal one, on all selection operations) and
133// just set/reset the flag telling it whether it should allow or forbid the
134// selection.
135//
136// Also notice that currently only a single object of this class may exist at
137// any given moment. It's just simpler like this and we don't need anything
138// more for now.
139
140extern "C"
141gboolean wxdataview_selection_func(GtkTreeSelection * WXUNUSED(selection),
142 GtkTreeModel * WXUNUSED(model),
143 GtkTreePath * WXUNUSED(path),
144 gboolean WXUNUSED(path_currently_selected),
145 gpointer data)
146{
147 return data == NULL;
148}
149
150class wxGtkTreeSelectionLock
151{
152public:
153 wxGtkTreeSelectionLock(GtkTreeSelection *selection)
154 : m_selection(selection)
155 {
156 wxASSERT_MSG( !ms_instance, "this class is not reentrant currently" );
157
158 ms_instance = this;
159
160 CheckCurrentSelectionFunc(NULL);
161
162 // Pass some non-NULL pointer as "data" for the callback, it doesn't
163 // matter what it is as long as it's non-NULL.
164 gtk_tree_selection_set_select_function(selection,
165 wxdataview_selection_func,
166 this,
167 NULL);
168 }
169
170 ~wxGtkTreeSelectionLock()
171 {
172 CheckCurrentSelectionFunc(wxdataview_selection_func);
173
174 gtk_tree_selection_set_select_function(m_selection,
175 wxdataview_selection_func,
176 NULL,
177 NULL);
178
179 ms_instance = NULL;
180 }
181
182private:
183 void CheckCurrentSelectionFunc(GtkTreeSelectionFunc func)
184 {
185 // We can only use gtk_tree_selection_get_select_function() with 2.14+
186 // so check for its availability both during compile- and run-time.
187#if GTK_CHECK_VERSION(2, 14, 0)
188 if ( gtk_check_version(2, 14, 0) != NULL )
189 return;
190
191 // If this assert is triggered, it means the code elsewhere has called
192 // gtk_tree_selection_set_select_function() but currently doing this
193 // breaks this class so the code here needs to be changed.
194 wxASSERT_MSG
195 (
196 gtk_tree_selection_get_select_function(m_selection) == func,
197 "selection function has changed unexpectedly, review this code!"
198 );
199#endif // GTK+ 2.14+
200
201 wxUnusedVar(func);
202 }
203
204 static wxGtkTreeSelectionLock *ms_instance;
205
206 GtkTreeSelection * const m_selection;
207
208 wxDECLARE_NO_COPY_CLASS(wxGtkTreeSelectionLock);
209};
210
211wxGtkTreeSelectionLock *wxGtkTreeSelectionLock::ms_instance = NULL;
212
af110130
RR
213//-----------------------------------------------------------------------------
214// wxDataViewCtrlInternal
215//-----------------------------------------------------------------------------
216
69892729 217WX_DECLARE_LIST(wxDataViewItem, ItemList);
a76c2f37 218WX_DEFINE_LIST(ItemList)
69892729 219
033a5ff5 220class wxDataViewCtrlInternal
af110130
RR
221{
222public:
673810ee 223 wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataViewModel *wx_model );
af110130 224 ~wxDataViewCtrlInternal();
b9db5f30 225
f6f0ef85 226 // model iface
2056dede 227 GtkTreeModelFlags get_flags();
af110130
RR
228 gboolean get_iter( GtkTreeIter *iter, GtkTreePath *path );
229 GtkTreePath *get_path( GtkTreeIter *iter);
af110130
RR
230 gboolean iter_next( GtkTreeIter *iter );
231 gboolean iter_children( GtkTreeIter *iter, GtkTreeIter *parent);
232 gboolean iter_has_child( GtkTreeIter *iter );
233 gint iter_n_children( GtkTreeIter *iter );
234 gboolean iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n );
235 gboolean iter_parent( GtkTreeIter *iter, GtkTreeIter *child );
b9db5f30 236
f6f0ef85 237 // dnd iface
8c2654ce 238
15cac64f 239 bool EnableDragSource( const wxDataFormat &format );
e4de825e 240 bool EnableDropTarget( const wxDataFormat &format );
8c2654ce 241
f6f0ef85
RR
242 gboolean row_draggable( GtkTreeDragSource *drag_source, GtkTreePath *path );
243 gboolean drag_data_delete( GtkTreeDragSource *drag_source, GtkTreePath* path );
7857346a 244 gboolean drag_data_get( GtkTreeDragSource *drag_source, GtkTreePath *path,
f6f0ef85 245 GtkSelectionData *selection_data );
7857346a 246 gboolean drag_data_received( GtkTreeDragDest *drag_dest, GtkTreePath *dest,
f6f0ef85 247 GtkSelectionData *selection_data );
7857346a 248 gboolean row_drop_possible( GtkTreeDragDest *drag_dest, GtkTreePath *dest_path,
f6f0ef85
RR
249 GtkSelectionData *selection_data );
250
251 // notifactions from wxDataViewModel
af110130 252 bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
469d3e9b 253 bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
d8331a01 254 bool ItemChanged( const wxDataViewItem &item );
d93cc830 255 bool ValueChanged( const wxDataViewItem &item, unsigned int model_column );
d8331a01 256 bool Cleared();
d8090b5e 257 bool BeforeReset();
673810ee 258 bool AfterReset();
af110130 259 void Resort();
b9db5f30 260
f6f0ef85 261 // sorting interface
b8b7b087 262 void SetSortOrder( GtkSortType sort_order ) { m_sort_order = sort_order; }
1f226ad8 263 GtkSortType GetSortOrder() const { return m_sort_order; }
7ee7191c 264
40196b1e 265 void SetSortColumn( int column ) { m_sort_column = column; }
1f226ad8 266 int GetSortColumn() const { return m_sort_column; }
b9db5f30 267
d32332aa
RR
268 void SetDataViewSortColumn( wxDataViewColumn *column ) { m_dataview_sort_column = column; }
269 wxDataViewColumn *GetDataViewSortColumn() { return m_dataview_sort_column; }
b9db5f30 270
40196b1e 271 bool IsSorted() { return (m_sort_column >= 0); }
b9db5f30 272
f6f0ef85
RR
273 // accessors
274 wxDataViewModel* GetDataViewModel() { return m_wx_model; }
1f226ad8 275 const wxDataViewModel* GetDataViewModel() const { return m_wx_model; }
f6f0ef85
RR
276 wxDataViewCtrl* GetOwner() { return m_owner; }
277 GtkWxTreeModel* GetGtkModel() { return m_gtk_model; }
b9db5f30 278
74035a19 279 // item can be deleted already in the model
8650c4ba
RR
280 int GetIndexOf( const wxDataViewItem &parent, const wxDataViewItem &item );
281
d8090b5e 282 virtual void OnInternalIdle();
ce00f59b 283
af110130
RR
284protected:
285 void InitTree();
d8090b5e 286 void ScheduleRefresh();
ce00f59b 287
af110130
RR
288 wxGtkTreeModelNode *FindNode( const wxDataViewItem &item );
289 wxGtkTreeModelNode *FindNode( GtkTreeIter *iter );
290 wxGtkTreeModelNode *FindParentNode( const wxDataViewItem &item );
291 wxGtkTreeModelNode *FindParentNode( GtkTreeIter *iter );
292 void BuildBranch( wxGtkTreeModelNode *branch );
b9db5f30 293
af110130
RR
294private:
295 wxGtkTreeModelNode *m_root;
296 wxDataViewModel *m_wx_model;
297 GtkWxTreeModel *m_gtk_model;
298 wxDataViewCtrl *m_owner;
b8b7b087 299 GtkSortType m_sort_order;
d32332aa 300 wxDataViewColumn *m_dataview_sort_column;
40196b1e 301 int m_sort_column;
8c2654ce 302
15cac64f
RR
303 GtkTargetEntry m_dragSourceTargetEntry;
304 wxCharBuffer m_dragSourceTargetEntryTarget;
591cc82d 305 wxDataObject *m_dragDataObject;
8c2654ce 306
e4de825e
RR
307 GtkTargetEntry m_dropTargetTargetEntry;
308 wxCharBuffer m_dropTargetTargetEntryTarget;
591cc82d 309 wxDataObject *m_dropDataObject;
ce00f59b 310
673810ee 311 wxGtkDataViewModelNotifier *m_notifier;
ce00f59b 312
d8090b5e 313 bool m_dirty;
af110130 314};
ef427989 315
af110130
RR
316
317//-----------------------------------------------------------------------------
318// wxGtkTreeModelNode
319//-----------------------------------------------------------------------------
320
8c2654ce 321static
40196b1e
RR
322int LINKAGEMODE wxGtkTreeModelChildCmp( void** id1, void** id2 )
323{
d5c4a81f 324 int ret = gs_internal->GetDataViewModel()->Compare( wxDataViewItem(*id1), wxDataViewItem(*id2),
8c2654ce 325 gs_internal->GetSortColumn(), (gs_internal->GetSortOrder() == GTK_SORT_ASCENDING) );
b9db5f30 326
40196b1e
RR
327 return ret;
328}
af110130
RR
329
330WX_DEFINE_ARRAY_PTR( wxGtkTreeModelNode*, wxGtkTreeModelNodes );
40196b1e 331WX_DEFINE_ARRAY_PTR( void*, wxGtkTreeModelChildren );
3b6280be
RR
332
333class wxGtkTreeModelNode
334{
335public:
ef427989 336 wxGtkTreeModelNode( wxGtkTreeModelNode* parent, const wxDataViewItem &item,
c2489d8e 337 wxDataViewCtrlInternal *internal )
b9db5f30
VS
338 {
339 m_parent = parent;
d5025dc0 340 m_item = item;
0be79c8a 341 m_internal = internal;
3b6280be 342 }
b9db5f30 343
3b6280be 344 ~wxGtkTreeModelNode()
b9db5f30 345 {
023eecb7 346 size_t count = m_nodes.GetCount();
3b6280be
RR
347 size_t i;
348 for (i = 0; i < count; i++)
349 {
af110130 350 wxGtkTreeModelNode *child = m_nodes.Item( i );
3b6280be
RR
351 delete child;
352 }
353 }
354
35219832 355 void AddNode( wxGtkTreeModelNode* child )
b9db5f30 356 {
af110130 357 m_nodes.Add( child );
b9db5f30 358
40196b1e 359 void *id = child->GetItem().GetID();
b9db5f30 360
40196b1e 361 m_children.Add( id );
0bd26819
RR
362
363 if (m_internal->IsSorted() || m_internal->GetDataViewModel()->HasDefaultCompare())
40196b1e 364 {
8c2654ce 365 gs_internal = m_internal;
40196b1e 366 m_children.Sort( &wxGtkTreeModelChildCmp );
35219832
VS
367 }
368 }
369
370 void InsertNode( wxGtkTreeModelNode* child, unsigned pos )
371 {
372 if (m_internal->IsSorted() || m_internal->GetDataViewModel()->HasDefaultCompare())
373 {
374 AddNode(child);
375 return;
40196b1e 376 }
0bd26819 377
35219832
VS
378 void *id = child->GetItem().GetID();
379
380 // Insert into m_nodes so that the order of nodes in m_nodes is the
381 // same as the order of their corresponding IDs in m_children:
382 const unsigned int count = m_nodes.GetCount();
383 for (unsigned i = 0; i < count; i++)
384 {
385 wxGtkTreeModelNode *node = m_nodes[i];
386 int posInChildren = m_children.Index(node->GetItem().GetID());
387 if ( (unsigned)posInChildren >= pos )
388 {
389 m_nodes.Insert(child, i);
390 break;
391 }
392 }
393
394 m_children.Insert( id, pos );
af110130 395 }
b9db5f30 396
35219832 397 void AddLeaf( void* id )
af110130 398 {
35219832
VS
399 InsertLeaf(id, m_children.size());
400 }
401
402 void InsertLeaf( void* id, unsigned pos )
403 {
404 m_children.Insert( id, pos );
0bd26819
RR
405
406 if (m_internal->IsSorted() || m_internal->GetDataViewModel()->HasDefaultCompare())
40196b1e 407 {
8c2654ce 408 gs_internal = m_internal;
40196b1e 409 m_children.Sort( &wxGtkTreeModelChildCmp );
40196b1e 410 }
af110130 411 }
b9db5f30 412
af110130
RR
413 void DeleteChild( void* id )
414 {
40196b1e 415 m_children.Remove( id );
b9db5f30 416
40196b1e
RR
417 unsigned int count = m_nodes.GetCount();
418 unsigned int pos;
af110130 419 for (pos = 0; pos < count; pos++)
b9db5f30 420 {
af110130
RR
421 wxGtkTreeModelNode *node = m_nodes.Item( pos );
422 if (node->GetItem().GetID() == id)
423 {
424 m_nodes.RemoveAt( pos );
425 delete node;
426 break;
427 }
428 }
af110130 429 }
b9db5f30
VS
430
431 wxGtkTreeModelNode* GetParent()
3b6280be 432 { return m_parent; }
b9db5f30 433 wxGtkTreeModelNodes &GetNodes()
af110130 434 { return m_nodes; }
b9db5f30 435 wxGtkTreeModelChildren &GetChildren()
40196b1e 436 { return m_children; }
b9db5f30 437
c2489d8e
FM
438 unsigned int GetChildCount() const { return m_children.GetCount(); }
439 unsigned int GetNodesCount() const { return m_nodes.GetCount(); }
3b6280be
RR
440
441 wxDataViewItem &GetItem() { return m_item; }
0be79c8a 442 wxDataViewCtrlInternal *GetInternal() { return m_internal; }
b9db5f30 443
4508fcd2 444 void Resort();
b9db5f30 445
3b6280be 446private:
0be79c8a 447 wxGtkTreeModelNode *m_parent;
af110130 448 wxGtkTreeModelNodes m_nodes;
40196b1e 449 wxGtkTreeModelChildren m_children;
b9db5f30 450 wxDataViewItem m_item;
0be79c8a 451 wxDataViewCtrlInternal *m_internal;
3b6280be
RR
452};
453
ef427989 454
790b137e
RR
455//-----------------------------------------------------------------------------
456// data
457//-----------------------------------------------------------------------------
458
459extern bool g_blockEventsOnDrag;
460
461//-----------------------------------------------------------------------------
e0062c04 462// define new GTK+ class wxGtkTreeModel
790b137e
RR
463//-----------------------------------------------------------------------------
464
465extern "C" {
466
e0062c04
RR
467#define GTK_TYPE_WX_TREE_MODEL (gtk_wx_tree_model_get_type ())
468#define GTK_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModel))
469#define GTK_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
470#define GTK_IS_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_TREE_MODEL))
471#define GTK_IS_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_TREE_MODEL))
472#define GTK_WX_TREE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
790b137e 473
e0062c04 474GType gtk_wx_tree_model_get_type (void);
790b137e 475
e0062c04 476typedef struct _GtkWxTreeModelClass GtkWxTreeModelClass;
790b137e 477
e0062c04 478struct _GtkWxTreeModel
790b137e
RR
479{
480 GObject parent;
481
482 /*< private >*/
483 gint stamp;
55fbde12 484 wxDataViewCtrlInternal *internal;
790b137e
RR
485};
486
e0062c04 487struct _GtkWxTreeModelClass
790b137e 488{
e152afc3 489 GObjectClass list_parent_class;
790b137e
RR
490};
491
e0062c04 492static GtkWxTreeModel *wxgtk_tree_model_new (void);
773cca48
RR
493static void wxgtk_tree_model_init (GtkWxTreeModel *tree_model);
494static void wxgtk_tree_model_class_init (GtkWxTreeModelClass *klass);
85136e3b
RR
495
496static void wxgtk_tree_model_tree_model_init (GtkTreeModelIface *iface);
497static void wxgtk_tree_model_sortable_init (GtkTreeSortableIface *iface);
498static void wxgtk_tree_model_drag_source_init(GtkTreeDragSourceIface *iface);
499static void wxgtk_tree_model_drag_dest_init (GtkTreeDragDestIface *iface);
500
e0062c04
RR
501static void wxgtk_tree_model_finalize (GObject *object);
502static GtkTreeModelFlags wxgtk_tree_model_get_flags (GtkTreeModel *tree_model);
503static gint wxgtk_tree_model_get_n_columns (GtkTreeModel *tree_model);
504static GType wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model,
93763ad5 505 gint index);
e0062c04 506static gboolean wxgtk_tree_model_get_iter (GtkTreeModel *tree_model,
93763ad5
WS
507 GtkTreeIter *iter,
508 GtkTreePath *path);
e0062c04 509static GtkTreePath *wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
93763ad5 510 GtkTreeIter *iter);
e0062c04 511static void wxgtk_tree_model_get_value (GtkTreeModel *tree_model,
93763ad5
WS
512 GtkTreeIter *iter,
513 gint column,
514 GValue *value);
e0062c04 515static gboolean wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
93763ad5 516 GtkTreeIter *iter);
e0062c04 517static gboolean wxgtk_tree_model_iter_children (GtkTreeModel *tree_model,
93763ad5
WS
518 GtkTreeIter *iter,
519 GtkTreeIter *parent);
e0062c04 520static gboolean wxgtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
93763ad5 521 GtkTreeIter *iter);
e0062c04 522static gint wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
93763ad5 523 GtkTreeIter *iter);
e0062c04 524static gboolean wxgtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
93763ad5
WS
525 GtkTreeIter *iter,
526 GtkTreeIter *parent,
527 gint n);
e0062c04 528static gboolean wxgtk_tree_model_iter_parent (GtkTreeModel *tree_model,
93763ad5
WS
529 GtkTreeIter *iter,
530 GtkTreeIter *child);
790b137e 531
773cca48
RR
532/* sortable */
533static gboolean wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
85136e3b 534 gint *sort_column_id,
c2489d8e 535 GtkSortType *order);
773cca48 536static void wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
85136e3b
RR
537 gint sort_column_id,
538 GtkSortType order);
773cca48 539static void wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable,
85136e3b
RR
540 gint sort_column_id,
541 GtkTreeIterCompareFunc func,
542 gpointer data,
385e8575 543 GDestroyNotify destroy);
773cca48 544static void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable,
85136e3b
RR
545 GtkTreeIterCompareFunc func,
546 gpointer data,
385e8575 547 GDestroyNotify destroy);
773cca48
RR
548static gboolean wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable);
549
85136e3b
RR
550/* drag'n'drop */
551static gboolean wxgtk_tree_model_row_draggable (GtkTreeDragSource *drag_source,
552 GtkTreePath *path);
553static gboolean wxgtk_tree_model_drag_data_delete (GtkTreeDragSource *drag_source,
554 GtkTreePath *path);
555static gboolean wxgtk_tree_model_drag_data_get (GtkTreeDragSource *drag_source,
556 GtkTreePath *path,
557 GtkSelectionData *selection_data);
558static gboolean wxgtk_tree_model_drag_data_received (GtkTreeDragDest *drag_dest,
559 GtkTreePath *dest,
560 GtkSelectionData *selection_data);
561static gboolean wxgtk_tree_model_row_drop_possible (GtkTreeDragDest *drag_dest,
562 GtkTreePath *dest_path,
c2489d8e 563 GtkSelectionData *selection_data);
773cca48
RR
564
565
e152afc3 566static GObjectClass *list_parent_class = NULL;
790b137e
RR
567
568GType
e0062c04 569gtk_wx_tree_model_get_type (void)
790b137e 570{
e0062c04 571 static GType tree_model_type = 0;
790b137e 572
e0062c04 573 if (!tree_model_type)
790b137e 574 {
e0062c04 575 const GTypeInfo tree_model_info =
93763ad5 576 {
e0062c04 577 sizeof (GtkWxTreeModelClass),
93763ad5
WS
578 NULL, /* base_init */
579 NULL, /* base_finalize */
e0062c04 580 (GClassInitFunc) wxgtk_tree_model_class_init,
93763ad5
WS
581 NULL, /* class_finalize */
582 NULL, /* class_data */
e0062c04 583 sizeof (GtkWxTreeModel),
93763ad5 584 0,
e0062c04 585 (GInstanceInitFunc) wxgtk_tree_model_init,
93763ad5 586 };
790b137e 587
773cca48
RR
588 static const GInterfaceInfo tree_model_iface_info =
589 {
590 (GInterfaceInitFunc) wxgtk_tree_model_tree_model_init,
591 NULL,
592 NULL
593 };
594
595 static const GInterfaceInfo sortable_iface_info =
596 {
597 (GInterfaceInitFunc) wxgtk_tree_model_sortable_init,
598 NULL,
599 NULL
600 };
790b137e 601
85136e3b
RR
602 static const GInterfaceInfo drag_source_iface_info =
603 {
604 (GInterfaceInitFunc) wxgtk_tree_model_drag_source_init,
605 NULL,
606 NULL
607 };
608
609 static const GInterfaceInfo drag_dest_iface_info =
610 {
611 (GInterfaceInitFunc) wxgtk_tree_model_drag_dest_init,
612 NULL,
613 NULL
614 };
615
773cca48 616 tree_model_type = g_type_register_static (G_TYPE_OBJECT, "GtkWxTreeModel",
e0062c04 617 &tree_model_info, (GTypeFlags)0 );
790b137e 618
773cca48
RR
619 g_type_add_interface_static (tree_model_type,
620 GTK_TYPE_TREE_MODEL,
621 &tree_model_iface_info);
622 g_type_add_interface_static (tree_model_type,
623 GTK_TYPE_TREE_SORTABLE,
624 &sortable_iface_info);
85136e3b
RR
625 g_type_add_interface_static (tree_model_type,
626 GTK_TYPE_TREE_DRAG_DEST,
627 &drag_dest_iface_info);
628 g_type_add_interface_static (tree_model_type,
629 GTK_TYPE_TREE_DRAG_SOURCE,
630 &drag_source_iface_info);
790b137e
RR
631 }
632
773cca48 633 return tree_model_type;
790b137e
RR
634}
635
e0062c04
RR
636static GtkWxTreeModel *
637wxgtk_tree_model_new(void)
1557c77b 638{
e0062c04 639 GtkWxTreeModel *retval = (GtkWxTreeModel *) g_object_new (GTK_TYPE_WX_TREE_MODEL, NULL);
e152afc3 640 return retval;
1557c77b
RR
641}
642
790b137e 643static void
e0062c04 644wxgtk_tree_model_class_init (GtkWxTreeModelClass *klass)
790b137e 645{
e152afc3
RR
646 list_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
647 GObjectClass *object_class = (GObjectClass*) klass;
e0062c04 648 object_class->finalize = wxgtk_tree_model_finalize;
790b137e
RR
649}
650
651static void
e0062c04
RR
652wxgtk_tree_model_tree_model_init (GtkTreeModelIface *iface)
653{
654 iface->get_flags = wxgtk_tree_model_get_flags;
655 iface->get_n_columns = wxgtk_tree_model_get_n_columns;
656 iface->get_column_type = wxgtk_tree_model_get_column_type;
657 iface->get_iter = wxgtk_tree_model_get_iter;
658 iface->get_path = wxgtk_tree_model_get_path;
659 iface->get_value = wxgtk_tree_model_get_value;
660 iface->iter_next = wxgtk_tree_model_iter_next;
661 iface->iter_children = wxgtk_tree_model_iter_children;
662 iface->iter_has_child = wxgtk_tree_model_iter_has_child;
663 iface->iter_n_children = wxgtk_tree_model_iter_n_children;
664 iface->iter_nth_child = wxgtk_tree_model_iter_nth_child;
665 iface->iter_parent = wxgtk_tree_model_iter_parent;
790b137e
RR
666}
667
773cca48
RR
668static void
669wxgtk_tree_model_sortable_init (GtkTreeSortableIface *iface)
670{
94b1f7bc
RR
671 iface->get_sort_column_id = wxgtk_tree_model_get_sort_column_id;
672 iface->set_sort_column_id = wxgtk_tree_model_set_sort_column_id;
673 iface->set_sort_func = wxgtk_tree_model_set_sort_func;
674 iface->set_default_sort_func = wxgtk_tree_model_set_default_sort_func;
675 iface->has_default_sort_func = wxgtk_tree_model_has_default_sort_func;
773cca48
RR
676}
677
7857346a 678static void
85136e3b
RR
679wxgtk_tree_model_drag_source_init(GtkTreeDragSourceIface *iface)
680{
681 iface->row_draggable = wxgtk_tree_model_row_draggable;
682 iface->drag_data_delete = wxgtk_tree_model_drag_data_delete;
683 iface->drag_data_get = wxgtk_tree_model_drag_data_get;
684}
685
7857346a 686static void
85136e3b
RR
687wxgtk_tree_model_drag_dest_init (GtkTreeDragDestIface *iface)
688{
689 iface->drag_data_received = wxgtk_tree_model_drag_data_received;
690 iface->row_drop_possible = wxgtk_tree_model_row_drop_possible;
691}
692
790b137e 693static void
e0062c04 694wxgtk_tree_model_init (GtkWxTreeModel *tree_model)
790b137e 695{
55fbde12 696 tree_model->internal = NULL;
e0062c04 697 tree_model->stamp = g_random_int();
790b137e
RR
698}
699
700static void
e0062c04 701wxgtk_tree_model_finalize (GObject *object)
790b137e 702{
790b137e 703 /* must chain up */
e152afc3 704 (* list_parent_class->finalize) (object);
790b137e 705}
93763ad5 706
790b137e
RR
707} // extern "C"
708
709//-----------------------------------------------------------------------------
e0062c04
RR
710// implement callbacks from wxGtkTreeModel class by letting
711// them call the methods of wxWidgets' wxDataViewModel
790b137e
RR
712//-----------------------------------------------------------------------------
713
714static GtkTreeModelFlags
e0062c04 715wxgtk_tree_model_get_flags (GtkTreeModel *tree_model)
790b137e 716{
2056dede
RR
717 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
718 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), (GtkTreeModelFlags)0 );
790b137e 719
2056dede 720 return wxtree_model->internal->get_flags();
790b137e
RR
721}
722
723static gint
e0062c04 724wxgtk_tree_model_get_n_columns (GtkTreeModel *tree_model)
790b137e 725{
e0062c04
RR
726 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
727 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), 0);
790b137e 728
55fbde12 729 return wxtree_model->internal->GetDataViewModel()->GetColumnCount();
790b137e
RR
730}
731
732static GType
e0062c04 733wxgtk_tree_model_get_column_type (GtkTreeModel *tree_model,
93763ad5 734 gint index)
790b137e 735{
e0062c04
RR
736 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
737 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), G_TYPE_INVALID);
790b137e 738
1557c77b 739 GType gtype = G_TYPE_INVALID;
93763ad5 740
55fbde12 741 wxString wxtype = wxtree_model->internal->GetDataViewModel()->GetColumnType( (unsigned int) index );
93763ad5 742
1557c77b
RR
743 if (wxtype == wxT("string"))
744 gtype = G_TYPE_STRING;
72a3ac9b
VZ
745 else
746 {
200c18cc
RR
747 gtype = G_TYPE_POINTER;
748 // wxFAIL_MSG( wxT("non-string columns not supported for searching yet") );
72a3ac9b 749 }
790b137e
RR
750
751 return gtype;
752}
753
754static gboolean
e0062c04 755wxgtk_tree_model_get_iter (GtkTreeModel *tree_model,
93763ad5
WS
756 GtkTreeIter *iter,
757 GtkTreePath *path)
790b137e 758{
e0062c04
RR
759 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
760 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
790b137e
RR
761 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
762
55fbde12 763 return wxtree_model->internal->get_iter( iter, path );
790b137e
RR
764}
765
766static GtkTreePath *
e0062c04 767wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
93763ad5 768 GtkTreeIter *iter)
790b137e 769{
e0062c04
RR
770 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
771 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), NULL);
772 g_return_val_if_fail (iter->stamp == GTK_WX_TREE_MODEL (wxtree_model)->stamp, NULL);
93763ad5 773
55fbde12 774 return wxtree_model->internal->get_path( iter );
790b137e
RR
775}
776
777static void
e0062c04 778wxgtk_tree_model_get_value (GtkTreeModel *tree_model,
93763ad5
WS
779 GtkTreeIter *iter,
780 gint column,
781 GValue *value)
790b137e 782{
e0062c04
RR
783 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
784 g_return_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model) );
239eaa41 785
55fbde12 786 wxDataViewModel *model = wxtree_model->internal->GetDataViewModel();
9861f022 787 wxString mtype = model->GetColumnType( (unsigned int) column );
1557c77b
RR
788 if (mtype == wxT("string"))
789 {
3f3af7e7 790 wxVariant variant;
1557c77b 791 g_value_init( value, G_TYPE_STRING );
9d52aad3 792 wxDataViewItem item( (void*) iter->user_data );
e0062c04 793 model->GetValue( variant, item, (unsigned int) column );
72a3ac9b 794
e0062c04 795 g_value_set_string( value, variant.GetString().utf8_str() );
1557c77b
RR
796 }
797 else
798 {
9a83f860 799 wxFAIL_MSG( wxT("non-string columns not supported yet") );
1557c77b 800 }
790b137e
RR
801}
802
803static gboolean
e0062c04 804wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
93763ad5 805 GtkTreeIter *iter)
790b137e 806{
e0062c04 807 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
7857346a 808
8a568372
RR
809 // This happens when clearing the view by calling .._set_model( NULL );
810 if (iter->stamp == 0) return FALSE;
33ba5a05 811
e0062c04 812 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
e0062c04 813 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
7857346a 814
55fbde12 815 return wxtree_model->internal->iter_next( iter );
790b137e
RR
816}
817
818static gboolean
e0062c04 819wxgtk_tree_model_iter_children (GtkTreeModel *tree_model,
93763ad5
WS
820 GtkTreeIter *iter,
821 GtkTreeIter *parent)
790b137e 822{
e0062c04
RR
823 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
824 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
3556d648
RR
825 if (parent)
826 {
827 g_return_val_if_fail (wxtree_model->stamp == parent->stamp, FALSE);
828 }
790b137e 829
55fbde12 830 return wxtree_model->internal->iter_children( iter, parent );
790b137e
RR
831}
832
833static gboolean
e0062c04 834wxgtk_tree_model_iter_has_child (GtkTreeModel *tree_model,
93763ad5 835 GtkTreeIter *iter)
790b137e 836{
e0062c04
RR
837 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
838 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
e0062c04 839 g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
d5025dc0 840
55fbde12 841 return wxtree_model->internal->iter_has_child( iter );
790b137e
RR
842}
843
844static gint
e0062c04 845wxgtk_tree_model_iter_n_children (GtkTreeModel *tree_model,
93763ad5 846 GtkTreeIter *iter)
790b137e 847{
e0062c04 848 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
8a568372 849 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), 0);
1bfabf36 850 g_return_val_if_fail ( !iter || wxtree_model->stamp == iter->stamp, 0);
c2489d8e 851
55fbde12 852 return wxtree_model->internal->iter_n_children( iter );
790b137e
RR
853}
854
855static gboolean
e0062c04 856wxgtk_tree_model_iter_nth_child (GtkTreeModel *tree_model,
93763ad5
WS
857 GtkTreeIter *iter,
858 GtkTreeIter *parent,
859 gint n)
790b137e 860{
e0062c04
RR
861 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
862 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
863
55fbde12 864 return wxtree_model->internal->iter_nth_child( iter, parent, n );
790b137e
RR
865}
866
867static gboolean
e0062c04 868wxgtk_tree_model_iter_parent (GtkTreeModel *tree_model,
93763ad5
WS
869 GtkTreeIter *iter,
870 GtkTreeIter *child)
790b137e 871{
e0062c04
RR
872 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
873 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
e0062c04 874 g_return_val_if_fail (wxtree_model->stamp == child->stamp, FALSE);
b9db5f30 875
55fbde12 876 return wxtree_model->internal->iter_parent( iter, child );
790b137e
RR
877}
878
85136e3b 879/* drag'n'drop iface */
7857346a 880static gboolean
85136e3b
RR
881wxgtk_tree_model_row_draggable (GtkTreeDragSource *drag_source,
882 GtkTreePath *path)
883{
f6f0ef85
RR
884 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_source;
885 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
7857346a 886
f6f0ef85 887 return wxtree_model->internal->row_draggable( drag_source, path );
85136e3b
RR
888}
889
7857346a 890static gboolean
85136e3b
RR
891wxgtk_tree_model_drag_data_delete (GtkTreeDragSource *drag_source,
892 GtkTreePath *path)
893{
f6f0ef85
RR
894 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_source;
895 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
7857346a 896
f6f0ef85 897 return wxtree_model->internal->drag_data_delete( drag_source, path );
85136e3b
RR
898}
899
7857346a 900static gboolean
85136e3b
RR
901wxgtk_tree_model_drag_data_get (GtkTreeDragSource *drag_source,
902 GtkTreePath *path,
903 GtkSelectionData *selection_data)
904{
f6f0ef85
RR
905 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_source;
906 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
7857346a 907
f6f0ef85 908#if 0
85136e3b 909 wxPrintf( "drag_get_data\n");
7857346a 910
f6f0ef85
RR
911 wxGtkString atom_selection(gdk_atom_name(selection_data->selection));
912 wxPrintf( "selection %s\n", wxString::FromAscii(atom_selection) );
7857346a 913
f6f0ef85
RR
914 wxGtkString atom_target(gdk_atom_name(selection_data->target));
915 wxPrintf( "target %s\n", wxString::FromAscii(atom_target) );
7857346a 916
f6f0ef85
RR
917 wxGtkString atom_type(gdk_atom_name(selection_data->type));
918 wxPrintf( "type %s\n", wxString::FromAscii(atom_type) );
919
920 wxPrintf( "format %d\n", selection_data->format );
921#endif
7857346a 922
f6f0ef85 923 return wxtree_model->internal->drag_data_get( drag_source, path, selection_data );
85136e3b
RR
924}
925
7857346a 926static gboolean
85136e3b
RR
927wxgtk_tree_model_drag_data_received (GtkTreeDragDest *drag_dest,
928 GtkTreePath *dest,
929 GtkSelectionData *selection_data)
930{
f6f0ef85
RR
931 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_dest;
932 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
7857346a 933
f6f0ef85 934 return wxtree_model->internal->drag_data_received( drag_dest, dest, selection_data );
85136e3b
RR
935}
936
7857346a 937static gboolean
85136e3b
RR
938wxgtk_tree_model_row_drop_possible (GtkTreeDragDest *drag_dest,
939 GtkTreePath *dest_path,
c2489d8e 940 GtkSelectionData *selection_data)
85136e3b 941{
f6f0ef85
RR
942 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) drag_dest;
943 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
7857346a 944
f6f0ef85 945 return wxtree_model->internal->row_drop_possible( drag_dest, dest_path, selection_data );
85136e3b
RR
946}
947
948/* sortable iface */
7857346a 949static gboolean
85136e3b
RR
950wxgtk_tree_model_get_sort_column_id (GtkTreeSortable *sortable,
951 gint *sort_column_id,
952 GtkSortType *order)
773cca48 953{
f6f0ef85 954 GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) sortable;
94b1f7bc
RR
955
956 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (sortable), FALSE);
957
f6f0ef85 958 if (!wxtree_model->internal->IsSorted())
40196b1e
RR
959 {
960 if (sort_column_id)
961 *sort_column_id = -1;
b9db5f30 962
40196b1e
RR
963 return TRUE;
964 }
965
966
94b1f7bc 967 if (sort_column_id)
f6f0ef85 968 *sort_column_id = wxtree_model->internal->GetSortColumn();
b9db5f30 969
94b1f7bc 970 if (order)
f6f0ef85 971 *order = wxtree_model->internal->GetSortOrder();
b9db5f30 972
94b1f7bc 973 return TRUE;
773cca48
RR
974}
975
d32332aa
RR
976wxDataViewColumn *gs_lastLeftClickHeader = NULL;
977
7857346a 978static void
85136e3b
RR
979wxgtk_tree_model_set_sort_column_id (GtkTreeSortable *sortable,
980 gint sort_column_id,
981 GtkSortType order)
773cca48 982{
94b1f7bc 983 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) sortable;
94b1f7bc
RR
984 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
985
d32332aa 986 tree_model->internal->SetDataViewSortColumn( gs_lastLeftClickHeader );
b9db5f30 987
d32332aa
RR
988 if ((sort_column_id != (gint) tree_model->internal->GetSortColumn()) ||
989 (order != tree_model->internal->GetSortOrder()))
990 {
991 tree_model->internal->SetSortColumn( sort_column_id );
992 tree_model->internal->SetSortOrder( order );
b9db5f30 993
d32332aa 994 gtk_tree_sortable_sort_column_changed (sortable);
b9db5f30 995
d32332aa
RR
996 tree_model->internal->GetDataViewModel()->Resort();
997 }
a84c5b6f 998
d32332aa
RR
999 if (gs_lastLeftClickHeader)
1000 {
b9db5f30 1001 wxDataViewCtrl *dv = tree_model->internal->GetOwner();
d32332aa
RR
1002 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, dv->GetId() );
1003 event.SetDataViewColumn( gs_lastLeftClickHeader );
1004 event.SetModel( dv->GetModel() );
937013e0 1005 dv->HandleWindowEvent( event );
d32332aa 1006 }
b9db5f30 1007
d32332aa 1008 gs_lastLeftClickHeader = NULL;
773cca48
RR
1009}
1010
7857346a 1011static void
85136e3b
RR
1012wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable,
1013 gint WXUNUSED(sort_column_id),
1014 GtkTreeIterCompareFunc func,
1015 gpointer WXUNUSED(data),
385e8575 1016 GDestroyNotify WXUNUSED(destroy))
773cca48 1017{
94b1f7bc
RR
1018 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
1019 g_return_if_fail (func != NULL);
773cca48
RR
1020}
1021
c2489d8e
FM
1022static void
1023wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable,
1024 GtkTreeIterCompareFunc func,
1025 gpointer WXUNUSED(data),
385e8575 1026 GDestroyNotify WXUNUSED(destroy))
773cca48 1027{
94b1f7bc 1028 g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) );
94b1f7bc
RR
1029 g_return_if_fail (func != NULL);
1030
c2489d8e
FM
1031 //wxPrintf( "wxgtk_tree_model_set_default_sort_func\n" );
1032 // TODO: remove this code
773cca48
RR
1033}
1034
c2489d8e
FM
1035static gboolean
1036wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable)
773cca48 1037{
c5c5395b 1038 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (sortable), FALSE );
7857346a 1039
773cca48
RR
1040 return FALSE;
1041}
1042
e152afc3 1043//-----------------------------------------------------------------------------
ecc32226
RR
1044// define new GTK+ class GtkWxRendererText
1045//-----------------------------------------------------------------------------
1046
1047extern "C" {
1048
1049#define GTK_TYPE_WX_CELL_RENDERER_TEXT (gtk_wx_cell_renderer_text_get_type ())
1050#define GTK_WX_CELL_RENDERER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_CELL_RENDERER_TEXT, GtkWxCellRendererText))
1051#define GTK_WX_CELL_RENDERER_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_CELL_RENDERER_TEXT, GtkWxCellRendererTextClass))
1052#define GTK_IS_WX_CELL_RENDERER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_CELL_RENDERER_TEXT))
1053#define GTK_IS_WX_CELL_RENDERER_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_CELL_RENDERER_TEXT))
1054#define GTK_WX_CELL_RENDERER_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_CELL_RENDERER_TEXT, GtkWxCellRendererTextClass))
1055
1056GType gtk_wx_cell_renderer_text_get_type (void);
1057
1058typedef struct _GtkWxCellRendererText GtkWxCellRendererText;
1059typedef struct _GtkWxCellRendererTextClass GtkWxCellRendererTextClass;
1060
1061struct _GtkWxCellRendererText
1062{
1063 GtkCellRendererText parent;
03647350 1064
ecc32226
RR
1065 wxDataViewRenderer *wx_renderer;
1066};
1067
1068struct _GtkWxCellRendererTextClass
1069{
1070 GtkCellRendererTextClass cell_parent_class;
1071};
1072
1073
1074static GtkWxCellRendererText *gtk_wx_cell_renderer_text_new (void);
1075static void gtk_wx_cell_renderer_text_init (
1076 GtkWxCellRendererText *cell );
1077static void gtk_wx_cell_renderer_text_class_init(
1078 GtkWxCellRendererTextClass *klass );
1079static void gtk_wx_cell_renderer_text_finalize (
1080 GObject *object );
1081static GtkCellEditable *gtk_wx_cell_renderer_text_start_editing(
1082 GtkCellRenderer *cell,
1083 GdkEvent *event,
1084 GtkWidget *widget,
1085 const gchar *path,
1086 GdkRectangle *background_area,
1087 GdkRectangle *cell_area,
1088 GtkCellRendererState flags );
1089
1090
1091static GObjectClass *text_cell_parent_class = NULL;
ecc32226
RR
1092
1093} // extern "C"
1094
1095GType
1096gtk_wx_cell_renderer_text_get_type (void)
1097{
1098 static GType cell_wx_type = 0;
1099
1100 if (!cell_wx_type)
1101 {
1102 const GTypeInfo cell_wx_info =
1103 {
1104 sizeof (GtkWxCellRendererTextClass),
1105 NULL, /* base_init */
1106 NULL, /* base_finalize */
1107 (GClassInitFunc) gtk_wx_cell_renderer_text_class_init,
1108 NULL, /* class_finalize */
1109 NULL, /* class_data */
1110 sizeof (GtkWxCellRendererText),
1111 0, /* n_preallocs */
1112 (GInstanceInitFunc) gtk_wx_cell_renderer_text_init,
1113 };
1114
1115 cell_wx_type = g_type_register_static( GTK_TYPE_CELL_RENDERER_TEXT,
1116 "GtkWxCellRendererText", &cell_wx_info, (GTypeFlags)0 );
1117 }
1118
1119 return cell_wx_type;
1120}
1121
1122static void
1123gtk_wx_cell_renderer_text_init (GtkWxCellRendererText *cell)
1124{
1125 cell->wx_renderer = NULL;
1126}
1127
1128static void
1129gtk_wx_cell_renderer_text_class_init (GtkWxCellRendererTextClass *klass)
1130{
1131 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1132 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
1133
1134 text_cell_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
1135
1136 object_class->finalize = gtk_wx_cell_renderer_text_finalize;
1137
1138 cell_class->start_editing = gtk_wx_cell_renderer_text_start_editing;
1139}
1140
1141static void
1142gtk_wx_cell_renderer_text_finalize (GObject *object)
1143{
1144 /* must chain up */
1145 (* G_OBJECT_CLASS (text_cell_parent_class)->finalize) (object);
1146}
1147
1148GtkWxCellRendererText*
1149gtk_wx_cell_renderer_text_new (void)
1150{
1151 return (GtkWxCellRendererText*) g_object_new (GTK_TYPE_WX_CELL_RENDERER_TEXT, NULL);
1152}
1153
1154static GtkCellEditable *gtk_wx_cell_renderer_text_start_editing(
1155 GtkCellRenderer *gtk_renderer,
1156 GdkEvent *gdk_event,
1157 GtkWidget *widget,
1158 const gchar *path,
1159 GdkRectangle *background_area,
1160 GdkRectangle *cell_area,
1161 GtkCellRendererState flags )
1162{
1163 GtkWxCellRendererText *wxgtk_renderer = (GtkWxCellRendererText *) gtk_renderer;
1164 wxDataViewRenderer *wx_renderer = wxgtk_renderer->wx_renderer;
0c2a7270 1165 wxDataViewColumn *column = wx_renderer->GetOwner();
ecc32226 1166
17d98558 1167 wxDataViewItem
0c2a7270 1168 item(column->GetOwner()->GTKPathToItem(wxGtkTreePath(path)));
ecc32226 1169
ecc32226
RR
1170 wxDataViewCtrl *dv = column->GetOwner();
1171 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_START_EDITING, dv->GetId() );
1172 event.SetDataViewColumn( column );
1173 event.SetModel( dv->GetModel() );
0c2a7270 1174 event.SetColumn( column->GetModelColumn() );
ecc32226
RR
1175 event.SetItem( item );
1176 dv->HandleWindowEvent( event );
03647350 1177
ecc32226
RR
1178 if (event.IsAllowed())
1179 return GTK_CELL_RENDERER_CLASS(text_cell_parent_class)->
1180 start_editing( gtk_renderer, gdk_event, widget, path, background_area, cell_area, flags );
1181 else
1182 return NULL;
1183}
1184
1185//-----------------------------------------------------------------------------
1186// define new GTK+ class GtkWxCellRenderer
e152afc3
RR
1187//-----------------------------------------------------------------------------
1188
1189extern "C" {
1190
1191#define GTK_TYPE_WX_CELL_RENDERER (gtk_wx_cell_renderer_get_type ())
1192#define GTK_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRenderer))
1193#define GTK_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
1194#define GTK_IS_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_CELL_RENDERER))
1195#define GTK_IS_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_CELL_RENDERER))
1196#define GTK_WX_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
1197
1198GType gtk_wx_cell_renderer_get_type (void);
1199
1200typedef struct _GtkWxCellRenderer GtkWxCellRenderer;
1201typedef struct _GtkWxCellRendererClass GtkWxCellRendererClass;
1202
1203struct _GtkWxCellRenderer
1204{
1205 GtkCellRenderer parent;
1206
1207 /*< private >*/
baa9ebc4 1208 wxDataViewCustomRenderer *cell;
4d496ecb 1209 guint32 last_click;
e152afc3
RR
1210};
1211
1212struct _GtkWxCellRendererClass
1213{
1214 GtkCellRendererClass cell_parent_class;
e152afc3
RR
1215};
1216
1217
1218static GtkCellRenderer *gtk_wx_cell_renderer_new (void);
553f7d8f
RR
1219static void gtk_wx_cell_renderer_init (
1220 GtkWxCellRenderer *cell );
1221static void gtk_wx_cell_renderer_class_init(
1222 GtkWxCellRendererClass *klass );
1223static void gtk_wx_cell_renderer_finalize (
1224 GObject *object );
1225static void gtk_wx_cell_renderer_get_size (
1226 GtkCellRenderer *cell,
93763ad5
WS
1227 GtkWidget *widget,
1228 GdkRectangle *rectangle,
1229 gint *x_offset,
1230 gint *y_offset,
1231 gint *width,
1232 gint *height );
553f7d8f
RR
1233static void gtk_wx_cell_renderer_render (
1234 GtkCellRenderer *cell,
93763ad5
WS
1235 GdkWindow *window,
1236 GtkWidget *widget,
1237 GdkRectangle *background_area,
1238 GdkRectangle *cell_area,
1239 GdkRectangle *expose_area,
1240 GtkCellRendererState flags );
553f7d8f
RR
1241static gboolean gtk_wx_cell_renderer_activate(
1242 GtkCellRenderer *cell,
1243 GdkEvent *event,
1244 GtkWidget *widget,
1245 const gchar *path,
1246 GdkRectangle *background_area,
1247 GdkRectangle *cell_area,
1248 GtkCellRendererState flags );
1e510b1e
RR
1249static GtkCellEditable *gtk_wx_cell_renderer_start_editing(
1250 GtkCellRenderer *cell,
1251 GdkEvent *event,
1252 GtkWidget *widget,
1253 const gchar *path,
1254 GdkRectangle *background_area,
1255 GdkRectangle *cell_area,
1256 GtkCellRendererState flags );
e8375af8 1257
e152afc3
RR
1258
1259static GObjectClass *cell_parent_class = NULL;
1260
1261} // extern "C"
1262
93763ad5 1263GType
e152afc3
RR
1264gtk_wx_cell_renderer_get_type (void)
1265{
553f7d8f 1266 static GType cell_wx_type = 0;
e152afc3 1267
553f7d8f 1268 if (!cell_wx_type)
e152afc3 1269 {
de4a74e2 1270 const GTypeInfo cell_wx_info =
553f7d8f
RR
1271 {
1272 sizeof (GtkWxCellRendererClass),
93763ad5
WS
1273 NULL, /* base_init */
1274 NULL, /* base_finalize */
553f7d8f 1275 (GClassInitFunc) gtk_wx_cell_renderer_class_init,
93763ad5
WS
1276 NULL, /* class_finalize */
1277 NULL, /* class_data */
553f7d8f
RR
1278 sizeof (GtkWxCellRenderer),
1279 0, /* n_preallocs */
1280 (GInstanceInitFunc) gtk_wx_cell_renderer_init,
1281 };
1282
93763ad5 1283 cell_wx_type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
553f7d8f 1284 "GtkWxCellRenderer", &cell_wx_info, (GTypeFlags)0 );
e152afc3
RR
1285 }
1286
553f7d8f 1287 return cell_wx_type;
e152afc3
RR
1288}
1289
1290static void
1291gtk_wx_cell_renderer_init (GtkWxCellRenderer *cell)
1292{
1293 cell->cell = NULL;
4d496ecb 1294 cell->last_click = 0;
e152afc3
RR
1295}
1296
1297static void
1298gtk_wx_cell_renderer_class_init (GtkWxCellRendererClass *klass)
1299{
1300 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1301 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
1302
1303 cell_parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
1304
1305 object_class->finalize = gtk_wx_cell_renderer_finalize;
1306
1307 cell_class->get_size = gtk_wx_cell_renderer_get_size;
1308 cell_class->render = gtk_wx_cell_renderer_render;
553f7d8f 1309 cell_class->activate = gtk_wx_cell_renderer_activate;
1e510b1e 1310 cell_class->start_editing = gtk_wx_cell_renderer_start_editing;
e152afc3
RR
1311}
1312
1313static void
1314gtk_wx_cell_renderer_finalize (GObject *object)
1315{
1316 /* must chain up */
1317 (* G_OBJECT_CLASS (cell_parent_class)->finalize) (object);
1318}
1319
1320GtkCellRenderer*
1321gtk_wx_cell_renderer_new (void)
1322{
1323 return (GtkCellRenderer*) g_object_new (GTK_TYPE_WX_CELL_RENDERER, NULL);
1324}
1325
1e510b1e
RR
1326static GtkCellEditable *gtk_wx_cell_renderer_start_editing(
1327 GtkCellRenderer *renderer,
c5c5395b 1328 GdkEvent *WXUNUSED(event),
1e510b1e
RR
1329 GtkWidget *widget,
1330 const gchar *path,
c5c5395b 1331 GdkRectangle *WXUNUSED(background_area),
1e510b1e 1332 GdkRectangle *cell_area,
c5c5395b 1333 GtkCellRendererState WXUNUSED(flags) )
1e510b1e
RR
1334{
1335 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
1336 wxDataViewCustomRenderer *cell = wxrenderer->cell;
bc0289bf 1337
c232dfe5 1338 // Renderer doesn't support in-place editing
1e510b1e
RR
1339 if (!cell->HasEditorCtrl())
1340 return NULL;
bc0289bf 1341
c232dfe5
RR
1342 // An in-place editing control is still around
1343 if (cell->GetEditorCtrl())
1344 return NULL;
e8375af8 1345
1e510b1e
RR
1346 GdkRectangle rect;
1347 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
1348 &rect.x,
1349 &rect.y,
1350 &rect.width,
1351 &rect.height);
1352
1353 rect.x += cell_area->x;
1354 rect.y += cell_area->y;
1355// rect.width -= renderer->xpad * 2;
1356// rect.height -= renderer->ypad * 2;
1357
9d02e494
VZ
1358// wxRect renderrect(wxRectFromGDKRect(&rect));
1359 wxRect renderrect(wxRectFromGDKRect(cell_area));
1e510b1e 1360
0c2a7270
VZ
1361 wxDataViewItem
1362 item(cell->GetOwner()->GetOwner()->GTKPathToItem(wxGtkTreePath(path)));
1e510b1e 1363
9d52aad3 1364 cell->StartEditing( item, renderrect );
30715fa1 1365
1e510b1e
RR
1366 return NULL;
1367}
1368
e152afc3
RR
1369static void
1370gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer,
c5c5395b 1371 GtkWidget *WXUNUSED(widget),
93763ad5
WS
1372 GdkRectangle *cell_area,
1373 gint *x_offset,
1374 gint *y_offset,
1375 gint *width,
1376 gint *height)
e152afc3
RR
1377{
1378 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
baa9ebc4 1379 wxDataViewCustomRenderer *cell = wxrenderer->cell;
93763ad5 1380
e152afc3
RR
1381 wxSize size = cell->GetSize();
1382
0f4a54a6
VZ
1383 wxDataViewCtrl * const ctrl = cell->GetOwner()->GetOwner();
1384
1385 // Uniform row height, if specified, overrides the value returned by the
1386 // renderer.
1387 if ( !ctrl->HasFlag(wxDV_VARIABLE_LINE_HEIGHT) )
1388 {
1389 const int uniformHeight = ctrl->GTKGetUniformRowHeight();
1390 if ( uniformHeight > 0 )
1391 size.y = uniformHeight;
1392 }
1393
385e8575
PC
1394 int xpad, ypad;
1395 gtk_cell_renderer_get_padding(renderer, &xpad, &ypad);
1396 int calc_width = xpad * 2 + size.x;
1397 int calc_height = ypad * 2 + size.y;
93763ad5
WS
1398
1399 if (x_offset)
e152afc3 1400 *x_offset = 0;
93763ad5 1401 if (y_offset)
e152afc3
RR
1402 *y_offset = 0;
1403
1404 if (cell_area && size.x > 0 && size.y > 0)
1405 {
385e8575
PC
1406 float xalign, yalign;
1407 gtk_cell_renderer_get_alignment(renderer, &xalign, &yalign);
e152afc3 1408 if (x_offset)
93763ad5 1409 {
385e8575
PC
1410 *x_offset = int(xalign * (cell_area->width - calc_width - 2 * xpad));
1411 *x_offset = MAX(*x_offset, 0) + xpad;
93763ad5 1412 }
e152afc3
RR
1413 if (y_offset)
1414 {
385e8575
PC
1415 *y_offset = int(yalign * (cell_area->height - calc_height - 2 * ypad));
1416 *y_offset = MAX(*y_offset, 0) + ypad;
e152afc3
RR
1417 }
1418 }
1419
1420 if (width)
1421 *width = calc_width;
93763ad5 1422
e152afc3
RR
1423 if (height)
1424 *height = calc_height;
1425}
1426
1427static void
1428gtk_wx_cell_renderer_render (GtkCellRenderer *renderer,
93763ad5
WS
1429 GdkWindow *window,
1430 GtkWidget *widget,
1431 GdkRectangle *background_area,
1432 GdkRectangle *cell_area,
1433 GdkRectangle *expose_area,
1434 GtkCellRendererState flags)
e152afc3
RR
1435
1436{
1437 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
baa9ebc4 1438 wxDataViewCustomRenderer *cell = wxrenderer->cell;
93763ad5 1439
2a454ffd
VZ
1440 cell->GTKStashRenderParams(window, widget,
1441 background_area, expose_area, flags);
f69c03de 1442
a923d77f 1443 wxRect rect(wxRectFromGDKRect(cell_area));
385e8575
PC
1444 int xpad, ypad;
1445 gtk_cell_renderer_get_padding(renderer, &xpad, &ypad);
1446 rect = rect.Deflate(xpad, ypad);
e152afc3 1447
a923d77f
VZ
1448 wxWindowDC* dc = (wxWindowDC*) cell->GetDC();
1449 wxWindowDCImpl *impl = (wxWindowDCImpl *) dc->GetImpl();
bc0289bf 1450
a923d77f
VZ
1451 // Reinitialize wxWindowDC's GDK window if drawing occurs into a different
1452 // window such as a DnD drop window.
1453 if (window != impl->m_gdkwindow)
e152afc3 1454 {
a923d77f
VZ
1455 impl->Destroy();
1456 impl->m_gdkwindow = window;
1457 impl->SetUpDC();
93763ad5 1458 }
a923d77f
VZ
1459
1460 int state = 0;
1461 if (flags & GTK_CELL_RENDERER_SELECTED)
1462 state |= wxDATAVIEW_CELL_SELECTED;
1463 if (flags & GTK_CELL_RENDERER_PRELIT)
1464 state |= wxDATAVIEW_CELL_PRELIT;
1465 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
1466 state |= wxDATAVIEW_CELL_INSENSITIVE;
1467 if (flags & GTK_CELL_RENDERER_INSENSITIVE)
1468 state |= wxDATAVIEW_CELL_INSENSITIVE;
1469 if (flags & GTK_CELL_RENDERER_FOCUSED)
1470 state |= wxDATAVIEW_CELL_FOCUSED;
1471 cell->WXCallRender( rect, dc, state );
e152afc3
RR
1472}
1473
93763ad5 1474static gboolean
553f7d8f
RR
1475gtk_wx_cell_renderer_activate(
1476 GtkCellRenderer *renderer,
1477 GdkEvent *event,
1478 GtkWidget *widget,
1479 const gchar *path,
c5c5395b 1480 GdkRectangle *WXUNUSED(background_area),
553f7d8f 1481 GdkRectangle *cell_area,
c5c5395b 1482 GtkCellRendererState WXUNUSED(flags) )
553f7d8f
RR
1483{
1484 GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer;
baa9ebc4 1485 wxDataViewCustomRenderer *cell = wxrenderer->cell;
93763ad5 1486
553f7d8f
RR
1487 GdkRectangle rect;
1488 gtk_wx_cell_renderer_get_size (renderer, widget, cell_area,
93763ad5
WS
1489 &rect.x,
1490 &rect.y,
1491 &rect.width,
1492 &rect.height);
553f7d8f
RR
1493
1494 rect.x += cell_area->x;
1495 rect.y += cell_area->y;
385e8575
PC
1496 int xpad, ypad;
1497 gtk_cell_renderer_get_padding(renderer, &xpad, &ypad);
1498 rect.width -= xpad * 2;
1499 rect.height -= ypad * 2;
93763ad5 1500
9d02e494 1501 wxRect renderrect(wxRectFromGDKRect(&rect));
93763ad5 1502
0c2a7270
VZ
1503 wxDataViewCtrl * const ctrl = cell->GetOwner()->GetOwner();
1504 wxDataViewModel *model = ctrl->GetModel();
93763ad5 1505
0c2a7270 1506 wxDataViewItem item(ctrl->GTKPathToItem(wxGtkTreePath(path)));
93763ad5 1507
0a71f9e9 1508 unsigned int model_col = cell->GetOwner()->GetModelColumn();
93763ad5 1509
456e5c21
RR
1510 if (!event)
1511 {
1512 bool ret = false;
e8375af8 1513
456e5c21 1514 // activated by <ENTER>
9d52aad3 1515 if (cell->Activate( renderrect, model, item, model_col ))
456e5c21 1516 ret = true;
e8375af8 1517
456e5c21
RR
1518 return ret;
1519 }
1520 else if (event->type == GDK_BUTTON_PRESS)
4d496ecb
RR
1521 {
1522 GdkEventButton *button_event = (GdkEventButton*) event;
93763ad5 1523 wxPoint pt( ((int) button_event->x) - renderrect.x,
4d496ecb 1524 ((int) button_event->y) - renderrect.y );
93763ad5 1525
4d496ecb
RR
1526 bool ret = false;
1527 if (button_event->button == 1)
1528 {
9d52aad3 1529 if (cell->LeftClick( pt, renderrect, model, item, model_col ))
4d496ecb 1530 ret = true;
7ea3a0de 1531 // TODO: query system double-click time
4d496ecb 1532 if (button_event->time - wxrenderer->last_click < 400)
9d52aad3 1533 if (cell->Activate( renderrect, model, item, model_col ))
4d496ecb
RR
1534 ret = true;
1535 }
4d496ecb 1536 wxrenderer->last_click = button_event->time;
93763ad5 1537
4d496ecb
RR
1538 return ret;
1539 }
93763ad5 1540
4d496ecb 1541 return false;
553f7d8f
RR
1542}
1543
93763ad5 1544// ---------------------------------------------------------
e0062c04 1545// wxGtkDataViewModelNotifier
93763ad5 1546// ---------------------------------------------------------
6e2e590f 1547
e0062c04 1548class wxGtkDataViewModelNotifier: public wxDataViewModelNotifier
6e2e590f
RR
1549{
1550public:
673810ee 1551 wxGtkDataViewModelNotifier( wxDataViewModel *wx_model, wxDataViewCtrlInternal *internal );
e0062c04
RR
1552 ~wxGtkDataViewModelNotifier();
1553
1554 virtual bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
469d3e9b 1555 virtual bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
e0062c04 1556 virtual bool ItemChanged( const wxDataViewItem &item );
d93cc830 1557 virtual bool ValueChanged( const wxDataViewItem &item, unsigned int model_column );
6e2e590f 1558 virtual bool Cleared();
4508fcd2 1559 virtual void Resort();
d8090b5e 1560 virtual bool BeforeReset();
673810ee 1561 virtual bool AfterReset();
ce00f59b 1562
673810ee 1563 void UpdateLastCount();
33ba5a05
RR
1564
1565private:
673810ee
RR
1566 wxDataViewModel *m_wx_model;
1567 wxDataViewCtrlInternal *m_internal;
6e2e590f
RR
1568};
1569
93763ad5 1570// ---------------------------------------------------------
6e2e590f 1571// wxGtkDataViewListModelNotifier
93763ad5 1572// ---------------------------------------------------------
6e2e590f 1573
e0062c04 1574wxGtkDataViewModelNotifier::wxGtkDataViewModelNotifier(
673810ee 1575 wxDataViewModel *wx_model, wxDataViewCtrlInternal *internal )
6e2e590f 1576{
6e2e590f 1577 m_wx_model = wx_model;
673810ee 1578 m_internal = internal;
6e2e590f 1579}
93763ad5 1580
e0062c04 1581wxGtkDataViewModelNotifier::~wxGtkDataViewModelNotifier()
f7ed8c89
RR
1582{
1583 m_wx_model = NULL;
673810ee 1584 m_internal = NULL;
f7ed8c89
RR
1585}
1586
e0062c04 1587bool wxGtkDataViewModelNotifier::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
6e2e590f 1588{
673810ee
RR
1589 m_internal->ItemAdded( parent, item );
1590 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
1e08ad10 1591
6e2e590f 1592 GtkTreeIter iter;
673810ee 1593 iter.stamp = wxgtk_model->stamp;
0c2a7270 1594 iter.user_data = item.GetID();
93763ad5 1595
0c2a7270 1596 wxGtkTreePath path(wxgtk_tree_model_get_path(
673810ee 1597 GTK_TREE_MODEL(wxgtk_model), &iter ));
b9db5f30 1598 gtk_tree_model_row_inserted(
673810ee 1599 GTK_TREE_MODEL(wxgtk_model), path, &iter);
93763ad5 1600
6e2e590f
RR
1601 return true;
1602}
1603
469d3e9b 1604bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
6e2e590f 1605{
673810ee 1606 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
8650c4ba
RR
1607#if 0
1608 // using _get_path for a deleted item cannot be
1609 // a good idea
605c2c4a 1610 GtkTreeIter iter;
673810ee 1611 iter.stamp = wxgtk_model->stamp;
e0062c04 1612 iter.user_data = (gpointer) item.GetID();
0c2a7270 1613 wxGtkTreePath path(wxgtk_tree_model_get_path(
673810ee 1614 GTK_TREE_MODEL(wxgtk_model), &iter ));
8650c4ba
RR
1615#else
1616 // so get the path from the parent
15d1fd3f
VS
1617 GtkTreeIter parentIter;
1618 parentIter.stamp = wxgtk_model->stamp;
1619 parentIter.user_data = (gpointer) parent.GetID();
1620 wxGtkTreePath parentPath(wxgtk_tree_model_get_path(
1621 GTK_TREE_MODEL(wxgtk_model), &parentIter ));
1622
8650c4ba 1623 // and add the final index ourselves
15d1fd3f 1624 wxGtkTreePath path(gtk_tree_path_copy(parentPath));
673810ee 1625 int index = m_internal->GetIndexOf( parent, item );
8650c4ba
RR
1626 gtk_tree_path_append_index( path, index );
1627#endif
74035a19 1628
e0062c04 1629 gtk_tree_model_row_deleted(
673810ee 1630 GTK_TREE_MODEL(wxgtk_model), path );
93763ad5 1631
673810ee 1632 m_internal->ItemDeleted( parent, item );
b9db5f30 1633
15d1fd3f
VS
1634 // Did we remove the last child, causing 'parent' to become a leaf?
1635 if ( !m_wx_model->IsContainer(parent) )
1636 {
1637 gtk_tree_model_row_has_child_toggled
1638 (
1639 GTK_TREE_MODEL(wxgtk_model),
1640 parentPath,
1641 &parentIter
1642 );
1643 }
1644
605c2c4a 1645 return true;
6e2e590f
RR
1646}
1647
4508fcd2
RR
1648void wxGtkDataViewModelNotifier::Resort()
1649{
673810ee 1650 m_internal->Resort();
4508fcd2
RR
1651}
1652
e0062c04 1653bool wxGtkDataViewModelNotifier::ItemChanged( const wxDataViewItem &item )
6e2e590f 1654{
673810ee 1655 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
ce00f59b 1656
4627af27 1657 GtkTreeIter iter;
673810ee 1658 iter.stamp = wxgtk_model->stamp;
e0062c04 1659 iter.user_data = (gpointer) item.GetID();
6e2e590f 1660
0c2a7270 1661 wxGtkTreePath path(wxgtk_tree_model_get_path(
673810ee 1662 GTK_TREE_MODEL(wxgtk_model), &iter ));
e0062c04 1663 gtk_tree_model_row_changed(
673810ee 1664 GTK_TREE_MODEL(wxgtk_model), path, &iter );
a7f61f76 1665
673810ee 1666 m_internal->ItemChanged( item );
b9db5f30 1667
a7f61f76 1668 return true;
6e2e590f
RR
1669}
1670
d93cc830 1671bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsigned int model_column )
6e2e590f 1672{
673810ee
RR
1673 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
1674 wxDataViewCtrl *ctrl = m_internal->GetOwner();
ce00f59b 1675
4eccd3a1 1676 // This adds GTK+'s missing MVC logic for ValueChanged
63415a42 1677 unsigned int index;
673810ee 1678 for (index = 0; index < ctrl->GetColumnCount(); index++)
8f850e28 1679 {
673810ee 1680 wxDataViewColumn *column = ctrl->GetColumn( index );
d93cc830 1681 if (column->GetModelColumn() == model_column)
8f850e28 1682 {
673810ee 1683 GtkTreeView *widget = GTK_TREE_VIEW(ctrl->GtkGetTreeView());
63415a42 1684 GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle());
8f850e28 1685
b30ad967
VZ
1686 // Don't attempt to refresh not yet realized tree, it is useless
1687 // and results in GTK errors.
1688 if ( gtk_widget_get_realized(ctrl->GtkGetTreeView()) )
1689 {
1690 // Get cell area
1691 GtkTreeIter iter;
1692 iter.stamp = wxgtk_model->stamp;
1693 iter.user_data = (gpointer) item.GetID();
1694 wxGtkTreePath path(wxgtk_tree_model_get_path(
1695 GTK_TREE_MODEL(wxgtk_model), &iter ));
1696 GdkRectangle cell_area;
1697 gtk_tree_view_get_cell_area( widget, path, gcolumn, &cell_area );
1698
1699 GtkAdjustment* hadjust = gtk_tree_view_get_hadjustment( widget );
1700 double d = gtk_adjustment_get_value( hadjust );
1701 int xdiff = (int) d;
1702
1703 int ydiff = gcolumn->button->allocation.height;
1704 // Redraw
1705 gtk_widget_queue_draw_area( GTK_WIDGET(widget),
1706 cell_area.x - xdiff, ydiff + cell_area.y, cell_area.width, cell_area.height );
1707 }
b9db5f30 1708
d93cc830 1709 m_internal->ValueChanged( item, model_column );
b9db5f30 1710
d8331a01 1711 return true;
8f850e28 1712 }
8f850e28 1713 }
93763ad5 1714
d8331a01 1715 return false;
6e2e590f
RR
1716}
1717
d8090b5e 1718bool wxGtkDataViewModelNotifier::BeforeReset()
673810ee
RR
1719{
1720 GtkWidget *treeview = m_internal->GetOwner()->GtkGetTreeView();
1721 gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), NULL );
d8090b5e 1722
673810ee
RR
1723 return true;
1724}
1725
1726bool wxGtkDataViewModelNotifier::AfterReset()
1727{
673810ee 1728 GtkWidget *treeview = m_internal->GetOwner()->GtkGetTreeView();
d8090b5e 1729 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
ce00f59b
VZ
1730
1731 m_internal->Cleared();
1732
d8090b5e 1733 gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(wxgtk_model) );
ce00f59b 1734
673810ee
RR
1735 return true;
1736}
1737
e0062c04 1738bool wxGtkDataViewModelNotifier::Cleared()
6e2e590f 1739{
673810ee 1740 GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
ce00f59b 1741
c225708f
RR
1742 // There is no call to tell the model that everything
1743 // has been deleted so call row_deleted() for every
1744 // child of root...
1745
673810ee 1746 int count = m_internal->iter_n_children( NULL ); // number of children of root
ce00f59b 1747
c225708f
RR
1748 GtkTreePath *path = gtk_tree_path_new_first(); // points to root
1749
1750 int i;
1751 for (i = 0; i < count; i++)
673810ee 1752 gtk_tree_model_row_deleted( GTK_TREE_MODEL(wxgtk_model), path );
ce00f59b 1753
c225708f 1754 gtk_tree_path_free( path );
ce00f59b 1755
673810ee 1756 m_internal->Cleared();
03647350 1757
8a568372 1758 return true;
6e2e590f
RR
1759}
1760
93763ad5 1761// ---------------------------------------------------------
baa9ebc4 1762// wxDataViewRenderer
93763ad5 1763// ---------------------------------------------------------
6842a71a 1764
a912e81f
RR
1765static gpointer s_user_data = NULL;
1766
1767static void
c5c5395b 1768wxgtk_cell_editable_editing_done( GtkCellEditable *WXUNUSED(editable),
a912e81f
RR
1769 wxDataViewRenderer *wxrenderer )
1770{
1771 wxDataViewColumn *column = wxrenderer->GetOwner();
1772 wxDataViewCtrl *dv = column->GetOwner();
1773 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE, dv->GetId() );
1774 event.SetDataViewColumn( column );
1775 event.SetModel( dv->GetModel() );
1776 wxDataViewItem item( s_user_data );
1777 event.SetItem( item );
937013e0 1778 dv->HandleWindowEvent( event );
a912e81f
RR
1779}
1780
b9db5f30 1781static void
c5c5395b 1782wxgtk_renderer_editing_started( GtkCellRenderer *WXUNUSED(cell), GtkCellEditable *editable,
a912e81f
RR
1783 gchar *path, wxDataViewRenderer *wxrenderer )
1784{
ecc32226
RR
1785 if (!editable)
1786 return;
1787
a912e81f
RR
1788 wxDataViewColumn *column = wxrenderer->GetOwner();
1789 wxDataViewCtrl *dv = column->GetOwner();
1790 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED, dv->GetId() );
1791 event.SetDataViewColumn( column );
1792 event.SetModel( dv->GetModel() );
0c2a7270 1793 wxDataViewItem item(dv->GTKPathToItem(wxGtkTreePath(path)));
a912e81f 1794 event.SetItem( item );
937013e0 1795 dv->HandleWindowEvent( event );
a912e81f
RR
1796
1797 if (GTK_IS_CELL_EDITABLE(editable))
1798 {
17d98558 1799 s_user_data = item.GetID();
b9db5f30 1800
a912e81f
RR
1801 g_signal_connect (GTK_CELL_EDITABLE (editable), "editing_done",
1802 G_CALLBACK (wxgtk_cell_editable_editing_done),
1803 (gpointer) wxrenderer );
b9db5f30 1804
a912e81f
RR
1805 }
1806}
1807
1808
baa9ebc4 1809IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
6842a71a 1810
9861f022
RR
1811wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode,
1812 int align ) :
1813 wxDataViewRendererBase( varianttype, mode, align )
6842a71a
RR
1814{
1815 m_renderer = NULL;
9fc221aa 1816 m_mode = mode;
9861f022 1817
b74399b9
VZ
1818 // we haven't changed them yet
1819 m_usingDefaultAttrs = true;
1820
9861f022
RR
1821 // NOTE: SetMode() and SetAlignment() needs to be called in the renderer's ctor,
1822 // after the m_renderer pointer has been initialized
1823}
1824
205bdf20
VZ
1825void wxDataViewRenderer::GtkPackIntoColumn(GtkTreeViewColumn *column)
1826{
1827 gtk_tree_view_column_pack_end( column, m_renderer, TRUE /* expand */);
1828}
1829
a912e81f
RR
1830void wxDataViewRenderer::GtkInitHandlers()
1831{
1832 if (!gtk_check_version(2,6,0))
1833 {
1834 g_signal_connect (GTK_CELL_RENDERER(m_renderer), "editing_started",
03647350
VZ
1835 G_CALLBACK (wxgtk_renderer_editing_started),
1836 this);
a912e81f
RR
1837 }
1838}
1839
9861f022
RR
1840void wxDataViewRenderer::SetMode( wxDataViewCellMode mode )
1841{
1842 GtkCellRendererMode gtkMode;
1843 switch (mode)
1844 {
25bc5c55
VZ
1845 case wxDATAVIEW_CELL_INERT:
1846 gtkMode = GTK_CELL_RENDERER_MODE_INERT;
1847 break;
1848
1849 case wxDATAVIEW_CELL_ACTIVATABLE:
1850 gtkMode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
1851 break;
1852
1853 case wxDATAVIEW_CELL_EDITABLE:
1854 gtkMode = GTK_CELL_RENDERER_MODE_EDITABLE;
1855 break;
1856
1857 default:
1858 wxFAIL_MSG( "unknown wxDataViewCellMode value" );
1859 return;
9861f022
RR
1860 }
1861
06f28e55
RD
1862 m_mode = mode;
1863
b9db5f30 1864 // This value is most often ignored in GtkTreeView
9861f022
RR
1865 GValue gvalue = { 0, };
1866 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
1867 g_value_set_enum( &gvalue, gtkMode );
1868 g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue );
1869 g_value_unset( &gvalue );
1870}
1871
1872wxDataViewCellMode wxDataViewRenderer::GetMode() const
1873{
1874 wxDataViewCellMode ret;
1875
1876 GValue gvalue;
1877 g_object_get( G_OBJECT(m_renderer), "mode", &gvalue, NULL);
1878
1879 switch (g_value_get_enum(&gvalue))
1880 {
25bc5c55
VZ
1881 default:
1882 wxFAIL_MSG( "unknown GtkCellRendererMode value" );
1883 // fall through (we have to return something)
1884
1885 case GTK_CELL_RENDERER_MODE_INERT:
1886 ret = wxDATAVIEW_CELL_INERT;
1887 break;
1888
1889 case GTK_CELL_RENDERER_MODE_ACTIVATABLE:
1890 ret = wxDATAVIEW_CELL_ACTIVATABLE;
1891 break;
1892
1893 case GTK_CELL_RENDERER_MODE_EDITABLE:
1894 ret = wxDATAVIEW_CELL_EDITABLE;
1895 break;
9861f022
RR
1896 }
1897
1898 g_value_unset( &gvalue );
1899
1900 return ret;
1901}
1902
3e81bbbf 1903void wxDataViewRenderer::GtkApplyAlignment(GtkCellRenderer *renderer)
9861f022 1904{
f2b7492a 1905 int align = m_alignment;
bc0289bf 1906
f2b7492a
RR
1907 // query alignment from column ?
1908 if (align == -1)
1909 {
1910 // None there yet
1911 if (GetOwner() == NULL)
1912 return;
bc0289bf 1913
f2b7492a
RR
1914 align = GetOwner()->GetAlignment();
1915 align |= wxALIGN_CENTRE_VERTICAL;
1916 }
bc0289bf 1917
9861f022
RR
1918 // horizontal alignment:
1919
1920 gfloat xalign = 0.0;
1921 if (align & wxALIGN_RIGHT)
1922 xalign = 1.0;
1923 else if (align & wxALIGN_CENTER_HORIZONTAL)
1924 xalign = 0.5;
1925
1926 GValue gvalue = { 0, };
1927 g_value_init( &gvalue, G_TYPE_FLOAT );
1928 g_value_set_float( &gvalue, xalign );
3e81bbbf 1929 g_object_set_property( G_OBJECT(renderer), "xalign", &gvalue );
9861f022
RR
1930 g_value_unset( &gvalue );
1931
1932 // vertical alignment:
1933
1934 gfloat yalign = 0.0;
1935 if (align & wxALIGN_BOTTOM)
1936 yalign = 1.0;
1937 else if (align & wxALIGN_CENTER_VERTICAL)
1938 yalign = 0.5;
1939
1940 GValue gvalue2 = { 0, };
1941 g_value_init( &gvalue2, G_TYPE_FLOAT );
1942 g_value_set_float( &gvalue2, yalign );
3e81bbbf 1943 g_object_set_property( G_OBJECT(renderer), "yalign", &gvalue2 );
9861f022 1944 g_value_unset( &gvalue2 );
6842a71a
RR
1945}
1946
f2b7492a 1947void wxDataViewRenderer::SetAlignment( int align )
9861f022 1948{
f2b7492a
RR
1949 m_alignment = align;
1950 GtkUpdateAlignment();
9861f022
RR
1951}
1952
f2b7492a
RR
1953int wxDataViewRenderer::GetAlignment() const
1954{
1955 return m_alignment;
1956}
9861f022 1957
c937bcac
VZ
1958void wxDataViewRenderer::EnableEllipsize(wxEllipsizeMode mode)
1959{
995d5aa2 1960#ifdef __WXGTK26__
c937bcac
VZ
1961 if ( gtk_check_version(2, 6, 0) != NULL )
1962 return;
1963
17cbc244
VZ
1964 GtkCellRendererText * const rend = GtkGetTextRenderer();
1965 if ( !rend )
1966 return;
1967
c937bcac
VZ
1968 // we use the same values in wxEllipsizeMode as PangoEllipsizeMode so we
1969 // can just cast between them
1970 GValue gvalue = { 0, };
1971 g_value_init( &gvalue, PANGO_TYPE_ELLIPSIZE_MODE );
1972 g_value_set_enum( &gvalue, static_cast<PangoEllipsizeMode>(mode) );
17cbc244 1973 g_object_set_property( G_OBJECT(rend), "ellipsize", &gvalue );
c937bcac 1974 g_value_unset( &gvalue );
995d5aa2
VZ
1975#else // GTK < 2.6
1976 wxUnusedVar(mode);
1977#endif // GTK 2.6/before
c937bcac
VZ
1978}
1979
1980wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const
1981{
995d5aa2 1982#ifdef __WXGTK26__
c937bcac
VZ
1983 if ( gtk_check_version(2, 6, 0) != NULL )
1984 return wxELLIPSIZE_NONE;
1985
17cbc244
VZ
1986 GtkCellRendererText * const rend = GtkGetTextRenderer();
1987 if ( !rend )
1988 return wxELLIPSIZE_NONE;
1989
c937bcac
VZ
1990 GValue gvalue = { 0, };
1991 g_value_init( &gvalue, PANGO_TYPE_ELLIPSIZE_MODE );
17cbc244 1992 g_object_get_property( G_OBJECT(rend), "ellipsize", &gvalue );
c937bcac
VZ
1993 wxEllipsizeMode
1994 mode = static_cast<wxEllipsizeMode>(g_value_get_enum( &gvalue ));
1995 g_value_unset( &gvalue );
1996
1997 return mode;
995d5aa2
VZ
1998#else // GTK < 2.6
1999 return wxELLIPSIZE_NONE;
2000#endif // GTK 2.6/before
c937bcac
VZ
2001}
2002
205bdf20
VZ
2003void
2004wxDataViewRenderer::GtkOnTextEdited(const gchar *itempath, const wxString& str)
2005{
2006 wxVariant value(str);
2007 if (!Validate( value ))
2008 return;
2009
0c2a7270
VZ
2010 wxDataViewItem
2011 item(GetOwner()->GetOwner()->GTKPathToItem(wxGtkTreePath(itempath)));
205bdf20
VZ
2012
2013 GtkOnCellChanged(value, item, GetOwner()->GetModelColumn());
2014}
2015
2016void
2017wxDataViewRenderer::GtkOnCellChanged(const wxVariant& value,
2018 const wxDataViewItem& item,
2019 unsigned col)
2020{
2021 wxDataViewModel *model = GetOwner()->GetOwner()->GetModel();
795dac4c 2022 model->ChangeValue( value, item, col );
205bdf20
VZ
2023}
2024
93763ad5 2025// ---------------------------------------------------------
baa9ebc4 2026// wxDataViewTextRenderer
93763ad5 2027// ---------------------------------------------------------
6842a71a 2028
205bdf20
VZ
2029extern "C"
2030{
a7f61f76 2031
c5c5395b 2032static void wxGtkTextRendererEditedCallback( GtkCellRendererText *WXUNUSED(renderer),
a7f61f76
RR
2033 gchar *arg1, gchar *arg2, gpointer user_data )
2034{
7448d67c 2035 wxDataViewRenderer *cell = (wxDataViewRenderer*) user_data;
93763ad5 2036
205bdf20
VZ
2037 cell->GtkOnTextEdited(arg1, wxGTK_CONV_BACK_FONT(
2038 arg2, cell->GetOwner()->GetOwner()->GetFont()));
2039}
93763ad5 2040
a7f61f76
RR
2041}
2042
c80cde00
VZ
2043namespace
2044{
2045
2046// helper function used by wxDataViewTextRenderer and
2047// wxDataViewCustomRenderer::RenderText(): it applies the attributes to the
2048// given text renderer and returns true if anything was done
2049bool GtkApplyAttr(GtkCellRendererText *renderer, const wxDataViewItemAttr& attr)
2050{
2051 bool usingDefaultAttrs = true;
2052 if (attr.HasColour())
2053 {
2054 const GdkColor * const gcol = attr.GetColour().GetColor();
2055
2056 GValue gvalue = { 0, };
2057 g_value_init( &gvalue, GDK_TYPE_COLOR );
2058 g_value_set_boxed( &gvalue, gcol );
2059 g_object_set_property( G_OBJECT(renderer), "foreground_gdk", &gvalue );
2060 g_value_unset( &gvalue );
2061
2062 usingDefaultAttrs = false;
2063 }
2064 else
2065 {
2066 GValue gvalue = { 0, };
2067 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2068 g_value_set_boolean( &gvalue, FALSE );
2069 g_object_set_property( G_OBJECT(renderer), "foreground-set", &gvalue );
2070 g_value_unset( &gvalue );
2071 }
2072
2073 if (attr.GetItalic())
2074 {
2075 GValue gvalue = { 0, };
2076 g_value_init( &gvalue, PANGO_TYPE_STYLE );
2077 g_value_set_enum( &gvalue, PANGO_STYLE_ITALIC );
2078 g_object_set_property( G_OBJECT(renderer), "style", &gvalue );
2079 g_value_unset( &gvalue );
2080
2081 usingDefaultAttrs = false;
2082 }
2083 else
2084 {
2085 GValue gvalue = { 0, };
2086 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2087 g_value_set_boolean( &gvalue, FALSE );
2088 g_object_set_property( G_OBJECT(renderer), "style-set", &gvalue );
2089 g_value_unset( &gvalue );
2090 }
2091
2092
2093 if (attr.GetBold())
2094 {
2095 GValue gvalue = { 0, };
2096 g_value_init( &gvalue, PANGO_TYPE_WEIGHT );
2097 g_value_set_enum( &gvalue, PANGO_WEIGHT_BOLD );
2098 g_object_set_property( G_OBJECT(renderer), "weight", &gvalue );
2099 g_value_unset( &gvalue );
2100
2101 usingDefaultAttrs = false;
2102 }
2103 else
2104 {
2105 GValue gvalue = { 0, };
2106 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2107 g_value_set_boolean( &gvalue, FALSE );
2108 g_object_set_property( G_OBJECT(renderer), "weight-set", &gvalue );
2109 g_value_unset( &gvalue );
2110 }
2111
2112#if 0
2113 if (attr.HasBackgroundColour())
2114 {
2115 wxColour colour = attr.GetBackgroundColour();
2116 const GdkColor * const gcol = colour.GetColor();
2117
2118 GValue gvalue = { 0, };
2119 g_value_init( &gvalue, GDK_TYPE_COLOR );
2120 g_value_set_boxed( &gvalue, gcol );
2121 g_object_set_property( G_OBJECT(renderer), "cell-background_gdk", &gvalue );
2122 g_value_unset( &gvalue );
2123 }
2124 else
2125 {
2126 GValue gvalue = { 0, };
2127 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2128 g_value_set_boolean( &gvalue, FALSE );
2129 g_object_set_property( G_OBJECT(renderer), "cell-background-set", &gvalue );
2130 g_value_unset( &gvalue );
2131 }
2132#endif
2133
2134 return !usingDefaultAttrs;
2135}
2136
2137} // anonymous namespace
2138
baa9ebc4 2139IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewRenderer)
6842a71a 2140
9861f022
RR
2141wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode,
2142 int align ) :
2143 wxDataViewRenderer( varianttype, mode, align )
6842a71a 2144{
ecc32226
RR
2145 GtkWxCellRendererText *text_renderer = gtk_wx_cell_renderer_text_new();
2146 text_renderer->wx_renderer = this;
2147 m_renderer = (GtkCellRenderer*) text_renderer;
93763ad5 2148
9861f022 2149 if (mode & wxDATAVIEW_CELL_EDITABLE)
a7f61f76
RR
2150 {
2151 GValue gvalue = { 0, };
2152 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2153 g_value_set_boolean( &gvalue, true );
2154 g_object_set_property( G_OBJECT(m_renderer), "editable", &gvalue );
2155 g_value_unset( &gvalue );
93763ad5 2156
a7f61f76 2157 g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
b9db5f30 2158
a912e81f 2159 GtkInitHandlers();
a7f61f76 2160 }
9861f022
RR
2161
2162 SetMode(mode);
2163 SetAlignment(align);
6842a71a 2164}
790b137e 2165
205bdf20 2166bool wxDataViewTextRenderer::SetTextValue(const wxString& str)
7b4fde82 2167{
7b4fde82
RR
2168 GValue gvalue = { 0, };
2169 g_value_init( &gvalue, G_TYPE_STRING );
205bdf20 2170 g_value_set_string( &gvalue, wxGTK_CONV_FONT( str, GetOwner()->GetOwner()->GetFont() ) );
7b4fde82
RR
2171 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
2172 g_value_unset( &gvalue );
93763ad5 2173
7b4fde82
RR
2174 return true;
2175}
2176
205bdf20 2177bool wxDataViewTextRenderer::GetTextValue(wxString& str) const
a7f61f76
RR
2178{
2179 GValue gvalue = { 0, };
2180 g_value_init( &gvalue, G_TYPE_STRING );
2181 g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
205bdf20 2182 str = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ), const_cast<wxDataViewTextRenderer*>(this)->GetOwner()->GetOwner()->GetFont() );
a7f61f76 2183 g_value_unset( &gvalue );
93763ad5 2184
a7f61f76
RR
2185 return true;
2186}
2187
9861f022
RR
2188void wxDataViewTextRenderer::SetAlignment( int align )
2189{
2190 wxDataViewRenderer::SetAlignment(align);
2191
01705e98
RR
2192 if (gtk_check_version(2,10,0))
2193 return;
9861f022 2194
01705e98 2195 // horizontal alignment:
9861f022
RR
2196 PangoAlignment pangoAlign = PANGO_ALIGN_LEFT;
2197 if (align & wxALIGN_RIGHT)
2198 pangoAlign = PANGO_ALIGN_RIGHT;
2199 else if (align & wxALIGN_CENTER_HORIZONTAL)
2200 pangoAlign = PANGO_ALIGN_CENTER;
2201
2202 GValue gvalue = { 0, };
2203 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
2204 g_value_set_enum( &gvalue, pangoAlign );
2205 g_object_set_property( G_OBJECT(m_renderer), "alignment", &gvalue );
2206 g_value_unset( &gvalue );
2207}
2208
c80cde00
VZ
2209bool wxDataViewTextRenderer::GtkSetAttr(const wxDataViewItemAttr& attr)
2210{
17cbc244
VZ
2211 return GtkApplyAttr(GtkGetTextRenderer(), attr);
2212}
2213
2214GtkCellRendererText *wxDataViewTextRenderer::GtkGetTextRenderer() const
2215{
2216 return GTK_CELL_RENDERER_TEXT(m_renderer);
c80cde00
VZ
2217}
2218
f4322df6 2219// ---------------------------------------------------------
baa9ebc4 2220// wxDataViewBitmapRenderer
f4322df6 2221// ---------------------------------------------------------
cbc9145c 2222
205bdf20
VZ
2223namespace
2224{
2225
2226// set "pixbuf" property on the given renderer
2227void SetPixbufProp(GtkCellRenderer *renderer, GdkPixbuf *pixbuf)
2228{
2229 GValue gvalue = { 0, };
2230 g_value_init( &gvalue, G_TYPE_OBJECT );
2231 g_value_set_object( &gvalue, pixbuf );
2232 g_object_set_property( G_OBJECT(renderer), "pixbuf", &gvalue );
2233 g_value_unset( &gvalue );
2234}
2235
2236} // anonymous namespace
2237
baa9ebc4 2238IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewRenderer)
cbc9145c 2239
9861f022
RR
2240wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode,
2241 int align ) :
2242 wxDataViewRenderer( varianttype, mode, align )
cbc9145c 2243{
205bdf20 2244 m_renderer = gtk_cell_renderer_pixbuf_new();
9861f022
RR
2245
2246 SetMode(mode);
2247 SetAlignment(align);
cbc9145c
RR
2248}
2249
baa9ebc4 2250bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
cbc9145c
RR
2251{
2252 if (value.GetType() == wxT("wxBitmap"))
2253 {
2586d4a1
RR
2254 wxBitmap bitmap;
2255 bitmap << value;
f4322df6 2256
205bdf20
VZ
2257 // GetPixbuf() may create a Pixbuf representation in the wxBitmap
2258 // object (and it will stay there and remain owned by wxBitmap)
2259 SetPixbufProp(m_renderer, bitmap.GetPixbuf());
2586d4a1 2260 }
205bdf20 2261 else if (value.GetType() == wxT("wxIcon"))
2586d4a1 2262 {
205bdf20
VZ
2263 wxIcon icon;
2264 icon << value;
f4322df6 2265
205bdf20
VZ
2266 SetPixbufProp(m_renderer, icon.GetPixbuf());
2267 }
2268 else
2269 {
2270 return false;
cbc9145c 2271 }
f4322df6 2272
205bdf20 2273 return true;
cbc9145c
RR
2274}
2275
c5c5395b 2276bool wxDataViewBitmapRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
cbc9145c
RR
2277{
2278 return false;
2279}
f4322df6 2280
93763ad5 2281// ---------------------------------------------------------
baa9ebc4 2282// wxDataViewToggleRenderer
93763ad5 2283// ---------------------------------------------------------
fa28826d 2284
605c2c4a 2285extern "C" {
93763ad5 2286static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
605c2c4a
RR
2287 gchar *path, gpointer user_data );
2288}
2289
93763ad5 2290static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer,
605c2c4a
RR
2291 gchar *path, gpointer user_data )
2292{
baa9ebc4 2293 wxDataViewToggleRenderer *cell = (wxDataViewToggleRenderer*) user_data;
605c2c4a 2294
93763ad5 2295 // get old value
605c2c4a
RR
2296 GValue gvalue = { 0, };
2297 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2298 g_object_get_property( G_OBJECT(renderer), "active", &gvalue );
93763ad5 2299 bool tmp = g_value_get_boolean( &gvalue );
605c2c4a
RR
2300 g_value_unset( &gvalue );
2301 // invert it
2302 tmp = !tmp;
93763ad5 2303
605c2c4a
RR
2304 wxVariant value = tmp;
2305 if (!cell->Validate( value ))
2306 return;
93763ad5 2307
0c2a7270
VZ
2308 wxDataViewCtrl * const ctrl = cell->GetOwner()->GetOwner();
2309 wxDataViewModel *model = ctrl->GetModel();
93763ad5 2310
0c2a7270 2311 wxDataViewItem item(ctrl->GTKPathToItem(wxGtkTreePath(path)));
93763ad5 2312
0a71f9e9 2313 unsigned int model_col = cell->GetOwner()->GetModelColumn();
93763ad5 2314
795dac4c 2315 model->ChangeValue( value, item, model_col );
605c2c4a
RR
2316}
2317
baa9ebc4 2318IMPLEMENT_CLASS(wxDataViewToggleRenderer, wxDataViewRenderer)
605c2c4a 2319
baa9ebc4 2320wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
9861f022
RR
2321 wxDataViewCellMode mode, int align ) :
2322 wxDataViewRenderer( varianttype, mode, align )
605c2c4a 2323{
ed38aa55 2324 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_toggle_new();
93763ad5 2325
9861f022 2326 if (mode & wxDATAVIEW_CELL_ACTIVATABLE)
605c2c4a 2327 {
9861f022
RR
2328 g_signal_connect_after( m_renderer, "toggled",
2329 G_CALLBACK(wxGtkToggleRendererToggledCallback), this );
553f7d8f
RR
2330 }
2331 else
2332 {
605c2c4a
RR
2333 GValue gvalue = { 0, };
2334 g_value_init( &gvalue, G_TYPE_BOOLEAN );
553f7d8f 2335 g_value_set_boolean( &gvalue, false );
605c2c4a
RR
2336 g_object_set_property( G_OBJECT(m_renderer), "activatable", &gvalue );
2337 g_value_unset( &gvalue );
605c2c4a 2338 }
9861f022
RR
2339
2340 SetMode(mode);
2341 SetAlignment(align);
605c2c4a
RR
2342}
2343
baa9ebc4 2344bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
605c2c4a
RR
2345{
2346 bool tmp = value;
93763ad5 2347
605c2c4a
RR
2348 GValue gvalue = { 0, };
2349 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2350 g_value_set_boolean( &gvalue, tmp );
2351 g_object_set_property( G_OBJECT(m_renderer), "active", &gvalue );
2352 g_value_unset( &gvalue );
93763ad5 2353
605c2c4a
RR
2354 return true;
2355}
2356
9861f022 2357bool wxDataViewToggleRenderer::GetValue( wxVariant &value ) const
605c2c4a
RR
2358{
2359 GValue gvalue = { 0, };
2360 g_value_init( &gvalue, G_TYPE_BOOLEAN );
2361 g_object_get_property( G_OBJECT(m_renderer), "active", &gvalue );
93763ad5 2362 bool tmp = g_value_get_boolean( &gvalue );
605c2c4a 2363 g_value_unset( &gvalue );
93763ad5 2364
605c2c4a
RR
2365 value = tmp;
2366
2367 return true;
2368}
93763ad5
WS
2369
2370// ---------------------------------------------------------
baa9ebc4 2371// wxDataViewCustomRenderer
93763ad5 2372// ---------------------------------------------------------
e152afc3 2373
888dde65 2374class wxDataViewCtrlDCImpl: public wxWindowDCImpl
e152afc3
RR
2375{
2376public:
888dde65
RR
2377 wxDataViewCtrlDCImpl( wxDC *owner, wxDataViewCtrl *window ) :
2378 wxWindowDCImpl( owner )
2379 {
1a367564 2380 GtkWidget *widget = window->m_treeview;
e152afc3 2381 // Set later
888dde65 2382 m_gdkwindow = NULL;
7857346a 2383
888dde65 2384 m_window = window;
4d496ecb 2385
496e7ec6 2386 m_context = window->GTKGetPangoDefaultContext();
e152afc3 2387 m_layout = pango_layout_new( m_context );
385e8575 2388 m_fontdesc = pango_font_description_copy(gtk_widget_get_style(widget)->font_desc);
e152afc3
RR
2389
2390 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
888dde65
RR
2391
2392 // Set m_gdkwindow later
4d496ecb 2393 // SetUpDC();
e152afc3
RR
2394 }
2395};
2396
888dde65
RR
2397class wxDataViewCtrlDC: public wxWindowDC
2398{
2399public:
c5c5395b
RR
2400 wxDataViewCtrlDC( wxDataViewCtrl *window ) :
2401 wxWindowDC( new wxDataViewCtrlDCImpl( this, window ) )
7857346a 2402 { }
888dde65 2403};
7857346a 2404
888dde65 2405
93763ad5 2406// ---------------------------------------------------------
baa9ebc4 2407// wxDataViewCustomRenderer
93763ad5 2408// ---------------------------------------------------------
e152afc3 2409
baa9ebc4 2410IMPLEMENT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
e152afc3 2411
baa9ebc4 2412wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
6eec70b9
VZ
2413 wxDataViewCellMode mode,
2414 int align,
2415 bool no_init )
2416 : wxDataViewCustomRendererBase( varianttype, mode, align )
e152afc3
RR
2417{
2418 m_dc = NULL;
f69c03de 2419 m_text_renderer = NULL;
93763ad5 2420
ad63bf41
RR
2421 if (no_init)
2422 m_renderer = NULL;
2423 else
9861f022 2424 Init(mode, align);
ad63bf41
RR
2425}
2426
3e81bbbf
VZ
2427void wxDataViewCustomRenderer::GtkInitTextRenderer()
2428{
2429 m_text_renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
2430 g_object_ref_sink(m_text_renderer);
2431
2432 GtkApplyAlignment(GTK_CELL_RENDERER(m_text_renderer));
2433}
2434
17cbc244
VZ
2435GtkCellRendererText *wxDataViewCustomRenderer::GtkGetTextRenderer() const
2436{
2437 if ( !m_text_renderer )
2438 {
2439 // we create it on demand so need to do it even from a const function
3e81bbbf 2440 const_cast<wxDataViewCustomRenderer *>(this)->GtkInitTextRenderer();
17cbc244
VZ
2441 }
2442
2443 return m_text_renderer;
2444}
2445
2a454ffd
VZ
2446void wxDataViewCustomRenderer::RenderText( const wxString &text,
2447 int xoffset,
2448 wxRect cell,
2449 wxDC *WXUNUSED(dc),
2450 int WXUNUSED(state) )
52e750fc 2451{
17cbc244
VZ
2452
2453 GtkCellRendererText * const textRenderer = GtkGetTextRenderer();
b9db5f30 2454
f69c03de
RR
2455 GValue gvalue = { 0, };
2456 g_value_init( &gvalue, G_TYPE_STRING );
1bf629bd 2457 g_value_set_string( &gvalue, wxGTK_CONV_FONT( text, GetOwner()->GetOwner()->GetFont() ) );
17cbc244 2458 g_object_set_property( G_OBJECT(textRenderer), "text", &gvalue );
f69c03de
RR
2459 g_value_unset( &gvalue );
2460
17cbc244 2461 GtkApplyAttr(textRenderer, GetAttr());
c80cde00 2462
2a454ffd
VZ
2463 GdkRectangle cell_area;
2464 wxRectToGDKRect(cell, cell_area);
2465 cell_area.x += xoffset;
2466 cell_area.width -= xoffset;
b9db5f30 2467
17cbc244 2468 gtk_cell_renderer_render( GTK_CELL_RENDERER(textRenderer),
2a454ffd
VZ
2469 m_renderParams.window,
2470 m_renderParams.widget,
2471 m_renderParams.background_area,
2472 &cell_area,
2473 m_renderParams.expose_area,
2474 (GtkCellRendererState) m_renderParams.flags );
52e750fc
RR
2475}
2476
9861f022 2477bool wxDataViewCustomRenderer::Init(wxDataViewCellMode mode, int align)
ad63bf41 2478{
e152afc3
RR
2479 GtkWxCellRenderer *renderer = (GtkWxCellRenderer *) gtk_wx_cell_renderer_new();
2480 renderer->cell = this;
93763ad5 2481
ed38aa55 2482 m_renderer = (GtkCellRenderer*) renderer;
93763ad5 2483
9861f022
RR
2484 SetMode(mode);
2485 SetAlignment(align);
93763ad5 2486
a912e81f 2487 GtkInitHandlers();
b9db5f30 2488
ad63bf41 2489 return true;
e152afc3
RR
2490}
2491
baa9ebc4 2492wxDataViewCustomRenderer::~wxDataViewCustomRenderer()
e152afc3
RR
2493{
2494 if (m_dc)
2495 delete m_dc;
f69c03de
RR
2496
2497 if (m_text_renderer)
385e8575 2498 g_object_unref(m_text_renderer);
e152afc3
RR
2499}
2500
baa9ebc4 2501wxDC *wxDataViewCustomRenderer::GetDC()
e152afc3
RR
2502{
2503 if (m_dc == NULL)
4d496ecb
RR
2504 {
2505 if (GetOwner() == NULL)
2506 return NULL;
2507 if (GetOwner()->GetOwner() == NULL)
2508 return NULL;
e152afc3 2509 m_dc = new wxDataViewCtrlDC( GetOwner()->GetOwner() );
4d496ecb 2510 }
93763ad5 2511
e152afc3
RR
2512 return m_dc;
2513}
93763ad5
WS
2514
2515// ---------------------------------------------------------
baa9ebc4 2516// wxDataViewProgressRenderer
93763ad5 2517// ---------------------------------------------------------
ad63bf41 2518
baa9ebc4 2519IMPLEMENT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
ad63bf41 2520
baa9ebc4 2521wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
9861f022
RR
2522 const wxString &varianttype, wxDataViewCellMode mode, int align ) :
2523 wxDataViewCustomRenderer( varianttype, mode, align, true )
ad63bf41
RR
2524{
2525 m_label = label;
2526 m_value = 0;
93763ad5 2527
ad63bf41
RR
2528#ifdef __WXGTK26__
2529 if (!gtk_check_version(2,6,0))
2530 {
ed38aa55 2531 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_progress_new();
93763ad5 2532
9861f022
RR
2533 SetMode(mode);
2534 SetAlignment(align);
fdd67a6a
VZ
2535
2536#if !wxUSE_UNICODE
2537 // We can't initialize the renderer just yet because we don't have the
2538 // pointer to the column that uses this renderer yet and so attempt to
2539 // dereference GetOwner() to get the font that is used as a source of
2540 // encoding in multibyte-to-Unicode conversion in GTKSetLabel() in
2541 // non-Unicode builds would crash. So simply remember to do it later.
2542 if ( !m_label.empty() )
2543 m_needsToSetLabel = true;
2544 else
2545#endif // !wxUSE_UNICODE
2546 GTKSetLabel();
ad63bf41
RR
2547 }
2548 else
2549#endif
2550 {
2551 // Use custom cell code
9861f022 2552 wxDataViewCustomRenderer::Init(mode, align);
ad63bf41
RR
2553 }
2554}
2555
baa9ebc4 2556wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
ad63bf41
RR
2557{
2558}
2559
fdd67a6a
VZ
2560void wxDataViewProgressRenderer::GTKSetLabel()
2561{
2562 GValue gvalue = { 0, };
2563 g_value_init( &gvalue, G_TYPE_STRING );
2564
2565 // Take care to not use GetOwner() here if the label is empty, we can be
2566 // called from ctor when GetOwner() is still NULL in this case.
2567 g_value_set_string( &gvalue,
2568 m_label.empty() ? ""
2569 : wxGTK_CONV_FONT(m_label,
2570 GetOwner()->GetOwner()->GetFont())
2571 );
2572 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
2573 g_value_unset( &gvalue );
2574
2575#if !wxUSE_UNICODE
2576 m_needsToSetLabel = false;
2577#endif // !wxUSE_UNICODE
2578}
2579
baa9ebc4 2580bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
ad63bf41
RR
2581{
2582#ifdef __WXGTK26__
2583 if (!gtk_check_version(2,6,0))
2584 {
fdd67a6a
VZ
2585#if !wxUSE_UNICODE
2586 if ( m_needsToSetLabel )
2587 GTKSetLabel();
2588#endif // !wxUSE_UNICODE
2589
7226118b 2590 gint tmp = (long) value;
ad63bf41
RR
2591 GValue gvalue = { 0, };
2592 g_value_init( &gvalue, G_TYPE_INT );
7226118b 2593 g_value_set_int( &gvalue, tmp );
ad63bf41
RR
2594 g_object_set_property( G_OBJECT(m_renderer), "value", &gvalue );
2595 g_value_unset( &gvalue );
2596 }
2597 else
2598#endif
2599 {
2600 m_value = (long) value;
93763ad5 2601
ad63bf41
RR
2602 if (m_value < 0) m_value = 0;
2603 if (m_value > 100) m_value = 100;
2604 }
93763ad5 2605
ad63bf41
RR
2606 return true;
2607}
93763ad5 2608
85136e3b 2609bool wxDataViewProgressRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
9861f022
RR
2610{
2611 return false;
2612}
2613
85136e3b 2614bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
ad63bf41
RR
2615{
2616 double pct = (double)m_value / 100.0;
2617 wxRect bar = cell;
2618 bar.width = (int)(cell.width * pct);
2619 dc->SetPen( *wxTRANSPARENT_PEN );
2620 dc->SetBrush( *wxBLUE_BRUSH );
2621 dc->DrawRectangle( bar );
2622
2623 dc->SetBrush( *wxTRANSPARENT_BRUSH );
2624 dc->SetPen( *wxBLACK_PEN );
2625 dc->DrawRectangle( cell );
93763ad5 2626
ad63bf41
RR
2627 return true;
2628}
2629
9861f022 2630wxSize wxDataViewProgressRenderer::GetSize() const
ad63bf41
RR
2631{
2632 return wxSize(40,12);
2633}
93763ad5 2634
7448d67c
RR
2635// -------------------------------------
2636// wxDataViewChoiceRenderer
2637// -------------------------------------
2638
2639wxDataViewChoiceRenderer::wxDataViewChoiceRenderer( const wxArrayString &choices,
2640 wxDataViewCellMode mode, int alignment ) :
2641 wxDataViewCustomRenderer( "string", mode, alignment, true )
2642{
2643 m_choices = choices;
2644
2645#ifdef __WXGTK26__
2646 if (!gtk_check_version(2,6,0))
2647 {
2648 m_renderer = (GtkCellRenderer*) gtk_cell_renderer_combo_new();
2649
2650 GtkListStore *store = gtk_list_store_new( 1, G_TYPE_STRING );
5baee1f4
VZ
2651 for (size_t n = 0; n < m_choices.GetCount(); n++)
2652 {
2653 gtk_list_store_insert_with_values(
2654 store, NULL, n, 0,
2655 static_cast<const char *>(m_choices[n].utf8_str()), -1 );
2656 }
bc0289bf 2657
7448d67c
RR
2658 g_object_set (m_renderer,
2659 "model", store,
2660 "text-column", 0,
2661 "has-entry", FALSE,
2662 NULL);
bc0289bf 2663
7448d67c
RR
2664 bool editable = (mode & wxDATAVIEW_CELL_EDITABLE);
2665 g_object_set (m_renderer, "editable", editable, NULL);
bc0289bf 2666
7448d67c 2667 SetAlignment(alignment);
bc0289bf 2668
7448d67c
RR
2669 g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
2670
2671 GtkInitHandlers();
2672 }
2673 else
2674#endif
2675 {
2676 // Use custom cell code
2677 wxDataViewCustomRenderer::Init(mode, alignment);
2678 }
2679}
2680
2681bool wxDataViewChoiceRenderer::Render( wxRect rect, wxDC *dc, int state )
2682{
2683 RenderText( m_data, 0, rect, dc, state );
2684 return true;
2685}
2686
2687wxSize wxDataViewChoiceRenderer::GetSize() const
2688{
2689 return wxSize(70,20);
2690}
2691
2692bool wxDataViewChoiceRenderer::SetValue( const wxVariant &value )
2693{
bc0289bf 2694
7448d67c
RR
2695#ifdef __WXGTK26__
2696 if (!gtk_check_version(2,6,0))
2697 {
2698 GValue gvalue = { 0, };
2699 g_value_init( &gvalue, G_TYPE_STRING );
d636e043
VZ
2700 g_value_set_string(&gvalue,
2701 wxGTK_CONV_FONT(value.GetString(),
2702 GetOwner()->GetOwner()->GetFont()));
7448d67c
RR
2703 g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
2704 g_value_unset( &gvalue );
2705 }
2706 else
2707#endif
2708 m_data = value.GetString();
2709
2710 return true;
2711}
2712
2713bool wxDataViewChoiceRenderer::GetValue( wxVariant &value ) const
2714{
2715#ifdef __WXGTK26__
2716 if (!gtk_check_version(2,6,0))
2717 {
2718 GValue gvalue = { 0, };
2719 g_value_init( &gvalue, G_TYPE_STRING );
2720 g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
d636e043
VZ
2721 wxString temp = wxGTK_CONV_BACK_FONT(g_value_get_string(&gvalue),
2722 GetOwner()->GetOwner()->GetFont());
7448d67c
RR
2723 g_value_unset( &gvalue );
2724 value = temp;
c2489d8e
FM
2725
2726 //wxPrintf( "temp %s\n", temp );
2727 // TODO: remove this code
7448d67c
RR
2728 }
2729 else
2730#endif
2731 value = m_data;
2732
2733 return true;
2734}
2735
2736void wxDataViewChoiceRenderer::SetAlignment( int align )
2737{
2738 wxDataViewCustomRenderer::SetAlignment(align);
2739
2740 if (gtk_check_version(2,10,0))
2741 return;
2742
2743 // horizontal alignment:
2744 PangoAlignment pangoAlign = PANGO_ALIGN_LEFT;
2745 if (align & wxALIGN_RIGHT)
2746 pangoAlign = PANGO_ALIGN_RIGHT;
2747 else if (align & wxALIGN_CENTER_HORIZONTAL)
2748 pangoAlign = PANGO_ALIGN_CENTER;
2749
2750 GValue gvalue = { 0, };
2751 g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
2752 g_value_set_enum( &gvalue, pangoAlign );
2753 g_object_set_property( G_OBJECT(m_renderer), "alignment", &gvalue );
2754 g_value_unset( &gvalue );
2755}
bc0289bf 2756
65887bd0
RR
2757// ----------------------------------------------------------------------------
2758// wxDataViewChoiceByIndexRenderer
2759// ----------------------------------------------------------------------------
2760
2761wxDataViewChoiceByIndexRenderer::wxDataViewChoiceByIndexRenderer( const wxArrayString &choices,
2762 wxDataViewCellMode mode, int alignment ) :
2763 wxDataViewChoiceRenderer( choices, mode, alignment )
2764{
2765}
ce00f59b 2766
65887bd0
RR
2767void wxDataViewChoiceByIndexRenderer::GtkOnTextEdited(const gchar *itempath, const wxString& str)
2768{
2769 wxVariant value( (long) GetChoices().Index( str ) );
2770
2771 if (!Validate( value ))
2772 return;
2773
0c2a7270
VZ
2774 wxDataViewItem
2775 item(GetOwner()->GetOwner()->GTKPathToItem(wxGtkTreePath(itempath)));
65887bd0
RR
2776
2777 GtkOnCellChanged(value, item, GetOwner()->GetModelColumn());
2778}
2779
2780bool wxDataViewChoiceByIndexRenderer::SetValue( const wxVariant &value )
2781{
2782 wxVariant string_value = GetChoice( value.GetLong() );
2783 return wxDataViewChoiceRenderer::SetValue( string_value );
2784}
ce00f59b 2785
65887bd0
RR
2786bool wxDataViewChoiceByIndexRenderer::GetValue( wxVariant &value ) const
2787{
2788 wxVariant string_value;
2789 if (!wxDataViewChoiceRenderer::GetValue( string_value ))
2790 return false;
ce00f59b 2791
65887bd0
RR
2792 value = (long) GetChoices().Index( string_value.GetString() );
2793 return true;
2794}
2795
93763ad5 2796// ---------------------------------------------------------
baa9ebc4 2797// wxDataViewDateRenderer
93763ad5 2798// ---------------------------------------------------------
4d496ecb 2799
baa9ebc4 2800class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
7ea3a0de 2801{
93763ad5 2802public:
baa9ebc4 2803 wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
e0062c04 2804 wxDataViewModel *model, const wxDataViewItem &item, unsigned int col ) :
7ea3a0de
RR
2805 wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
2806 {
2807 m_model = model;
e0062c04 2808 m_item = item;
7ea3a0de 2809 m_col = col;
7ea3a0de
RR
2810 m_cal = new wxCalendarCtrl( this, -1, *value );
2811 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
2812 sizer->Add( m_cal, 1, wxGROW );
2813 SetSizer( sizer );
2814 sizer->Fit( this );
2815 }
93763ad5 2816
7ea3a0de
RR
2817 virtual void OnDismiss()
2818 {
2819 }
93763ad5 2820
7ea3a0de 2821 void OnCalendar( wxCalendarEvent &event );
93763ad5 2822
e0062c04
RR
2823 wxCalendarCtrl *m_cal;
2824 wxDataViewModel *m_model;
2825 wxDataViewItem m_item;
2826 unsigned int m_col;
93763ad5 2827
7ea3a0de
RR
2828private:
2829 DECLARE_EVENT_TABLE()
2830};
2831
baa9ebc4
RR
2832BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
2833 EVT_CALENDAR( -1, wxDataViewDateRendererPopupTransient::OnCalendar )
7ea3a0de
RR
2834END_EVENT_TABLE()
2835
baa9ebc4 2836void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
7ea3a0de 2837{
795dac4c 2838 m_model->ChangeValue( event.GetDate(), m_item, m_col );
7ea3a0de
RR
2839 DismissAndNotify();
2840}
2841
baa9ebc4 2842IMPLEMENT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
4d496ecb 2843
baa9ebc4 2844wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
9861f022
RR
2845 wxDataViewCellMode mode, int align ) :
2846 wxDataViewCustomRenderer( varianttype, mode, align )
4d496ecb 2847{
9861f022
RR
2848 SetMode(mode);
2849 SetAlignment(align);
4d496ecb 2850}
93763ad5 2851
baa9ebc4 2852bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
4d496ecb
RR
2853{
2854 m_date = value.GetDateTime();
93763ad5 2855
4d496ecb
RR
2856 return true;
2857}
2858
85136e3b 2859bool wxDataViewDateRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
9861f022
RR
2860{
2861 return false;
2862}
2863
baa9ebc4 2864bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state )
4d496ecb
RR
2865{
2866 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
2867 wxString tmp = m_date.FormatDate();
52e750fc 2868 RenderText( tmp, 0, cell, dc, state );
4d496ecb
RR
2869 return true;
2870}
2871
9861f022 2872wxSize wxDataViewDateRenderer::GetSize() const
4d496ecb 2873{
4d496ecb
RR
2874 wxString tmp = m_date.FormatDate();
2875 wxCoord x,y,d;
9861f022 2876 GetView()->GetTextExtent( tmp, &x, &y, &d );
4d496ecb
RR
2877 return wxSize(x,y+d);
2878}
2879
b586d4c7 2880bool wxDataViewDateRenderer::Activate( const wxRect& WXUNUSED(cell), wxDataViewModel *model,
e0062c04 2881 const wxDataViewItem &item, unsigned int col )
4d496ecb 2882{
3f3af7e7 2883 wxVariant variant;
e0062c04 2884 model->GetValue( variant, item, col );
7ea3a0de
RR
2885 wxDateTime value = variant.GetDateTime();
2886
baa9ebc4 2887 wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
e0062c04 2888 GetOwner()->GetOwner()->GetParent(), &value, model, item, col );
7ea3a0de
RR
2889 wxPoint pos = wxGetMousePosition();
2890 popup->Move( pos );
2891 popup->Layout();
2892 popup->Popup( popup->m_cal );
4d496ecb
RR
2893
2894 return true;
2895}
2896
c9c13e70 2897
b9db5f30 2898// ---------------------------------------------------------
c9c13e70 2899// wxDataViewIconTextRenderer
b9db5f30 2900// ---------------------------------------------------------
c9c13e70
RR
2901
2902IMPLEMENT_CLASS(wxDataViewIconTextRenderer, wxDataViewCustomRenderer)
2903
205bdf20
VZ
2904wxDataViewIconTextRenderer::wxDataViewIconTextRenderer
2905 (
2906 const wxString &varianttype,
2907 wxDataViewCellMode mode,
2908 int align
2909 )
2910 : wxDataViewTextRenderer(varianttype, mode, align)
c9c13e70 2911{
205bdf20 2912 m_rendererIcon = gtk_cell_renderer_pixbuf_new();
c9c13e70
RR
2913}
2914
2915wxDataViewIconTextRenderer::~wxDataViewIconTextRenderer()
2916{
2917}
b9db5f30 2918
205bdf20 2919void wxDataViewIconTextRenderer::GtkPackIntoColumn(GtkTreeViewColumn *column)
c9c13e70 2920{
205bdf20
VZ
2921 // add the icon renderer first
2922 gtk_tree_view_column_pack_start(column, m_rendererIcon, FALSE /* !expand */);
c9c13e70 2923
205bdf20
VZ
2924 // add the text renderer too
2925 wxDataViewRenderer::GtkPackIntoColumn(column);
c9c13e70 2926}
b9db5f30 2927
205bdf20 2928bool wxDataViewIconTextRenderer::SetValue( const wxVariant &value )
c9c13e70 2929{
205bdf20 2930 m_value << value;
b9db5f30 2931
205bdf20
VZ
2932 SetTextValue(m_value.GetText());
2933 SetPixbufProp(m_rendererIcon, m_value.GetIcon().GetPixbuf());
c9c13e70
RR
2934
2935 return true;
2936}
2937
205bdf20 2938bool wxDataViewIconTextRenderer::GetValue(wxVariant& value) const
c9c13e70 2939{
205bdf20
VZ
2940 wxString str;
2941 if ( !GetTextValue(str) )
2942 return false;
c9c13e70 2943
205bdf20
VZ
2944 // user doesn't have any way to edit the icon so leave it unchanged
2945 value << wxDataViewIconText(str, m_value.GetIcon());
2946
2947 return true;
c9c13e70
RR
2948}
2949
205bdf20
VZ
2950void
2951wxDataViewIconTextRenderer::GtkOnCellChanged(const wxVariant& value,
2952 const wxDataViewItem& item,
2953 unsigned col)
c9c13e70 2954{
205bdf20
VZ
2955 // we receive just the text part of our value as it's the only one which
2956 // can be edited, but we need the full wxDataViewIconText value for the
2957 // model
2958 wxVariant valueIconText;
2959 valueIconText << wxDataViewIconText(value.GetString(), m_value.GetIcon());
2960 wxDataViewTextRenderer::GtkOnCellChanged(valueIconText, item, col);
c9c13e70
RR
2961}
2962
93763ad5 2963// ---------------------------------------------------------
605c2c4a 2964// wxDataViewColumn
93763ad5 2965// ---------------------------------------------------------
7b4fde82 2966
31fb32e1
RR
2967
2968static gboolean
ad386793 2969gtk_dataview_header_button_press_callback( GtkWidget *WXUNUSED(widget),
31fb32e1
RR
2970 GdkEventButton *gdk_event,
2971 wxDataViewColumn *column )
2972{
2973 if (gdk_event->type != GDK_BUTTON_PRESS)
94b1f7bc 2974 return FALSE;
f4322df6 2975
31fb32e1
RR
2976 if (gdk_event->button == 1)
2977 {
d32332aa 2978 gs_lastLeftClickHeader = column;
7857346a 2979
31fb32e1
RR
2980 wxDataViewCtrl *dv = column->GetOwner();
2981 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, dv->GetId() );
2982 event.SetDataViewColumn( column );
2983 event.SetModel( dv->GetModel() );
937013e0 2984 if (dv->HandleWindowEvent( event ))
a84c5b6f 2985 return FALSE;
31fb32e1 2986 }
f4322df6 2987
dadc879e
RR
2988 if (gdk_event->button == 3)
2989 {
2990 wxDataViewCtrl *dv = column->GetOwner();
2991 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, dv->GetId() );
2992 event.SetDataViewColumn( column );
2993 event.SetModel( dv->GetModel() );
937013e0 2994 if (dv->HandleWindowEvent( event ))
dadc879e
RR
2995 return FALSE;
2996 }
2997
94b1f7bc 2998 return FALSE;
31fb32e1
RR
2999}
3000
47583ac1
VZ
3001extern "C"
3002{
7b4fde82 3003
ad386793 3004static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column),
7b4fde82
RR
3005 GtkCellRenderer *renderer,
3006 GtkTreeModel *model,
3007 GtkTreeIter *iter,
3008 gpointer data )
3009{
e0062c04
RR
3010 g_return_if_fail (GTK_IS_WX_TREE_MODEL (model));
3011 GtkWxTreeModel *tree_model = (GtkWxTreeModel *) model;
93763ad5 3012
baa9ebc4 3013 wxDataViewRenderer *cell = (wxDataViewRenderer*) data;
a7f61f76 3014
9d52aad3 3015 wxDataViewItem item( (void*) iter->user_data );
93763ad5 3016
a826202e
RR
3017 wxDataViewModel *wx_model = tree_model->internal->GetDataViewModel();
3018
e39de702 3019 if (!wx_model->IsVirtualListModel())
2056dede 3020 {
47583ac1
VZ
3021 gboolean visible;
3022 if (wx_model->IsContainer( item ))
a826202e 3023 {
47583ac1
VZ
3024 visible = wx_model->HasContainerColumns( item ) ||
3025 (cell->GetOwner()->GetModelColumn() == 0);
a826202e
RR
3026 }
3027 else
3028 {
47583ac1 3029 visible = true;
a826202e 3030 }
47583ac1 3031
a826202e
RR
3032 GValue gvalue = { 0, };
3033 g_value_init( &gvalue, G_TYPE_BOOLEAN );
47583ac1 3034 g_value_set_boolean( &gvalue, visible );
a826202e
RR
3035 g_object_set_property( G_OBJECT(renderer), "visible", &gvalue );
3036 g_value_unset( &gvalue );
b9db5f30 3037
47583ac1
VZ
3038 if ( !visible )
3039 return;
2056dede 3040 }
a826202e 3041
3f3af7e7 3042 wxVariant value;
a826202e 3043 wx_model->GetValue( value, item, cell->GetOwner()->GetModelColumn() );
7b4fde82
RR
3044
3045 if (value.GetType() != cell->GetVariantType())
af588446 3046 {
f4322df6
VZ
3047 wxLogError( wxT("Wrong type, required: %s but: %s"),
3048 value.GetType().c_str(),
cbc9145c 3049 cell->GetVariantType().c_str() );
af588446 3050 }
93763ad5 3051
7b4fde82 3052 cell->SetValue( value );
e0743e63 3053
9c09addd
RR
3054 // deal with disabled items
3055 bool enabled = wx_model->IsEnabled( item, cell->GetOwner()->GetModelColumn() );
3056
3057 // a) this sets the appearance to disabled grey
3058 GValue gvalue = { 0, };
3059 g_value_init( &gvalue, G_TYPE_BOOLEAN );
3060 g_value_set_boolean( &gvalue, enabled );
3061 g_object_set_property( G_OBJECT(renderer), "sensitive", &gvalue );
3062 g_value_unset( &gvalue );
3063
3064 // b) this actually disables the control/renderer
3065 if (enabled)
3066 cell->SetMode( cell->GtkGetMode() );
3067 else
3068 cell->SetMode( wxDATAVIEW_CELL_INERT );
3069
b74399b9 3070
c80cde00
VZ
3071 // deal with attributes: if the renderer doesn't support them at all, we
3072 // don't even need to query the model for them
c2a738e3
VZ
3073 if ( !cell->GtkSupportsAttrs() )
3074 return;
3075
c80cde00 3076 // it can support attributes so check if this item has any
2d0d7813 3077 wxDataViewItemAttr attr;
c80cde00
VZ
3078 if ( wx_model->GetAttr( item, cell->GetOwner()->GetModelColumn(), attr )
3079 || !cell->GtkIsUsingDefaultAttrs() )
b74399b9 3080 {
c80cde00
VZ
3081 bool usingDefaultAttrs = !cell->GtkSetAttr(attr);
3082 cell->GtkSetUsingDefaultAttrs(usingDefaultAttrs);
b74399b9 3083 }
c80cde00
VZ
3084 // else: no custom attributes specified and we're already using the default
3085 // ones -- nothing to do
9fc221aa 3086
7b4fde82
RR
3087}
3088
47583ac1
VZ
3089} // extern "C"
3090
91a6c655 3091#include <wx/listimpl.cpp>
a76c2f37 3092WX_DEFINE_LIST(wxDataViewColumnList)
91a6c655 3093
f4322df6
VZ
3094wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell,
3095 unsigned int model_column, int width,
835d0d55
VZ
3096 wxAlignment align, int flags )
3097 : wxDataViewColumnBase( cell, model_column )
fa28826d 3098{
9861f022 3099 Init( align, flags, width );
31fb32e1 3100
31fb32e1 3101 SetTitle( title );
fa28826d
RR
3102}
3103
f4322df6
VZ
3104wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell,
3105 unsigned int model_column, int width,
835d0d55
VZ
3106 wxAlignment align, int flags )
3107 : wxDataViewColumnBase( bitmap, cell, model_column )
9861f022
RR
3108{
3109 Init( align, flags, width );
3110
3111 SetBitmap( bitmap );
3112}
3113
3114void wxDataViewColumn::Init(wxAlignment align, int flags, int width)
07a84e7b 3115{
31fb32e1 3116 m_isConnected = false;
07a84e7b
RR
3117
3118 GtkTreeViewColumn *column = gtk_tree_view_column_new();
9861f022 3119 m_column = (GtkWidget*) column;
07a84e7b 3120
9861f022
RR
3121 SetFlags( flags );
3122 SetAlignment( align );
07a84e7b 3123
ad386793 3124 SetWidth( width );
07a84e7b 3125
419a3607
RR
3126 // Create container for icon and label
3127 GtkWidget *box = gtk_hbox_new( FALSE, 1 );
3128 gtk_widget_show( box );
3129 // gtk_container_set_border_width((GtkContainer*)box, 2);
3130 m_image = gtk_image_new();
3131 gtk_box_pack_start(GTK_BOX(box), m_image, FALSE, FALSE, 1);
3132 m_label = gtk_label_new("");
3133 gtk_box_pack_end( GTK_BOX(box), GTK_WIDGET(m_label), FALSE, FALSE, 1 );
3134 gtk_tree_view_column_set_widget( column, box );
bc0289bf 3135
205bdf20
VZ
3136 wxDataViewRenderer * const colRenderer = GetRenderer();
3137 GtkCellRenderer * const cellRenderer = colRenderer->GetGtkHandle();
3138
3139 colRenderer->GtkPackIntoColumn(column);
07a84e7b 3140
205bdf20
VZ
3141 gtk_tree_view_column_set_cell_data_func( column, cellRenderer,
3142 wxGtkTreeCellDataFunc, (gpointer) colRenderer, NULL );
07a84e7b
RR
3143}
3144
31fb32e1
RR
3145void wxDataViewColumn::OnInternalIdle()
3146{
3147 if (m_isConnected)
3148 return;
ce00f59b 3149
fc9ab22a 3150 if (gtk_widget_get_realized(GetOwner()->m_treeview))
31fb32e1 3151 {
9861f022 3152 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
31fb32e1
RR
3153 if (column->button)
3154 {
3155 g_signal_connect(column->button, "button_press_event",
3156 G_CALLBACK (gtk_dataview_header_button_press_callback), this);
f4322df6 3157
5d9e1605 3158 // otherwise the event will be blocked by GTK+
ce00f59b
VZ
3159 gtk_tree_view_column_set_clickable( column, TRUE );
3160
31fb32e1
RR
3161 m_isConnected = true;
3162 }
3163 }
3164}
3165
b94db696
RR
3166void wxDataViewColumn::SetOwner( wxDataViewCtrl *owner )
3167{
3168 wxDataViewColumnBase::SetOwner( owner );
f4322df6 3169
9861f022 3170 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
f4322df6 3171
b94db696 3172 gtk_tree_view_column_set_title( column, wxGTK_CONV_FONT(GetTitle(), GetOwner()->GetFont() ) );
b94db696
RR
3173}
3174
fa28826d
RR
3175void wxDataViewColumn::SetTitle( const wxString &title )
3176{
09dfa6a0 3177 wxDataViewCtrl *ctrl = GetOwner();
419a3607 3178 gtk_label_set_text( GTK_LABEL(m_label), ctrl ? wxGTK_CONV_FONT(title, ctrl->GetFont())
09dfa6a0 3179 : wxGTK_CONV_SYS(title) );
419a3607
RR
3180 if (title.empty())
3181 gtk_widget_hide( m_label );
3182 else
3183 gtk_widget_show( m_label );
07a84e7b
RR
3184}
3185
9861f022
RR
3186wxString wxDataViewColumn::GetTitle() const
3187{
7f6cbcea
VZ
3188 return wxGTK_CONV_BACK_FONT(
3189 gtk_label_get_text( GTK_LABEL(m_label) ),
3190 GetOwner()->GetFont()
3191 );
9861f022
RR
3192}
3193
07a84e7b
RR
3194void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap )
3195{
3196 wxDataViewColumnBase::SetBitmap( bitmap );
3197
a1b806b9 3198 if (bitmap.IsOk())
07a84e7b 3199 {
419a3607 3200 GtkImage *gtk_image = GTK_IMAGE(m_image);
f4322df6 3201
d3b9f782 3202 GdkBitmap *mask = NULL;
07a84e7b
RR
3203 if (bitmap.GetMask())
3204 mask = bitmap.GetMask()->GetBitmap();
3205
3206 if (bitmap.HasPixbuf())
3207 {
3208 gtk_image_set_from_pixbuf(GTK_IMAGE(gtk_image),
3209 bitmap.GetPixbuf());
3210 }
3211 else
3212 {
3213 gtk_image_set_from_pixmap(GTK_IMAGE(gtk_image),
3214 bitmap.GetPixmap(), mask);
3215 }
419a3607 3216 gtk_widget_show( m_image );
07a84e7b
RR
3217 }
3218 else
3219 {
419a3607 3220 gtk_widget_hide( m_image );
07a84e7b 3221 }
fa28826d
RR
3222}
3223
9861f022
RR
3224void wxDataViewColumn::SetHidden( bool hidden )
3225{
3226 gtk_tree_view_column_set_visible( GTK_TREE_VIEW_COLUMN(m_column), !hidden );
3227}
3228
d13b34d3 3229void wxDataViewColumn::SetResizeable( bool resizable )
9861f022 3230{
d13b34d3 3231 gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizable );
9861f022
RR
3232}
3233
47cef10f
RR
3234void wxDataViewColumn::SetAlignment( wxAlignment align )
3235{
9861f022 3236 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
f4322df6 3237
47cef10f
RR
3238 gfloat xalign = 0.0;
3239 if (align == wxALIGN_RIGHT)
3240 xalign = 1.0;
9861f022
RR
3241 if (align == wxALIGN_CENTER_HORIZONTAL ||
3242 align == wxALIGN_CENTER)
47cef10f 3243 xalign = 0.5;
f4322df6 3244
9861f022 3245 gtk_tree_view_column_set_alignment( column, xalign );
bc0289bf 3246
f2b7492a
RR
3247 if (m_renderer && m_renderer->GetAlignment() == -1)
3248 m_renderer->GtkUpdateAlignment();
9861f022
RR
3249}
3250
3251wxAlignment wxDataViewColumn::GetAlignment() const
3252{
3253 gfloat xalign = gtk_tree_view_column_get_alignment( GTK_TREE_VIEW_COLUMN(m_column) );
3254
3255 if (xalign == 1.0)
3256 return wxALIGN_RIGHT;
3257 if (xalign == 0.5)
3258 return wxALIGN_CENTER_HORIZONTAL;
f4322df6 3259
9861f022 3260 return wxALIGN_LEFT;
47cef10f
RR
3261}
3262
31fb32e1
RR
3263void wxDataViewColumn::SetSortable( bool sortable )
3264{
9861f022 3265 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
b9db5f30 3266
140a119a
VZ
3267 if ( sortable )
3268 {
3269 gtk_tree_view_column_set_sort_column_id( column, GetModelColumn() );
3270 }
3271 else
3272 {
3273 gtk_tree_view_column_set_sort_column_id( column, -1 );
3274 gtk_tree_view_column_set_sort_indicator( column, FALSE );
3275 gtk_tree_view_column_set_clickable( column, FALSE );
3276 }
e2bfe673
VZ
3277}
3278
3279bool wxDataViewColumn::IsSortable() const
3280{
3281 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3282 return gtk_tree_view_column_get_clickable( column );
3283}
3284
140a119a 3285void wxDataViewColumn::SetAsSortKey( bool WXUNUSED(sort) )
e2bfe673 3286{
dcb6cbec 3287 // it might not make sense to have this function in wxHeaderColumn at
140a119a
VZ
3288 // all in fact, changing of the sort order should only be done using the
3289 // associated control API
3290 wxFAIL_MSG( "not implemented" );
31fb32e1
RR
3291}
3292
e2bfe673 3293bool wxDataViewColumn::IsSortKey() const
31fb32e1 3294{
9861f022 3295 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
140a119a 3296 return gtk_tree_view_column_get_sort_indicator( column );
31fb32e1
RR
3297}
3298
9861f022
RR
3299bool wxDataViewColumn::IsResizeable() const
3300{
3301 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3302 return gtk_tree_view_column_get_resizable( column );
3303}
3304
3305bool wxDataViewColumn::IsHidden() const
3306{
3307 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
3308 return !gtk_tree_view_column_get_visible( column );
3309}
3310
47cef10f
RR
3311void wxDataViewColumn::SetSortOrder( bool ascending )
3312{
9861f022 3313 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
f4322df6 3314
47cef10f
RR
3315 if (ascending)
3316 gtk_tree_view_column_set_sort_order( column, GTK_SORT_ASCENDING );
3317 else
3318 gtk_tree_view_column_set_sort_order( column, GTK_SORT_DESCENDING );
0bd26819
RR
3319
3320 gtk_tree_view_column_set_sort_indicator( column, TRUE );
47cef10f
RR
3321}
3322
87f0efe2 3323bool wxDataViewColumn::IsSortOrderAscending() const
31fb32e1 3324{
9861f022 3325 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
f4322df6 3326
31fb32e1
RR
3327 return (gtk_tree_view_column_get_sort_order( column ) != GTK_SORT_DESCENDING);
3328}
3329
9861f022 3330void wxDataViewColumn::SetMinWidth( int width )
533544f2 3331{
9861f022 3332 gtk_tree_view_column_set_min_width( GTK_TREE_VIEW_COLUMN(m_column), width );
533544f2
RR
3333}
3334
9861f022
RR
3335int wxDataViewColumn::GetMinWidth() const
3336{
3337 return gtk_tree_view_column_get_min_width( GTK_TREE_VIEW_COLUMN(m_column) );
3338}
3339
3340int wxDataViewColumn::GetWidth() const
533544f2 3341{
9861f022 3342 return gtk_tree_view_column_get_width( GTK_TREE_VIEW_COLUMN(m_column) );
533544f2
RR
3343}
3344
9861f022 3345void wxDataViewColumn::SetWidth( int width )
533544f2 3346{
d0154e3a 3347 if ( width == wxCOL_WIDTH_AUTOSIZE )
ad386793 3348 {
d0154e3a 3349 // NB: this disables user resizing
ad386793
RR
3350 gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_AUTOSIZE );
3351 }
3352 else
3353 {
d0154e3a
VS
3354 if ( width == wxCOL_WIDTH_DEFAULT )
3355 {
3356 // TODO find a better calculation
3357 width = wxDVC_DEFAULT_WIDTH;
3358 }
7857346a 3359
d0154e3a 3360 gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED );
ad386793
RR
3361 gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), width );
3362 }
533544f2
RR
3363}
3364
99c75ebc
RR
3365void wxDataViewColumn::SetReorderable( bool reorderable )
3366{
3367 gtk_tree_view_column_set_reorderable( GTK_TREE_VIEW_COLUMN(m_column), reorderable );
3368}
3369
3370bool wxDataViewColumn::IsReorderable() const
3371{
3372 return gtk_tree_view_column_get_reorderable( GTK_TREE_VIEW_COLUMN(m_column) );
3373}
9861f022 3374
4508fcd2
RR
3375//-----------------------------------------------------------------------------
3376// wxGtkTreeModelNode
3377//-----------------------------------------------------------------------------
3378
5b276ac1 3379#if 0
1f226ad8
RR
3380class wxGtkTreeModelChildWithPos
3381{
3382public:
3383 unsigned int pos;
3384 void *id;
3385};
3386
3387static
3388int wxGtkTreeModelChildWithPosCmp( const void* data1, const void* data2, const void* user_data )
3389{
3390 const wxGtkTreeModelChildWithPos* child1 = (const wxGtkTreeModelChildWithPos*) data1;
3391 const wxGtkTreeModelChildWithPos* child2 = (const wxGtkTreeModelChildWithPos*) data2;
3392 const wxDataViewCtrlInternal *internal = (const wxDataViewCtrlInternal *) user_data;
3393 int ret = internal->GetDataViewModel()->Compare( child1->id, child2->id,
5b276ac1 3394 internal->GetSortColumn(), (internal->GetSortOrder() == GTK_SORT_DESCENDING) );
1f226ad8
RR
3395
3396 return ret;
3397}
5b276ac1
RR
3398#else
3399static
3400int LINKAGEMODE wxGtkTreeModelChildPtrCmp( void*** data1, void*** data2 )
3401{
d5c4a81f 3402 return gs_internal->GetDataViewModel()->Compare( wxDataViewItem(**data1), wxDataViewItem(**data2),
5b276ac1
RR
3403 gs_internal->GetSortColumn(), (gs_internal->GetSortOrder() == GTK_SORT_ASCENDING) );
3404}
3405
3406WX_DEFINE_ARRAY_PTR( void**, wxGtkTreeModelChildrenPtr );
3407#endif
1f226ad8 3408
4508fcd2
RR
3409void wxGtkTreeModelNode::Resort()
3410{
af110130
RR
3411 size_t child_count = GetChildCount();
3412 if (child_count == 0)
0be79c8a
RR
3413 return;
3414
af110130
RR
3415 size_t node_count = GetNodesCount();
3416
3417 if (child_count == 1)
0be79c8a 3418 {
af110130
RR
3419 if (node_count == 1)
3420 {
3421 wxGtkTreeModelNode *node = m_nodes.Item( 0 );
3422 node->Resort();
3423 }
0be79c8a
RR
3424 return;
3425 }
3426
5b276ac1
RR
3427 gint *new_order = new gint[child_count];
3428
1f226ad8 3429#if 1
5b276ac1
RR
3430 // m_children has the original *void
3431 // ptrs points to these
3432 wxGtkTreeModelChildrenPtr ptrs;
3433 size_t i;
3434 for (i = 0; i < child_count; i++)
3435 ptrs.Add( &(m_children[i]) );
3436 // Sort the ptrs
3437 gs_internal = m_internal;
3438 ptrs.Sort( &wxGtkTreeModelChildPtrCmp );
03647350 3439
5b276ac1
RR
3440 wxGtkTreeModelChildren temp;
3441 void** base_ptr = &(m_children[0]);
03647350 3442 // Transfer positions to new_order array and
5b276ac1
RR
3443 // IDs to temp
3444 for (i = 0; i < child_count; i++)
3445 {
3446 new_order[i] = ptrs[i] - base_ptr;
3447 temp.Add( *ptrs[i] );
3448 }
3449
3450 // Transfer IDs back to m_children
3451 m_children.Clear();
3452 WX_APPEND_ARRAY( temp, m_children );
3453#endif
3454#if 0
3455 // Too slow
3456
1f226ad8
RR
3457 // Build up array with IDs and original positions
3458 wxGtkTreeModelChildWithPos* temp = new wxGtkTreeModelChildWithPos[child_count];
3459 size_t i;
3460 for (i = 0; i < child_count; i++)
3461 {
3462 temp[i].pos = i;
3463 temp[i].id = m_children[i];
3464 }
3465 // Sort array keeping original positions
3466 wxQsort( temp, child_count, sizeof(wxGtkTreeModelChildWithPos),
3467 &wxGtkTreeModelChildWithPosCmp, m_internal );
e4a8d29c
RR
3468 // Transfer positions to new_order array and
3469 // IDs to m_children
3470 m_children.Clear();
1f226ad8 3471 for (i = 0; i < child_count; i++)
e4a8d29c 3472 {
1f226ad8 3473 new_order[i] = temp[i].pos;
1f226ad8 3474 m_children.Add( temp[i].id );
e4a8d29c 3475 }
1f226ad8
RR
3476 // Delete array
3477 delete [] temp;
5b276ac1
RR
3478#endif
3479
3480#if 0
3481 // Too slow
03647350 3482
40196b1e
RR
3483 wxGtkTreeModelChildren temp;
3484 WX_APPEND_ARRAY( temp, m_children );
b9db5f30 3485
8c2654ce 3486 gs_internal = m_internal;
40196b1e 3487 m_children.Sort( &wxGtkTreeModelChildCmp );
03647350 3488
40196b1e 3489 unsigned int pos;
af110130 3490 for (pos = 0; pos < child_count; pos++)
4508fcd2 3491 {
40196b1e
RR
3492 void *id = m_children.Item( pos );
3493 int old_pos = temp.Index( id );
3494 new_order[pos] = old_pos;
4508fcd2 3495 }
1f226ad8 3496#endif
b9db5f30 3497
0be79c8a
RR
3498 GtkTreeModel *gtk_tree_model = GTK_TREE_MODEL( m_internal->GetGtkModel() );
3499
3500 GtkTreeIter iter;
40196b1e 3501 iter.user_data = GetItem().GetID();
0be79c8a 3502 iter.stamp = m_internal->GetGtkModel()->stamp;
b9db5f30 3503
0c2a7270
VZ
3504 gtk_tree_model_rows_reordered( gtk_tree_model,
3505 wxGtkTreePath(m_internal->get_path(&iter)), &iter, new_order );
b9db5f30 3506
0be79c8a 3507 delete [] new_order;
03647350 3508
1f226ad8 3509 unsigned int pos;
af110130 3510 for (pos = 0; pos < node_count; pos++)
4508fcd2 3511 {
af110130 3512 wxGtkTreeModelNode *node = m_nodes.Item( pos );
4508fcd2
RR
3513 node->Resort();
3514 }
3515}
3516
55fbde12
RR
3517//-----------------------------------------------------------------------------
3518// wxDataViewCtrlInternal
3519//-----------------------------------------------------------------------------
3520
673810ee 3521wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataViewModel *wx_model )
b9db5f30 3522{
55fbde12 3523 m_owner = owner;
b9db5f30 3524 m_wx_model = wx_model;
ce00f59b 3525
673810ee 3526 m_gtk_model = NULL;
b9db5f30 3527 m_root = NULL;
b8b7b087 3528 m_sort_order = GTK_SORT_ASCENDING;
40196b1e 3529 m_sort_column = -1;
d32332aa 3530 m_dataview_sort_column = NULL;
8c2654ce 3531
591cc82d
RR
3532 m_dragDataObject = NULL;
3533 m_dropDataObject = NULL;
b9db5f30 3534
d8090b5e 3535 m_dirty = false;
ce00f59b 3536
673810ee
RR
3537 m_gtk_model = wxgtk_tree_model_new();
3538 m_gtk_model->internal = this;
3539
3540 m_notifier = new wxGtkDataViewModelNotifier( wx_model, this );
3541
3542 wx_model->AddNotifier( m_notifier );
3543
3544 // g_object_unref( gtk_model ); ???
3545
e39de702 3546 if (!m_wx_model->IsVirtualListModel())
2056dede 3547 InitTree();
ce00f59b 3548
673810ee 3549 gtk_tree_view_set_model( GTK_TREE_VIEW(m_owner->GtkGetTreeView()), GTK_TREE_MODEL(m_gtk_model) );
55fbde12 3550}
b9db5f30 3551
55fbde12
RR
3552wxDataViewCtrlInternal::~wxDataViewCtrlInternal()
3553{
673810ee
RR
3554 m_wx_model->RemoveNotifier( m_notifier );
3555
ce00f59b 3556 // remove the model from the GtkTreeView before it gets destroyed
673810ee
RR
3557 gtk_tree_view_set_model( GTK_TREE_VIEW( m_owner->GtkGetTreeView() ), NULL );
3558
55fbde12 3559 g_object_unref( m_gtk_model );
8c2654ce 3560
591cc82d
RR
3561 delete m_dragDataObject;
3562 delete m_dropDataObject;
55fbde12 3563}
b9db5f30 3564
d8090b5e
RR
3565void wxDataViewCtrlInternal::ScheduleRefresh()
3566{
3567 m_dirty = true;
3568}
3569
3570void wxDataViewCtrlInternal::OnInternalIdle()
3571{
3572 if (m_dirty)
3573 {
3574 GtkWidget *widget = m_owner->GtkGetTreeView();
3575 gtk_widget_queue_draw( widget );
3576 m_dirty = false;
3577 }
3578}
3579
ef427989
RR
3580void wxDataViewCtrlInternal::InitTree()
3581{
3582 wxDataViewItem item;
0be79c8a 3583 m_root = new wxGtkTreeModelNode( NULL, item, this );
ef427989
RR
3584
3585 BuildBranch( m_root );
3586}
3587
55fbde12
RR
3588void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node )
3589{
3590 if (node->GetChildCount() == 0)
3591 {
74fe973b
RR
3592 wxDataViewItemArray children;
3593 unsigned int count = m_wx_model->GetChildren( node->GetItem(), children );
ce00f59b 3594
74fe973b
RR
3595 unsigned int pos;
3596 for (pos = 0; pos < count; pos++)
55fbde12 3597 {
74fe973b 3598 wxDataViewItem child = children[pos];
b9db5f30 3599
af110130
RR
3600 if (m_wx_model->IsContainer( child ))
3601 node->AddNode( new wxGtkTreeModelNode( node, child, this ) );
3602 else
35219832 3603 node->AddLeaf( child.GetID() );
b9db5f30 3604
effd54b0 3605 // Don't send any events here
55fbde12
RR
3606 }
3607 }
3608}
3609
f6f0ef85
RR
3610// GTK+ dnd iface
3611
15cac64f
RR
3612bool wxDataViewCtrlInternal::EnableDragSource( const wxDataFormat &format )
3613{
3614 wxGtkString atom_str( gdk_atom_name( format ) );
3615 m_dragSourceTargetEntryTarget = wxCharBuffer( atom_str );
8c2654ce 3616
15cac64f
RR
3617 m_dragSourceTargetEntry.target = m_dragSourceTargetEntryTarget.data();
3618 m_dragSourceTargetEntry.flags = 0;
3619 m_dragSourceTargetEntry.info = static_cast<guint>(-1);
8c2654ce 3620
15cac64f
RR
3621 gtk_tree_view_enable_model_drag_source( GTK_TREE_VIEW(m_owner->GtkGetTreeView() ),
3622 GDK_BUTTON1_MASK, &m_dragSourceTargetEntry, 1, (GdkDragAction) GDK_ACTION_COPY );
8c2654ce 3623
15cac64f
RR
3624 return true;
3625}
3626
e4de825e
RR
3627bool wxDataViewCtrlInternal::EnableDropTarget( const wxDataFormat &format )
3628{
3629 wxGtkString atom_str( gdk_atom_name( format ) );
3630 m_dropTargetTargetEntryTarget = wxCharBuffer( atom_str );
8c2654ce 3631
b4c40918 3632 m_dropTargetTargetEntry.target = m_dropTargetTargetEntryTarget.data();
e4de825e
RR
3633 m_dropTargetTargetEntry.flags = 0;
3634 m_dropTargetTargetEntry.info = static_cast<guint>(-1);
8c2654ce 3635
e4de825e
RR
3636 gtk_tree_view_enable_model_drag_dest( GTK_TREE_VIEW(m_owner->GtkGetTreeView() ),
3637 &m_dropTargetTargetEntry, 1, (GdkDragAction) GDK_ACTION_COPY );
8c2654ce 3638
e4de825e
RR
3639 return true;
3640}
3641
7857346a 3642gboolean wxDataViewCtrlInternal::row_draggable( GtkTreeDragSource *WXUNUSED(drag_source),
f6f0ef85
RR
3643 GtkTreePath *path )
3644{
591cc82d 3645 delete m_dragDataObject;
41936464 3646 m_dragDataObject = NULL;
8c2654ce 3647
17d98558
VZ
3648 wxDataViewItem item(GetOwner()->GTKPathToItem(path));
3649 if ( !item )
3650 return FALSE;
f6f0ef85 3651
591cc82d 3652 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_BEGIN_DRAG, m_owner->GetId() );
e4de825e 3653 event.SetEventObject( m_owner );
15cac64f
RR
3654 event.SetItem( item );
3655 event.SetModel( m_wx_model );
08a379c5
RR
3656 gint x, y;
3657 gtk_widget_get_pointer(m_owner->GtkGetTreeView(), &x, &y);
3658 event.SetPosition(x, y);
591cc82d
RR
3659 if (!m_owner->HandleWindowEvent( event ))
3660 return FALSE;
8c2654ce 3661
591cc82d
RR
3662 if (!event.IsAllowed())
3663 return FALSE;
8c2654ce 3664
591cc82d
RR
3665 wxDataObject *obj = event.GetDataObject();
3666 if (!obj)
3667 return FALSE;
8c2654ce 3668
591cc82d 3669 m_dragDataObject = obj;
8c2654ce 3670
591cc82d 3671 return TRUE;
f6f0ef85
RR
3672}
3673
7857346a
VZ
3674gboolean
3675wxDataViewCtrlInternal::drag_data_delete(GtkTreeDragSource *WXUNUSED(drag_source),
3676 GtkTreePath *WXUNUSED(path))
f6f0ef85
RR
3677{
3678 return FALSE;
3679}
3680
7857346a 3681gboolean wxDataViewCtrlInternal::drag_data_get( GtkTreeDragSource *WXUNUSED(drag_source),
f6f0ef85
RR
3682 GtkTreePath *path, GtkSelectionData *selection_data )
3683{
17d98558
VZ
3684 wxDataViewItem item(GetOwner()->GTKPathToItem(path));
3685 if ( !item )
3686 return FALSE;
7857346a 3687
385e8575
PC
3688 GdkAtom target = gtk_selection_data_get_target(selection_data);
3689 if (!m_dragDataObject->IsSupported(target))
591cc82d 3690 return FALSE;
7857346a 3691
385e8575 3692 size_t size = m_dragDataObject->GetDataSize(target);
591cc82d
RR
3693 if (size == 0)
3694 return FALSE;
8c2654ce 3695
591cc82d 3696 void *buf = malloc( size );
8c2654ce 3697
15cac64f 3698 gboolean res = FALSE;
385e8575 3699 if (m_dragDataObject->GetDataHere(target, buf))
15cac64f 3700 {
15cac64f 3701 res = TRUE;
8c2654ce 3702
385e8575 3703 gtk_selection_data_set(selection_data, target,
591cc82d 3704 8, (const guchar*) buf, size );
15cac64f 3705 }
f6f0ef85 3706
591cc82d 3707 free( buf );
7857346a 3708
15cac64f 3709 return res;
f6f0ef85
RR
3710}
3711
7857346a
VZ
3712gboolean
3713wxDataViewCtrlInternal::drag_data_received(GtkTreeDragDest *WXUNUSED(drag_dest),
e4de825e
RR
3714 GtkTreePath *path,
3715 GtkSelectionData *selection_data)
f6f0ef85 3716{
17d98558
VZ
3717 wxDataViewItem item(GetOwner()->GTKPathToItem(path));
3718 if ( !item )
3719 return FALSE;
8c2654ce 3720
e4de825e
RR
3721 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP, m_owner->GetId() );
3722 event.SetEventObject( m_owner );
3723 event.SetItem( item );
3724 event.SetModel( m_wx_model );
385e8575
PC
3725 event.SetDataFormat(gtk_selection_data_get_target(selection_data));
3726 event.SetDataSize(gtk_selection_data_get_length(selection_data));
3727 event.SetDataBuffer(const_cast<guchar*>(gtk_selection_data_get_data(selection_data)));
e4de825e
RR
3728 if (!m_owner->HandleWindowEvent( event ))
3729 return FALSE;
8c2654ce 3730
e4de825e
RR
3731 if (!event.IsAllowed())
3732 return FALSE;
3733
3734 return TRUE;
f6f0ef85
RR
3735}
3736
7857346a
VZ
3737gboolean
3738wxDataViewCtrlInternal::row_drop_possible(GtkTreeDragDest *WXUNUSED(drag_dest),
e4de825e
RR
3739 GtkTreePath *path,
3740 GtkSelectionData *selection_data)
f6f0ef85 3741{
17d98558
VZ
3742 wxDataViewItem item(GetOwner()->GTKPathToItem(path));
3743 if ( !item )
3744 return FALSE;
8c2654ce 3745
e4de825e
RR
3746 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP_POSSIBLE, m_owner->GetId() );
3747 event.SetEventObject( m_owner );
3748 event.SetItem( item );
3749 event.SetModel( m_wx_model );
385e8575 3750 event.SetDataFormat(gtk_selection_data_get_target(selection_data));
e4de825e
RR
3751 if (!m_owner->HandleWindowEvent( event ))
3752 return FALSE;
8c2654ce 3753
e4de825e
RR
3754 if (!event.IsAllowed())
3755 return FALSE;
8c2654ce 3756
e4de825e 3757 return TRUE;
f6f0ef85
RR
3758}
3759
3760// notifications from wxDataViewModel
3761
33ba5a05
RR
3762bool wxDataViewCtrlInternal::Cleared()
3763{
3764 if (m_root)
3765 {
3766 delete m_root;
c225708f 3767 m_root = NULL;
7857346a 3768 }
ce00f59b 3769
c225708f 3770 InitTree();
ce00f59b 3771
d8090b5e 3772 ScheduleRefresh();
ce00f59b 3773
33ba5a05
RR
3774 return true;
3775}
3776
4508fcd2
RR
3777void wxDataViewCtrlInternal::Resort()
3778{
e39de702 3779 if (!m_wx_model->IsVirtualListModel())
2056dede 3780 m_root->Resort();
ce00f59b 3781
d8090b5e 3782 ScheduleRefresh();
4508fcd2
RR
3783}
3784
55fbde12
RR
3785bool wxDataViewCtrlInternal::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
3786{
e39de702 3787 if (!m_wx_model->IsVirtualListModel())
2056dede
RR
3788 {
3789 wxGtkTreeModelNode *parent_node = FindNode( parent );
35219832 3790 wxCHECK_MSG(parent_node, false,
c2489d8e
FM
3791 "Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
3792
35219832
VS
3793 wxDataViewItemArray siblings;
3794 m_wx_model->GetChildren(parent, siblings);
3795 int itemPos = siblings.Index(item, /*fromEnd=*/true);
3796 wxCHECK_MSG( itemPos != wxNOT_FOUND, false, "adding non-existent item?" );
3797
2056dede 3798 if (m_wx_model->IsContainer( item ))
35219832 3799 parent_node->InsertNode( new wxGtkTreeModelNode( parent_node, item, this ), itemPos );
2056dede 3800 else
35219832 3801 parent_node->InsertLeaf( item.GetID(), itemPos );
2056dede 3802 }
b9db5f30 3803
d8090b5e 3804 ScheduleRefresh();
ce00f59b 3805
55fbde12
RR
3806 return true;
3807}
3808
469d3e9b 3809bool wxDataViewCtrlInternal::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
55fbde12 3810{
e39de702 3811 if (!m_wx_model->IsVirtualListModel())
2056dede
RR
3812 {
3813 wxGtkTreeModelNode *parent_node = FindNode( parent );
c2489d8e
FM
3814 wxASSERT_MSG(parent_node,
3815 "Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
3816
2056dede
RR
3817 parent_node->DeleteChild( item.GetID() );
3818 }
b9db5f30 3819
d8090b5e 3820 ScheduleRefresh();
ce00f59b 3821
d8331a01
RR
3822 return true;
3823}
3824
3825bool wxDataViewCtrlInternal::ItemChanged( const wxDataViewItem &item )
3826{
6608fdab 3827 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, m_owner->GetId() );
d8331a01
RR
3828 event.SetEventObject( m_owner );
3829 event.SetModel( m_owner->GetModel() );
3830 event.SetItem( item );
937013e0 3831 m_owner->HandleWindowEvent( event );
b9db5f30 3832
d8331a01
RR
3833 return true;
3834}
3835
d93cc830 3836bool wxDataViewCtrlInternal::ValueChanged( const wxDataViewItem &item, unsigned int view_column )
d8331a01 3837{
6608fdab 3838 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, m_owner->GetId() );
d8331a01
RR
3839 event.SetEventObject( m_owner );
3840 event.SetModel( m_owner->GetModel() );
d93cc830
RR
3841 event.SetColumn( view_column );
3842 event.SetDataViewColumn( GetOwner()->GetColumn(view_column) );
d8331a01 3843 event.SetItem( item );
937013e0 3844 m_owner->HandleWindowEvent( event );
b9db5f30 3845
d8331a01
RR
3846 return true;
3847}
3848
f6f0ef85
RR
3849// GTK+ model iface
3850
2056dede
RR
3851GtkTreeModelFlags wxDataViewCtrlInternal::get_flags()
3852{
ce5abbf9
VS
3853 int flags = 0;
3854
3855 if ( m_wx_model->IsListModel() )
3856 flags |= GTK_TREE_MODEL_LIST_ONLY;
3857
3858 if ( !m_wx_model->IsVirtualListModel() )
3859 flags |= GTK_TREE_MODEL_ITERS_PERSIST;
3860
3861 return GtkTreeModelFlags(flags);
2056dede
RR
3862}
3863
55fbde12
RR
3864gboolean wxDataViewCtrlInternal::get_iter( GtkTreeIter *iter, GtkTreePath *path )
3865{
9330d5af 3866
e39de702 3867 if (m_wx_model->IsVirtualListModel())
2056dede 3868 {
9330d5af 3869 wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model;
03647350 3870
2056dede 3871 unsigned int i = (unsigned int)gtk_tree_path_get_indices (path)[0];
03647350 3872
9330d5af 3873 if (i >= wx_model->GetCount())
2056dede 3874 return FALSE;
55fbde12 3875
2056dede 3876 iter->stamp = m_gtk_model->stamp;
0ae51f62
RR
3877 // user_data is just the index +1
3878 iter->user_data = (gpointer) (i+1);
55fbde12 3879
2056dede
RR
3880 return TRUE;
3881 }
3882 else
55fbde12 3883 {
2056dede
RR
3884 int depth = gtk_tree_path_get_depth( path );
3885
3886 wxGtkTreeModelNode *node = m_root;
3887
3888 int i;
b9db5f30 3889 for (i = 0; i < depth; i++)
2056dede
RR
3890 {
3891 BuildBranch( node );
b9db5f30 3892
2056dede
RR
3893 gint pos = gtk_tree_path_get_indices (path)[i];
3894 if (pos < 0) return FALSE;
3895 if ((size_t)pos >= node->GetChildCount()) return FALSE;
b9db5f30 3896
2056dede 3897 void* id = node->GetChildren().Item( (size_t) pos );
b9db5f30 3898
2056dede 3899 if (i == depth-1)
af110130 3900 {
2056dede
RR
3901 iter->stamp = m_gtk_model->stamp;
3902 iter->user_data = id;
3903 return TRUE;
af110130 3904 }
2056dede
RR
3905
3906 size_t count = node->GetNodes().GetCount();
3907 size_t pos2;
3908 for (pos2 = 0; pos2 < count; pos2++)
3909 {
3910 wxGtkTreeModelNode *child_node = node->GetNodes().Item( pos2 );
3911 if (child_node->GetItem().GetID() == id)
3912 {
3913 node = child_node;
3914 break;
3915 }
b9db5f30 3916 }
2056dede 3917 }
af110130 3918 }
55fbde12 3919
af110130 3920 return FALSE;
55fbde12
RR
3921}
3922
3923GtkTreePath *wxDataViewCtrlInternal::get_path( GtkTreeIter *iter )
3924{
8650c4ba
RR
3925 // When this is called from ItemDeleted(), the item is already
3926 // deleted in the model.
3927
55fbde12 3928 GtkTreePath *retval = gtk_tree_path_new ();
b9db5f30 3929
e39de702 3930 if (m_wx_model->IsVirtualListModel())
2056dede 3931 {
559c42a5
RR
3932 // iter is root, add nothing
3933 if (!iter->user_data)
3934 return retval;
74035a19 3935
0ae51f62
RR
3936 // user_data is just the index +1
3937 int i = ( (wxUIntPtr) iter->user_data ) -1;
2056dede
RR
3938 gtk_tree_path_append_index (retval, i);
3939 }
3940 else
55fbde12 3941 {
b9db5f30
VS
3942 void *id = iter->user_data;
3943
2056dede
RR
3944 wxGtkTreeModelNode *node = FindParentNode( iter );
3945 while (node)
3946 {
3947 int pos = node->GetChildren().Index( id );
ce00f59b 3948
2056dede 3949 gtk_tree_path_prepend_index( retval, pos );
b9db5f30 3950
2056dede
RR
3951 id = node->GetItem().GetID();
3952 node = node->GetParent();
3953 }
55fbde12 3954 }
b9db5f30 3955
55fbde12
RR
3956 return retval;
3957}
3958
3959gboolean wxDataViewCtrlInternal::iter_next( GtkTreeIter *iter )
3960{
e39de702 3961 if (m_wx_model->IsVirtualListModel())
2056dede 3962 {
9330d5af 3963 wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model;
b9db5f30 3964
0ae51f62
RR
3965 // user_data is just the index +1
3966 int n = ( (wxUIntPtr) iter->user_data ) -1;
69892729 3967
2056dede 3968 if (n == -1)
8a568372
RR
3969 {
3970 iter->user_data = NULL;
2056dede 3971 return FALSE;
8a568372 3972 }
40196b1e 3973
8a568372
RR
3974 if (n >= (int) wx_model->GetCount()-1)
3975 {
3976 iter->user_data = NULL;
2056dede 3977 return FALSE;
8a568372 3978 }
03647350 3979
0ae51f62
RR
3980 // user_data is just the index +1 (+2 because we need the next)
3981 iter->user_data = (gpointer) (n+2);
2056dede
RR
3982 }
3983 else
3984 {
3985 wxGtkTreeModelNode *parent = FindParentNode( iter );
3986 if( parent == NULL )
8a568372
RR
3987 {
3988 iter->user_data = NULL;
2056dede 3989 return FALSE;
8a568372 3990 }
2056dede
RR
3991
3992 int pos = parent->GetChildren().Index( iter->user_data );
3993
3994 if (pos == (int) parent->GetChildCount()-1)
8a568372
RR
3995 {
3996 iter->user_data = NULL;
2056dede 3997 return FALSE;
8a568372 3998 }
b9db5f30 3999
2056dede
RR
4000 iter->user_data = parent->GetChildren().Item( pos+1 );
4001 }
55fbde12
RR
4002
4003 return TRUE;
4004}
4005
4006gboolean wxDataViewCtrlInternal::iter_children( GtkTreeIter *iter, GtkTreeIter *parent )
4007{
e39de702 4008 if (m_wx_model->IsVirtualListModel())
2056dede
RR
4009 {
4010 // this is a list, nodes have no children
4011 if (parent)
4012 return FALSE;
4013
4014 iter->stamp = m_gtk_model->stamp;
9330d5af 4015 iter->user_data = (gpointer) 1;
2056dede
RR
4016
4017 return TRUE;
4018 }
4019 else
4020 {
8a568372
RR
4021 if (iter == NULL)
4022 {
4023 if (m_root->GetChildCount() == 0) return FALSE;
4024 iter->stamp = m_gtk_model->stamp;
4025 iter->user_data = (gpointer) m_root->GetChildren().Item( 0 );
4026 return TRUE;
4027 }
03647350 4028
74035a19 4029
3556d648
RR
4030 wxDataViewItem item;
4031 if (parent)
4032 item = wxDataViewItem( (void*) parent->user_data );
b9db5f30 4033
2056dede
RR
4034 if (!m_wx_model->IsContainer( item ))
4035 return FALSE;
b9db5f30 4036
2056dede 4037 wxGtkTreeModelNode *parent_node = FindNode( parent );
c2489d8e
FM
4038 wxASSERT_MSG(parent_node,
4039 "Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
4040
2056dede 4041 BuildBranch( parent_node );
b9db5f30 4042
2056dede
RR
4043 if (parent_node->GetChildCount() == 0)
4044 return FALSE;
b9db5f30 4045
2056dede
RR
4046 iter->stamp = m_gtk_model->stamp;
4047 iter->user_data = (gpointer) parent_node->GetChildren().Item( 0 );
4048 }
b9db5f30 4049
55fbde12
RR
4050 return TRUE;
4051}
4052
4053gboolean wxDataViewCtrlInternal::iter_has_child( GtkTreeIter *iter )
4054{
e39de702 4055 if (m_wx_model->IsVirtualListModel())
2056dede 4056 {
9330d5af
RR
4057 wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model;
4058
4059 if (iter == NULL)
8a568372 4060 return (wx_model->GetCount() > 0);
03647350 4061
2056dede
RR
4062 // this is a list, nodes have no children
4063 return FALSE;
4064 }
4065 else
4066 {
8a568372
RR
4067 if (iter == NULL)
4068 return (m_root->GetChildCount() > 0);
03647350 4069
2056dede 4070 wxDataViewItem item( (void*) iter->user_data );
b9db5f30 4071
2056dede 4072 bool is_container = m_wx_model->IsContainer( item );
b9db5f30 4073
2056dede
RR
4074 if (!is_container)
4075 return FALSE;
b9db5f30 4076
2056dede 4077 wxGtkTreeModelNode *node = FindNode( iter );
c2489d8e
FM
4078 wxASSERT_MSG(node,
4079 "Did you forget a call to ItemAdded()? The iterator is unknown to the wxGtkTreeModel");
4080
2056dede 4081 BuildBranch( node );
b9db5f30 4082
2056dede
RR
4083 return (node->GetChildCount() > 0);
4084 }
55fbde12
RR
4085}
4086
4087gint wxDataViewCtrlInternal::iter_n_children( GtkTreeIter *iter )
4088{
e39de702 4089 if (m_wx_model->IsVirtualListModel())
2056dede 4090 {
9330d5af 4091 wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model;
b9db5f30 4092
2056dede 4093 if (iter == NULL)
9330d5af 4094 return (gint) wx_model->GetCount();
2056dede 4095
55fbde12 4096 return 0;
2056dede
RR
4097 }
4098 else
4099 {
11f20f99
RR
4100 if (iter == NULL)
4101 return m_root->GetChildCount();
c2489d8e 4102
2056dede 4103 wxDataViewItem item( (void*) iter->user_data );
b9db5f30 4104
2056dede
RR
4105 if (!m_wx_model->IsContainer( item ))
4106 return 0;
b9db5f30 4107
2056dede 4108 wxGtkTreeModelNode *parent_node = FindNode( iter );
c2489d8e
FM
4109 wxASSERT_MSG(parent_node,
4110 "Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
4111
2056dede 4112 BuildBranch( parent_node );
ef427989 4113
2056dede
RR
4114 return parent_node->GetChildCount();
4115 }
55fbde12
RR
4116}
4117
4118gboolean wxDataViewCtrlInternal::iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n )
4119{
e39de702 4120 if (m_wx_model->IsVirtualListModel())
2056dede 4121 {
9330d5af 4122 wxDataViewVirtualListModel *wx_model = (wxDataViewVirtualListModel*) m_wx_model;
b9db5f30 4123
2056dede
RR
4124 if (parent)
4125 return FALSE;
4126
4127 if (n < 0)
4128 return FALSE;
4129
9330d5af 4130 if (n >= (gint) wx_model->GetCount())
2056dede
RR
4131 return FALSE;
4132
4133 iter->stamp = m_gtk_model->stamp;
0ae51f62 4134 // user_data is just the index +1
9330d5af 4135 iter->user_data = (gpointer) (n+1);
2056dede
RR
4136
4137 return TRUE;
4138 }
4139 else
4140 {
4141 void* id = NULL;
4142 if (parent) id = (void*) parent->user_data;
4143 wxDataViewItem item( id );
b9db5f30 4144
2056dede
RR
4145 if (!m_wx_model->IsContainer( item ))
4146 return FALSE;
b9db5f30 4147
2056dede 4148 wxGtkTreeModelNode *parent_node = FindNode( parent );
c2489d8e
FM
4149 wxASSERT_MSG(parent_node,
4150 "Did you forget a call to ItemAdded()? The parent node is unknown to the wxGtkTreeModel");
4151
2056dede 4152 BuildBranch( parent_node );
55fbde12 4153
2056dede
RR
4154 iter->stamp = m_gtk_model->stamp;
4155 iter->user_data = parent_node->GetChildren().Item( n );
55fbde12 4156
2056dede
RR
4157 return TRUE;
4158 }
55fbde12
RR
4159}
4160
4161gboolean wxDataViewCtrlInternal::iter_parent( GtkTreeIter *iter, GtkTreeIter *child )
4162{
e39de702 4163 if (m_wx_model->IsVirtualListModel())
2056dede 4164 {
55fbde12 4165 return FALSE;
2056dede
RR
4166 }
4167 else
4168 {
4169 wxGtkTreeModelNode *node = FindParentNode( child );
4170 if (!node)
4171 return FALSE;
b9db5f30 4172
2056dede
RR
4173 iter->stamp = m_gtk_model->stamp;
4174 iter->user_data = (gpointer) node->GetItem().GetID();
55fbde12 4175
2056dede
RR
4176 return TRUE;
4177 }
55fbde12 4178}
b9db5f30 4179
74035a19 4180// item can be deleted already in the model
8650c4ba
RR
4181int wxDataViewCtrlInternal::GetIndexOf( const wxDataViewItem &parent, const wxDataViewItem &item )
4182{
559c42a5
RR
4183 if (m_wx_model->IsVirtualListModel())
4184 {
74035a19 4185 return wxPtrToUInt(item.GetID()) - 1;
559c42a5
RR
4186 }
4187 else
8650c4ba 4188 {
559c42a5
RR
4189 wxGtkTreeModelNode *parent_node = FindNode( parent );
4190 wxGtkTreeModelChildren &children = parent_node->GetChildren();
4191 size_t j;
4192 for (j = 0; j < children.GetCount(); j++)
4193 {
4194 if (children[j] == item.GetID())
4195 return j;
4196 }
8650c4ba
RR
4197 }
4198 return -1;
4199}
4200
4201
55fbde12 4202static wxGtkTreeModelNode*
69892729 4203wxDataViewCtrlInternal_FindNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item )
55fbde12 4204{
69892729
RR
4205 if( model == NULL )
4206 return NULL;
55fbde12 4207
69892729
RR
4208 ItemList list;
4209 list.DeleteContents( true );
4210 wxDataViewItem it( item );
b9db5f30 4211
69892729 4212 while( it.IsOk() )
55fbde12 4213 {
69892729
RR
4214 wxDataViewItem * pItem = new wxDataViewItem( it );
4215 list.Insert( pItem );
4216 it = model->GetParent( it );
4217 }
4218
4219 wxGtkTreeModelNode * node = treeNode;
966cb94d 4220 for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
69892729
RR
4221 {
4222 if( node && node->GetNodes().GetCount() != 0 )
ef427989 4223 {
69892729 4224 int len = node->GetNodes().GetCount();
8650c4ba 4225 wxGtkTreeModelNodes &nodes = node->GetNodes();
69892729
RR
4226 int j = 0;
4227 for( ; j < len; j ++)
4228 {
4229 if( nodes[j]->GetItem() == *(n->GetData()))
4230 {
4231 node = nodes[j];
4232 break;
b9db5f30 4233 }
69892729
RR
4234 }
4235
4236 if( j == len )
4237 {
4238 return NULL;
4239 }
ef427989 4240 }
69892729
RR
4241 else
4242 return NULL;
55fbde12 4243 }
69892729
RR
4244 return node;
4245
55fbde12
RR
4246}
4247
4248wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( GtkTreeIter *iter )
4249{
4250 if (!iter)
4251 return m_root;
4252
4253 wxDataViewItem item( (void*) iter->user_data );
0be79c8a
RR
4254 if (!item.IsOk())
4255 return m_root;
b9db5f30 4256
69892729 4257 wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
b9db5f30 4258
c2489d8e 4259/*
55fbde12
RR
4260 if (!result)
4261 {
26f119eb 4262 wxLogDebug( "Not found %p", iter->user_data );
55fbde12
RR
4263 char *crash = NULL;
4264 *crash = 0;
4265 }
c2489d8e
FM
4266 // TODO: remove this code
4267*/
b9db5f30 4268
55fbde12
RR
4269 return result;
4270}
4271
4272wxGtkTreeModelNode *wxDataViewCtrlInternal::FindNode( const wxDataViewItem &item )
4273{
0be79c8a
RR
4274 if (!item.IsOk())
4275 return m_root;
4276
69892729 4277 wxGtkTreeModelNode *result = wxDataViewCtrlInternal_FindNode( m_wx_model, m_root, item );
b9db5f30 4278
c2489d8e 4279/*
55fbde12
RR
4280 if (!result)
4281 {
26f119eb 4282 wxLogDebug( "Not found %p", item.GetID() );
55fbde12
RR
4283 char *crash = NULL;
4284 *crash = 0;
4285 }
c2489d8e
FM
4286 // TODO: remove this code
4287*/
b9db5f30 4288
55fbde12
RR
4289 return result;
4290}
4291
af110130 4292static wxGtkTreeModelNode*
69892729 4293wxDataViewCtrlInternal_FindParentNode( wxDataViewModel * model, wxGtkTreeModelNode *treeNode, const wxDataViewItem &item )
af110130 4294{
69892729
RR
4295 if( model == NULL )
4296 return NULL;
4297
4298 ItemList list;
4299 list.DeleteContents( true );
4300 if( !item.IsOk() )
4301 return NULL;
4302
4303 wxDataViewItem it( model->GetParent( item ) );
4304 while( it.IsOk() )
af110130 4305 {
69892729
RR
4306 wxDataViewItem * pItem = new wxDataViewItem( it );
4307 list.Insert( pItem );
4308 it = model->GetParent( it );
af110130
RR
4309 }
4310
69892729 4311 wxGtkTreeModelNode * node = treeNode;
966cb94d 4312 for( ItemList::compatibility_iterator n = list.GetFirst(); n; n = n->GetNext() )
af110130 4313 {
69892729 4314 if( node && node->GetNodes().GetCount() != 0 )
af110130 4315 {
69892729
RR
4316 int len = node->GetNodes().GetCount();
4317 wxGtkTreeModelNodes nodes = node->GetNodes();
4318 int j = 0;
4319 for( ; j < len; j ++)
4320 {
4321 if( nodes[j]->GetItem() == *(n->GetData()))
4322 {
4323 node = nodes[j];
4324 break;
b9db5f30 4325 }
69892729
RR
4326 }
4327
4328 if( j == len )
4329 {
4330 return NULL;
4331 }
af110130 4332 }
69892729
RR
4333 else
4334 return NULL;
4335 }
4336 //Examine whether the node is item's parent node
4337 int len = node->GetChildCount();
4338 for( int i = 0; i < len ; i ++ )
4339 {
4340 if( node->GetChildren().Item( i ) == item.GetID() )
4341 return node;
af110130 4342 }
af110130
RR
4343 return NULL;
4344}
4345
4346wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( GtkTreeIter *iter )
4347{
4348 if (!iter)
4349 return NULL;
b9db5f30 4350
af110130
RR
4351 wxDataViewItem item( (void*) iter->user_data );
4352 if (!item.IsOk())
4353 return NULL;
4354
69892729 4355 return wxDataViewCtrlInternal_FindParentNode( m_wx_model, m_root, item );
af110130
RR
4356}
4357
4358wxGtkTreeModelNode *wxDataViewCtrlInternal::FindParentNode( const wxDataViewItem &item )
4359{
4360 if (!item.IsOk())
4361 return NULL;
4362
69892729 4363 return wxDataViewCtrlInternal_FindParentNode( m_wx_model, m_root, item );
af110130
RR
4364}
4365
eb7f97f8
RR
4366//-----------------------------------------------------------------------------
4367// wxDataViewCtrl signal callbacks
4368//-----------------------------------------------------------------------------
4369
4370static void
ad386793 4371wxdataview_selection_changed_callback( GtkTreeSelection* WXUNUSED(selection), wxDataViewCtrl *dv )
eb7f97f8 4372{
fc9ab22a 4373 if (!gtk_widget_get_realized(dv->m_widget))
b94db696 4374 return;
f4322df6 4375
d86c1870 4376 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, dv->GetId() );
6848478c 4377 event.SetItem( dv->GetSelection() );
eb7f97f8 4378 event.SetModel( dv->GetModel() );
937013e0 4379 dv->HandleWindowEvent( event );
eb7f97f8
RR
4380}
4381
f828871d 4382static void
ad386793
RR
4383wxdataview_row_activated_callback( GtkTreeView* WXUNUSED(treeview), GtkTreePath *path,
4384 GtkTreeViewColumn *WXUNUSED(column), wxDataViewCtrl *dv )
f828871d 4385{
e0062c04 4386 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, dv->GetId() );
55fbde12 4387
17d98558 4388 wxDataViewItem item(dv->GTKPathToItem(path));
55fbde12 4389 event.SetItem( item );
f828871d 4390 event.SetModel( dv->GetModel() );
937013e0 4391 dv->HandleWindowEvent( event );
f828871d
RR
4392}
4393
718fd180 4394static gboolean
ad386793
RR
4395wxdataview_test_expand_row_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
4396 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
718fd180
RR
4397{
4398 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING, dv->GetId() );
4399
4400 wxDataViewItem item( (void*) iter->user_data );;
4401 event.SetItem( item );
4402 event.SetModel( dv->GetModel() );
937013e0 4403 dv->HandleWindowEvent( event );
b9db5f30 4404
718fd180
RR
4405 return !event.IsAllowed();
4406}
4407
4408static void
ad386793
RR
4409wxdataview_row_expanded_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
4410 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
718fd180
RR
4411{
4412 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED, dv->GetId() );
4413
4414 wxDataViewItem item( (void*) iter->user_data );;
4415 event.SetItem( item );
4416 event.SetModel( dv->GetModel() );
937013e0 4417 dv->HandleWindowEvent( event );
718fd180
RR
4418}
4419
4420static gboolean
ad386793
RR
4421wxdataview_test_collapse_row_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
4422 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
718fd180
RR
4423{
4424 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING, dv->GetId() );
4425
4426 wxDataViewItem item( (void*) iter->user_data );;
4427 event.SetItem( item );
4428 event.SetModel( dv->GetModel() );
937013e0 4429 dv->HandleWindowEvent( event );
b9db5f30 4430
718fd180
RR
4431 return !event.IsAllowed();
4432}
4433
4434static void
ad386793
RR
4435wxdataview_row_collapsed_callback( GtkTreeView* WXUNUSED(treeview), GtkTreeIter* iter,
4436 GtkTreePath *WXUNUSED(path), wxDataViewCtrl *dv )
718fd180
RR
4437{
4438 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED, dv->GetId() );
4439
4440 wxDataViewItem item( (void*) iter->user_data );;
4441 event.SetItem( item );
4442 event.SetModel( dv->GetModel() );
937013e0 4443 dv->HandleWindowEvent( event );
718fd180
RR
4444}
4445
790b137e 4446//-----------------------------------------------------------------------------
718fd180 4447 // wxDataViewCtrl
790b137e
RR
4448//-----------------------------------------------------------------------------
4449
48200154 4450void wxDataViewCtrl::AddChildGTK(wxWindowGTK* child)
1e510b1e 4451{
48200154 4452 GtkWidget* treeview = GtkGetTreeView();
1e510b1e
RR
4453
4454 // Insert widget in GtkTreeView
fc9ab22a 4455 if (gtk_widget_get_realized(treeview))
e8375af8 4456 gtk_widget_set_parent_window( child->m_widget,
1e510b1e
RR
4457 gtk_tree_view_get_bin_window( GTK_TREE_VIEW(treeview) ) );
4458 gtk_widget_set_parent( child->m_widget, treeview );
4459}
4460
4461static
4462void gtk_dataviewctrl_size_callback( GtkWidget *WXUNUSED(widget),
ad386793 4463 GtkAllocation *WXUNUSED(gtk_alloc),
1e510b1e
RR
4464 wxDataViewCtrl *win )
4465{
966cb94d 4466 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
1e510b1e
RR
4467 while (node)
4468 {
4469 wxWindow *child = node->GetData();
e8375af8 4470
1e510b1e
RR
4471 GtkRequisition req;
4472 gtk_widget_size_request( child->m_widget, &req );
e8375af8 4473
1e510b1e
RR
4474 GtkAllocation alloc;
4475 alloc.x = child->m_x;
4476 alloc.y = child->m_y;
4477 alloc.width = child->m_width;
4478 alloc.height = child->m_height;
4479 gtk_widget_size_allocate( child->m_widget, &alloc );
e8375af8 4480
1e510b1e
RR
4481 node = node->GetNext();
4482 }
4483}
4484
4485
6608fdab
RR
4486//-----------------------------------------------------------------------------
4487// "motion_notify_event"
4488//-----------------------------------------------------------------------------
4489
4490static gboolean
ad386793 4491gtk_dataview_motion_notify_callback( GtkWidget *WXUNUSED(widget),
74dea0de
RR
4492 GdkEventMotion *gdk_event,
4493 wxDataViewCtrl *dv )
6608fdab
RR
4494{
4495 if (gdk_event->is_hint)
4496 {
4497 int x = 0;
4498 int y = 0;
4499 GdkModifierType state;
4500 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
4501 gdk_event->x = x;
4502 gdk_event->y = y;
4503 }
4504
0c2a7270 4505 wxGtkTreePath path;
6608fdab
RR
4506 GtkTreeViewColumn *column = NULL;
4507 gint cell_x = 0;
4508 gint cell_y = 0;
b9db5f30 4509 if (gtk_tree_view_get_path_at_pos(
6608fdab
RR
4510 GTK_TREE_VIEW(dv->GtkGetTreeView()),
4511 (int) gdk_event->x, (int) gdk_event->y,
0c2a7270 4512 path.ByRef(),
6608fdab
RR
4513 &column,
4514 &cell_x,
4515 &cell_y))
4516 {
4517 if (path)
4518 {
4519 GtkTreeIter iter;
4520 dv->GtkGetInternal()->get_iter( &iter, path );
6608fdab
RR
4521 }
4522 }
4523
4524
4525 return FALSE;
4526}
4527
74dea0de
RR
4528//-----------------------------------------------------------------------------
4529// "button_press_event"
4530//-----------------------------------------------------------------------------
4531
4532static gboolean
4533gtk_dataview_button_press_callback( GtkWidget *WXUNUSED(widget),
4534 GdkEventButton *gdk_event,
4535 wxDataViewCtrl *dv )
4536{
4537 if ((gdk_event->button == 3) && (gdk_event->type == GDK_BUTTON_PRESS))
4538 {
0c2a7270 4539 wxGtkTreePath path;
74dea0de
RR
4540 GtkTreeViewColumn *column = NULL;
4541 gint cell_x = 0;
4542 gint cell_y = 0;
4543 if (gtk_tree_view_get_path_at_pos(
4544 GTK_TREE_VIEW(dv->GtkGetTreeView()),
4545 (int) gdk_event->x, (int) gdk_event->y,
0c2a7270 4546 path.ByRef(),
74dea0de
RR
4547 &column,
4548 &cell_x,
4549 &cell_y))
4550 {
4551 if (path)
4552 {
74dea0de 4553 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, dv->GetId() );
17d98558 4554 event.SetItem(dv->GTKPathToItem(path));
74dea0de 4555 event.SetModel( dv->GetModel() );
0c2a7270 4556 return dv->HandleWindowEvent( event );
74dea0de
RR
4557 }
4558 }
4559 }
4560
4561 return FALSE;
4562}
1e510b1e 4563
239eaa41
RR
4564IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
4565
4566wxDataViewCtrl::~wxDataViewCtrl()
4567{
b2fd3bea
VZ
4568 // Stop editing before destroying the control to remove any event handlers
4569 // which are added when editing started: if we didn't do this, the base
4570 // class dtor would assert as it checks for any leftover handlers.
4571 if ( m_treeview )
4572 {
4573 GtkTreeViewColumn *col;
4574 gtk_tree_view_get_cursor(GTK_TREE_VIEW(m_treeview), NULL, &col);
4575
4576 wxDataViewColumn * const wxcol = FromGTKColumn(col);
4577 if ( wxcol )
4578 {
4579 // This won't do anything if we're not editing it
4580 wxcol->GetRenderer()->CancelEditing();
4581 }
4582 }
4583
ef11ea71
RR
4584 m_cols.Clear();
4585
55fbde12 4586 delete m_internal;
239eaa41
RR
4587}
4588
4589void wxDataViewCtrl::Init()
4590{
33ba5a05 4591 m_internal = NULL;
bc0289bf 4592
ef11ea71 4593 m_cols.DeleteContents( true );
0f4a54a6
VZ
4594
4595 m_uniformRowHeight = -1;
239eaa41
RR
4596}
4597
62e9285a
VZ
4598bool wxDataViewCtrl::Create(wxWindow *parent,
4599 wxWindowID id,
4600 const wxPoint& pos,
4601 const wxSize& size,
4602 long style,
4603 const wxValidator& validator,
4604 const wxString& name)
239eaa41 4605{
239eaa41 4606 if (!PreCreation( parent, pos, size ) ||
62e9285a 4607 !CreateBase( parent, id, pos, size, style, validator, name ))
239eaa41
RR
4608 {
4609 wxFAIL_MSG( wxT("wxDataViewCtrl creation failed") );
93763ad5 4610 return false;
239eaa41 4611 }
1a367564
RR
4612
4613 m_widget = gtk_scrolled_window_new (NULL, NULL);
9ff9d30c 4614 g_object_ref(m_widget);
6493aaca 4615
496e7ec6 4616 GTKScrolledWindowSetBorder(m_widget, style);
1a367564
RR
4617
4618 m_treeview = gtk_tree_view_new();
4619 gtk_container_add (GTK_CONTAINER (m_widget), m_treeview);
e8375af8 4620
1e510b1e
RR
4621 g_signal_connect (m_treeview, "size_allocate",
4622 G_CALLBACK (gtk_dataviewctrl_size_callback), this);
ed4b0fdc 4623
b94db696
RR
4624#ifdef __WXGTK26__
4625 if (!gtk_check_version(2,6,0))
344ed1f3
RR
4626 {
4627 bool fixed = (style & wxDV_VARIABLE_LINE_HEIGHT) == 0;
4628 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), fixed );
4629 }
b94db696
RR
4630#endif
4631
daebb44c
RR
4632 if (style & wxDV_MULTIPLE)
4633 {
4634 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4635 gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
4636 }
93763ad5 4637
9861f022
RR
4638 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(m_treeview), (style & wxDV_NO_HEADER) == 0 );
4639
4640#ifdef __WXGTK210__
4641 if (!gtk_check_version(2,10,0))
4642 {
4643 GtkTreeViewGridLines grid = GTK_TREE_VIEW_GRID_LINES_NONE;
f4322df6
VZ
4644
4645 if ((style & wxDV_HORIZ_RULES) != 0 &&
9861f022
RR
4646 (style & wxDV_VERT_RULES) != 0)
4647 grid = GTK_TREE_VIEW_GRID_LINES_BOTH;
4648 else if (style & wxDV_VERT_RULES)
4649 grid = GTK_TREE_VIEW_GRID_LINES_VERTICAL;
4650 else if (style & wxDV_HORIZ_RULES)
4651 grid = GTK_TREE_VIEW_GRID_LINES_HORIZONTAL;
4652
1a07a730
RR
4653 if (grid != GTK_TREE_VIEW_GRID_LINES_NONE)
4654 gtk_tree_view_set_grid_lines( GTK_TREE_VIEW(m_treeview), grid );
9861f022 4655 }
9861f022 4656#endif
1a07a730
RR
4657
4658 gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(m_treeview), (style & wxDV_ROW_LINES) != 0 );
9861f022 4659
1a367564 4660 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_widget),
16eab2e1 4661 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1a367564 4662 gtk_widget_show (m_treeview);
93763ad5 4663
239eaa41
RR
4664 m_parent->DoAddChild( this );
4665
b94db696
RR
4666 PostCreation(size);
4667
b086d55f
RR
4668 GtkEnableSelectionEvents();
4669
718fd180 4670 g_signal_connect_after (m_treeview, "row-activated",
f828871d 4671 G_CALLBACK (wxdataview_row_activated_callback), this);
eb7f97f8 4672
718fd180
RR
4673 g_signal_connect (m_treeview, "test-collapse-row",
4674 G_CALLBACK (wxdataview_test_collapse_row_callback), this);
4675
4676 g_signal_connect_after (m_treeview, "row-collapsed",
4677 G_CALLBACK (wxdataview_row_collapsed_callback), this);
4678
4679 g_signal_connect (m_treeview, "test-expand-row",
4680 G_CALLBACK (wxdataview_test_expand_row_callback), this);
b9db5f30 4681
718fd180
RR
4682 g_signal_connect_after (m_treeview, "row-expanded",
4683 G_CALLBACK (wxdataview_row_expanded_callback), this);
4684
6608fdab
RR
4685 g_signal_connect (m_treeview, "motion_notify_event",
4686 G_CALLBACK (gtk_dataview_motion_notify_callback), this);
4687
74dea0de
RR
4688 g_signal_connect (m_treeview, "button_press_event",
4689 G_CALLBACK (gtk_dataview_button_press_callback), this);
7857346a 4690
239eaa41
RR
4691 return true;
4692}
4693
17d98558
VZ
4694wxDataViewItem wxDataViewCtrl::GTKPathToItem(GtkTreePath *path) const
4695{
4696 GtkTreeIter iter;
4697 return wxDataViewItem(path && m_internal->get_iter(&iter, path)
4698 ? iter.user_data
4699 : NULL);
4700}
4701
31fb32e1
RR
4702void wxDataViewCtrl::OnInternalIdle()
4703{
4704 wxWindow::OnInternalIdle();
ce00f59b 4705
d8090b5e 4706 m_internal->OnInternalIdle();
f4322df6 4707
9861f022 4708 unsigned int cols = GetColumnCount();
31fb32e1
RR
4709 unsigned int i;
4710 for (i = 0; i < cols; i++)
4711 {
4712 wxDataViewColumn *col = GetColumn( i );
4713 col->OnInternalIdle();
4714 }
ce00f59b 4715
3f53dd3a
RR
4716 if (m_ensureVisibleDefered.IsOk())
4717 {
4718 ExpandAncestors(m_ensureVisibleDefered);
4719 GtkTreeIter iter;
4720 iter.user_data = (gpointer) m_ensureVisibleDefered.GetID();
4721 wxGtkTreePath path(m_internal->get_path( &iter ));
4722 gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW(m_treeview), path, NULL, false, 0.0, 0.0 );
4723 m_ensureVisibleDefered = wxDataViewItem(0);
4724 }
31fb32e1
RR
4725}
4726
e0062c04 4727bool wxDataViewCtrl::AssociateModel( wxDataViewModel *model )
239eaa41 4728{
5276b0a5 4729 wxDELETE(m_internal);
7857346a 4730
239eaa41
RR
4731 if (!wxDataViewCtrlBase::AssociateModel( model ))
4732 return false;
4733
344ed1f3
RR
4734#ifdef __WXGTK26__
4735 if (!gtk_check_version(2,6,0))
4736 {
4737 bool fixed = (((GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT) == 0) || (model->IsVirtualListModel()));
4738 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), fixed );
4739 }
4740#endif
4741
673810ee 4742 m_internal = new wxDataViewCtrlInternal( this, model );
93763ad5 4743
239eaa41
RR
4744 return true;
4745}
790b137e 4746
15cac64f
RR
4747bool wxDataViewCtrl::EnableDragSource( const wxDataFormat &format )
4748{
4749 return m_internal->EnableDragSource( format );
4750}
4751
e4de825e
RR
4752bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat &format )
4753{
4754 return m_internal->EnableDropTarget( format );
4755}
4756
fa28826d
RR
4757bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
4758{
4759 if (!wxDataViewCtrlBase::AppendColumn(col))
4760 return false;
93763ad5 4761
91a6c655
RR
4762 m_cols.Append( col );
4763
ad386793
RR
4764#ifdef __WXGTK26__
4765 if (!gtk_check_version(2,6,0))
4766 {
4767 if (gtk_tree_view_column_get_sizing( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) ) !=
4768 GTK_TREE_VIEW_COLUMN_FIXED)
4769 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), FALSE );
4770 }
4771#endif
4772
b9db5f30 4773 gtk_tree_view_append_column( GTK_TREE_VIEW(m_treeview),
91a6c655
RR
4774 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) );
4775
4776 return true;
4777}
4778
736fe67c
RR
4779bool wxDataViewCtrl::PrependColumn( wxDataViewColumn *col )
4780{
4781 if (!wxDataViewCtrlBase::PrependColumn(col))
4782 return false;
4783
4784 m_cols.Insert( col );
4785
ad386793
RR
4786#ifdef __WXGTK26__
4787 if (!gtk_check_version(2,6,0))
4788 {
4789 if (gtk_tree_view_column_get_sizing( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) ) !=
4790 GTK_TREE_VIEW_COLUMN_FIXED)
4791 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), FALSE );
4792 }
4793#endif
4794
b9db5f30 4795 gtk_tree_view_insert_column( GTK_TREE_VIEW(m_treeview),
736fe67c
RR
4796 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()), 0 );
4797
4798 return true;
4799}
4800
19723525
RR
4801bool wxDataViewCtrl::InsertColumn( unsigned int pos, wxDataViewColumn *col )
4802{
4803 if (!wxDataViewCtrlBase::InsertColumn(pos,col))
4804 return false;
4805
4806 m_cols.Insert( pos, col );
4807
4808#ifdef __WXGTK26__
4809 if (!gtk_check_version(2,6,0))
4810 {
4811 if (gtk_tree_view_column_get_sizing( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) ) !=
4812 GTK_TREE_VIEW_COLUMN_FIXED)
4813 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview), FALSE );
4814 }
4815#endif
4816
4817 gtk_tree_view_insert_column( GTK_TREE_VIEW(m_treeview),
4818 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()), pos );
4819
4820 return true;
4821}
4822
91a6c655
RR
4823unsigned int wxDataViewCtrl::GetColumnCount() const
4824{
4825 return m_cols.GetCount();
4826}
4827
b2fd3bea 4828wxDataViewColumn* wxDataViewCtrl::FromGTKColumn(GtkTreeViewColumn *gtk_col) const
91a6c655 4829{
b2fd3bea 4830 if ( !gtk_col )
91a6c655 4831 return NULL;
b9db5f30 4832
91a6c655 4833 wxDataViewColumnList::const_iterator iter;
ef11ea71 4834 for (iter = m_cols.begin(); iter != m_cols.end(); ++iter)
91a6c655
RR
4835 {
4836 wxDataViewColumn *col = *iter;
4837 if (GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) == gtk_col)
4838 {
4839 return col;
4840 }
4841 }
b9db5f30 4842
b2fd3bea
VZ
4843 wxFAIL_MSG( "No matching column?" );
4844
91a6c655
RR
4845 return NULL;
4846}
4847
b2fd3bea
VZ
4848wxDataViewColumn* wxDataViewCtrl::GetColumn( unsigned int pos ) const
4849{
4850 GtkTreeViewColumn *gtk_col = gtk_tree_view_get_column( GTK_TREE_VIEW(m_treeview), pos );
4851
4852 return FromGTKColumn(gtk_col);
4853}
4854
91a6c655
RR
4855bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column )
4856{
b9db5f30 4857 gtk_tree_view_remove_column( GTK_TREE_VIEW(m_treeview),
91a6c655
RR
4858 GTK_TREE_VIEW_COLUMN(column->GetGtkHandle()) );
4859
ef11ea71 4860 m_cols.DeleteObject( column );
fa28826d
RR
4861
4862 return true;
4863}
4864
91a6c655
RR
4865bool wxDataViewCtrl::ClearColumns()
4866{
4867 wxDataViewColumnList::iterator iter;
ef11ea71 4868 for (iter = m_cols.begin(); iter != m_cols.end(); ++iter)
91a6c655
RR
4869 {
4870 wxDataViewColumn *col = *iter;
b9db5f30 4871 gtk_tree_view_remove_column( GTK_TREE_VIEW(m_treeview),
91a6c655
RR
4872 GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) );
4873 }
b9db5f30 4874
ef11ea71 4875 m_cols.Clear();
b9db5f30 4876
91a6c655
RR
4877 return true;
4878}
4879
453091c2
RR
4880int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const
4881{
b3a8aa92 4882 GtkTreeViewColumn *gtk_column = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle());
aed836f3 4883
0eec47e4 4884 wxGtkList list(gtk_tree_view_get_columns(GTK_TREE_VIEW(m_treeview)));
b9db5f30 4885
0eec47e4 4886 return g_list_index( list, (gconstpointer) gtk_column );
453091c2
RR
4887}
4888
21f47fb9
RR
4889wxDataViewColumn *wxDataViewCtrl::GetSortingColumn() const
4890{
d32332aa 4891 return m_internal->GetDataViewSortColumn();
21f47fb9
RR
4892}
4893
f71d3ba4
RR
4894void wxDataViewCtrl::Expand( const wxDataViewItem & item )
4895{
4896 GtkTreeIter iter;
4897 iter.user_data = item.GetID();
0c2a7270 4898 wxGtkTreePath path(m_internal->get_path( &iter ));
f71d3ba4 4899 gtk_tree_view_expand_row( GTK_TREE_VIEW(m_treeview), path, false );
f71d3ba4
RR
4900}
4901
4902void wxDataViewCtrl::Collapse( const wxDataViewItem & item )
4903{
4904 GtkTreeIter iter;
4905 iter.user_data = item.GetID();
0c2a7270 4906 wxGtkTreePath path(m_internal->get_path( &iter ));
f71d3ba4 4907 gtk_tree_view_collapse_row( GTK_TREE_VIEW(m_treeview), path );
739a8399
RR
4908}
4909
4910bool wxDataViewCtrl::IsExpanded( const wxDataViewItem & item ) const
4911{
4912 GtkTreeIter iter;
4913 iter.user_data = item.GetID();
0c2a7270
VZ
4914 wxGtkTreePath path(m_internal->get_path( &iter ));
4915 return gtk_tree_view_row_expanded( GTK_TREE_VIEW(m_treeview), path );
f71d3ba4
RR
4916}
4917
80ce465c
VZ
4918wxDataViewItem wxDataViewCtrl::DoGetCurrentItem() const
4919{
4920 // The tree doesn't have any current item if it hadn't been created yet but
4921 // it's arguably not an error to call this function in this case so just
4922 // return an invalid item without asserting.
4923 if ( !m_treeview )
4924 return wxDataViewItem();
4925
4926 wxGtkTreePath path;
4927 gtk_tree_view_get_cursor(GTK_TREE_VIEW(m_treeview), path.ByRef(), NULL);
4928
4929 return GTKPathToItem(path);
4930}
4931
4932void wxDataViewCtrl::DoSetCurrentItem(const wxDataViewItem& item)
4933{
4934 wxCHECK_RET( m_treeview,
4935 "Current item can't be set before creating the control." );
4936
4937 // We need to make sure the model knows about this item or the path would
4938 // be invalid and gtk_tree_view_set_cursor() would silently do nothing.
4939 ExpandAncestors(item);
4940
4941 // We also need to preserve the existing selection from changing.
4942 // Unfortunately the only way to do it seems to use our own selection
4943 // function and forbid any selection changes during set cursor call.
4944 wxGtkTreeSelectionLock
4945 lock(gtk_tree_view_get_selection(GTK_TREE_VIEW(m_treeview)));
4946
4947 // Do move the cursor now.
4948 GtkTreeIter iter;
4949 iter.user_data = item.GetID();
4950 wxGtkTreePath path(m_internal->get_path( &iter ));
4951
4952 gtk_tree_view_set_cursor(GTK_TREE_VIEW(m_treeview), path, NULL, FALSE);
4953}
4954
eeea3b03
RD
4955void wxDataViewCtrl::StartEditor(const wxDataViewItem& item, unsigned int column)
4956{
4957 wxCHECK_RET( m_treeview,
4958 "Current item can't be set before creating the control." );
4959
4960 // We need to make sure the model knows about this item or the path would
4961 // be invalid and gtk_tree_view_set_cursor() would silently do nothing.
4962 ExpandAncestors(item);
4963
4964 wxDataViewColumn *dvcolumn = GetColumn(column);
4965 wxASSERT_MSG(dvcolumn, "Could not retrieve column");
4966 GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(dvcolumn->GetGtkHandle());
4967
4968 // We also need to preserve the existing selection from changing.
4969 // Unfortunately the only way to do it seems to use our own selection
4970 // function and forbid any selection changes during set cursor call.
4971 wxGtkTreeSelectionLock
4972 lock(gtk_tree_view_get_selection(GTK_TREE_VIEW(m_treeview)));
4973
4974 // Do move the cursor now.
4975 GtkTreeIter iter;
4976 iter.user_data = item.GetID();
4977 wxGtkTreePath path(m_internal->get_path( &iter ));
4978
4979 gtk_tree_view_set_cursor(GTK_TREE_VIEW(m_treeview), path, gcolumn, TRUE);
4980}
4981
fa93d732 4982int wxDataViewCtrl::GetSelectedItemsCount() const
1e08ad10
RR
4983{
4984 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
b9db5f30 4985
fa93d732 4986 return gtk_tree_selection_count_selected_rows(selection);
1e08ad10
RR
4987}
4988
718fd180
RR
4989int wxDataViewCtrl::GetSelections( wxDataViewItemArray & sel ) const
4990{
6848478c
RR
4991 sel.Clear();
4992
4993 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
4994 if (HasFlag(wxDV_MULTIPLE))
4995 {
4996 GtkTreeModel *model;
0eec47e4 4997 wxGtkTreePathList list(gtk_tree_selection_get_selected_rows(selection, &model));
6848478c 4998
0eec47e4 4999 for ( GList* current = list; current; current = g_list_next(current) )
6848478c 5000 {
fa93d732 5001 GtkTreePath *path = (GtkTreePath*) current->data;
b9db5f30 5002
17d98558 5003 sel.Add(GTKPathToItem(path));
6848478c 5004 }
6848478c
RR
5005 }
5006 else
5007 {
6848478c 5008 GtkTreeIter iter;
fa93d732 5009 if (gtk_tree_selection_get_selected( selection, NULL, &iter ))
6848478c 5010 {
fa93d732 5011 sel.Add( wxDataViewItem(iter.user_data) );
6848478c
RR
5012 }
5013 }
5014
fa93d732 5015 return sel.size();
718fd180
RR
5016}
5017
5018void wxDataViewCtrl::SetSelections( const wxDataViewItemArray & sel )
5019{
6848478c 5020 GtkDisableSelectionEvents();
b9db5f30 5021
6848478c
RR
5022 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5023
5024 gtk_tree_selection_unselect_all( selection );
b9db5f30 5025
4219d8b0
RR
5026 wxDataViewItem last_parent;
5027
6848478c
RR
5028 size_t i;
5029 for (i = 0; i < sel.GetCount(); i++)
5030 {
4219d8b0
RR
5031 wxDataViewItem item = sel[i];
5032 wxDataViewItem parent = GetModel()->GetParent( item );
5033 if (parent)
5034 {
5035 if (parent != last_parent)
5036 ExpandAncestors(item);
5037 }
5038 last_parent = parent;
5039
6848478c 5040 GtkTreeIter iter;
0e50223f 5041 iter.stamp = m_internal->GetGtkModel()->stamp;
4219d8b0 5042 iter.user_data = (gpointer) item.GetID();
6848478c
RR
5043 gtk_tree_selection_select_iter( selection, &iter );
5044 }
b9db5f30 5045
6848478c 5046 GtkEnableSelectionEvents();
718fd180
RR
5047}
5048
5049void wxDataViewCtrl::Select( const wxDataViewItem & item )
5050{
4219d8b0
RR
5051 ExpandAncestors(item);
5052
6848478c
RR
5053 GtkDisableSelectionEvents();
5054
5055 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5056
5057 GtkTreeIter iter;
0e50223f 5058 iter.stamp = m_internal->GetGtkModel()->stamp;
6848478c
RR
5059 iter.user_data = (gpointer) item.GetID();
5060 gtk_tree_selection_select_iter( selection, &iter );
5061
5062 GtkEnableSelectionEvents();
718fd180
RR
5063}
5064
5065void wxDataViewCtrl::Unselect( const wxDataViewItem & item )
5066{
6848478c
RR
5067 GtkDisableSelectionEvents();
5068
5069 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5070
5071 GtkTreeIter iter;
0e50223f 5072 iter.stamp = m_internal->GetGtkModel()->stamp;
6848478c
RR
5073 iter.user_data = (gpointer) item.GetID();
5074 gtk_tree_selection_unselect_iter( selection, &iter );
5075
5076 GtkEnableSelectionEvents();
718fd180
RR
5077}
5078
5079bool wxDataViewCtrl::IsSelected( const wxDataViewItem & item ) const
5080{
6848478c
RR
5081 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
5082
5083 GtkTreeIter iter;
0e50223f 5084 iter.stamp = m_internal->GetGtkModel()->stamp;
6848478c 5085 iter.user_data = (gpointer) item.GetID();
b9db5f30 5086
6848478c 5087 return gtk_tree_selection_iter_is_selected( selection, &iter );
718fd180
RR
5088}
5089
5090void wxDataViewCtrl::SelectAll()
5091{
6848478c 5092 GtkDisableSelectionEvents();
b9db5f30 5093
6848478c 5094 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
b9db5f30 5095
6848478c 5096 gtk_tree_selection_select_all( selection );
b9db5f30 5097
6848478c 5098 GtkEnableSelectionEvents();
718fd180
RR
5099}
5100
5101void wxDataViewCtrl::UnselectAll()
5102{
6848478c 5103 GtkDisableSelectionEvents();
b9db5f30 5104
6848478c 5105 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
b9db5f30 5106
6848478c 5107 gtk_tree_selection_unselect_all( selection );
b9db5f30 5108
6848478c 5109 GtkEnableSelectionEvents();
718fd180
RR
5110}
5111
7857346a 5112void wxDataViewCtrl::EnsureVisible(const wxDataViewItem& item,
4219d8b0 5113 const wxDataViewColumn *WXUNUSED(column))
718fd180 5114{
3f53dd3a 5115 m_ensureVisibleDefered = item;
4219d8b0 5116 ExpandAncestors(item);
a881f34e 5117
6154212e
RR
5118 GtkTreeIter iter;
5119 iter.user_data = (gpointer) item.GetID();
0c2a7270 5120 wxGtkTreePath path(m_internal->get_path( &iter ));
6154212e 5121 gtk_tree_view_scroll_to_cell( GTK_TREE_VIEW(m_treeview), path, NULL, false, 0.0, 0.0 );
718fd180
RR
5122}
5123
cd771560 5124void wxDataViewCtrl::HitTest(const wxPoint& point,
7857346a
VZ
5125 wxDataViewItem& item,
5126 wxDataViewColumn *& column) const
66e09788 5127{
cd771560
RR
5128 // gtk_tree_view_get_dest_row_at_pos() is the right one. But it does not tell the column.
5129 // gtk_tree_view_get_path_at_pos() is the wrong function. It doesn't mind the header but returns column.
5130 // See http://mail.gnome.org/archives/gtkmm-list/2005-January/msg00080.html
5131 // So we have to use both of them.
5132 // Friedrich Haase 2010-9-20
5133 wxGtkTreePath path, pathScratch;
5134 GtkTreeViewColumn* GtkColumn = NULL;
5135 GtkTreeViewDropPosition pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
5136 gint cell_x = 0;
5137 gint cell_y = 0;
5138
5139 // cannot directly call GtkGetTreeView(), HitTest is const and so is this pointer
5140 wxDataViewCtrl* ctrl = (wxDataViewCtrl*)this; // ugly workaround, ctrl is NOT const
5141 GtkTreeView* treeView = GTK_TREE_VIEW(ctrl->GtkGetTreeView());
5142
5143 // is there possibly a better suited function to get the column?
5144 gtk_tree_view_get_path_at_pos( // and this is the wrong call but it delivers the column
5145 treeView,
5146 (int) point.x, (int) point.y,
5147 pathScratch.ByRef(),
5148 &GtkColumn, // here we get the GtkColumn
5149 &cell_x,
5150 &cell_y );
5151
5152 if ( GtkColumn != NULL )
5153 {
5154 // we got GTK column
5155 // the right call now which takes the header into account
5156 gtk_tree_view_get_dest_row_at_pos( treeView, (int) point.x, (int) point.y, path.ByRef(), &pos);
5157
5158 if (path)
5159 item = wxDataViewItem(GTKPathToItem(path));
5160 // else we got a GTK column but the position is not over an item, e.g. below last item
5161 for ( unsigned int i=0, cols=GetColumnCount(); i<cols; ++i ) // search the wx column
5162 {
5163 wxDataViewColumn* col = GetColumn(i);
5164 if ( GTK_TREE_VIEW_COLUMN(col->GetGtkHandle()) == GtkColumn )
5165 {
5166 column = col; // here we get the wx column
5167 break;
5168 }
5169 }
5170 }
5171 // else no column and thus no item, both null
66e09788
RR
5172}
5173
7857346a
VZ
5174wxRect
5175wxDataViewCtrl::GetItemRect(const wxDataViewItem& WXUNUSED(item),
5176 const wxDataViewColumn *WXUNUSED(column)) const
66e09788
RR
5177{
5178 return wxRect();
5179}
5180
0f4a54a6
VZ
5181bool wxDataViewCtrl::SetRowHeight(int rowHeight)
5182{
5183 m_uniformRowHeight = rowHeight;
5184 return true;
5185}
5186
3b6280be
RR
5187void wxDataViewCtrl::DoSetExpanderColumn()
5188{
b9db5f30 5189 gtk_tree_view_set_expander_column( GTK_TREE_VIEW(m_treeview),
1b27b2bd 5190 GTK_TREE_VIEW_COLUMN( GetExpanderColumn()->GetGtkHandle() ) );
3b6280be
RR
5191}
5192
5193void wxDataViewCtrl::DoSetIndent()
5194{
5195}
5196
b086d55f
RR
5197void wxDataViewCtrl::GtkDisableSelectionEvents()
5198{
5199 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
6848478c
RR
5200 g_signal_handlers_disconnect_by_func( selection,
5201 (gpointer) (wxdataview_selection_changed_callback), this);
b086d55f
RR
5202}
5203
5204void wxDataViewCtrl::GtkEnableSelectionEvents()
5205{
5206 GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) );
6848478c
RR
5207 g_signal_connect_after (selection, "changed",
5208 G_CALLBACK (wxdataview_selection_changed_callback), this);
b086d55f
RR
5209}
5210
ddb44248
VZ
5211// ----------------------------------------------------------------------------
5212// visual attributes stuff
5213// ----------------------------------------------------------------------------
5214
b94db696
RR
5215// static
5216wxVisualAttributes
5217wxDataViewCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
5218{
5219 return GetDefaultAttributesFromGTKWidget(gtk_tree_view_new);
5220}
5221
ddb44248
VZ
5222void wxDataViewCtrl::DoApplyWidgetStyle(GtkRcStyle *style)
5223{
5224 wxDataViewCtrlBase::DoApplyWidgetStyle(style);
5225 gtk_widget_modify_style(m_treeview, style);
5226}
6ff7eee7 5227
ddb44248 5228#endif // !wxUSE_GENERICDATAVIEWCTRL
790b137e 5229
ddb44248 5230#endif // wxUSE_DATAVIEWCTRL