blob: db0a4b35c258826e1b53904d23f9006260910ecf [file] [log] [blame]
Stepan Salenikovich9816a942015-04-22 17:49:16 -04001/*
Stepan Salenikovichbe87d2c2016-01-25 14:14:34 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Stepan Salenikovich9816a942015-04-22 17:49:16 -04003 * 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.
Stepan Salenikovich9816a942015-04-22 17:49:16 -040018 */
19
20#include "models.h"
21
22#include <gtk/gtk.h>
23#include "../models/gtkqtreemodel.h"
24#include "../models/gtkqsortfiltertreemodel.h"
25#include <QtCore/QModelIndex>
Stepan Salenikovich7a1e71c2015-05-07 11:14:48 -040026#include <QtCore/QItemSelectionModel>
Stepan Salenikovich9816a942015-04-22 17:49:16 -040027
28QModelIndex
29get_index_from_selection(GtkTreeSelection *selection)
30{
31 GtkTreeIter iter;
32 GtkTreeModel *model = NULL;
33
34 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
35 if (GTK_IS_Q_TREE_MODEL(model))
36 return gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
37 else if (GTK_IS_Q_SORT_FILTER_TREE_MODEL(model))
38 return gtk_q_sort_filter_tree_model_get_source_idx(GTK_Q_SORT_FILTER_TREE_MODEL(model), &iter);
39 }
40 return QModelIndex();
Stepan Salenikovich7a1e71c2015-05-07 11:14:48 -040041}
42
43QModelIndex
44gtk_combo_box_get_index(GtkComboBox *box)
45{
46 GtkTreeIter filter_iter;
47 GtkTreeIter child_iter;
48 GtkTreeModel *filter_model = gtk_combo_box_get_model(box);
49 GtkTreeModel *model = filter_model;
50
51 GtkTreeIter *iter = NULL;
52
53 if (GTK_IS_TREE_MODEL_FILTER(filter_model))
54 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(filter_model));
55
56 if (gtk_combo_box_get_active_iter(box, &filter_iter)) {
57 if (GTK_IS_TREE_MODEL_FILTER(filter_model)) {
58 gtk_tree_model_filter_convert_iter_to_child_iter(
59 GTK_TREE_MODEL_FILTER(filter_model),
60 &child_iter,
61 &filter_iter);
62 iter = &child_iter;
63 } else {
64 iter = &filter_iter;
65 }
66
67 if (GTK_IS_Q_TREE_MODEL(model))
68 return gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), iter);
69 else if (GTK_IS_Q_SORT_FILTER_TREE_MODEL(model))
70 return gtk_q_sort_filter_tree_model_get_source_idx(GTK_Q_SORT_FILTER_TREE_MODEL(model), iter);
71 }
72 return QModelIndex();
73}
74
75static void
76update_selection(GtkComboBox *box, QItemSelectionModel *selection_model)
77{
78 QModelIndex idx = gtk_combo_box_get_index(box);
79 if (idx.isValid()) {
80 selection_model->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
81 }
82}
83
84static gboolean
85filter_disabled_items(GtkTreeModel *model, GtkTreeIter *iter, G_GNUC_UNUSED gpointer data)
86{
87 QModelIndex idx;
88 if (GTK_IS_Q_TREE_MODEL(model))
89 idx = gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), iter);
90 else if (GTK_IS_Q_SORT_FILTER_TREE_MODEL(model))
91 idx = gtk_q_sort_filter_tree_model_get_source_idx(GTK_Q_SORT_FILTER_TREE_MODEL(model), iter);
92
93 if (idx.isValid()) {
94 return idx.flags() & Qt::ItemIsEnabled ? TRUE : FALSE;
95 }
96 return FALSE;
97}
98
99void
100gtk_combo_box_set_active_index(GtkComboBox *box, const QModelIndex& idx)
101{
102 if (idx.isValid()) {
103 GtkTreeIter new_iter;
104 GtkTreeModel *filter_model = gtk_combo_box_get_model(box);
105 g_return_if_fail(filter_model);
106 GtkTreeModel *model = filter_model;
107
108 if (GTK_IS_TREE_MODEL_FILTER(filter_model))
109 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(filter_model));
110
Stepan Salenikoviche97b9402015-12-24 14:06:23 -0500111 gboolean valid = FALSE;
Stepan Salenikovich7a1e71c2015-05-07 11:14:48 -0400112 if (GTK_IS_Q_TREE_MODEL(model)) {
113 valid = gtk_q_tree_model_source_index_to_iter(
114 GTK_Q_TREE_MODEL(model), idx, &new_iter);
115 } else if (GTK_IS_Q_SORT_FILTER_TREE_MODEL(model)) {
116 valid = gtk_q_sort_filter_tree_model_source_index_to_iter(
117 GTK_Q_SORT_FILTER_TREE_MODEL(model), idx, &new_iter);
118 }
119
120 if (valid) {
121 if (GTK_IS_TREE_MODEL_FILTER(filter_model)) {
122 GtkTreeIter filter_iter;
123 if (gtk_tree_model_filter_convert_child_iter_to_iter(
124 GTK_TREE_MODEL_FILTER(filter_model),
125 &filter_iter,
126 &new_iter)
127 ) {
128 gtk_combo_box_set_active_iter(box, &filter_iter);
129 } else {
130 g_warning("failed to convert iter from source model to filter model iter");
131 }
132 } else {
133 gtk_combo_box_set_active_iter(box, &new_iter);
134 }
135 } else {
136 g_warning("Given QModelIndex doesn't exist in GtkTreeModel");
137 }
138 }
139}
140
141QMetaObject::Connection
142gtk_combo_box_set_qmodel(GtkComboBox *box, QAbstractItemModel *qmodel, QItemSelectionModel *selection_model)
143{
144 QMetaObject::Connection connection;
145 GtkTreeModel *model;
146
147 /* check if its a QAbstractItemModel or a QSortFilterProxyModel */
148 QSortFilterProxyModel *proxy_qmodel = qobject_cast<QSortFilterProxyModel*>(qmodel);
149 if (proxy_qmodel) {
150 model = (GtkTreeModel *)gtk_q_sort_filter_tree_model_new(
151 proxy_qmodel,
152 1,
153 Qt::DisplayRole, G_TYPE_STRING);
154 } else {
155 model = (GtkTreeModel *)gtk_q_tree_model_new(
156 qmodel,
157 1,
158 Qt::DisplayRole, G_TYPE_STRING);
159 }
160
161 /* use a filter model to remove disabled items */
162 GtkTreeModel *filter_model = gtk_tree_model_filter_new(model, NULL);
163 gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filter_model),
164 (GtkTreeModelFilterVisibleFunc)filter_disabled_items,
165 NULL, NULL);
166
167 gtk_combo_box_set_model(box, GTK_TREE_MODEL(filter_model));
168 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
169 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box), renderer, FALSE);
170 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(box), renderer,
171 "text", 0, NULL);
172
Stepan Salenikovichf2d76c52015-07-17 17:54:56 -0400173 if (!selection_model) return connection;
174
Stepan Salenikovich9d294492015-05-14 16:34:24 -0400175 /* sync the initial selection */
176 gtk_combo_box_set_active_index(box, selection_model->currentIndex());
177
Stepan Salenikovich7a1e71c2015-05-07 11:14:48 -0400178 /* connect signals to and from the selection model */
179 connection = QObject::connect(
180 selection_model,
181 &QItemSelectionModel::currentChanged,
Stepan Salenikovich9d294492015-05-14 16:34:24 -0400182 [=](const QModelIndex current, G_GNUC_UNUSED const QModelIndex & previous) {
Stepan Salenikovich7a1e71c2015-05-07 11:14:48 -0400183 gtk_combo_box_set_active_index(box, current);
184 }
185 );
186 g_signal_connect(box,
187 "changed",
188 G_CALLBACK(update_selection),
189 selection_model);
190
Stepan Salenikovich7a1e71c2015-05-07 11:14:48 -0400191 return connection;
Stepan Salenikovich9d294492015-05-14 16:34:24 -0400192}