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