]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/dataview.cpp
8dc3eccca7559f8caaba7f131732bc47de6ef494
[wxWidgets.git] / src / gtk / dataview.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dataview.cpp
3 // Purpose: wxDataViewCtrl GTK+2 implementation
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #include "wx/defs.h"
14
15 #if wxUSE_DATAVIEWCTRL
16
17 #include "wx/dataview.h"
18 #include "wx/stockitem.h"
19
20 #include "wx/gtk/private.h"
21 #include "wx/gtk/win_gtk.h"
22
23 #include <gobject/gvaluecollector.h>
24 #include "gtktreemodel.h"
25 #include "gtktreedatalist.h"
26 #include "gtktreednd.h"
27
28 //-----------------------------------------------------------------------------
29 // classes
30 //-----------------------------------------------------------------------------
31
32 class wxDataViewCtrl;
33
34 //-----------------------------------------------------------------------------
35 // idle system
36 //-----------------------------------------------------------------------------
37
38 extern void wxapp_install_idle_handler();
39 extern bool g_isIdle;
40
41 //-----------------------------------------------------------------------------
42 // data
43 //-----------------------------------------------------------------------------
44
45 extern bool g_blockEventsOnDrag;
46
47 //-----------------------------------------------------------------------------
48 // define new GTK+ class wxGtkListStore
49 //-----------------------------------------------------------------------------
50
51 extern "C" {
52
53 #define GTK_TYPE_WX_LIST_STORE (gtk_wx_list_store_get_type ())
54 #define GTK_WX_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_LIST_STORE, GtkWxListStore))
55 #define GTK_WX_LIST_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_LIST_STORE, GtkWxListStoreClass))
56 #define GTK_IS_WX_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_LIST_STORE))
57 #define GTK_IS_WX_LIST_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_LIST_STORE))
58 #define GTK_WX_LIST_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_LIST_STORE, GtkWxListStoreClass))
59
60 GType gtk_wx_list_store_get_type (void);
61
62 typedef struct _GtkWxListStore GtkWxListStore;
63 typedef struct _GtkWxListStoreClass GtkWxListStoreClass;
64
65 struct _GtkWxListStore
66 {
67 GObject parent;
68
69 /*< private >*/
70 gint stamp;
71 wxDataViewListModel *model;
72 };
73
74 struct _GtkWxListStoreClass
75 {
76 GObjectClass parent_class;
77
78 };
79
80 static void wxgtk_list_store_init (GtkWxListStore *list_store);
81 static void wxgtk_list_store_class_init (GtkWxListStoreClass *class);
82 static void wxgtk_list_store_tree_model_init (GtkTreeModelIface *iface);
83 static void wxgtk_list_store_finalize (GObject *object);
84 static GtkTreeModelFlags wxgtk_list_store_get_flags (GtkTreeModel *tree_model);
85 static gint wxgtk_list_store_get_n_columns (GtkTreeModel *tree_model);
86 static GType wxgtk_list_store_get_column_type (GtkTreeModel *tree_model,
87 gint index);
88 static gboolean wxgtk_list_store_get_iter (GtkTreeModel *tree_model,
89 GtkTreeIter *iter,
90 GtkTreePath *path);
91 static GtkTreePath *wxgtk_list_store_get_path (GtkTreeModel *tree_model,
92 GtkTreeIter *iter);
93 static void wxgtk_list_store_get_value (GtkTreeModel *tree_model,
94 GtkTreeIter *iter,
95 gint column,
96 GValue *value);
97 static gboolean wxgtk_list_store_iter_next (GtkTreeModel *tree_model,
98 GtkTreeIter *iter);
99 static gboolean wxgtk_list_store_iter_children (GtkTreeModel *tree_model,
100 GtkTreeIter *iter,
101 GtkTreeIter *parent);
102 static gboolean wxgtk_list_store_iter_has_child (GtkTreeModel *tree_model,
103 GtkTreeIter *iter);
104 static gint wxgtk_list_store_iter_n_children (GtkTreeModel *tree_model,
105 GtkTreeIter *iter);
106 static gboolean wxgtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
107 GtkTreeIter *iter,
108 GtkTreeIter *parent,
109 gint n);
110 static gboolean wxgtk_list_store_iter_parent (GtkTreeModel *tree_model,
111 GtkTreeIter *iter,
112 GtkTreeIter *child);
113
114 static void gtk_list_store_set_n_columns (GtkWxListStore *list_store,
115 gint n_columns);
116 static void gtk_list_store_set_column_type (GtkWxListStore *list_store,
117 gint column,
118 GType type);
119
120 static GObjectClass *parent_class = NULL;
121
122 GType
123 wxgtk_list_store_get_type (void)
124 {
125 static GType list_store_type = 0;
126
127 if (!list_store_type)
128 {
129 static const GTypeInfo list_store_info =
130 {
131 sizeof (GtkWxListStoreClass),
132 NULL, /* base_init */
133 NULL, /* base_finalize */
134 (GClassInitFunc) wxgtk_list_store_class_init,
135 NULL, /* class_finalize */
136 NULL, /* class_data */
137 sizeof (GtkWxListStore),
138 0,
139 (GInstanceInitFunc) wxgtk_list_store_init,
140 };
141
142 static const GInterfaceInfo tree_model_info =
143 {
144 (GInterfaceInitFunc) wxgtk_list_store_tree_model_init,
145 NULL,
146 NULL
147 };
148
149 list_store_type = g_type_register_static (G_TYPE_OBJECT, "GtkWxListStore",
150 &list_store_info, 0);
151
152 g_type_add_interface_static (list_store_type,
153 GTK_TYPE_TREE_MODEL,
154 &tree_model_info);
155 }
156
157 return list_store_type;
158 }
159
160 static void
161 wxgtk_list_store_class_init (GtkWxListStoreClass *class)
162 {
163 GObjectClass *object_class;
164 parent_class = g_type_class_peek_parent (class);
165 object_class = (GObjectClass*) class;
166 object_class->finalize = wxgtk_list_store_finalize;
167 }
168
169 static void
170 wxgtk_list_store_tree_model_init (GtkTreeModelIface *iface)
171 {
172 iface->get_flags = wxgtk_list_store_get_flags;
173 iface->get_n_columns = wxgtk_list_store_get_n_columns;
174 iface->get_column_type = wxgtk_list_store_get_column_type;
175 iface->get_iter = wxgtk_list_store_get_iter;
176 iface->get_path = wxgtk_list_store_get_path;
177 iface->get_value = wxgtk_list_store_get_value;
178 iface->iter_next = wxgtk_list_store_iter_next;
179 iface->iter_children = wxgtk_list_store_iter_children;
180 iface->iter_has_child = wxgtk_list_store_iter_has_child;
181 iface->iter_n_children = wxgtk_list_store_iter_n_children;
182 iface->iter_nth_child = wxgtk_list_store_iter_nth_child;
183 iface->iter_parent = wxgtk_list_store_iter_parent;
184 }
185
186 static void
187 wxgtk_list_store_init (GtkWxListStore *list_store)
188 {
189 list_store->model = NULL;
190 list_store->stamp = g_random_init();
191 }
192
193 static void
194 wxgtk_list_store_finalize (GObject *object)
195 {
196 GtkWxListStore *list_store = GTK_LIST_STORE (object);
197
198 /* we need to sort out, which class deletes what */
199 /* delete model; */
200
201 /* must chain up */
202 (* parent_class->finalize) (object);
203 }
204
205 } // extern "C"
206
207 //-----------------------------------------------------------------------------
208 // implement callbacks from wxGtkListStore class by letting
209 // them call the methods of wxWidgets' wxDataViewListModel
210 //-----------------------------------------------------------------------------
211
212 static GtkTreeModelFlags
213 wxgtk_list_store_get_flags (GtkTreeModel *tree_model)
214 {
215 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), 0);
216
217 // GTK+ list store uses a linked list for storing the
218 // items and a pointer to a child is used as the member
219 // field of a GtkTreeIter. This means that the iter is
220 // valid in the GtkListStore as long as the child exists.
221 // We use the index of the row and since the index of a
222 // specific row will change if a row above is deleted,
223 // the iter does not persist
224 return /* GTK_TREE_MODEL_ITERS_PERSIST | */ GTK_TREE_MODEL_LIST_ONLY;
225 }
226
227 static gint
228 wxgtk_list_store_get_n_columns (GtkTreeModel *tree_model)
229 {
230 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
231 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), 0);
232
233 return list_store->model->GetNumberOfCols();
234 }
235
236 static GType
237 wxgtk_list_store_get_column_type (GtkTreeModel *tree_model,
238 gint index)
239 {
240 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
241 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), G_TYPE_INVALID);
242
243 GType gtype = G_TYPE_STRING;
244
245 #if 0
246 wxString wxtype = list_store->model->GetColType( index );
247 // convert wxtype to GType
248 gtype = ..
249 #endif
250
251 return gtype;
252 }
253
254 static gboolean
255 wxgtk_list_store_get_iter (GtkTreeModel *tree_model,
256 GtkTreeIter *iter,
257 GtkTreePath *path)
258 {
259 GtkWxListStore *list_store = (GtkWxListStore *) tree_model;
260 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
261 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
262
263 i = gtk_tree_path_get_indices (path)[0];
264
265 if (i >= list_store->model->GetCount())
266 return FALSE;
267
268 iter->stamp = list_store->stamp;
269 // user_data is just the index
270 iter->user_data = (gpointer) i;
271
272 return TRUE;
273 }
274
275 static GtkTreePath *
276 wxgtk_list_store_get_path (GtkTreeModel *tree_model,
277 GtkTreeIter *iter)
278 {
279 GtkWxListStore *list_store = (GtkListStore *) tree_model;
280 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), NULL);
281
282 g_return_val_if_fail (iter->stamp == GTK_WX_LIST_STORE (tree_model)->stamp, NULL);
283
284 GtkTreePath *retval = gtk_tree_path_new ();
285 // user_data is just the index
286 int i = (int) item->user_data;
287 gtk_tree_path_append_index (retval, i);
288 return retval;
289 }
290
291 static void
292 wxgtk_list_store_get_value (GtkTreeModel *tree_model,
293 GtkTreeIter *iter,
294 gint column,
295 GValue *value)
296 {
297 GtkWxListStore *list_store = (GtkListStore *) tree_model;
298 g_return_if_fail (GTK_IS_WX_LIST_STORE (tree_model) );
299
300 g_value_init( value, G_TYPE_STRING );
301 g_value_set_string( value, "Hello" );
302
303 #if 0
304 GtkTreeDataList *list;
305 gint tmp_column = column;
306
307 g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
308 g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
309
310 list = G_SLIST (iter->user_data)->data;
311
312 while (tmp_column-- > 0 && list)
313 list = list->next;
314
315 if (list == NULL)
316 g_value_init (value, GTK_LIST_STORE (tree_model)->column_headers[column]);
317 else
318 _gtk_tree_data_list_node_to_value (list,
319 GTK_LIST_STORE (tree_model)->column_headers[column],
320 value);
321 #endif
322
323 }
324
325 static gboolean
326 wxgtk_list_store_iter_next (GtkTreeModel *tree_model,
327 GtkTreeIter *iter)
328 {
329 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
330 GtkWxListStore *list_store = (GtkListStore *) tree_model;
331
332 g_return_val_if_fail (list_store->stamp == iter->stamp, FALSE);
333
334 int n = (int) iter->user_data;
335
336 if (n == -1)
337 return FALSE;
338
339 if (n >= (int) list_store->model->GetRowCount())
340 return FALSE;
341
342 iter->user_data = (gpointer) n++;
343
344 return TRUE;
345 }
346
347 static gboolean
348 wxgtk_list_store_iter_children (GtkTreeModel *tree_model,
349 GtkTreeIter *iter,
350 GtkTreeIter *parent)
351 {
352 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
353 GtkWxListStore *list_store = (GtkListStore *) tree_model;
354
355 // this is a list, nodes have no children
356 if (parent)
357 return FALSE;
358
359 iter->stamp = list_store->stamp;
360 iter->user_data = (gpointer) -1;
361
362 return TRUE;
363 }
364
365 static gboolean
366 wxgtk_list_store_iter_has_child (GtkTreeModel *tree_model,
367 GtkTreeIter *iter)
368 {
369 return FALSE;
370 }
371
372 static gint
373 wxgtk_list_store_iter_n_children (GtkTreeModel *tree_model,
374 GtkTreeIter *iter)
375 {
376 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), -1);
377 GtkWxListStore *list_store = (GtkListStore *) tree_model;
378
379 if (iter == NULL)
380 return (gint) list_store->model->GetRowCount();
381
382 g_return_val_if_fail (list_store->stamp == iter->stamp, -1);
383
384 return 0;
385 }
386
387 static gboolean
388 wxgtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
389 GtkTreeIter *iter,
390 GtkTreeIter *parent,
391 gint n)
392 {
393 g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), FALSE);
394 GtkWxListStore *list_store = (GtkListStore *) tree_model;
395
396 if (parent)
397 return FALSE;
398
399 if (n < 0)
400 return FALSE;
401
402 if (n >= (gint) list_store->model->GetRowCount())
403 return FALSE;
404
405 iter->stamp = list_store->stamp;
406 iter->user_data = (gpointer) n;
407
408 return TRUE;
409 }
410
411 static gboolean
412 wxgtk_list_store_iter_parent (GtkTreeModel *tree_model,
413 GtkTreeIter *iter,
414 GtkTreeIter *child)
415 {
416 return FALSE;
417 }
418
419
420 //-----------------------------------------------------------------------------
421 // wxDataViewCtrl
422 //-----------------------------------------------------------------------------
423
424 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
425
426 wxDataViewCtrl::~wxDataViewCtrl()
427 {
428 }
429
430 void wxDataViewCtrl::Init()
431 {
432 }
433
434 bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
435 const wxPoint& pos, const wxSize& size,
436 long style, const wxValidator& validator )
437 {
438 Init();
439
440 m_needParent = TRUE;
441 m_acceptsFocus = TRUE;
442
443 if (!PreCreation( parent, pos, size ) ||
444 !CreateBase( parent, id, pos, size, style, validator ))
445 {
446 wxFAIL_MSG( wxT("wxDataViewCtrl creation failed") );
447 return FALSE;
448 }
449
450 m_widget = gtk_tree_view_new();
451
452 m_parent->DoAddChild( this );
453
454 PostCreation(size);
455
456 return true;
457 }
458
459 bool wxDataViewCtrl::AppendStringColumn( const wxString &label )
460 {
461 GtkCellRenderer *renderer
462 = gtk_cell_renderer_text_new();
463
464 GtkTreeViewColumn *column
465 = gtk_tree_view_column_new_with_attributes( wxGTK_CONV(label), renderer, "text", index, NULL );
466
467 gtk_tree_view_append_column( GTK_TREE_VIEW(m_widget), column );
468
469 return true;
470 }
471
472 bool wxDataViewCtrl::AssociateModel( wxDataViewStore *model )
473 {
474 if (!wxDataViewCtrlBase::AssociateModel( model ))
475 return false;
476
477 // Right now we only have the GTK+ port's
478 // list store variant, so cast to that...
479
480 wxDataViewListStore *liststore = (wxDataViewListStore*) store;
481
482 gtk_tree_view_set_model( GTK_TREE_VIEW(m_widget), GTK_TREE_MODEL(liststore->GetGtkListStore()) );
483
484 return true;
485 }
486
487
488 #endif // wxUSE_DATAVIEWCTRL
489