GnuCash 2.4.99
gnc-tree-model-account-types.c
00001 /*
00002  * gnc-tree-model-account-types.c -- GtkTreeModel implementation
00003  *      to display account types in a GtkTreeView.
00004  *
00005  * Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
00006  * Copyright (C) 2005, 2006 Chris Shoemaker <c.shoemaker@cox.net>
00007  * Copyright (C) 2006 Eskil Bylund <eskil.bylund@gmail.com>
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License as
00011  * published by the Free Software Foundation; either version 2 of
00012  * the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, contact:
00021  *
00022  * Free Software Foundation           Voice:  +1-617-542-5942
00023  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00024  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00025  */
00026 
00027 #include "config.h"
00028 
00029 #include <gtk/gtk.h>
00030 
00031 #include "qof.h"
00032 #include "gnc-tree-model-account-types.h"
00033 #include "Account.h"
00034 
00035 static QofLogModule log_module = GNC_MOD_GUI;
00036 static GtkTreeModel *account_types_tree_model = NULL;
00037 
00038 #define TYPE_MASK "type-mask"
00039 
00040 /* Functions for the type system */
00041 static void
00042 gnc_tree_model_account_types_class_init (GncTreeModelAccountTypesClass *klass);
00043 static void
00044 gnc_tree_model_account_types_init (GncTreeModelAccountTypes * model);
00045 static void
00046 gnc_tree_model_account_types_finalize (GObject * object);
00047 
00048 
00049 /* Functions implementing GtkTreeModel */
00050 static void
00051 gnc_tree_model_account_types_tree_model_init (GtkTreeModelIface * iface);
00052 
00053 typedef struct GncTreeModelAccountTypesPrivate
00054 {
00055     guint32 selected;
00056 } GncTreeModelAccountTypesPrivate;
00057 
00058 #define GNC_TREE_MODEL_ACCOUNT_TYPES_GET_PRIVATE(o)  \
00059    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_TREE_MODEL_ACCOUNT_TYPES, \
00060                                  GncTreeModelAccountTypesPrivate))
00061 
00062 static GObjectClass *parent_class = NULL;
00063 
00064 GType
00065 gnc_tree_model_account_types_get_type (void)
00066 {
00067     static GType gnc_tree_model_account_types_type = 0;
00068 
00069     if (gnc_tree_model_account_types_type == 0)
00070     {
00071         static const GTypeInfo our_info =
00072         {
00073             sizeof (GncTreeModelAccountTypesClass),
00074             NULL,
00075             NULL,
00076             (GClassInitFunc) gnc_tree_model_account_types_class_init,
00077             NULL,
00078             NULL,
00079             sizeof (GncTreeModelAccountTypes),
00080             0,
00081             (GInstanceInitFunc) gnc_tree_model_account_types_init
00082         };
00083 
00084         static const GInterfaceInfo tree_model_info =
00085         {
00086             (GInterfaceInitFunc) gnc_tree_model_account_types_tree_model_init,
00087             NULL,
00088             NULL
00089         };
00090 
00091         gnc_tree_model_account_types_type =
00092             g_type_register_static (G_TYPE_OBJECT,
00093                                     "GncTreeModelAccountTypes",
00094                                     &our_info, 0);
00095 
00096         g_type_add_interface_static (gnc_tree_model_account_types_type,
00097                                      GTK_TYPE_TREE_MODEL, &tree_model_info);
00098     }
00099 
00100     return gnc_tree_model_account_types_type;
00101 }
00102 
00103 static void
00104 gnc_tree_model_account_types_class_init (GncTreeModelAccountTypesClass * klass)
00105 {
00106     GObjectClass *object_class = G_OBJECT_CLASS (klass);
00107 
00108     parent_class = g_type_class_peek_parent (klass);
00109 
00110     object_class->finalize = gnc_tree_model_account_types_finalize;
00111 
00112     g_type_class_add_private(klass, sizeof(GncTreeModelAccountTypesPrivate));
00113 }
00114 
00115 static void
00116 gnc_tree_model_account_types_init (GncTreeModelAccountTypes * model)
00117 {
00118     while (model->stamp == 0)
00119     {
00120         model->stamp = g_random_int ();
00121     }
00122 }
00123 
00124 static void
00125 gnc_tree_model_account_types_finalize (GObject * object)
00126 {
00127     GncTreeModelAccountTypes *model;
00128     GncTreeModelAccountTypesPrivate *priv;
00129 
00130     g_return_if_fail (object != NULL);
00131     g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (object));
00132 
00133     model = GNC_TREE_MODEL_ACCOUNT_TYPES (object);
00134     priv = GNC_TREE_MODEL_ACCOUNT_TYPES_GET_PRIVATE (model);
00135 
00136     G_OBJECT_CLASS (parent_class)->finalize (object);
00137 }
00138 
00139 GtkTreeModel *
00140 gnc_tree_model_account_types_new (guint32 selected)
00141 {
00142     GncTreeModelAccountTypes *model;
00143     GncTreeModelAccountTypesPrivate *priv;
00144 
00145     model = g_object_new (GNC_TYPE_TREE_MODEL_ACCOUNT_TYPES, NULL);
00146     priv = GNC_TREE_MODEL_ACCOUNT_TYPES_GET_PRIVATE(model);
00147     priv->selected = selected;
00148 
00149     return GTK_TREE_MODEL (model);
00150 }
00151 
00152 static GtkTreeModel *
00153 gnc_tree_model_account_types_master(void)
00154 {
00155     if (!account_types_tree_model)
00156         account_types_tree_model = gnc_tree_model_account_types_new(0);
00157     return account_types_tree_model;
00158 }
00159 
00160 
00161 static gboolean
00162 gnc_tree_model_account_types_is_valid (GtkTreeModel *model,
00163                                        GtkTreeIter *iter, gpointer data)
00164 {
00165     GNCAccountType type;
00166     GObject *f_model = G_OBJECT (data);
00167     guint32 valid_types = GPOINTER_TO_UINT (g_object_get_data (
00168             f_model, TYPE_MASK));
00169 
00170     gtk_tree_model_get (model, iter,
00171                         GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE, &type, -1);
00172     return (valid_types & (1 << type)) ? TRUE : FALSE;
00173 }
00174 
00175 GtkTreeModel *
00176 gnc_tree_model_account_types_filter_using_mask (guint32 types)
00177 {
00178     GtkTreeModel *f_model;
00179 
00180     f_model = gtk_tree_model_filter_new (gnc_tree_model_account_types_master (),
00181                                          NULL);
00182     g_object_set_data (G_OBJECT (f_model), TYPE_MASK, GUINT_TO_POINTER (types));
00183     gtk_tree_model_filter_set_visible_func (
00184         GTK_TREE_MODEL_FILTER (f_model), gnc_tree_model_account_types_is_valid,
00185         f_model, NULL);
00186 
00187     return f_model;
00188 }
00189 
00190 void
00191 gnc_tree_model_account_types_set_mask (GtkTreeModel *f_model,
00192                                        guint32 types)
00193 {
00194     g_return_if_fail (f_model);
00195 
00196     g_object_set_data (G_OBJECT (f_model), TYPE_MASK, GUINT_TO_POINTER (types));
00197     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (f_model));
00198 }
00199 
00200 guint32
00201 gnc_tree_model_account_types_get_mask (GtkTreeModel *f_model)
00202 {
00203     g_return_val_if_fail (f_model, 0);
00204 
00205     return GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (f_model), TYPE_MASK));
00206 }
00207 
00208 guint32
00209 gnc_tree_model_account_types_get_selection (GtkTreeSelection *sel)
00210 {
00211     GtkTreeModel *f_model, *model;
00212     GtkTreePath *path;
00213     GtkTreeView *view;
00214     GList *list, *node;
00215     guint32 bits = 0;
00216 
00217     g_return_val_if_fail(GTK_IS_TREE_SELECTION(sel), 0);
00218     view = gtk_tree_selection_get_tree_view(sel);
00219     g_return_val_if_fail (view, 0);
00220 
00221     /* circumvent a bug in gtk+ not always filling f_model */
00222     f_model = NULL;
00223     list = gtk_tree_selection_get_selected_rows(sel, &f_model);
00224     if (!f_model)
00225         f_model = gtk_tree_view_get_model(view);
00226 
00227     model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
00228     if (model != account_types_tree_model)
00229         PERR("TreeSelection's TreeModel is not the account-types Model");
00230     else
00231     {
00232         for (node = list; node; node = node->next)
00233         {
00234             path = gtk_tree_model_filter_convert_path_to_child_path(
00235                        GTK_TREE_MODEL_FILTER(f_model), (GtkTreePath*)node->data);
00236             if (!path || gtk_tree_path_get_depth(path) != 1)
00237             {
00238                 PERR("Invalid Account-types TreePath.");
00239                 continue;
00240             }
00241             bits |= (1 << gtk_tree_path_get_indices(path)[0]);
00242         }
00243     }
00244 
00245     g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
00246     g_list_free (list);
00247 
00248     return bits;
00249 }
00250 
00251 GNCAccountType
00252 gnc_tree_model_account_types_get_selection_single(GtkTreeSelection *sel)
00253 {
00254     gint i;
00255     guint32 selected = gnc_tree_model_account_types_get_selection(sel);
00256 
00257     for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
00258         if (selected & (1 << i))
00259             return i;
00260     return ACCT_TYPE_NONE;
00261 }
00262 
00263 void
00264 gnc_tree_model_account_types_set_selection (GtkTreeSelection *sel,
00265         guint32 selected)
00266 {
00267     GtkTreePath *path, *f_path;
00268     GtkTreeModelFilter *f_model;
00269     gint i;
00270     GtkTreeView *view;
00271 
00272     g_return_if_fail(GTK_IS_TREE_SELECTION(sel));
00273     view = gtk_tree_selection_get_tree_view(sel);
00274     g_return_if_fail (view);
00275     f_model = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(view));
00276     g_return_if_fail(gtk_tree_model_filter_get_model(f_model) ==
00277                      account_types_tree_model);
00278     gtk_tree_selection_unselect_all(sel);
00279     path = gtk_tree_path_new_first();
00280 
00281     for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
00282     {
00283         if (selected & (1 << i))
00284         {
00285             f_path = gtk_tree_model_filter_convert_child_path_to_path(
00286                          f_model, path);
00287             gtk_tree_selection_select_path(sel, f_path);
00288             gtk_tree_view_scroll_to_cell(view, f_path, NULL, FALSE, 0.0, 0.0);
00289         }
00290         gtk_tree_path_next(path);
00291     }
00292     gtk_tree_path_free(path);
00293 }
00294 
00295 
00296 /* Static functions implementing GtkTreeModel */
00297 
00298 static GtkTreeModelFlags
00299 gnc_tree_model_account_types_get_flags (GtkTreeModel * tree_model)
00300 {
00301     return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
00302 }
00303 
00304 static int
00305 gnc_tree_model_account_types_get_n_columns (GtkTreeModel * tree_model)
00306 {
00307     return GNC_TREE_MODEL_ACCOUNT_TYPES_NUM_COLUMNS;
00308 }
00309 
00310 static GType
00311 gnc_tree_model_account_types_get_column_type (GtkTreeModel * tree_model,
00312         int index)
00313 {
00314     g_return_val_if_fail(GNC_IS_TREE_MODEL_ACCOUNT_TYPES (tree_model),
00315                          G_TYPE_INVALID);
00316     g_return_val_if_fail((index < GNC_TREE_MODEL_ACCOUNT_TYPES_NUM_COLUMNS)
00317                          && (index >= 0), G_TYPE_INVALID);
00318 
00319     switch (index)
00320     {
00321     case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE:
00322         return G_TYPE_INT;
00323     case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME:
00324         return G_TYPE_STRING;
00325     case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_SELECTED:
00326         return G_TYPE_BOOLEAN;
00327     default:
00328         g_assert_not_reached ();
00329         return G_TYPE_INVALID;
00330     }
00331 }
00332 
00333 static gboolean
00334 gnc_tree_model_account_types_get_iter (GtkTreeModel * tree_model,
00335                                        GtkTreeIter * iter, GtkTreePath * path)
00336 {
00337     GncTreeModelAccountTypes *model = GNC_TREE_MODEL_ACCOUNT_TYPES(tree_model);
00338     gint i;
00339 
00340     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (model), FALSE);
00341     g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
00342 
00343     i = gtk_tree_path_get_indices (path)[0];
00344 
00345     if (i > ACCT_TYPE_NONE && i < NUM_ACCOUNT_TYPES)
00346     {
00347         iter->stamp = model->stamp;
00348         iter->user_data = GINT_TO_POINTER (i);
00349         return TRUE;
00350     }
00351 
00352     iter->stamp = 0;
00353     return FALSE;
00354 }
00355 
00356 static GtkTreePath *
00357 gnc_tree_model_account_types_get_path (GtkTreeModel * tree_model,
00358                                        GtkTreeIter * iter)
00359 {
00360     GncTreeModelAccountTypes *model = GNC_TREE_MODEL_ACCOUNT_TYPES(tree_model);
00361     GtkTreePath *path;
00362 
00363     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (model), NULL);
00364     g_return_val_if_fail (iter != NULL, NULL);
00365     g_return_val_if_fail (iter->stamp == model->stamp, NULL);
00366 
00367     path = gtk_tree_path_new ();
00368 
00369     gtk_tree_path_append_index (path, GPOINTER_TO_INT (iter->user_data));
00370 
00371     return path;
00372 }
00373 
00374 static void
00375 gnc_tree_model_account_types_get_value (GtkTreeModel * tree_model,
00376                                         GtkTreeIter * iter, int column,
00377                                         GValue * value)
00378 {
00379     GncTreeModelAccountTypes *model = GNC_TREE_MODEL_ACCOUNT_TYPES(tree_model);
00380     GncTreeModelAccountTypesPrivate *priv;
00381 
00382     g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (model));
00383     g_return_if_fail (iter != NULL);
00384     g_return_if_fail (iter->stamp == model->stamp);
00385 
00386     priv = GNC_TREE_MODEL_ACCOUNT_TYPES_GET_PRIVATE(model);
00387     switch (column)
00388     {
00389     case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_TYPE:
00390         g_value_init (value, G_TYPE_INT);
00391         g_value_set_int (value, GPOINTER_TO_INT (iter->user_data));
00392         break;
00393     case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_NAME:
00394         g_value_init (value, G_TYPE_STRING);
00395         g_value_set_string (value, xaccAccountGetTypeStr (
00396                                 GPOINTER_TO_INT (iter->user_data)));
00397         break;
00398     case GNC_TREE_MODEL_ACCOUNT_TYPES_COL_SELECTED:
00399         g_value_init (value, G_TYPE_BOOLEAN);
00400         g_value_set_boolean (value, priv->selected &
00401                              (1 << GPOINTER_TO_INT (iter->user_data)));
00402         break;
00403     default:
00404         g_assert_not_reached ();
00405     }
00406 }
00407 
00408 static gboolean
00409 gnc_tree_model_account_types_iter_next (GtkTreeModel * tree_model,
00410                                         GtkTreeIter * iter)
00411 {
00412     GncTreeModelAccountTypes *model = GNC_TREE_MODEL_ACCOUNT_TYPES(tree_model);
00413 
00414     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (model), FALSE);
00415     g_return_val_if_fail (iter != NULL, FALSE);
00416     g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
00417 
00418     if (GPOINTER_TO_INT (iter->user_data) < NUM_ACCOUNT_TYPES - 1)
00419     {
00420         iter->user_data = GINT_TO_POINTER(
00421                               GPOINTER_TO_INT(iter->user_data) + 1);
00422         return TRUE;
00423     }
00424 
00425     iter->stamp = 0;
00426     return FALSE;
00427 }
00428 
00429 static gboolean
00430 gnc_tree_model_account_types_iter_children (GtkTreeModel * tree_model,
00431         GtkTreeIter * iter,
00432         GtkTreeIter * parent)
00433 {
00434 
00435     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES(tree_model), FALSE);
00436 
00437     if (parent != NULL)
00438         return FALSE;
00439 
00440     iter->stamp = GNC_TREE_MODEL_ACCOUNT_TYPES (tree_model)->stamp;
00441     iter->user_data = GINT_TO_POINTER (0);
00442 
00443     return TRUE;
00444 }
00445 
00446 static gboolean
00447 gnc_tree_model_account_types_iter_has_child (GtkTreeModel * tree_model,
00448         GtkTreeIter * iter)
00449 {
00450     return FALSE;
00451 }
00452 
00453 static int
00454 gnc_tree_model_account_types_iter_n_children (GtkTreeModel * tree_model,
00455         GtkTreeIter * iter)
00456 {
00457     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (tree_model), -1);
00458 
00459     if (iter == NULL)
00460         return NUM_ACCOUNT_TYPES;
00461 
00462     g_return_val_if_fail (
00463         GNC_TREE_MODEL_ACCOUNT_TYPES (tree_model)->stamp == iter->stamp, -1);
00464 
00465     return 0;
00466 }
00467 
00468 static gboolean
00469 gnc_tree_model_account_types_iter_nth_child (GtkTreeModel * tree_model,
00470         GtkTreeIter * iter,
00471         GtkTreeIter * parent, int n)
00472 {
00473     GncTreeModelAccountTypes *model;
00474 
00475     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT_TYPES (tree_model), FALSE);
00476 
00477     if (parent != NULL)
00478         return FALSE;
00479 
00480     model = GNC_TREE_MODEL_ACCOUNT_TYPES (tree_model);
00481 
00482     if (n > ACCT_TYPE_NONE && n < NUM_ACCOUNT_TYPES)
00483     {
00484         iter->stamp = model->stamp;
00485         iter->user_data = GINT_TO_POINTER (n);
00486         return TRUE;
00487     }
00488 
00489     iter->stamp = 0;
00490     return FALSE;
00491 }
00492 
00493 static gboolean
00494 gnc_tree_model_account_types_iter_parent (GtkTreeModel * tree_model,
00495         GtkTreeIter * iter,
00496         GtkTreeIter * child)
00497 {
00498     return FALSE;
00499 }
00500 
00501 static void
00502 gnc_tree_model_account_types_tree_model_init (GtkTreeModelIface * iface)
00503 {
00504     iface->get_flags = gnc_tree_model_account_types_get_flags;
00505     iface->get_n_columns = gnc_tree_model_account_types_get_n_columns;
00506     iface->get_column_type = gnc_tree_model_account_types_get_column_type;
00507     iface->get_iter = gnc_tree_model_account_types_get_iter;
00508     iface->get_path = gnc_tree_model_account_types_get_path;
00509     iface->get_value = gnc_tree_model_account_types_get_value;
00510     iface->iter_next = gnc_tree_model_account_types_iter_next;
00511     iface->iter_children = gnc_tree_model_account_types_iter_children;
00512     iface->iter_has_child = gnc_tree_model_account_types_iter_has_child;
00513     iface->iter_n_children = gnc_tree_model_account_types_iter_n_children;
00514     iface->iter_nth_child = gnc_tree_model_account_types_iter_nth_child;
00515     iface->iter_parent = gnc_tree_model_account_types_iter_parent;
00516 }
00517 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines