1 /*
2 * gnc-tree-model-account-types.c -- GtkTreeModel implementation
3 * to display account types in a GtkTreeView.
4 *
5 * Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
6 * Copyright (C) 2005, 2006 Chris Shoemaker <c.shoemaker@cox.net>
7 * Copyright (C) 2006 Eskil Bylund <eskil.bylund@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, contact:
21 *
22 * Free Software Foundation Voice: +1-617-542-5942
23 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
24 * Boston, MA 02110-1301, USA gnu@gnu.org
25 */
26
27 #include <config.h>
28
29 #include <gtk/gtk.h>
30
31 #include "qof.h"
32 #include "gnc-tree-model-account-types.h"
33 #include "Account.h"
34
35 static QofLogModule log_module = GNC_MOD_GUI;
36 static GtkTreeModel *account_types_tree_model = NULL;
37
38 #define TYPE_MASK "type-mask"
39
40 /* Functions for the type system */
41 static void
42 gnc_tree_model_account_types_class_init (GncTreeModelAccountTypesClass *klass);
43 static void
44 gnc_tree_model_account_types_init (GncTreeModelAccountTypes * model);
45 static void
46 gnc_tree_model_account_types_finalize (GObject * object);
47
48
49 /* Functions implementing GtkTreeModel */
50 static void
51 gnc_tree_model_account_types_tree_model_init (GtkTreeModelIface * iface);
52
53 typedef struct GncTreeModelAccountTypesPrivate
54 {
55 guint32 selected;
56 } GncTreeModelAccountTypesPrivate;
57
58 #define GNC_TREE_MODEL_ACCOUNT_TYPES_GET_PRIVATE(o) \
59 ((GncTreeModelAccountTypesPrivate*)g_type_instance_get_private((GTypeInstance*)o, GNC_TYPE_TREE_MODEL_ACCOUNT_TYPES))
60
61 static GObjectClass *parent_class = NULL;
62
G_DEFINE_TYPE_WITH_CODE(GncTreeModelAccountTypes,gnc_tree_model_account_types,G_TYPE_OBJECT,G_ADD_PRIVATE (GncTreeModelAccountTypes)G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,gnc_tree_model_account_types_tree_model_init))63 G_DEFINE_TYPE_WITH_CODE(GncTreeModelAccountTypes, gnc_tree_model_account_types, G_TYPE_OBJECT,
64 G_ADD_PRIVATE(GncTreeModelAccountTypes)
65 G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL,
66 gnc_tree_model_account_types_tree_model_init))
67
68 static void
69 gnc_tree_model_account_types_class_init (GncTreeModelAccountTypesClass * klass)
70 {
71 GObjectClass *object_class = G_OBJECT_CLASS (klass);
72
73 parent_class = g_type_class_peek_parent (klass);
74
75 object_class->finalize = gnc_tree_model_account_types_finalize;
76 }
77
78 static void
gnc_tree_model_account_types_init(GncTreeModelAccountTypes * model)79 gnc_tree_model_account_types_init (GncTreeModelAccountTypes * model)
80 {
81 while (model->stamp == 0)
82 {
83 model->stamp = g_random_int ();
84 }
85 }
86
87 static void
gnc_tree_model_account_types_finalize(GObject * object)88 gnc_tree_model_account_types_finalize (GObject * object)
89 {
90 g_return_if_fail (object != NULL);
91 g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (object));
92
93 G_OBJECT_CLASS (parent_class)->finalize (object);
94 }
95
96 GtkTreeModel *
gnc_tree_model_account_types_new(guint32 selected)97 gnc_tree_model_account_types_new (guint32 selected)
98 {
99 GncTreeModelAccountTypes *model;
100 GncTreeModelAccountTypesPrivate *priv;
101
102 model = g_object_new (GNC_TYPE_TREE_MODEL_ACCOUNT_TYPES, NULL);
103 priv = GNC_TREE_MODEL_ACCOUNT_TYPES_GET_PRIVATE(model);
104 priv->selected = selected;
105
106 return GTK_TREE_MODEL (model);
107 }
108
109 static GtkTreeModel *
gnc_tree_model_account_types_master(void)110 gnc_tree_model_account_types_master(void)
111 {
112 if (!account_types_tree_model)
113 account_types_tree_model = gnc_tree_model_account_types_new(0);
114 return account_types_tree_model;
115 }
116
117
118 static gboolean
gnc_tree_model_account_types_is_valid(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)119 gnc_tree_model_account_types_is_valid (GtkTreeModel *model,
120 GtkTreeIter *iter, gpointer data)
121 {
122 GNCAccountType type;
123 GObject *f_model = G_OBJECT (data);
124 guint32 valid_types = GPOINTER_TO_UINT (g_object_get_data (
125 f_model, TYPE_MASK));
126
127 gtk_tree_model_get (model, iter,
128 GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE, &type, -1);
129 return (valid_types & (1 << type)) ? TRUE : FALSE;
130 }
131
132 GtkTreeModel *
gnc_tree_model_account_types_filter_using_mask(guint32 types)133 gnc_tree_model_account_types_filter_using_mask (guint32 types)
134 {
135 GtkTreeModel *f_model;
136
137 f_model = gtk_tree_model_filter_new (gnc_tree_model_account_types_master (),
138 NULL);
139 g_object_set_data (G_OBJECT (f_model), TYPE_MASK, GUINT_TO_POINTER (types));
140 gtk_tree_model_filter_set_visible_func (
141 GTK_TREE_MODEL_FILTER (f_model), gnc_tree_model_account_types_is_valid,
142 f_model, NULL);
143
144 return f_model;
145 }
146
147 void
gnc_tree_model_account_types_set_mask(GtkTreeModel * f_model,guint32 types)148 gnc_tree_model_account_types_set_mask (GtkTreeModel *f_model,
149 guint32 types)
150 {
151 g_return_if_fail (f_model);
152
153 g_object_set_data (G_OBJECT (f_model), TYPE_MASK, GUINT_TO_POINTER (types));
154 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (f_model));
155 }
156
157 guint32
gnc_tree_model_account_types_get_mask(GtkTreeModel * f_model)158 gnc_tree_model_account_types_get_mask (GtkTreeModel *f_model)
159 {
160 g_return_val_if_fail (f_model, 0);
161
162 return GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (f_model), TYPE_MASK));
163 }
164
165 guint32
gnc_tree_model_account_types_get_selection(GtkTreeSelection * sel)166 gnc_tree_model_account_types_get_selection (GtkTreeSelection *sel)
167 {
168 GtkTreeModel *f_model, *model;
169 GtkTreePath *path;
170 GtkTreeView *view;
171 GList *list, *node;
172 guint32 bits = 0;
173
174 g_return_val_if_fail(GTK_IS_TREE_SELECTION(sel), 0);
175 view = gtk_tree_selection_get_tree_view(sel);
176 g_return_val_if_fail (view, 0);
177
178 /* circumvent a bug in gtk+ not always filling f_model */
179 f_model = NULL;
180 list = gtk_tree_selection_get_selected_rows(sel, &f_model);
181 if (!f_model)
182 f_model = gtk_tree_view_get_model(view);
183
184 model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
185 if (model != account_types_tree_model)
186 PERR("TreeSelection's TreeModel is not the account-types Model");
187 else
188 {
189 for (node = list; node; node = node->next)
190 {
191 path = gtk_tree_model_filter_convert_path_to_child_path(
192 GTK_TREE_MODEL_FILTER(f_model), (GtkTreePath*)node->data);
193 if (!path || gtk_tree_path_get_depth(path) != 1)
194 {
195 PERR("Invalid Account-types TreePath.");
196 continue;
197 }
198 bits |= (1 << gtk_tree_path_get_indices(path)[0]);
199 }
200 }
201
202 g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
203 g_list_free (list);
204
205 return bits;
206 }
207
208 GNCAccountType
gnc_tree_model_account_types_get_selection_single(GtkTreeSelection * sel)209 gnc_tree_model_account_types_get_selection_single(GtkTreeSelection *sel)
210 {
211 gint i;
212 guint32 selected = gnc_tree_model_account_types_get_selection(sel);
213
214 for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
215 if (selected & (1 << i))
216 return i;
217 return ACCT_TYPE_NONE;
218 }
219
220 void
gnc_tree_model_account_types_set_selection(GtkTreeSelection * sel,guint32 selected)221 gnc_tree_model_account_types_set_selection (GtkTreeSelection *sel,
222 guint32 selected)
223 {
224 GtkTreePath *path, *f_path;
225 GtkTreeModelFilter *f_model;
226 gint i;
227 GtkTreeView *view;
228
229 g_return_if_fail(GTK_IS_TREE_SELECTION(sel));
230 view = gtk_tree_selection_get_tree_view(sel);
231 g_return_if_fail (view);
232 f_model = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(view));
233 g_return_if_fail(gtk_tree_model_filter_get_model(f_model) ==
234 account_types_tree_model);
235 gtk_tree_selection_unselect_all(sel);
236 path = gtk_tree_path_new_first();
237
238 for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
239 {
240 if (selected & (1 << i))
241 {
242 f_path = gtk_tree_model_filter_convert_child_path_to_path(
243 f_model, path);
244 gtk_tree_selection_select_path(sel, f_path);
245 gtk_tree_view_scroll_to_cell(view, f_path, NULL, FALSE, 0.0, 0.0);
246 }
247 gtk_tree_path_next(path);
248 }
249 gtk_tree_path_free(path);
250 }
251
252
253 /* Static functions implementing GtkTreeModel */
254
255 static GtkTreeModelFlags
gnc_tree_model_account_types_get_flags(GtkTreeModel * tree_model)256 gnc_tree_model_account_types_get_flags (GtkTreeModel * tree_model)
257 {
258 return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
259 }
260
261 static int
gnc_tree_model_account_types_get_n_columns(GtkTreeModel * tree_model)262 gnc_tree_model_account_types_get_n_columns (GtkTreeModel * tree_model)
263 {
264 return GNC_TREE_MODEL_ACCOUNT_TYPES_NUM_COLUMNS;
265 }
266
267 static GType
gnc_tree_model_account_types_get_column_type(GtkTreeModel * tree_model,int index)268 gnc_tree_model_account_types_get_column_type (GtkTreeModel * tree_model,
269 int index)
270 {
271 g_return_val_if_fail(GNC_IS_TREE_MODEL_ACCOUNT_TYPES (tree_model),
272 G_TYPE_INVALID);
273 g_return_val_if_fail((index < GNC_TREE_MODEL_ACCOUNT_TYPES_NUM_COLUMNS)
274 && (index >= 0), G_TYPE_INVALID);
275
276 switch (index)
277 {
278 case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE:
279 return G_TYPE_INT;
280 case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME:
281 return G_TYPE_STRING;
282 case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_SELECTED:
283 return G_TYPE_BOOLEAN;
284 default:
285 g_assert_not_reached ();
286 return G_TYPE_INVALID;
287 }
288 }
289
290 static gboolean
gnc_tree_model_account_types_get_iter(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreePath * path)291 gnc_tree_model_account_types_get_iter (GtkTreeModel * tree_model,
292 GtkTreeIter * iter, GtkTreePath * path)
293 {
294 GncTreeModelAccountTypes *model = GNC_TREE_MODEL_ACCOUNT_TYPES(tree_model);
295 gint i;
296
297 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (model), FALSE);
298 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
299
300 i = gtk_tree_path_get_indices (path)[0];
301
302 if (i > ACCT_TYPE_NONE && i < NUM_ACCOUNT_TYPES)
303 {
304 iter->stamp = model->stamp;
305 iter->user_data = GINT_TO_POINTER (i);
306 return TRUE;
307 }
308
309 iter->stamp = 0;
310 return FALSE;
311 }
312
313 static GtkTreePath *
gnc_tree_model_account_types_get_path(GtkTreeModel * tree_model,GtkTreeIter * iter)314 gnc_tree_model_account_types_get_path (GtkTreeModel * tree_model,
315 GtkTreeIter * iter)
316 {
317 GncTreeModelAccountTypes *model = GNC_TREE_MODEL_ACCOUNT_TYPES(tree_model);
318 GtkTreePath *path;
319
320 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (model), NULL);
321 g_return_val_if_fail (iter != NULL, NULL);
322 g_return_val_if_fail (iter->stamp == model->stamp, NULL);
323
324 path = gtk_tree_path_new ();
325
326 gtk_tree_path_append_index (path, GPOINTER_TO_INT (iter->user_data));
327
328 return path;
329 }
330
331 static void
gnc_tree_model_account_types_get_value(GtkTreeModel * tree_model,GtkTreeIter * iter,int column,GValue * value)332 gnc_tree_model_account_types_get_value (GtkTreeModel * tree_model,
333 GtkTreeIter * iter, int column,
334 GValue * value)
335 {
336 GncTreeModelAccountTypes *model = GNC_TREE_MODEL_ACCOUNT_TYPES(tree_model);
337 GncTreeModelAccountTypesPrivate *priv;
338
339 g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (model));
340 g_return_if_fail (iter != NULL);
341 g_return_if_fail (iter->stamp == model->stamp);
342
343 priv = GNC_TREE_MODEL_ACCOUNT_TYPES_GET_PRIVATE(model);
344 switch (column)
345 {
346 case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE:
347 g_value_init (value, G_TYPE_INT);
348 g_value_set_int (value, GPOINTER_TO_INT (iter->user_data));
349 break;
350 case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME:
351 g_value_init (value, G_TYPE_STRING);
352 g_value_set_string (value, xaccAccountGetTypeStr (
353 GPOINTER_TO_INT (iter->user_data)));
354 break;
355 case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_SELECTED:
356 g_value_init (value, G_TYPE_BOOLEAN);
357 g_value_set_boolean (value, priv->selected &
358 (1 << GPOINTER_TO_INT (iter->user_data)));
359 break;
360 default:
361 g_assert_not_reached ();
362 }
363 }
364
365 static gboolean
gnc_tree_model_account_types_iter_next(GtkTreeModel * tree_model,GtkTreeIter * iter)366 gnc_tree_model_account_types_iter_next (GtkTreeModel * tree_model,
367 GtkTreeIter * iter)
368 {
369 GncTreeModelAccountTypes *model = GNC_TREE_MODEL_ACCOUNT_TYPES(tree_model);
370
371 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (model), FALSE);
372 g_return_val_if_fail (iter != NULL, FALSE);
373 g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
374
375 if (GPOINTER_TO_INT (iter->user_data) < NUM_ACCOUNT_TYPES - 1)
376 {
377 iter->user_data = GINT_TO_POINTER(
378 GPOINTER_TO_INT(iter->user_data) + 1);
379 return TRUE;
380 }
381
382 iter->stamp = 0;
383 return FALSE;
384 }
385
386 static gboolean
gnc_tree_model_account_types_iter_children(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent)387 gnc_tree_model_account_types_iter_children (GtkTreeModel * tree_model,
388 GtkTreeIter * iter,
389 GtkTreeIter * parent)
390 {
391
392 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES(tree_model), FALSE);
393
394 if (parent != NULL)
395 return FALSE;
396
397 iter->stamp = GNC_TREE_MODEL_ACCOUNT_TYPES (tree_model)->stamp;
398 iter->user_data = GINT_TO_POINTER (0);
399
400 return TRUE;
401 }
402
403 static gboolean
gnc_tree_model_account_types_iter_has_child(GtkTreeModel * tree_model,GtkTreeIter * iter)404 gnc_tree_model_account_types_iter_has_child (GtkTreeModel * tree_model,
405 GtkTreeIter * iter)
406 {
407 return FALSE;
408 }
409
410 static int
gnc_tree_model_account_types_iter_n_children(GtkTreeModel * tree_model,GtkTreeIter * iter)411 gnc_tree_model_account_types_iter_n_children (GtkTreeModel * tree_model,
412 GtkTreeIter * iter)
413 {
414 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (tree_model), -1);
415
416 if (iter == NULL)
417 return NUM_ACCOUNT_TYPES;
418
419 g_return_val_if_fail (
420 GNC_TREE_MODEL_ACCOUNT_TYPES (tree_model)->stamp == iter->stamp, -1);
421
422 return 0;
423 }
424
425 static gboolean
gnc_tree_model_account_types_iter_nth_child(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent,int n)426 gnc_tree_model_account_types_iter_nth_child (GtkTreeModel * tree_model,
427 GtkTreeIter * iter,
428 GtkTreeIter * parent, int n)
429 {
430 GncTreeModelAccountTypes *model;
431
432 g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (tree_model), FALSE);
433
434 if (parent != NULL)
435 return FALSE;
436
437 model = GNC_TREE_MODEL_ACCOUNT_TYPES (tree_model);
438
439 if (n > ACCT_TYPE_NONE && n < NUM_ACCOUNT_TYPES)
440 {
441 iter->stamp = model->stamp;
442 iter->user_data = GINT_TO_POINTER (n);
443 return TRUE;
444 }
445
446 iter->stamp = 0;
447 return FALSE;
448 }
449
450 static gboolean
gnc_tree_model_account_types_iter_parent(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * child)451 gnc_tree_model_account_types_iter_parent (GtkTreeModel * tree_model,
452 GtkTreeIter * iter,
453 GtkTreeIter * child)
454 {
455 return FALSE;
456 }
457
458 static void
gnc_tree_model_account_types_tree_model_init(GtkTreeModelIface * iface)459 gnc_tree_model_account_types_tree_model_init (GtkTreeModelIface * iface)
460 {
461 iface->get_flags = gnc_tree_model_account_types_get_flags;
462 iface->get_n_columns = gnc_tree_model_account_types_get_n_columns;
463 iface->get_column_type = gnc_tree_model_account_types_get_column_type;
464 iface->get_iter = gnc_tree_model_account_types_get_iter;
465 iface->get_path = gnc_tree_model_account_types_get_path;
466 iface->get_value = gnc_tree_model_account_types_get_value;
467 iface->iter_next = gnc_tree_model_account_types_iter_next;
468 iface->iter_children = gnc_tree_model_account_types_iter_children;
469 iface->iter_has_child = gnc_tree_model_account_types_iter_has_child;
470 iface->iter_n_children = gnc_tree_model_account_types_iter_n_children;
471 iface->iter_nth_child = gnc_tree_model_account_types_iter_nth_child;
472 iface->iter_parent = gnc_tree_model_account_types_iter_parent;
473 }
474
475