blob: 6ba1fe907b496a6a38754e195e720da8c96f5220 [file] [log] [blame]
Stepan Salenikovicha3557452015-02-20 14:14:12 -05001/*
2 * Copyright (C) 2015 Savoir-Faire Linux Inc.
3 * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Additional permission under GNU GPL version 3 section 7:
20 *
21 * If you modify this program, or any covered work, by linking or
22 * combining it with the OpenSSL project's OpenSSL library (or a
23 * modified version of that library), containing parts covered by the
24 * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
25 * grants you additional permission to convey the resulting work.
26 * Corresponding Source for a non-source form of such a combination
27 * shall include the source code for the parts of OpenSSL used as well
28 * as that of the covered work.
29 */
30
31#include "gtkqtreemodel.h"
32#include <gtk/gtk.h>
33#include <QtCore/QAbstractItemModel>
34#include <QtCore/QDebug>
35#include "gtkaccessproxymodel.h"
36
37typedef union _int_ptr_t
38{
39 gint value;
Stepan Salenikovichd2dbcee2015-02-27 16:52:28 -050040 void *ptr;
Stepan Salenikovicha3557452015-02-20 14:14:12 -050041} int_ptr_t;
42
43typedef struct _QIter {
44 gint stamp;
45 int_ptr_t row;
46 int_ptr_t column;
Stepan Salenikovichd2dbcee2015-02-27 16:52:28 -050047 void *id;
Stepan Salenikovicha3557452015-02-20 14:14:12 -050048 gpointer user_data;
49} QIter;
50
51typedef struct _GtkQTreeModelPrivate GtkQTreeModelPrivate;
52
53struct _GtkQTreeModel
54{
55 GObject parent;
56
57 /* private */
58 GtkQTreeModelPrivate *priv;
59};
60
61struct _GtkQTreeModelClass
62{
63 GObjectClass parent_class;
64};
65
66struct _GtkQTreeModelPrivate
67{
68 GType *column_headers;
69 gint *column_roles;
70
71 gint stamp;
72 gint n_columns;
73
74 GtkAccessProxyModel *model;
75};
76
77/* static prototypes */
78
79/* GtkTreeModel prototypes */
80static void gtk_q_tree_model_tree_model_init (GtkTreeModelIface * );
81static void gtk_q_tree_model_finalize (GObject * );
82static GtkTreeModelFlags gtk_q_tree_model_get_flags (GtkTreeModel * );
83static gint gtk_q_tree_model_get_n_columns (GtkTreeModel * );
84static GType gtk_q_tree_model_get_column_type (GtkTreeModel *,
85 gint );
86static gboolean gtk_q_tree_model_get_iter (GtkTreeModel *,
87 GtkTreeIter *,
88 GtkTreePath * );
89static GtkTreePath * gtk_q_tree_model_get_path (GtkTreeModel *,
90 GtkTreeIter * );
91static void gtk_q_tree_model_get_value (GtkTreeModel *,
92 GtkTreeIter *,
93 gint,
94 GValue * );
95static gboolean gtk_q_tree_model_iter_next (GtkTreeModel *,
96 GtkTreeIter * );
97static gboolean gtk_q_tree_model_iter_previous (GtkTreeModel *,
98 GtkTreeIter * );
99static gboolean gtk_q_tree_model_iter_children (GtkTreeModel *,
100 GtkTreeIter *,
101 GtkTreeIter * );
102static gboolean gtk_q_tree_model_iter_has_child (GtkTreeModel *,
103 GtkTreeIter * );
104static gint gtk_q_tree_model_iter_n_children (GtkTreeModel *,
105 GtkTreeIter * );
106static gboolean gtk_q_tree_model_iter_nth_child (GtkTreeModel *,
107 GtkTreeIter *,
108 GtkTreeIter *,
109 gint );
110static gboolean gtk_q_tree_model_iter_parent (GtkTreeModel *,
111 GtkTreeIter *,
112 GtkTreeIter * );
113
114/* implementation prototypes */
115static void qmodelindex_to_iter (const QModelIndex &,
116 GtkTreeIter * );
117// static void gtk_q_tree_model_increment_stamp (GtkQTreeModel * );
118
119static gint gtk_q_tree_model_length (GtkQTreeModel * );
120
121static void gtk_q_tree_model_set_n_columns (GtkQTreeModel *,
122 gint );
123static void gtk_q_tree_model_set_column_type (GtkQTreeModel *,
124 gint,
125 gint,
126 GType );
127
128/* End private prototypes */
129
130/* define type, inherit from GObject, define implemented interface(s) */
131G_DEFINE_TYPE_WITH_CODE (GtkQTreeModel, gtk_q_tree_model, G_TYPE_OBJECT,
132 G_ADD_PRIVATE (GtkQTreeModel)
133 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
134 gtk_q_tree_model_tree_model_init))
135
136#define GTK_Q_TREEMODEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_Q_TREE_MODEL, GtkQTreeModelPrivate))
137
138#define Q_ITER(iter) ((QIter *)iter)
139
140static void
141gtk_q_tree_model_class_init(GtkQTreeModelClass *klass)
142{
143 G_OBJECT_CLASS(klass)->finalize = gtk_q_tree_model_finalize;
144}
145
146static void
147gtk_q_tree_model_tree_model_init(GtkTreeModelIface *iface)
148{
149 iface->get_flags = gtk_q_tree_model_get_flags;
150 iface->get_n_columns = gtk_q_tree_model_get_n_columns;
151 iface->get_column_type = gtk_q_tree_model_get_column_type;
152 iface->get_iter = gtk_q_tree_model_get_iter;
153 iface->get_path = gtk_q_tree_model_get_path;
154 iface->get_value = gtk_q_tree_model_get_value;
155 iface->iter_next = gtk_q_tree_model_iter_next;
156 iface->iter_previous = gtk_q_tree_model_iter_previous;
157 iface->iter_children = gtk_q_tree_model_iter_children;
158 iface->iter_has_child = gtk_q_tree_model_iter_has_child;
159 iface->iter_n_children = gtk_q_tree_model_iter_n_children;
160 iface->iter_nth_child = gtk_q_tree_model_iter_nth_child;
161 iface->iter_parent = gtk_q_tree_model_iter_parent;
162}
163
164static void
165gtk_q_tree_model_init(GtkQTreeModel *q_tree_model)
166{
167 GtkQTreeModelPrivate *priv = GTK_Q_TREEMODEL_GET_PRIVATE(q_tree_model);
168 q_tree_model->priv = priv;
169
170 priv->stamp = g_random_int();
171 priv->model = NULL;
172}
173
174/**
175 * gtk_q_tree_model_get_qmodel
176 * returns the original model from which this GtkQTreeModel is created
177 */
178QAbstractItemModel *
179gtk_q_tree_model_get_qmodel(GtkQTreeModel *q_tree_model)
180{
181 GtkQTreeModelPrivate *priv = GTK_Q_TREEMODEL_GET_PRIVATE(q_tree_model);
182 return priv->model->sourceModel();
183}
184
185/**
186 * gtk_q_tree_model_get_source_idx
187 * Returns the index of the original model used to create this GtkQTreeModel from
188 * the given iter, if there is one.
189 */
190QModelIndex
191gtk_q_tree_model_get_source_idx(GtkQTreeModel *q_tree_model, GtkTreeIter *iter)
192{
193 GtkQTreeModelPrivate *priv = GTK_Q_TREEMODEL_GET_PRIVATE(q_tree_model);
194 /* get the call */
195 QIter *qiter = Q_ITER(iter);
196 GtkAccessProxyModel *proxy_model = priv->model;
197 QModelIndex proxy_idx = proxy_model->indexFromId(qiter->row.value, qiter->column.value, qiter->id);
198 if (proxy_idx.isValid()) {
199 /* we have the proxy model idx, now get the actual idx so we can get the call object */
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500200 return proxy_model->mapToSource(proxy_idx);
201 } else {
Stepan Salenikovich69771842015-02-24 18:11:45 -0500202 g_warning("could not get valid QModelIndex from given GtkTreeIter");
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500203 return QModelIndex();
204 }
205}
206
207/**
208 * Takes a QModelIndex from the original QAbstractItemModel and returns a valid GtkTreeIter in the corresponding
209 * GtkQTreeModel
210 */
211gboolean
212gtk_q_tree_model_source_index_to_iter(GtkQTreeModel *q_tree_model, const QModelIndex &idx, GtkTreeIter *iter)
213{
214 GtkQTreeModelPrivate *priv = GTK_Q_TREEMODEL_GET_PRIVATE(q_tree_model);
215
Stepan Salenikovich69771842015-02-24 18:11:45 -0500216 /* the the proxy_idx from the source idx */
217 QModelIndex proxy_idx = priv->model->mapFromSource(idx);
218 if (!proxy_idx.isValid())
219 return FALSE;
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500220
221 /* make sure iter is valid */
222 iter->stamp = priv->stamp;
223
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500224 /* map the proxy idx to iter */
225 Q_ITER(iter)->row.value = proxy_idx.row();
Stepan Salenikovich7ff47962015-03-16 15:10:14 -0400226 Q_ITER(iter)->column.value = proxy_idx.column();
Stepan Salenikovichd2dbcee2015-02-27 16:52:28 -0500227 Q_ITER(iter)->id = proxy_idx.internalPointer();
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500228 return TRUE;
229}
230
231/**
232 * gtk_q_tree_model_new:
233 * @model: QAbstractItemModel to which this model will bind.
234 * @n_columns: number of columns in the list store
235 * @...: all #GType follwed by the #Role pair for each column.
236 *
237 * Return value: a new #GtkQTreeModel
238 */
239GtkQTreeModel *
240gtk_q_tree_model_new(QAbstractItemModel *model, size_t n_columns, ...)
241{
242 GtkQTreeModel *retval;
243 va_list args;
244 gint i;
245
246 g_return_val_if_fail(n_columns > 0, NULL);
247
248 retval = (GtkQTreeModel *)g_object_new(GTK_TYPE_Q_TREE_MODEL, NULL);
249 gtk_q_tree_model_set_n_columns(retval, n_columns);
250
251 /* get proxy model from given model */
252 GtkAccessProxyModel* proxy_model = new GtkAccessProxyModel();
253 proxy_model->setSourceModel(model);
254 retval->priv->model = proxy_model;
255 gint stamp = retval->priv->stamp;
256
257 n_columns = 2*n_columns;
258 va_start (args, n_columns);
259
260 for (i = 0; i < (gint)(n_columns/2); i++) {
261 /* first get the role of the QModel */
262 gint role = va_arg(args, gint);
263
264 /* then get the type the role will be interpreted as */
265 GType type = va_arg(args, GType);
266
267 /* TODO: check if its a type supported by our model
268 * if (! _gtk_tree_data_list_check_type (type))
269 * {
270 * g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
271 * g_object_unref (retval);
272 * va_end (args);
273 *
274 * return NULL;
275 * }
276 */
277
278 gtk_q_tree_model_set_column_type (retval, i, role, type);
279 }
280
281 va_end (args);
282
283 gtk_q_tree_model_length(retval);
284
285 /* connect signals */
286 QObject::connect(
287 model,
288 &QAbstractItemModel::rowsInserted,
289 [=](const QModelIndex & parent, int first, int last) {
290 for( int row = first; row <= last; row++) {
291 GtkTreeIter *iter = g_new0(GtkTreeIter, 1);
292 QModelIndex idx = retval->priv->model->index(row, 0, parent);
293 iter->stamp = stamp;
294 qmodelindex_to_iter(idx, iter);
295 GtkTreePath *path = gtk_q_tree_model_get_path(GTK_TREE_MODEL(retval), iter);
296 gtk_tree_model_row_inserted(GTK_TREE_MODEL(retval), path, iter);
297 }
298 }
299 );
300
301 QObject::connect(
302 model,
303 &QAbstractItemModel::rowsAboutToBeMoved,
Stepan Salenikovich69771842015-02-24 18:11:45 -0500304 [=](const QModelIndex & sourceParent, int sourceStart, int sourceEnd,
305 G_GNUC_UNUSED const QModelIndex & destinationParent, G_GNUC_UNUSED int destinationRow) {
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500306 /* first remove the row from old location
307 * then insert them at the new location on the "rowsMoved signal */
308 for( int row = sourceStart; row <= sourceEnd; row++) {
309 QModelIndex idx = retval->priv->model->index(row, 0, sourceParent);
310 GtkTreeIter iter_old;
311 qmodelindex_to_iter(idx, &iter_old);
312 GtkTreePath *path_old = gtk_q_tree_model_get_path(GTK_TREE_MODEL(retval), &iter_old);
313 gtk_tree_model_row_deleted(GTK_TREE_MODEL(retval), path_old);
314 }
315 }
316 );
317
318 QObject::connect(
319 model,
320 &QAbstractItemModel::rowsMoved,
Stepan Salenikovich69771842015-02-24 18:11:45 -0500321 [=](G_GNUC_UNUSED const QModelIndex & sourceParent, int sourceStart, int sourceEnd,
322 const QModelIndex & destinationParent, int destinationRow) {
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500323 /* these rows should have been removed in the "rowsAboutToBeMoved" handler
324 * now insert them in the new location */
325 for( int row = sourceStart; row <= sourceEnd; row++) {
326 GtkTreeIter *iter_new = g_new0(GtkTreeIter, 1);
327 QModelIndex idx = retval->priv->model->index(destinationRow, 0, destinationParent);
328 iter_new->stamp = stamp;
329 qmodelindex_to_iter(idx, iter_new);
330 GtkTreePath *path_new = gtk_q_tree_model_get_path(GTK_TREE_MODEL(retval), iter_new);
331 gtk_tree_model_row_inserted(GTK_TREE_MODEL(retval), path_new, iter_new);
332 destinationRow++;
333 }
334 }
335 );
336
337 QObject::connect(
338 model,
339 &QAbstractItemModel::rowsAboutToBeRemoved,
340 [=](const QModelIndex & parent, int first, int last) {
341 for( int row = first; row <= last; row++) {
342 QModelIndex idx = retval->priv->model->index(row, 0, parent);
343 GtkTreeIter iter;
344 iter.stamp = stamp;
345 qmodelindex_to_iter(idx, &iter);
346 GtkTreePath *path = gtk_q_tree_model_get_path(GTK_TREE_MODEL(retval), &iter);
347 gtk_tree_model_row_deleted(GTK_TREE_MODEL(retval), path);
348 }
349 }
350 );
351
352 QObject::connect(
353 model,
354 &QAbstractItemModel::dataChanged,
Stepan Salenikovich69771842015-02-24 18:11:45 -0500355 [=](const QModelIndex & topLeft, const QModelIndex & bottomRight,
356 G_GNUC_UNUSED const QVector<int> & roles = QVector<int> ()) {
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500357 /* we have to assume only one column */
358 int first = topLeft.row();
359 int last = bottomRight.row();
360 if (topLeft.column() != bottomRight.column() ) {
361 g_warning("more than one column is not supported!");
362 }
363 /* the first idx IS topLeft, the reset are his siblings */
364 GtkTreeIter *iter = g_new0(GtkTreeIter, 1);
365 QModelIndex idx = topLeft;
366 iter->stamp = stamp;
367 qmodelindex_to_iter(idx, iter);
368 GtkTreePath *path = gtk_q_tree_model_get_path(GTK_TREE_MODEL(retval), iter);
369 gtk_tree_model_row_changed(GTK_TREE_MODEL(retval), path, iter);
370 for( int row = first + 1; row <= last; row++) {
371 iter = g_new0(GtkTreeIter, 1);
372 idx = topLeft.sibling(row, 0);
373 iter->stamp = stamp;
374 qmodelindex_to_iter(idx, iter);
375 path = gtk_q_tree_model_get_path(GTK_TREE_MODEL(retval), iter);
376 gtk_tree_model_row_changed(GTK_TREE_MODEL(retval), path, iter);
377 }
378 }
379 );
380
381 return retval;
382}
383
384static gint
385gtk_q_tree_model_length(GtkQTreeModel *q_tree_model)
386{
387 GtkQTreeModelPrivate *priv = q_tree_model->priv;
388 return priv->model->rowCount();
389}
390
391static void
392gtk_q_tree_model_set_n_columns(GtkQTreeModel *q_tree_model,
393 gint n_columns)
394{
395 GtkQTreeModelPrivate *priv = q_tree_model->priv;
396 int i;
397
398 if (priv->n_columns == n_columns)
399 return;
400
401 priv->column_headers = g_renew (GType, priv->column_headers, n_columns);
402 for (i = priv->n_columns; i < n_columns; i++)
403 priv->column_headers[i] = G_TYPE_INVALID;
404 priv->n_columns = n_columns;
405
406 priv->column_roles = g_renew (gint, priv->column_roles, n_columns);
407 for (i = priv->n_columns; i < n_columns; i++)
408 priv->column_roles[i] = -1;
409}
410
411static void
412gtk_q_tree_model_set_column_type(GtkQTreeModel *q_tree_model,
413 gint column,
414 gint role,
415 GType type)
416{
417 GtkQTreeModelPrivate *priv = q_tree_model->priv;
418
419 /* TODO: check if its a type supported by our model
420 * if (!_gtk_tree_data_list_check_type (type))
421 * {
422 * g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
423 * return;
424 * }
425 */
426
427 priv->column_headers[column] = type;
428 priv->column_roles[column] = role;
429}
430
431
432static void
433gtk_q_tree_model_finalize(GObject *object)
434{
435 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (object);
436 GtkQTreeModelPrivate *priv = q_tree_model->priv;
437
438 g_free(priv->column_headers);
439 g_free(priv->column_roles);
440
441 /* delete the created proxy model */
442 delete priv->model;
443
444 G_OBJECT_CLASS(gtk_q_tree_model_parent_class)->finalize (object);
445}
446
447static gboolean
448iter_is_valid(GtkTreeIter *iter,
449 GtkQTreeModel *q_tree_model)
450{
451 gboolean retval;
452 g_return_val_if_fail(iter != NULL, FALSE);
453 QIter *qiter = Q_ITER(iter);
454 retval = q_tree_model->priv->model->indexFromId(qiter->row.value, qiter->column.value, qiter->id).isValid();
455 return retval;
456}
457
458static void
459qmodelindex_to_iter(const QModelIndex &idx, GtkTreeIter *iter)
460{
461 Q_ITER(iter)->row.value = idx.row();
Stepan Salenikovich7ff47962015-03-16 15:10:14 -0400462 Q_ITER(iter)->column.value = idx.column();
Stepan Salenikovichd2dbcee2015-02-27 16:52:28 -0500463 Q_ITER(iter)->id = idx.internalPointer();
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500464}
465
466static gboolean
467validate_index(gint stamp, const QModelIndex &idx, GtkTreeIter *iter)
468{
469 if (idx.isValid()) {
470 iter->stamp = stamp;
471 qmodelindex_to_iter(idx, iter);
472 } else {
473 iter->stamp = 0;
474 return FALSE;
475 }
476 return TRUE;
477}
478
479/* Start Fulfill the GtkTreeModel requirements */
480
481/* flags supported by this interface */
482static GtkTreeModelFlags
483gtk_q_tree_model_get_flags(G_GNUC_UNUSED GtkTreeModel *tree_model)
484{
485 // TODO: possibly return based on the model?
486 return (GtkTreeModelFlags)(GTK_TREE_MODEL_ITERS_PERSIST);
487}
488
489/* number of columns supported by this tree model */
490static gint
491gtk_q_tree_model_get_n_columns(GtkTreeModel *tree_model)
492{
493 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL(tree_model);
494 GtkQTreeModelPrivate *priv = q_tree_model->priv;
495
496 return priv->model->columnCount();
497}
498
499/* get given column type */
500static GType
501gtk_q_tree_model_get_column_type(GtkTreeModel *tree_model,
502 gint index)
503{
504 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
505 GtkQTreeModelPrivate *priv = q_tree_model->priv;
506
507 g_return_val_if_fail (index < gtk_q_tree_model_get_n_columns(tree_model), G_TYPE_INVALID);
508
509 return priv->column_headers[index];
510}
511
512/* Sets @iter to a valid iterator pointing to @path. If @path does
513 * not exist, @iter is set to an invalid iterator and %FALSE is returned.
514 */
515static gboolean
516gtk_q_tree_model_get_iter(GtkTreeModel *tree_model,
517 GtkTreeIter *iter,
518 GtkTreePath *path)
519{
520 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
521 GtkQTreeModelPrivate *priv = q_tree_model->priv;
522
523 /* GtkTreePath is a list of indices, each one indicates
524 * the child of the previous one.
525 * Since GtkTreeModel only has rows (columns are only used to
526 * store data in each item), each index is basically the row
527 * at the given tree level.
528 * To get the iter, we want to get the QModelIndex. To get
529 * the QModelIndex we simply start at the first level and
530 * traverse the model the number of layers equal to the number
531 * of indices in the path.
532 */
533 gint depth;
534 gint* indices = gtk_tree_path_get_indices_with_depth(path, &depth);
535 QModelIndex idx = priv->model->index(indices[0], 0);
536 for(int layer = 1; layer < depth; layer++ ) {
537 /* check if previous iter is valid */
538 if (!idx.isValid()) {
539 break;
540 } else {
541 idx = idx.child(indices[layer], 0);
542 }
543 }
544
545 if (!idx.isValid()) {
546 iter->stamp = 0;
547 return FALSE;
548 } else {
549 /* we have a valid QModelIndex; turn it into an iter */
550 iter->stamp = priv->stamp;
551 qmodelindex_to_iter(idx, iter);
552 }
553
554 return TRUE;
555}
556
557/* Returns a newly-created #GtkTreePath referenced by @iter.
558 *
559 * This path should be freed with gtk_tree_path_free().
560 */
561static GtkTreePath *
562gtk_q_tree_model_get_path(GtkTreeModel *tree_model,
563 GtkTreeIter *iter)
564{
565 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
566 GtkQTreeModelPrivate *priv = q_tree_model->priv;
567 GtkTreePath *path;
568
569 g_return_val_if_fail (iter->stamp == priv->stamp, NULL);
570 g_return_val_if_fail (iter_is_valid(iter, q_tree_model), NULL);
571
572 /* To get the path, we have to traverse from the child all the way up */
573 path = gtk_tree_path_new();
574 QIter *qiter = Q_ITER(iter);
575 QModelIndex idx = priv->model->indexFromId(qiter->row.value, qiter->column.value, qiter->id);
576 while( idx.isValid() ){
577 gtk_tree_path_prepend_index(path, idx.row());
578 idx = idx.parent();
579 }
580 return path;
581}
582
583static inline GType
584get_fundamental_type(GType type)
585{
586 GType result;
587
588 result = G_TYPE_FUNDAMENTAL (type);
589
590 if (result == G_TYPE_INTERFACE) {
591 if (g_type_is_a (type, G_TYPE_OBJECT))
592 result = G_TYPE_OBJECT;
593 }
594
595 return result;
596}
597
598/* Initializes and sets @value to that at @column. */
599static void
600gtk_q_tree_model_get_value(GtkTreeModel *tree_model,
601 GtkTreeIter *iter,
602 gint column,
603 GValue *value)
604{
605 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
606 GtkQTreeModelPrivate *priv = q_tree_model->priv;
607
608 g_return_if_fail (column < priv->n_columns);
609 g_return_if_fail (iter_is_valid(iter, q_tree_model));
610
611 /* get the data */
612 QIter *qiter = Q_ITER(iter);
613 QModelIndex idx = priv->model->indexFromId(qiter->row.value, qiter->column.value, qiter->id);
614 int role = priv->column_roles[column];
615 QVariant var = priv->model->data(idx, role);
616 GType type = priv->column_headers[column];
617 g_value_init (value, type);
618 switch (get_fundamental_type (type))
619 {
620 /* TODO: implement the rest of the data types the we plan to support
621 * otherwise get rid of the code and make sure un-implemented types
622 * are not allowed
623 */
624 case G_TYPE_BOOLEAN:
625 g_value_set_boolean (value, (gboolean) var.toBool());
626 break;
627 // case G_TYPE_CHAR:
628 // g_value_set_schar (value, (gchar) list->data.v_char);
629 // break;
630 // case G_TYPE_UCHAR:
631 // g_value_set_uchar (value, (guchar) list->data.v_uchar);
632 // break;
633 case G_TYPE_INT:
634 g_value_set_int (value, (gint) var.toInt());
635 break;
636 case G_TYPE_UINT:
637 g_value_set_uint (value, (guint) var.toUInt());
638 break;
639 // case G_TYPE_LONG:
640 // g_value_set_long (value, list->data.v_long);
641 // break;
642 // case G_TYPE_ULONG:
643 // g_value_set_ulong (value, list->data.v_ulong);
644 // break;
645 // case G_TYPE_INT64:
646 // g_value_set_int64 (value, list->data.v_int64);
647 // break;
648 // case G_TYPE_UINT64:
649 // g_value_set_uint64 (value, list->data.v_uint64);
650 // break;
651 // case G_TYPE_ENUM:
652 // g_value_set_enum (value, list->data.v_int);
653 // break;
654 // case G_TYPE_FLAGS:
655 // g_value_set_flags (value, list->data.v_uint);
656 // break;
657 // case G_TYPE_FLOAT:
658 // g_value_set_float (value, (gfloat) list->data.v_float);
659 // break;
660 // case G_TYPE_DOUBLE:
661 // g_value_set_double (value, (gdouble) list->data.v_double);
662 // break;
663 case G_TYPE_STRING:
Stepan Salenikovich69771842015-02-24 18:11:45 -0500664 {
665 QByteArray ba = var.toString().toLocal8Bit();
Stepan Salenikovich297b5d12015-02-26 17:51:13 -0500666 g_value_set_string(value, (gchar *)ba.constData());
Stepan Salenikovich69771842015-02-24 18:11:45 -0500667 }
668 break;
Stepan Salenikovicha3557452015-02-20 14:14:12 -0500669 // case G_TYPE_POINTER:
670 // g_value_set_pointer (value, (gpointer) list->data.v_pointer);
671 // break;
672 // case G_TYPE_BOXED:
673 // g_value_set_boxed (value, (gpointer) list->data.v_pointer);
674 // break;
675 // case G_TYPE_VARIANT:
676 // g_value_set_variant (value, (gpointer) list->data.v_pointer);
677 // break;
678 // case G_TYPE_OBJECT:
679 // g_value_set_object (value, (GObject *) list->data.v_pointer);
680 // break;
681 default:
682 g_warning ("%s: Unsupported type (%s) retrieved.", G_STRLOC, g_type_name (value->g_type));
683 break;
684 }
685
686 return;
687}
688
689/* Sets @iter to point to the node following it at the current level.
690 *
691 * If there is no next @iter, %FALSE is returned and @iter is set
692 * to be invalid.
693 */
694static gboolean
695gtk_q_tree_model_iter_next(GtkTreeModel *tree_model,
696 GtkTreeIter *iter)
697{
698 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
699 GtkQTreeModelPrivate *priv = q_tree_model->priv;
700
701 g_return_val_if_fail (iter_is_valid(iter, q_tree_model), FALSE);
702
703 QIter *qiter = Q_ITER(iter);
704 QModelIndex idx = priv->model->indexFromId(qiter->row.value, qiter->column.value, qiter->id);
705 idx = idx.sibling(idx.row()+1, idx.column());
706
707 /* validate */
708 if (validate_index(priv->stamp, idx, iter) ) {
709 GtkTreePath *path = gtk_q_tree_model_get_path(tree_model, iter);
710 gtk_tree_path_free(path);
711 return TRUE;
712 } else {
713 return FALSE;
714 }
715}
716
717/* Sets @iter to point to the previous node at the current level.
718 *
719 * If there is no previous @iter, %FALSE is returned and @iter is
720 * set to be invalid.
721 */
722static gboolean
723gtk_q_tree_model_iter_previous(GtkTreeModel *tree_model,
724 GtkTreeIter *iter)
725{
726 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
727 GtkQTreeModelPrivate *priv = q_tree_model->priv;
728
729 g_return_val_if_fail (iter_is_valid(iter, q_tree_model), FALSE);
730
731 QIter *qiter = Q_ITER(iter);
732 QModelIndex idx = priv->model->indexFromId(qiter->row.value, qiter->column.value, qiter->id);
733 idx = idx.sibling(idx.row()-1, idx.column());
734
735 /* validate */
736 return validate_index(priv->stamp, idx, iter);
737}
738
739/* Sets @iter to point to the first child of @parent.
740 *
741 * If @parent has no children, %FALSE is returned and @iter is
742 * set to be invalid. @parent will remain a valid node after this
743 * function has been called.
744 *
745 * If @parent is %NULL returns the first node
746 */
747static gboolean
748gtk_q_tree_model_iter_children(GtkTreeModel *tree_model,
749 GtkTreeIter *iter,
750 GtkTreeIter *parent)
751{
752 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
753 GtkQTreeModelPrivate *priv = q_tree_model->priv;
754 QModelIndex idx;
755
756 /* make sure parent if valid node if its not NULL */
757 if (parent)
758 g_return_val_if_fail(iter_is_valid(parent, q_tree_model), FALSE);
759
760 if (parent) {
761 /* get first child */
762 QIter *qparent = Q_ITER(parent);
763 idx = priv->model->indexFromId(qparent->row.value, qparent->column.value, qparent->id);
764 idx = idx.child(0, 0);
765 } else {
766 /* parent is NULL, get the first node */
767 idx = priv->model->index(0, 0);
768 }
769
770 /* validate child */
771 return validate_index(priv->stamp, idx, iter);
772}
773
774/* Returns %TRUE if @iter has children, %FALSE otherwise. */
775static gboolean
776gtk_q_tree_model_iter_has_child (GtkTreeModel *tree_model,
777 GtkTreeIter *iter)
778{
779 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
780 GtkQTreeModelPrivate *priv = q_tree_model->priv;
781 g_return_val_if_fail(iter_is_valid(iter, q_tree_model), FALSE);
782
783 QIter *qiter = Q_ITER(iter);
784 QModelIndex idx = priv->model->indexFromId(qiter->row.value, qiter->column.value, qiter->id);
785 return priv->model->hasChildren(idx);
786}
787
788/* Returns the number of children that @iter has.
789 *
790 * As a special case, if @iter is %NULL, then the number
791 * of toplevel nodes is returned.
792 */
793static gint
794gtk_q_tree_model_iter_n_children (GtkTreeModel *tree_model,
795 GtkTreeIter *iter)
796{
797 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
798 GtkQTreeModelPrivate *priv = q_tree_model->priv;
799
800 if (iter == NULL)
801 return gtk_q_tree_model_length(q_tree_model);
802
803 g_return_val_if_fail(iter_is_valid(iter, q_tree_model), -1);
804 QIter *qiter = Q_ITER(iter);
805 QModelIndex idx = priv->model->indexFromId(qiter->row.value, qiter->column.value, qiter->id);
806 return priv->model->rowCount(idx);
807}
808
809/* Sets @iter to be the child of @parent, using the given index.
810 *
811 * The first index is 0. If @n is too big, or @parent has no children,
812 * @iter is set to an invalid iterator and %FALSE is returned. @parent
813 * will remain a valid node after this function has been called. As a
814 * special case, if @parent is %NULL, then the @n<!-- -->th root node
815 * is set.
816 */
817static gboolean
818gtk_q_tree_model_iter_nth_child(GtkTreeModel *tree_model,
819 GtkTreeIter *iter,
820 GtkTreeIter *parent,
821 gint n)
822{
823 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
824 GtkQTreeModelPrivate *priv = q_tree_model->priv;
825 QModelIndex idx;
826
827 if (parent) {
828 g_return_val_if_fail(iter_is_valid(parent, q_tree_model), FALSE);
829
830 /* get the nth child */
831 QIter *qparent = Q_ITER(parent);
832 idx = priv->model->indexFromId(qparent->row.value, qparent->column.value, qparent->id);
833 idx = idx.child(n, 0);
834 } else {
835 idx = priv->model->index(n, 0);
836 }
837
838 /* validate */
839 return validate_index(priv->stamp, idx, iter);
840}
841
842/* Sets @iter to be the parent of @child.
843 *
844 * If @child is at the toplevel, and doesn't have a parent, then
845 * @iter is set to an invalid iterator and %FALSE is returned.
846 * @child will remain a valid node after this function has been
847 * called.
848 */
849static gboolean
850gtk_q_tree_model_iter_parent(GtkTreeModel *tree_model,
851 GtkTreeIter *iter,
852 GtkTreeIter *child)
853{
854 GtkQTreeModel *q_tree_model = GTK_Q_TREE_MODEL (tree_model);
855 GtkQTreeModelPrivate *priv = q_tree_model->priv;
856 QModelIndex idx;
857
858 g_return_val_if_fail(iter_is_valid(child, q_tree_model), FALSE);
859
860 QIter *qchild = Q_ITER(child);
861 idx = priv->model->indexFromId(qchild->row.value, qchild->column.value, qchild->id);
862 idx = idx.parent();
863
864 /* validate */
865 return validate_index(priv->stamp, idx, iter);
866}
867
Stepan Salenikovich69771842015-02-24 18:11:45 -0500868/* End Fulfill the GtkTreeModel requirements */