GnuCash 2.4.99
gnc-tree-model-account.c
00001 /*
00002  * gnc-tree-model-account.c -- GtkTreeModel implementation to
00003  *      display accounts in a GtkTreeView.
00004  *
00005  * Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
00006  * Copyright (C) 2003 David Hampton <hampton@employees.org>
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License as
00010  * published by the Free Software Foundation; either version 2 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, contact:
00020  *
00021  * Free Software Foundation           Voice:  +1-617-542-5942
00022  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00023  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00024  */
00025 
00026 #include "config.h"
00027 
00028 #include <gtk/gtk.h>
00029 #include <glib/gi18n.h>
00030 #include <string.h>
00031 
00032 #include "gnc-tree-model-account.h"
00033 #include "gnc-component-manager.h"
00034 #include "Account.h"
00035 #include "gnc-accounting-period.h"
00036 #include "gnc-commodity.h"
00037 #include "gnc-gconf-utils.h"
00038 #include "gnc-engine.h"
00039 #include "gnc-event.h"
00040 #include "gnc-gobject-utils.h"
00041 #include "gnc-ui-balances.h"
00042 #include "gnc-ui-util.h"
00043 
00044 #define TREE_MODEL_ACCOUNT_CM_CLASS "tree-model-account"
00045 
00047 static QofLogModule log_module = GNC_MOD_GUI;
00048 
00050 static void gnc_tree_model_account_class_init (GncTreeModelAccountClass *klass);
00051 static void gnc_tree_model_account_init (GncTreeModelAccount *model);
00052 static void gnc_tree_model_account_finalize (GObject *object);
00053 static void gnc_tree_model_account_dispose (GObject *object);
00054 
00056 static void gnc_tree_model_account_tree_model_init (GtkTreeModelIface *iface);
00057 static GtkTreeModelFlags gnc_tree_model_account_get_flags (GtkTreeModel *tree_model);
00058 static int gnc_tree_model_account_get_n_columns (GtkTreeModel *tree_model);
00059 static GType gnc_tree_model_account_get_column_type (GtkTreeModel *tree_model,
00060         int index);
00061 static gboolean gnc_tree_model_account_get_iter (GtkTreeModel *tree_model,
00062         GtkTreeIter *iter,
00063         GtkTreePath *path);
00064 static GtkTreePath *gnc_tree_model_account_get_path (GtkTreeModel *tree_model,
00065         GtkTreeIter *iter);
00066 static void gnc_tree_model_account_get_value (GtkTreeModel *tree_model,
00067         GtkTreeIter *iter,
00068         int column,
00069         GValue *value);
00070 static gboolean gnc_tree_model_account_iter_next (GtkTreeModel *tree_model,
00071         GtkTreeIter *iter);
00072 static gboolean gnc_tree_model_account_iter_children (GtkTreeModel *tree_model,
00073         GtkTreeIter *iter,
00074         GtkTreeIter *parent);
00075 static gboolean gnc_tree_model_account_iter_has_child (GtkTreeModel *tree_model,
00076         GtkTreeIter *iter);
00077 static int gnc_tree_model_account_iter_n_children (GtkTreeModel *tree_model,
00078         GtkTreeIter *iter);
00079 static gboolean gnc_tree_model_account_iter_nth_child (GtkTreeModel *tree_model,
00080         GtkTreeIter *iter,
00081         GtkTreeIter *parent,
00082         int n);
00083 static gboolean gnc_tree_model_account_iter_parent (GtkTreeModel *tree_model,
00084         GtkTreeIter *iter,
00085         GtkTreeIter *child);
00086 
00088 static void gnc_tree_model_account_event_handler (QofInstance *entity,
00089         QofEventId event_type,
00090         GncTreeModelAccount *model,
00091         GncEventData *ed);
00092 
00094 typedef struct GncTreeModelAccountPrivate
00095 {
00096     QofBook *book;
00097     Account *root;
00098     gint event_handler_id;
00099     const gchar *negative_color;
00100 } GncTreeModelAccountPrivate;
00101 
00102 #define GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(o)  \
00103    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_TREE_MODEL_ACCOUNT, GncTreeModelAccountPrivate))
00104 
00105 
00106 /************************************************************/
00107 /*           Account Tree Model - Misc Functions            */
00108 /************************************************************/
00109 
00116 static void
00117 gnc_tree_model_account_update_color (GConfEntry *entry, gpointer user_data)
00118 {
00119     GncTreeModelAccountPrivate *priv;
00120     GncTreeModelAccount *model;
00121     GConfValue *value;
00122     gboolean use_red;
00123 
00124     g_return_if_fail(GNC_IS_TREE_MODEL_ACCOUNT(user_data));
00125     model = user_data;
00126     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00127     value = gconf_entry_get_value(entry);
00128     use_red = gconf_value_get_bool(value);
00129     priv->negative_color = use_red ? "red" : "black";
00130 }
00131 /************************************************************/
00132 /*               g_object required functions                */
00133 /************************************************************/
00134 
00136 static GtkObjectClass *parent_class = NULL;
00137 
00138 GType
00139 gnc_tree_model_account_get_type (void)
00140 {
00141     static GType gnc_tree_model_account_type = 0;
00142 
00143     if (gnc_tree_model_account_type == 0)
00144     {
00145         static const GTypeInfo our_info =
00146         {
00147             sizeof (GncTreeModelAccountClass), /* class_size */
00148             NULL,                              /* base_init */
00149             NULL,                              /* base_finalize */
00150             (GClassInitFunc) gnc_tree_model_account_class_init,
00151             NULL,                              /* class_finalize */
00152             NULL,                              /* class_data */
00153             sizeof (GncTreeModelAccount),      /* */
00154             0,                                 /* n_preallocs */
00155             (GInstanceInitFunc) gnc_tree_model_account_init
00156         };
00157 
00158         static const GInterfaceInfo tree_model_info =
00159         {
00160             (GInterfaceInitFunc) gnc_tree_model_account_tree_model_init,
00161             NULL,
00162             NULL
00163         };
00164 
00165         gnc_tree_model_account_type = g_type_register_static (GNC_TYPE_TREE_MODEL,
00166                                       GNC_TREE_MODEL_ACCOUNT_NAME,
00167                                       &our_info, 0);
00168 
00169         g_type_add_interface_static (gnc_tree_model_account_type,
00170                                      GTK_TYPE_TREE_MODEL,
00171                                      &tree_model_info);
00172     }
00173 
00174     return gnc_tree_model_account_type;
00175 }
00176 
00177 static void
00178 gnc_tree_model_account_class_init (GncTreeModelAccountClass *klass)
00179 {
00180     GObjectClass *o_class;
00181 
00182     parent_class = g_type_class_peek_parent (klass);
00183 
00184     o_class = G_OBJECT_CLASS (klass);
00185 
00186     /* GObject signals */
00187     o_class->finalize = gnc_tree_model_account_finalize;
00188     o_class->dispose = gnc_tree_model_account_dispose;
00189 
00190     g_type_class_add_private(klass, sizeof(GncTreeModelAccountPrivate));
00191 }
00192 
00193 static void
00194 gnc_tree_model_account_init (GncTreeModelAccount *model)
00195 {
00196     GncTreeModelAccountPrivate *priv;
00197     gboolean red;
00198 
00199     ENTER("model %p", model);
00200     while (model->stamp == 0)
00201     {
00202         model->stamp = g_random_int ();
00203     }
00204 
00205     red = gnc_gconf_get_bool(GCONF_GENERAL, KEY_NEGATIVE_IN_RED, NULL);
00206 
00207     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00208     priv->book = NULL;
00209     priv->root = NULL;
00210     priv->negative_color = red ? "red" : "black";
00211 
00212     gnc_gconf_general_register_cb(KEY_NEGATIVE_IN_RED,
00213                                   gnc_tree_model_account_update_color,
00214                                   model);
00215 
00216     LEAVE(" ");
00217 }
00218 
00219 static void
00220 gnc_tree_model_account_finalize (GObject *object)
00221 {
00222     GncTreeModelAccountPrivate *priv;
00223     GncTreeModelAccount *model;
00224 
00225     g_return_if_fail (object != NULL);
00226     g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (object));
00227 
00228     ENTER("model %p", object);
00229 
00230     model = GNC_TREE_MODEL_ACCOUNT (object);
00231     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00232 
00233     gnc_gconf_general_remove_cb(KEY_NEGATIVE_IN_RED,
00234                                 gnc_tree_model_account_update_color,
00235                                 model);
00236 
00237     priv->book = NULL;
00238 
00239     if (G_OBJECT_CLASS (parent_class)->finalize)
00240         G_OBJECT_CLASS(parent_class)->finalize (object);
00241     LEAVE(" ");
00242 }
00243 
00244 static void
00245 gnc_tree_model_account_dispose (GObject *object)
00246 {
00247     GncTreeModelAccountPrivate *priv;
00248     GncTreeModelAccount *model;
00249 
00250     g_return_if_fail (object != NULL);
00251     g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (object));
00252 
00253     ENTER("model %p", object);
00254 
00255     model = GNC_TREE_MODEL_ACCOUNT (object);
00256     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00257 
00258     if (priv->event_handler_id)
00259     {
00260         qof_event_unregister_handler (priv->event_handler_id);
00261         priv->event_handler_id = 0;
00262     }
00263 
00264     gnc_gconf_general_remove_cb(KEY_NEGATIVE_IN_RED,
00265                                 gnc_tree_model_account_update_color,
00266                                 model);
00267 
00268     if (G_OBJECT_CLASS (parent_class)->dispose)
00269         G_OBJECT_CLASS (parent_class)->dispose (object);
00270     LEAVE(" ");
00271 }
00272 
00273 
00274 /************************************************************/
00275 /*                   New Model Creation                     */
00276 /************************************************************/
00277 
00278 GtkTreeModel *
00279 gnc_tree_model_account_new (Account *root)
00280 {
00281     GncTreeModelAccount *model;
00282     GncTreeModelAccountPrivate *priv;
00283     const GList *item;
00284 
00285     ENTER("root %p", root);
00286     item = gnc_gobject_tracking_get_list(GNC_TREE_MODEL_ACCOUNT_NAME);
00287     for ( ; item; item = g_list_next(item))
00288     {
00289         model = (GncTreeModelAccount *)item->data;
00290         priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00291         if (priv->root == root)
00292         {
00293             g_object_ref(G_OBJECT(model));
00294             LEAVE("returning existing model %p", model);
00295             return GTK_TREE_MODEL(model);
00296         }
00297     }
00298 
00299     model = g_object_new (GNC_TYPE_TREE_MODEL_ACCOUNT,
00300                           NULL);
00301 
00302     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00303     priv->book = gnc_get_current_book();
00304     priv->root = root;
00305 
00306     priv->event_handler_id = qof_event_register_handler
00307                              ((QofEventHandler)gnc_tree_model_account_event_handler, model);
00308 
00309     LEAVE("model %p", model);
00310     return GTK_TREE_MODEL (model);
00311 }
00312 
00313 
00314 /************************************************************/
00315 /*        Gnc Tree Model Debugging Utility Function         */
00316 /************************************************************/
00317 
00318 #define ITER_STRING_LEN 128
00319 
00320 static const gchar *
00321 iter_to_string (GtkTreeIter *iter)
00322 {
00323 #ifdef G_THREADS_ENABLED
00324     static GStaticPrivate gtmits_buffer_key = G_STATIC_PRIVATE_INIT;
00325     gchar *string;
00326 
00327     string = g_static_private_get (&gtmits_buffer_key);
00328     if (string == NULL)
00329     {
00330         string = g_malloc(ITER_STRING_LEN + 1);
00331         g_static_private_set (&gtmits_buffer_key, string, g_free);
00332     }
00333 #else
00334     static char string[ITER_STRING_LEN + 1];
00335 #endif
00336 
00337     if (iter)
00338         snprintf(string, ITER_STRING_LEN,
00339                  "[stamp:%x data:%p (%s), %p, %d]",
00340                  iter->stamp, iter->user_data,
00341                  xaccAccountGetName ((Account *) iter->user_data),
00342                  iter->user_data2, GPOINTER_TO_INT(iter->user_data3));
00343     else
00344         strcpy(string, "(null)");
00345     return string;
00346 }
00347 
00348 
00349 /************************************************************/
00350 /*       Gtk Tree Model Required Interface Functions        */
00351 /************************************************************/
00352 
00353 static void
00354 gnc_tree_model_account_tree_model_init (GtkTreeModelIface *iface)
00355 {
00356     iface->get_flags       = gnc_tree_model_account_get_flags;
00357     iface->get_n_columns   = gnc_tree_model_account_get_n_columns;
00358     iface->get_column_type = gnc_tree_model_account_get_column_type;
00359     iface->get_iter        = gnc_tree_model_account_get_iter;
00360     iface->get_path        = gnc_tree_model_account_get_path;
00361     iface->get_value       = gnc_tree_model_account_get_value;
00362     iface->iter_next       = gnc_tree_model_account_iter_next;
00363     iface->iter_children   = gnc_tree_model_account_iter_children;
00364     iface->iter_has_child  = gnc_tree_model_account_iter_has_child;
00365     iface->iter_n_children = gnc_tree_model_account_iter_n_children;
00366     iface->iter_nth_child  = gnc_tree_model_account_iter_nth_child;
00367     iface->iter_parent     = gnc_tree_model_account_iter_parent;
00368 }
00369 
00370 static GtkTreeModelFlags
00371 gnc_tree_model_account_get_flags (GtkTreeModel *tree_model)
00372 {
00373     return 0;
00374 }
00375 
00376 static int
00377 gnc_tree_model_account_get_n_columns (GtkTreeModel *tree_model)
00378 {
00379     g_return_val_if_fail(GNC_IS_TREE_MODEL_ACCOUNT(tree_model), -1);
00380 
00381     return GNC_TREE_MODEL_ACCOUNT_NUM_COLUMNS;
00382 }
00383 
00384 static GType
00385 gnc_tree_model_account_get_column_type (GtkTreeModel *tree_model,
00386                                         int index)
00387 {
00388     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), G_TYPE_INVALID);
00389     g_return_val_if_fail ((index < GNC_TREE_MODEL_ACCOUNT_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
00390 
00391     switch (index)
00392     {
00393     case GNC_TREE_MODEL_ACCOUNT_COL_NAME:
00394     case GNC_TREE_MODEL_ACCOUNT_COL_TYPE:
00395     case GNC_TREE_MODEL_ACCOUNT_COL_COMMODITY:
00396     case GNC_TREE_MODEL_ACCOUNT_COL_CODE:
00397     case GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION:
00398     case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT:
00399     case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT_REPORT:
00400     case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE:
00401     case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_REPORT:
00402     case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_PERIOD:
00403     case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED:
00404     case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED_REPORT:
00405     case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED:
00406     case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_REPORT:
00407     case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_DATE:
00408     case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN:
00409     case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN_REPORT:
00410     case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL:
00411     case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_REPORT:
00412     case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_PERIOD:
00413     case GNC_TREE_MODEL_ACCOUNT_COL_NOTES:
00414     case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO:
00415     case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO_SUB_ACCT:
00416     case GNC_TREE_MODEL_ACCOUNT_COL_LASTNUM:
00417 
00418     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_PRESENT:
00419     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE:
00420     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE_PERIOD:
00421     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_CLEARED:
00422     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_RECONCILED:
00423     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_FUTURE_MIN:
00424     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL:
00425     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL_PERIOD:
00426         return G_TYPE_STRING;
00427 
00428     case GNC_TREE_MODEL_ACCOUNT_COL_PLACEHOLDER:
00429         return G_TYPE_BOOLEAN;
00430 
00431     default:
00432         g_assert_not_reached ();
00433         return G_TYPE_INVALID;
00434     }
00435 }
00436 
00437 static gboolean
00438 gnc_tree_model_account_get_iter (GtkTreeModel *tree_model,
00439                                  GtkTreeIter *iter,
00440                                  GtkTreePath *path)
00441 {
00442     GncTreeModelAccountPrivate *priv;
00443     GncTreeModelAccount *model;
00444     Account *account, *parent;
00445     gint i, *indices;
00446 
00447     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
00448 
00449     {
00450         gchar *path_string = gtk_tree_path_to_string(path);
00451         ENTER("model %p, iter %p, path %s", tree_model, iter, path_string);
00452         g_free(path_string);
00453     }
00454 
00455     model = GNC_TREE_MODEL_ACCOUNT (tree_model);
00456     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00457 
00458     if (gtk_tree_path_get_depth (path) <= 0)
00459     {
00460         LEAVE("bad depth");
00461         return FALSE;
00462     }
00463 
00464     indices = gtk_tree_path_get_indices (path);
00465     if (indices[0] != 0)
00466     {
00467         LEAVE("bad root index");
00468         return FALSE;
00469     }
00470 
00471     parent = NULL;
00472     account = priv->root;
00473     for (i = 1; i < gtk_tree_path_get_depth (path); i++)
00474     {
00475         parent = account;
00476         account = gnc_account_nth_child(parent, indices[i]);
00477         if (account == NULL)
00478         {
00479             iter->stamp = 0;
00480             LEAVE("bad index");
00481             return FALSE;
00482         }
00483     }
00484 
00485     iter->stamp = model->stamp;
00486     iter->user_data = account;
00487     iter->user_data2 = parent;
00488     iter->user_data3 = GINT_TO_POINTER (indices[i - 1]);
00489 
00490     LEAVE("iter %s", iter_to_string(iter));
00491     return TRUE;
00492 }
00493 
00494 static GtkTreePath *
00495 gnc_tree_model_account_get_path (GtkTreeModel *tree_model,
00496                                  GtkTreeIter *iter)
00497 {
00498     GncTreeModelAccount *model = GNC_TREE_MODEL_ACCOUNT (tree_model);
00499     GncTreeModelAccountPrivate *priv;
00500     Account *account, *parent;
00501     GtkTreePath *path;
00502     gint i;
00503 
00504     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), NULL);
00505     g_return_val_if_fail (iter != NULL, NULL);
00506     g_return_val_if_fail (iter->user_data != NULL, NULL);
00507     g_return_val_if_fail (iter->stamp == model->stamp, NULL);
00508 
00509     ENTER("model %p, iter %s", model, iter_to_string(iter));
00510 
00511     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00512     if (priv->root == NULL)
00513     {
00514         LEAVE("failed (1)");
00515         return NULL;
00516     }
00517 
00518     account = (Account *) iter->user_data;
00519     parent = (Account *) iter->user_data2;
00520 
00521     path = gtk_tree_path_new ();
00522     while (parent)
00523     {
00524         i = gnc_account_child_index(parent, account);
00525         if (i == -1)
00526         {
00527             gtk_tree_path_free (path);
00528             LEAVE("failed (3)");
00529             return NULL;
00530         }
00531         gtk_tree_path_prepend_index (path, i);
00532         account = parent;
00533         parent = gnc_account_get_parent(account);
00534     };
00535 
00536     /* Add the root node. */
00537     gtk_tree_path_prepend_index (path, 0);
00538 
00539     {
00540         gchar *path_string = gtk_tree_path_to_string(path);
00541         LEAVE("path (4) %s", path_string);
00542         g_free(path_string);
00543     }
00544     return path;
00545 }
00546 
00547 static void
00548 gnc_tree_model_account_set_color(GncTreeModelAccount *model,
00549                                  gboolean negative,
00550                                  GValue *value)
00551 {
00552     GncTreeModelAccountPrivate *priv;
00553 
00554     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00555     if (negative)
00556         g_value_set_static_string (value, priv->negative_color);
00557     else
00558         g_value_set_static_string (value, "black");
00559 }
00560 
00561 static gchar *
00562 gnc_tree_model_account_compute_period_balance(GncTreeModelAccount *model,
00563         Account *acct,
00564         gboolean recurse,
00565         gboolean *negative)
00566 {
00567     GncTreeModelAccountPrivate *priv;
00568     time_t t1, t2;
00569     gnc_numeric b3;
00570 
00571     if ( negative )
00572         *negative = FALSE;
00573 
00574     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00575     if (acct == priv->root)
00576         return g_strdup("");
00577 
00578     t1 = gnc_accounting_period_fiscal_start();
00579     t2 = gnc_accounting_period_fiscal_end();
00580 
00581     if (t1 > t2)
00582         return g_strdup("");
00583 
00584     b3 = xaccAccountGetBalanceChangeForPeriod(acct, t1, t2, recurse);
00585     if (gnc_reverse_balance (acct))
00586         b3 = gnc_numeric_neg (b3);
00587 
00588     if (negative)
00589         *negative = gnc_numeric_negative_p(b3);
00590 
00591     return g_strdup(xaccPrintAmount(b3, gnc_account_print_info(acct, TRUE)));
00592 }
00593 
00594 static void
00595 gnc_tree_model_account_get_value (GtkTreeModel *tree_model,
00596                                   GtkTreeIter *iter,
00597                                   int column,
00598                                   GValue *value)
00599 {
00600     GncTreeModelAccount *model = GNC_TREE_MODEL_ACCOUNT (tree_model);
00601     GncTreeModelAccountPrivate *priv;
00602     Account *account;
00603     gboolean negative; /* used to set "deficit style" also known as red numbers */
00604     gchar *string;
00605     time_t last_date;
00606 
00607     g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model));
00608     g_return_if_fail (iter != NULL);
00609     g_return_if_fail (iter->user_data != NULL);
00610     g_return_if_fail (iter->stamp == model->stamp);
00611 
00612     ENTER("model %p, iter %s, col %d", tree_model,
00613           iter_to_string(iter), column);
00614 
00615     account = (Account *) iter->user_data;
00616     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00617 
00618     switch (column)
00619     {
00620     case GNC_TREE_MODEL_ACCOUNT_COL_NAME:
00621         g_value_init (value, G_TYPE_STRING);
00622         if (account == priv->root)
00623             g_value_set_string (value, _("New top level account"));
00624         else
00625             g_value_set_string (value, xaccAccountGetName (account));
00626         break;
00627     case GNC_TREE_MODEL_ACCOUNT_COL_TYPE:
00628         g_value_init (value, G_TYPE_STRING);
00629         g_value_set_string (value,
00630                             xaccAccountGetTypeStr (xaccAccountGetType (account)));
00631         break;
00632     case GNC_TREE_MODEL_ACCOUNT_COL_CODE:
00633         g_value_init (value, G_TYPE_STRING);
00634         g_value_set_string (value, xaccAccountGetCode (account));
00635         break;
00636     case GNC_TREE_MODEL_ACCOUNT_COL_COMMODITY:
00637         g_value_init (value, G_TYPE_STRING);
00638         g_value_set_string (value,
00639                             gnc_commodity_get_fullname(xaccAccountGetCommodity (account)));
00640         break;
00641     case GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION:
00642         g_value_init (value, G_TYPE_STRING);
00643         g_value_set_string (value, xaccAccountGetDescription (account));
00644         break;
00645 
00646     case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT:
00647         g_value_init (value, G_TYPE_STRING);
00648         string = gnc_ui_account_get_print_balance(xaccAccountGetPresentBalanceInCurrency,
00649                  account, TRUE, &negative);
00650         g_value_take_string (value, string);
00651         break;
00652     case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT_REPORT:
00653         g_value_init (value, G_TYPE_STRING);
00654         string = gnc_ui_account_get_print_report_balance(xaccAccountGetPresentBalanceInCurrency,
00655                  account, TRUE, &negative);
00656         g_value_take_string (value, string);
00657         break;
00658     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_PRESENT:
00659         g_value_init (value, G_TYPE_STRING);
00660         string = gnc_ui_account_get_print_balance(xaccAccountGetPresentBalanceInCurrency,
00661                  account, TRUE, &negative);
00662         gnc_tree_model_account_set_color(model, negative, value);
00663         g_free(string);
00664         break;
00665 
00666     case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE:
00667         g_value_init (value, G_TYPE_STRING);
00668         string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency,
00669                  account, TRUE, &negative);
00670         g_value_take_string (value, string);
00671         break;
00672     case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_REPORT:
00673         g_value_init (value, G_TYPE_STRING);
00674         string = gnc_ui_account_get_print_report_balance(xaccAccountGetBalanceInCurrency,
00675                  account, TRUE, &negative);
00676         g_value_take_string (value, string);
00677         break;
00678     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE:
00679         g_value_init (value, G_TYPE_STRING);
00680         string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency,
00681                  account, TRUE, &negative);
00682         gnc_tree_model_account_set_color(model, negative, value);
00683         g_free(string);
00684         break;
00685     case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_PERIOD:
00686         g_value_init (value, G_TYPE_STRING);
00687         string = gnc_tree_model_account_compute_period_balance(model, account, FALSE, &negative);
00688         g_value_take_string (value, string);
00689         break;
00690     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE_PERIOD:
00691         g_value_init (value, G_TYPE_STRING);
00692         string = gnc_tree_model_account_compute_period_balance(model, account, FALSE, &negative);
00693         gnc_tree_model_account_set_color(model, negative, value);
00694         g_free (string);
00695         break;
00696 
00697     case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED:
00698         g_value_init (value, G_TYPE_STRING);
00699         string = gnc_ui_account_get_print_balance(xaccAccountGetClearedBalanceInCurrency,
00700                  account, TRUE, &negative);
00701         g_value_take_string (value, string);
00702         break;
00703     case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED_REPORT:
00704         g_value_init (value, G_TYPE_STRING);
00705         string = gnc_ui_account_get_print_report_balance(xaccAccountGetClearedBalanceInCurrency,
00706                  account, TRUE, &negative);
00707         g_value_take_string (value, string);
00708         break;
00709     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_CLEARED:
00710         g_value_init (value, G_TYPE_STRING);
00711         string = gnc_ui_account_get_print_balance(xaccAccountGetClearedBalanceInCurrency,
00712                  account, TRUE, &negative);
00713         gnc_tree_model_account_set_color(model, negative, value);
00714         g_free(string);
00715         break;
00716 
00717     case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED:
00718         g_value_init (value, G_TYPE_STRING);
00719         string = gnc_ui_account_get_print_balance(xaccAccountGetReconciledBalanceInCurrency,
00720                  account, TRUE, &negative);
00721         g_value_take_string (value, string);
00722         break;
00723     case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_REPORT:
00724         g_value_init (value, G_TYPE_STRING);
00725         string = gnc_ui_account_get_print_report_balance(xaccAccountGetReconciledBalanceInCurrency,
00726                  account, TRUE, &negative);
00727         g_value_take_string (value, string);
00728         break;
00729     case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_DATE:
00730         g_value_init (value, G_TYPE_STRING);
00731         if (xaccAccountGetReconcileLastDate(account, &last_date))
00732         {
00733             g_value_take_string(value, qof_print_date(last_date));
00734         }
00735         break;
00736 
00737     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_RECONCILED:
00738         g_value_init (value, G_TYPE_STRING);
00739         string = gnc_ui_account_get_print_balance(xaccAccountGetReconciledBalanceInCurrency,
00740                  account, TRUE, &negative);
00741         gnc_tree_model_account_set_color(model, negative, value);
00742         g_free (string);
00743         break;
00744 
00745     case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN:
00746         g_value_init (value, G_TYPE_STRING);
00747         string = gnc_ui_account_get_print_balance(xaccAccountGetProjectedMinimumBalanceInCurrency,
00748                  account, TRUE, &negative);
00749         g_value_take_string (value, string);
00750         break;
00751     case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN_REPORT:
00752         g_value_init (value, G_TYPE_STRING);
00753         string = gnc_ui_account_get_print_report_balance(xaccAccountGetProjectedMinimumBalanceInCurrency,
00754                  account, TRUE, &negative);
00755         g_value_take_string (value, string);
00756         break;
00757     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_FUTURE_MIN:
00758         g_value_init (value, G_TYPE_STRING);
00759         string = gnc_ui_account_get_print_balance(xaccAccountGetProjectedMinimumBalanceInCurrency,
00760                  account, TRUE, &negative);
00761         gnc_tree_model_account_set_color(model, negative, value);
00762         g_free (string);
00763         break;
00764 
00765     case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL:
00766         g_value_init (value, G_TYPE_STRING);
00767         string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency,
00768                  account, TRUE, &negative);
00769         g_value_take_string (value, string);
00770         break;
00771     case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_REPORT:
00772         g_value_init (value, G_TYPE_STRING);
00773         string = gnc_ui_account_get_print_report_balance(xaccAccountGetBalanceInCurrency,
00774                  account, TRUE, &negative);
00775         g_value_take_string (value, string);
00776         break;
00777     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL:
00778         g_value_init (value, G_TYPE_STRING);
00779         string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency,
00780                  account, TRUE, &negative);
00781         gnc_tree_model_account_set_color(model, negative, value);
00782         g_free (string);
00783         break;
00784     case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_PERIOD:
00785         g_value_init (value, G_TYPE_STRING);
00786         string = gnc_tree_model_account_compute_period_balance(model, account, TRUE, &negative);
00787         g_value_take_string (value, string);
00788         break;
00789     case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL_PERIOD:
00790         g_value_init (value, G_TYPE_STRING);
00791         string = gnc_tree_model_account_compute_period_balance(model, account, TRUE, &negative);
00792         gnc_tree_model_account_set_color(model, negative, value);
00793         g_free (string);
00794         break;
00795 
00796     case GNC_TREE_MODEL_ACCOUNT_COL_NOTES:
00797         g_value_init (value, G_TYPE_STRING);
00798         g_value_set_string (value, xaccAccountGetNotes (account));
00799         break;
00800 
00801     case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO:
00802         g_value_init (value, G_TYPE_STRING);
00803         g_value_take_string (value, gnc_ui_account_get_tax_info_string (account));
00804         break;
00805 
00806     case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO_SUB_ACCT:
00807         g_value_init (value, G_TYPE_STRING);
00808         g_value_take_string (value, gnc_ui_account_get_tax_info_sub_acct_string (account));
00809         break;
00810 
00811     case GNC_TREE_MODEL_ACCOUNT_COL_LASTNUM:
00812         g_value_init (value, G_TYPE_STRING);
00813         g_value_set_string (value, xaccAccountGetLastNum (account));
00814         break;
00815 
00816     case GNC_TREE_MODEL_ACCOUNT_COL_PLACEHOLDER:
00817         g_value_init (value, G_TYPE_BOOLEAN);
00818         g_value_set_boolean (value, xaccAccountGetPlaceholder (account));
00819         break;
00820 
00821     default:
00822         g_assert_not_reached ();
00823     }
00824     LEAVE(" ");
00825 }
00826 
00827 static gboolean
00828 gnc_tree_model_account_iter_next (GtkTreeModel *tree_model,
00829                                   GtkTreeIter *iter)
00830 {
00831     GncTreeModelAccount *model = GNC_TREE_MODEL_ACCOUNT (tree_model);
00832     GncTreeModelAccountPrivate *priv;
00833     Account *account, *parent;
00834     gint i;
00835 
00836     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), FALSE);
00837     g_return_val_if_fail (iter != NULL, FALSE);
00838     g_return_val_if_fail (iter->user_data != NULL, FALSE);
00839     g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
00840 
00841     ENTER("model %p, iter %s", tree_model, iter_to_string(iter));
00842 
00843     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00844 
00845     parent = (Account *) iter->user_data2;
00846     if (parent == NULL)
00847     {
00848         /* This is the root. There is no next. */
00849         LEAVE("at root");
00850         return FALSE;
00851     }
00852 
00853     /* Get the *next* sibling account. */
00854     i = GPOINTER_TO_INT (iter->user_data3);
00855     account = gnc_account_nth_child (parent, i + 1);
00856     if (account == NULL)
00857     {
00858         iter->stamp = 0;
00859         LEAVE("failed (3)");
00860         return FALSE;
00861     }
00862 
00863     iter->user_data = account;
00864     iter->user_data2 = parent;
00865     iter->user_data3 = GINT_TO_POINTER (i + 1);
00866 
00867     LEAVE("iter %s", iter_to_string(iter));
00868     return TRUE;
00869 }
00870 
00871 static gboolean
00872 gnc_tree_model_account_iter_children (GtkTreeModel *tree_model,
00873                                       GtkTreeIter *iter,
00874                                       GtkTreeIter *parent_iter)
00875 {
00876     GncTreeModelAccountPrivate *priv;
00877     GncTreeModelAccount *model;
00878     Account *account, *parent;
00879 
00880     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
00881     ENTER("model %p, iter %p (to be filed in), parent %s",
00882           tree_model, iter, (parent_iter ? iter_to_string(parent_iter) : "(null)"));
00883 
00884     model = GNC_TREE_MODEL_ACCOUNT (tree_model);
00885     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00886 
00887     if (priv->root == NULL)
00888     {
00889         iter->stamp = 0;
00890         LEAVE("failed (no root)");
00891         return FALSE;
00892     }
00893 
00894     /* Special case when no parent supplied. */
00895     if (!parent_iter)
00896     {
00897         iter->user_data = priv->root;
00898         iter->user_data2 = NULL;
00899         iter->user_data3 = GINT_TO_POINTER (0);
00900         iter->stamp = model->stamp;
00901         LEAVE("iter (2) %s", iter_to_string(iter));
00902         return TRUE;
00903     }
00904 
00905     gnc_leave_return_val_if_fail (parent_iter != NULL, FALSE);
00906     gnc_leave_return_val_if_fail (parent_iter->user_data != NULL, FALSE);
00907     gnc_leave_return_val_if_fail (parent_iter->stamp == model->stamp, FALSE);
00908 
00909     parent = (Account *)parent_iter->user_data;
00910     account = gnc_account_nth_child (parent, 0);
00911 
00912     if (account == NULL)
00913     {
00914         iter->stamp = 0;
00915         LEAVE("failed (child account is null)");
00916         return FALSE;
00917     }
00918 
00919     iter->user_data = account;
00920     iter->user_data2 = parent;
00921     iter->user_data3 = GINT_TO_POINTER (0);
00922     iter->stamp = model->stamp;
00923     LEAVE("iter (3) %s", iter_to_string(iter));
00924     return TRUE;
00925 }
00926 
00927 static gboolean
00928 gnc_tree_model_account_iter_has_child (GtkTreeModel *tree_model,
00929                                        GtkTreeIter *iter)
00930 {
00931     GncTreeModelAccount *model;
00932     GncTreeModelAccountPrivate *priv;
00933     Account *account;
00934 
00935     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
00936 
00937     ENTER("model %p, iter %s", tree_model, iter_to_string(iter));
00938 
00939     model = GNC_TREE_MODEL_ACCOUNT (tree_model);
00940     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00941 
00942     gnc_leave_return_val_if_fail (iter != NULL, FALSE);
00943     gnc_leave_return_val_if_fail (iter->user_data != NULL, FALSE);
00944     gnc_leave_return_val_if_fail (iter->stamp == model->stamp, FALSE);
00945 
00946     account = (Account *) iter->user_data;
00947     if (gnc_account_n_children(account) > 0)
00948     {
00949         LEAVE("yes");
00950         return TRUE;
00951     }
00952 
00953     LEAVE("no");
00954     return FALSE;
00955 }
00956 
00957 static int
00958 gnc_tree_model_account_iter_n_children (GtkTreeModel *tree_model,
00959                                         GtkTreeIter *iter)
00960 {
00961     GncTreeModelAccount *model;
00962     GncTreeModelAccountPrivate *priv;
00963     gint num;
00964 
00965     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
00966     ENTER("model %p, iter %s", tree_model, iter_to_string(iter));
00967 
00968     model = GNC_TREE_MODEL_ACCOUNT (tree_model);
00969     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
00970 
00971     if (iter == NULL)
00972     {
00973         /* How many children does the invisible root node
00974          * have. One! Its the real root account node. */
00975         LEAVE("count is 1");
00976         return 1;
00977     }
00978 
00979     gnc_leave_return_val_if_fail (iter != NULL, FALSE);
00980     gnc_leave_return_val_if_fail (iter->user_data != NULL, FALSE);
00981     gnc_leave_return_val_if_fail (iter->stamp == model->stamp, FALSE);
00982 
00983     num = gnc_account_n_children(iter->user_data);
00984     LEAVE("count is %d", num);
00985     return num;
00986 }
00987 
00988 static gboolean
00989 gnc_tree_model_account_iter_nth_child (GtkTreeModel *tree_model,
00990                                        GtkTreeIter *iter,
00991                                        GtkTreeIter *parent_iter,
00992                                        int n)
00993 {
00994     GncTreeModelAccount *model;
00995     GncTreeModelAccountPrivate *priv;
00996     Account *account, *parent;
00997 
00998     if (parent_iter)
00999     {
01000         gchar *parent_string;
01001         parent_string = g_strdup(iter_to_string(parent_iter));
01002         ENTER("model %p, iter %s, parent_iter %s, n %d",
01003               tree_model, iter_to_string(iter),
01004               parent_string, n);
01005         g_free(parent_string);
01006     }
01007     else
01008     {
01009         ENTER("model %p, iter %s, parent_iter (null), n %d",
01010               tree_model, iter_to_string(iter), n);
01011     }
01012     gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
01013 
01014     model = GNC_TREE_MODEL_ACCOUNT (tree_model);
01015     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
01016 
01017     /* Special case when no parent supplied. */
01018     if (!parent_iter)
01019     {
01020         if (n != 0)
01021         {
01022             LEAVE("bad root index");
01023             return FALSE;
01024         }
01025 
01026         iter->user_data = priv->root;
01027         iter->user_data2 = NULL;
01028         iter->user_data3 = GINT_TO_POINTER (0);
01029         iter->stamp = model->stamp;
01030         LEAVE("root %s", iter_to_string(iter));
01031         return TRUE;
01032     }
01033 
01034     gnc_leave_return_val_if_fail (parent_iter->user_data != NULL, FALSE);
01035     gnc_leave_return_val_if_fail (parent_iter->stamp == model->stamp, FALSE);
01036 
01037     parent = (Account *)parent_iter->user_data;
01038     account = gnc_account_nth_child(parent, n);
01039     if (account == NULL)
01040     {
01041         iter->stamp = 0;
01042         LEAVE("failed (2)");
01043         return FALSE;
01044     }
01045 
01046     iter->user_data = account;
01047     iter->user_data2 = parent;
01048     iter->user_data3 = GINT_TO_POINTER (n);
01049     iter->stamp = model->stamp;
01050     LEAVE("iter (2) %s", iter_to_string(iter));
01051     return TRUE;
01052 }
01053 
01054 static gboolean
01055 gnc_tree_model_account_iter_parent (GtkTreeModel *tree_model,
01056                                     GtkTreeIter *iter,
01057                                     GtkTreeIter *child)
01058 {
01059     GncTreeModelAccount *model;
01060     GncTreeModelAccountPrivate *priv;
01061     Account *account, *parent;
01062     gint i;
01063 
01064     if (child)
01065     {
01066         gchar *child_string;
01067 
01068         child_string = g_strdup(iter_to_string(child));
01069         ENTER("model %p, iter %s, child %s",
01070               tree_model, iter_to_string(iter),
01071               child_string);
01072         g_free(child_string);
01073     }
01074     else
01075     {
01076         ENTER("model %p, iter %s, child (null)",
01077               tree_model, iter_to_string(iter));
01078     }
01079     gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
01080 
01081     model = GNC_TREE_MODEL_ACCOUNT (tree_model);
01082     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
01083 
01084     gnc_leave_return_val_if_fail (child != NULL, FALSE);
01085     gnc_leave_return_val_if_fail (child->user_data != NULL, FALSE);
01086     gnc_leave_return_val_if_fail (child->stamp == model->stamp, FALSE);
01087 
01088     account = (Account *) child->user_data;
01089     account = gnc_account_get_parent(account);
01090     if (account == NULL)
01091     {
01092         /* Can't go up from the root node */
01093         iter->stamp = 0;
01094         LEAVE("failed (1)");
01095         return FALSE;
01096     }
01097 
01098     parent = gnc_account_get_parent(account);
01099     if (parent == NULL)
01100     {
01101         /* Now at the root. */
01102         i = 0;
01103     }
01104     else
01105     {
01106         i = gnc_account_child_index(parent, account);
01107     }
01108     iter->user_data = account;
01109     iter->user_data2 = parent;
01110     iter->user_data3 = GINT_TO_POINTER (i);
01111     iter->stamp = model->stamp;
01112     LEAVE("iter (2) %s", iter_to_string(iter));
01113     return TRUE;
01114 }
01115 
01116 
01117 /************************************************************/
01118 /*            Account Tree View Filter Functions            */
01119 /************************************************************/
01120 
01121 /*
01122  * Convert a model/iter pair to a gnucash account.  This routine should
01123  * only be called from an account tree view filter function.
01124  */
01125 Account *
01126 gnc_tree_model_account_get_account (GncTreeModelAccount *model,
01127                                     GtkTreeIter *iter)
01128 {
01129     g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), NULL);
01130     g_return_val_if_fail (iter != NULL, NULL);
01131     g_return_val_if_fail (iter->user_data != NULL, NULL);
01132     g_return_val_if_fail (iter->stamp == model->stamp, NULL);
01133 
01134     return (Account *) iter->user_data;
01135 }
01136 
01137 /*
01138  * Convert a model/account pair into a gtk_tree_model_iter.  This
01139  * routine should only be called from the file
01140  * gnc-tree-view-account.c.
01141  */
01142 gboolean
01143 gnc_tree_model_account_get_iter_from_account (GncTreeModelAccount *model,
01144         Account *account,
01145         GtkTreeIter *iter)
01146 {
01147     GncTreeModelAccountPrivate *priv;
01148     Account *parent;
01149     gint i;
01150 
01151     ENTER("model %p, account %p, iter %p", model, account, iter);
01152     gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), FALSE);
01153     gnc_leave_return_val_if_fail ((account != NULL), FALSE);
01154     gnc_leave_return_val_if_fail ((iter != NULL), FALSE);
01155 
01156     iter->user_data = account;
01157     iter->stamp = model->stamp;
01158 
01159     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
01160     if (account == priv->root)
01161     {
01162         iter->user_data2 = NULL;
01163         iter->user_data3 = GINT_TO_POINTER (0);
01164         LEAVE("Matched root");
01165         return TRUE;
01166     }
01167 
01168     if (priv->root != gnc_account_get_root (account))
01169     {
01170         LEAVE("Root doesn't match");
01171         return FALSE;
01172     }
01173 
01174     parent = gnc_account_get_parent(account);
01175     i = gnc_account_child_index(parent, account);
01176     iter->user_data2 = parent;
01177     iter->user_data3 = GINT_TO_POINTER (i);
01178     LEAVE("iter %s", iter_to_string(iter));
01179     return (i != -1);
01180 }
01181 
01182 /*
01183  * Convert a model/account pair into a gtk_tree_model_path.  This
01184  * routine should only be called from the file
01185  * gnc-tree-view-account.c.
01186  */
01187 GtkTreePath *
01188 gnc_tree_model_account_get_path_from_account (GncTreeModelAccount *model,
01189         Account *account)
01190 {
01191     GtkTreeIter tree_iter;
01192     GtkTreePath *tree_path;
01193 
01194     ENTER("model %p, account %p", model, account);
01195     gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), NULL);
01196     gnc_leave_return_val_if_fail (account != NULL, NULL);
01197 
01198     if (!gnc_tree_model_account_get_iter_from_account (model, account,
01199             &tree_iter))
01200     {
01201         LEAVE("no iter");
01202         return NULL;
01203     }
01204 
01205     tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &tree_iter);
01206     if (tree_path)
01207     {
01208         gchar *path_string = gtk_tree_path_to_string(tree_path);
01209         LEAVE("path (2) %s", path_string);
01210         g_free(path_string);
01211     }
01212     else
01213     {
01214         LEAVE("no path");
01215     }
01216     return tree_path;
01217 }
01218 
01219 /************************************************************/
01220 /*   Account Tree Model - Engine Event Handling Functions   */
01221 /************************************************************/
01222 
01223 static void
01224 increment_stamp(GncTreeModelAccount *model)
01225 {
01226     do model->stamp++;
01227     while (!model->stamp);
01228 }
01229 
01230 static void
01231 propagate_change(GtkTreeModel *model, GtkTreePath *path, gint toggle_if_num)
01232 {
01233     GtkTreeIter iter;
01234 
01235     /* Already at the invisible root node? */
01236     if (!gtk_tree_path_up(path))
01237         return;
01238 
01239     /* Did we just move up to the invisible root node? */
01240     if (gtk_tree_path_get_depth(path) == 0)
01241         return;
01242 
01243     /* Handle the immediate parent */
01244     if (gtk_tree_model_get_iter(model, &iter, path))
01245     {
01246         gtk_tree_model_row_changed(model, path, &iter);
01247         if (gtk_tree_model_iter_n_children(model, &iter) == toggle_if_num)
01248             gtk_tree_model_row_has_child_toggled(model, path, &iter);
01249     }
01250 
01251     /* All other ancestors */
01252     while (gtk_tree_path_up(path) && gtk_tree_path_get_depth(path) > 0 &&
01253             gtk_tree_model_get_iter(model, &iter, path))
01254     {
01255         gtk_tree_model_row_changed(model, path, &iter);
01256     }
01257 }
01258 
01287 static void
01288 gnc_tree_model_account_event_handler (QofInstance *entity,
01289                                       QofEventId event_type,
01290                                       GncTreeModelAccount *model,
01291                                       GncEventData *ed)
01292 {
01293     GncTreeModelAccountPrivate *priv;
01294     const gchar *parent_name;
01295     GtkTreePath *path = NULL;
01296     GtkTreeIter iter;
01297     Account *account, *parent;
01298 
01299     g_return_if_fail(model);    /* Required */
01300     if (!GNC_IS_ACCOUNT(entity))
01301         return;
01302 
01303     ENTER("entity %p of type %d, model %p, event_data %p",
01304           entity, event_type, model, ed);
01305     priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
01306 
01307     account = GNC_ACCOUNT(entity);
01308     if (gnc_account_get_book(account) != priv->book)
01309     {
01310         LEAVE("not in this book");
01311         return;
01312     }
01313     if (gnc_account_get_root(account) != priv->root)
01314     {
01315         LEAVE("not in this model");
01316         return;
01317     }
01318     /* What to do, that to do. */
01319     switch (event_type)
01320     {
01321     case QOF_EVENT_ADD:
01322         /* Tell the filters/views where the new account was added. */
01323         DEBUG("add account %p (%s)", account, xaccAccountGetName(account));
01324         path = gnc_tree_model_account_get_path_from_account(model, account);
01325         if (!path)
01326         {
01327             DEBUG("can't generate path");
01328             break;
01329         }
01330         increment_stamp(model);
01331         if (!gnc_tree_model_account_get_iter(GTK_TREE_MODEL(model), &iter, path))
01332         {
01333             DEBUG("can't generate iter");
01334             break;
01335         }
01336         gtk_tree_model_row_inserted (GTK_TREE_MODEL(model), path, &iter);
01337         propagate_change(GTK_TREE_MODEL(model), path, 1);
01338         break;
01339 
01340     case QOF_EVENT_REMOVE:
01341         if (!ed) /* Required for a remove. */
01342             break;
01343         parent = ed->node ? GNC_ACCOUNT(ed->node) : priv->root;
01344         parent_name = ed->node ? xaccAccountGetName(parent) : "Root";
01345         DEBUG("remove child %d of account %p (%s)", ed->idx, parent, parent_name);
01346         path = gnc_tree_model_account_get_path_from_account(model, parent);
01347         if (!path)
01348         {
01349             DEBUG("can't generate path");
01350             break;
01351         }
01352         increment_stamp(model);
01353         gtk_tree_path_append_index (path, ed->idx);
01354         gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), path);
01355         propagate_change(GTK_TREE_MODEL(model), path, 0);
01356         break;
01357 
01358     case QOF_EVENT_MODIFY:
01359         DEBUG("modify  account %p (%s)", account, xaccAccountGetName(account));
01360         path = gnc_tree_model_account_get_path_from_account(model, account);
01361         if (!path)
01362         {
01363             DEBUG("can't generate path");
01364             break;
01365         }
01366         if (!gnc_tree_model_account_get_iter(GTK_TREE_MODEL(model), &iter, path))
01367         {
01368             DEBUG("can't generate iter");
01369             break;
01370         }
01371         gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter);
01372         propagate_change(GTK_TREE_MODEL(model), path, -1);
01373         break;
01374 
01375     default:
01376         LEAVE("unknown event type");
01377         return;
01378     }
01379 
01380     if (path)
01381         gtk_tree_path_free(path);
01382     LEAVE(" ");
01383     return;
01384 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines