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