GnuCash 2.4.99
gnc-tree-model-commodity.c
00001 /*
00002  * gnc-tree-model-commodity.c -- GtkTreeModel implementation to
00003  *      display commodities 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 /*
00027  * In this model, valid paths take the form "X" or "X:Y", where:
00028  *   X is an index into the namespaces list held by the commodity db
00029  *   Y is an index into the commodity list for the namespace
00030  *
00031  * Iterators are populated with the following private data:
00032  * iter->user_data   Type NAMESPACE | COMMODITY
00033  * iter->user_data2  A pointer to the namespace/commodity
00034  * iter->user_data3  The index of the namespace/commodity within its parent list
00035  */
00036 
00037 #include "config.h"
00038 
00039 #include <gtk/gtk.h>
00040 #include <string.h>
00041 
00042 #include "gnc-tree-model-commodity.h"
00043 #include "gnc-component-manager.h"
00044 #include "gnc-engine.h"
00045 #include "gnc-gobject-utils.h"
00046 #include "gnc-ui-util.h"
00047 
00048 #define ITER_IS_NAMESPACE GINT_TO_POINTER(1)
00049 #define ITER_IS_COMMODITY GINT_TO_POINTER(2)
00050 
00052 static QofLogModule log_module = GNC_MOD_GUI;
00053 
00055 static void gnc_tree_model_commodity_class_init (GncTreeModelCommodityClass *klass);
00056 static void gnc_tree_model_commodity_init (GncTreeModelCommodity *model);
00057 static void gnc_tree_model_commodity_finalize (GObject *object);
00058 static void gnc_tree_model_commodity_dispose (GObject *object);
00059 
00060 static void gnc_tree_model_commodity_tree_model_init (GtkTreeModelIface *iface);
00061 static GtkTreeModelFlags gnc_tree_model_commodity_get_flags (GtkTreeModel *tree_model);
00062 static int gnc_tree_model_commodity_get_n_columns (GtkTreeModel *tree_model);
00063 static GType gnc_tree_model_commodity_get_column_type (GtkTreeModel *tree_model,
00064         int index);
00065 static gboolean gnc_tree_model_commodity_get_iter (GtkTreeModel *tree_model,
00066         GtkTreeIter *iter,
00067         GtkTreePath *path);
00068 static GtkTreePath *gnc_tree_model_commodity_get_path (GtkTreeModel *tree_model,
00069         GtkTreeIter *iter);
00070 static void gnc_tree_model_commodity_get_value (GtkTreeModel *tree_model,
00071         GtkTreeIter *iter,
00072         int column,
00073         GValue *value);
00074 static gboolean gnc_tree_model_commodity_iter_next (GtkTreeModel *tree_model,
00075         GtkTreeIter *iter);
00076 static gboolean gnc_tree_model_commodity_iter_children (GtkTreeModel *tree_model,
00077         GtkTreeIter *iter,
00078         GtkTreeIter *parent);
00079 static gboolean gnc_tree_model_commodity_iter_has_child (GtkTreeModel *tree_model,
00080         GtkTreeIter *iter);
00081 static int gnc_tree_model_commodity_iter_n_children (GtkTreeModel *tree_model,
00082         GtkTreeIter *iter);
00083 static gboolean gnc_tree_model_commodity_iter_nth_child (GtkTreeModel *tree_model,
00084         GtkTreeIter *iter,
00085         GtkTreeIter *parent,
00086         int n);
00087 static gboolean gnc_tree_model_commodity_iter_parent (GtkTreeModel *tree_model,
00088         GtkTreeIter *iter,
00089         GtkTreeIter *child);
00090 static void gnc_tree_model_commodity_event_handler (QofInstance *entity,
00091         QofEventId event_type,
00092         gpointer user_data,
00093         gpointer event_data);
00094 
00096 typedef struct GncTreeModelCommodityPrivate
00097 {
00098     QofBook *book;
00099     gnc_commodity_table *commodity_table;
00100     gint event_handler_id;
00101 } GncTreeModelCommodityPrivate;
00102 
00103 #define GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(o)  \
00104    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_TREE_MODEL_COMMODITY, GncTreeModelCommodityPrivate))
00105 
00107 static GtkObjectClass *parent_class = NULL;
00108 
00109 GType
00110 gnc_tree_model_commodity_get_type (void)
00111 {
00112     static GType gnc_tree_model_commodity_type = 0;
00113 
00114     if (gnc_tree_model_commodity_type == 0)
00115     {
00116         static const GTypeInfo our_info =
00117         {
00118             sizeof (GncTreeModelCommodityClass),
00119             NULL,
00120             NULL,
00121             (GClassInitFunc) gnc_tree_model_commodity_class_init,
00122             NULL,
00123             NULL,
00124             sizeof (GncTreeModelCommodity),
00125             0,
00126             (GInstanceInitFunc) gnc_tree_model_commodity_init
00127         };
00128 
00129         static const GInterfaceInfo tree_model_info =
00130         {
00131             (GInterfaceInitFunc) gnc_tree_model_commodity_tree_model_init,
00132             NULL,
00133             NULL
00134         };
00135 
00136         gnc_tree_model_commodity_type = g_type_register_static (GNC_TYPE_TREE_MODEL,
00137                                         GNC_TREE_MODEL_COMMODITY_NAME,
00138                                         &our_info, 0);
00139 
00140         g_type_add_interface_static (gnc_tree_model_commodity_type,
00141                                      GTK_TYPE_TREE_MODEL,
00142                                      &tree_model_info);
00143     }
00144 
00145     return gnc_tree_model_commodity_type;
00146 }
00147 
00148 static void
00149 gnc_tree_model_commodity_class_init (GncTreeModelCommodityClass *klass)
00150 {
00151     GObjectClass *o_class = G_OBJECT_CLASS (klass);
00152 
00153     parent_class = g_type_class_peek_parent (klass);
00154 
00155     o_class->finalize = gnc_tree_model_commodity_finalize;
00156     o_class->dispose = gnc_tree_model_commodity_dispose;
00157 
00158     g_type_class_add_private(klass, sizeof(GncTreeModelCommodityPrivate));
00159 }
00160 
00161 static void
00162 gnc_tree_model_commodity_init (GncTreeModelCommodity *model)
00163 {
00164     while (model->stamp == 0)
00165     {
00166         model->stamp = g_random_int ();
00167     }
00168 }
00169 
00170 static void
00171 gnc_tree_model_commodity_finalize (GObject *object)
00172 {
00173     GncTreeModelCommodity *model;
00174     GncTreeModelCommodityPrivate *priv;
00175 
00176     g_return_if_fail (object != NULL);
00177     g_return_if_fail (GNC_IS_TREE_MODEL_COMMODITY (object));
00178 
00179     ENTER("model %p", object);
00180 
00181     model = GNC_TREE_MODEL_COMMODITY (object);
00182     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00183     priv->book = NULL;
00184     priv->commodity_table = NULL;
00185 
00186     G_OBJECT_CLASS (parent_class)->finalize (object);
00187     LEAVE(" ");
00188 }
00189 
00190 static void
00191 gnc_tree_model_commodity_dispose (GObject *object)
00192 {
00193     GncTreeModelCommodity *model;
00194     GncTreeModelCommodityPrivate *priv;
00195 
00196     g_return_if_fail (object != NULL);
00197     g_return_if_fail (GNC_IS_TREE_MODEL_COMMODITY (object));
00198 
00199     ENTER("model %p", object);
00200     model = GNC_TREE_MODEL_COMMODITY (object);
00201     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00202 
00203     if (priv->event_handler_id)
00204     {
00205         qof_event_unregister_handler (priv->event_handler_id);
00206         priv->event_handler_id = 0;
00207     }
00208 
00209     if (G_OBJECT_CLASS (parent_class)->dispose)
00210         G_OBJECT_CLASS (parent_class)->dispose (object);
00211     LEAVE(" ");
00212 }
00213 
00214 GtkTreeModel *
00215 gnc_tree_model_commodity_new (QofBook *book, gnc_commodity_table *ct)
00216 {
00217     GncTreeModelCommodity *model;
00218     GncTreeModelCommodityPrivate *priv;
00219     const GList *item;
00220 
00221     ENTER("");
00222 
00223     item = gnc_gobject_tracking_get_list(GNC_TREE_MODEL_COMMODITY_NAME);
00224     for ( ; item; item = g_list_next(item))
00225     {
00226         model = (GncTreeModelCommodity *)item->data;
00227         priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00228         if (priv->commodity_table == ct)
00229         {
00230             g_object_ref(G_OBJECT(model));
00231             LEAVE("returning existing model %p", model);
00232             return GTK_TREE_MODEL(model);
00233         }
00234     }
00235 
00236     model = g_object_new (GNC_TYPE_TREE_MODEL_COMMODITY, NULL);
00237     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00238     priv->book = book;
00239     priv->commodity_table = ct;
00240 
00241     priv->event_handler_id =
00242         qof_event_register_handler (gnc_tree_model_commodity_event_handler, model);
00243 
00244     LEAVE("");
00245     return GTK_TREE_MODEL (model);
00246 }
00247 
00248 gboolean
00249 gnc_tree_model_commodity_iter_is_namespace (GncTreeModelCommodity *model,
00250         GtkTreeIter *iter)
00251 {
00252     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), FALSE);
00253     g_return_val_if_fail (iter != NULL, FALSE);
00254     g_return_val_if_fail (iter->user_data != NULL, FALSE);
00255     g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
00256 
00257     return (iter->user_data == ITER_IS_NAMESPACE);
00258 }
00259 
00260 gboolean
00261 gnc_tree_model_commodity_iter_is_commodity (GncTreeModelCommodity *model,
00262         GtkTreeIter *iter)
00263 {
00264     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), FALSE);
00265     g_return_val_if_fail (iter != NULL, FALSE);
00266     g_return_val_if_fail (iter->user_data != NULL, FALSE);
00267     g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
00268 
00269     return (iter->user_data == ITER_IS_COMMODITY);
00270 }
00271 
00272 gnc_commodity_namespace *
00273 gnc_tree_model_commodity_get_namespace (GncTreeModelCommodity *model,
00274                                         GtkTreeIter *iter)
00275 {
00276     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), NULL);
00277     g_return_val_if_fail (iter != NULL, NULL);
00278     g_return_val_if_fail (iter->user_data != NULL, NULL);
00279     g_return_val_if_fail (iter->stamp == model->stamp, NULL);
00280 
00281     if (iter->user_data != ITER_IS_NAMESPACE)
00282         return NULL;
00283     return (gnc_commodity_namespace *)iter->user_data2;
00284 }
00285 
00286 gnc_commodity *
00287 gnc_tree_model_commodity_get_commodity (GncTreeModelCommodity *model,
00288                                         GtkTreeIter *iter)
00289 {
00290     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), NULL);
00291     g_return_val_if_fail (iter != NULL, NULL);
00292     g_return_val_if_fail (iter->user_data != NULL, NULL);
00293     g_return_val_if_fail (iter->stamp == model->stamp, NULL);
00294 
00295     if (iter->user_data != ITER_IS_COMMODITY)
00296         return NULL;
00297     return (gnc_commodity *)iter->user_data2;
00298 }
00299 
00300 /************************************************************/
00301 /*        Gnc Tree Model Debugging Utility Function         */
00302 /************************************************************/
00303 
00304 #define debug_path(fn, path) {                                  \
00305     gchar *path_string = gtk_tree_path_to_string(path);         \
00306     fn("tree path %s", path_string? path_string : "NULL");      \
00307     g_free(path_string);                                        \
00308   }
00309 
00310 #define ITER_STRING_LEN 128
00311 
00312 static const gchar *
00313 iter_to_string (GtkTreeIter *iter)
00314 {
00315     gnc_commodity_namespace *namespace;
00316     gnc_commodity *commodity = NULL;
00317 #ifdef G_THREADS_ENABLED
00318     static GStaticPrivate gtmits_buffer_key = G_STATIC_PRIVATE_INIT;
00319     gchar *string;
00320 
00321     string = g_static_private_get (&gtmits_buffer_key);
00322     if (string == NULL)
00323     {
00324         string = g_malloc(ITER_STRING_LEN + 1);
00325         g_static_private_set (&gtmits_buffer_key, string, g_free);
00326     }
00327 #else
00328     static char string[ITER_STRING_LEN + 1];
00329 #endif
00330     if (iter)
00331     {
00332         switch (GPOINTER_TO_INT(iter->user_data))
00333         {
00334         case GPOINTER_TO_INT(ITER_IS_NAMESPACE):
00335             namespace = (gnc_commodity_namespace *) iter->user_data2;
00336             snprintf(string, ITER_STRING_LEN,
00337                      "[stamp:%x data:%d (NAMESPACE), %p (%s), %d]",
00338                      iter->stamp, GPOINTER_TO_INT(iter->user_data),
00339                      iter->user_data2, gnc_commodity_namespace_get_name (namespace),
00340                      GPOINTER_TO_INT(iter->user_data3));
00341             break;
00342 
00343         case GPOINTER_TO_INT(ITER_IS_COMMODITY):
00344             commodity = (gnc_commodity *) iter->user_data2;
00345             snprintf(string, ITER_STRING_LEN,
00346                      "[stamp:%x data:%d (COMMODITY), %p (%s), %d]",
00347                      iter->stamp, GPOINTER_TO_INT(iter->user_data),
00348                      iter->user_data2, gnc_commodity_get_mnemonic (commodity),
00349                      GPOINTER_TO_INT(iter->user_data3));
00350             break;
00351 
00352         default:
00353             snprintf(string, ITER_STRING_LEN,
00354                      "[stamp:%x data:%d (UNKNOWN), %p, %d]",
00355                      iter->stamp,
00356                      GPOINTER_TO_INT(iter->user_data),
00357                      iter->user_data2,
00358                      GPOINTER_TO_INT(iter->user_data3));
00359             break;
00360         }
00361     }
00362     return string;
00363 }
00364 
00365 
00366 /************************************************************/
00367 /*       Gtk Tree Model Required Interface Functions        */
00368 /************************************************************/
00369 
00370 static void
00371 gnc_tree_model_commodity_tree_model_init (GtkTreeModelIface *iface)
00372 {
00373     iface->get_flags       = gnc_tree_model_commodity_get_flags;
00374     iface->get_n_columns   = gnc_tree_model_commodity_get_n_columns;
00375     iface->get_column_type = gnc_tree_model_commodity_get_column_type;
00376     iface->get_iter        = gnc_tree_model_commodity_get_iter;
00377     iface->get_path        = gnc_tree_model_commodity_get_path;
00378     iface->get_value       = gnc_tree_model_commodity_get_value;
00379     iface->iter_next       = gnc_tree_model_commodity_iter_next;
00380     iface->iter_children   = gnc_tree_model_commodity_iter_children;
00381     iface->iter_has_child  = gnc_tree_model_commodity_iter_has_child;
00382     iface->iter_n_children = gnc_tree_model_commodity_iter_n_children;
00383     iface->iter_nth_child  = gnc_tree_model_commodity_iter_nth_child;
00384     iface->iter_parent     = gnc_tree_model_commodity_iter_parent;
00385 }
00386 
00387 static GtkTreeModelFlags
00388 gnc_tree_model_commodity_get_flags (GtkTreeModel *tree_model)
00389 {
00390     return 0;
00391 }
00392 
00393 static int
00394 gnc_tree_model_commodity_get_n_columns (GtkTreeModel *tree_model)
00395 {
00396     return GNC_TREE_MODEL_COMMODITY_NUM_COLUMNS;
00397 }
00398 
00399 static GType
00400 gnc_tree_model_commodity_get_column_type (GtkTreeModel *tree_model,
00401         int index)
00402 {
00403     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), G_TYPE_INVALID);
00404     g_return_val_if_fail ((index < GNC_TREE_MODEL_COMMODITY_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
00405 
00406     switch (index)
00407     {
00408     case GNC_TREE_MODEL_COMMODITY_COL_MNEMONIC:
00409     case GNC_TREE_MODEL_COMMODITY_COL_NAMESPACE:
00410     case GNC_TREE_MODEL_COMMODITY_COL_FULLNAME:
00411     case GNC_TREE_MODEL_COMMODITY_COL_PRINTNAME:
00412     case GNC_TREE_MODEL_COMMODITY_COL_CUSIP:
00413     case GNC_TREE_MODEL_COMMODITY_COL_UNIQUE_NAME:
00414     case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_SOURCE:
00415     case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_TZ:
00416         return G_TYPE_STRING;
00417     case GNC_TREE_MODEL_COMMODITY_COL_FRACTION:
00418         return G_TYPE_INT;
00419     case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_FLAG:
00420     case GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY:
00421         return G_TYPE_BOOLEAN;
00422     default:
00423         g_assert_not_reached ();
00424         return G_TYPE_INVALID;
00425     }
00426 }
00427 
00428 static gboolean
00429 gnc_tree_model_commodity_get_iter (GtkTreeModel *tree_model,
00430                                    GtkTreeIter *iter,
00431                                    GtkTreePath *path)
00432 {
00433     GncTreeModelCommodity *model;
00434     GncTreeModelCommodityPrivate *priv;
00435     gnc_commodity_table *ct;
00436     gnc_commodity_namespace *namespace;
00437     gnc_commodity *commodity = NULL;
00438     GList *list;
00439     guint i, depth;
00440 
00441     iter->stamp = 0;
00442     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), FALSE);
00443     g_return_val_if_fail (iter != NULL, FALSE);
00444     g_return_val_if_fail (path != NULL, FALSE);
00445 
00446     depth = gtk_tree_path_get_depth (path);
00447     ENTER("model %p, iter %p, path %p (depth %d)", tree_model, iter, path, depth);
00448     debug_path(DEBUG, path);
00449 
00450     /* Check the path depth. */
00451     if (depth == 0)
00452     {
00453         LEAVE("depth too small");
00454         return FALSE;
00455     }
00456     if (depth > 2)
00457     {
00458         LEAVE("depth too big");
00459         return FALSE;
00460     }
00461 
00462     /* Make sure the model has a commodity db. */
00463     model = GNC_TREE_MODEL_COMMODITY (tree_model);
00464     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00465     ct = priv->commodity_table;
00466     if (ct == NULL)
00467     {
00468         LEAVE("no commodity table");
00469         return FALSE;
00470     }
00471 
00472     /* Verify the first part of the path: the namespace. */
00473     list = gnc_commodity_table_get_namespaces_list(ct);
00474     i = gtk_tree_path_get_indices (path)[0];
00475     namespace = g_list_nth_data (list, i);
00476     if (!namespace)
00477     {
00478         LEAVE("invalid path at namespace");
00479         return FALSE;
00480     }
00481 
00482     if (depth == 1)
00483     {
00484         /* Return an iterator for the namespace. */
00485         iter->stamp      = model->stamp;
00486         iter->user_data  = ITER_IS_NAMESPACE;
00487         iter->user_data2 = namespace;
00488         iter->user_data3 = GINT_TO_POINTER(i);
00489         LEAVE("iter (ns) %s", iter_to_string(iter));
00490         return TRUE;
00491     }
00492 
00493     /* Verify the second part of the path: the commodity. */
00494     list = gnc_commodity_namespace_get_commodity_list(namespace);
00495     i = gtk_tree_path_get_indices (path)[1];
00496     commodity = g_list_nth_data (list, i);
00497     if (!commodity)
00498     {
00499         LEAVE("invalid path at commodity");
00500         return FALSE;
00501     }
00502 
00503     /* Return an iterator for the commodity. */
00504     iter->stamp      = model->stamp;
00505     iter->user_data  = ITER_IS_COMMODITY;
00506     iter->user_data2 = commodity;
00507     iter->user_data3 = GINT_TO_POINTER(i);
00508     LEAVE("iter (cm) %s", iter_to_string(iter));
00509     return TRUE;
00510 }
00511 
00512 static GtkTreePath *
00513 gnc_tree_model_commodity_get_path (GtkTreeModel *tree_model,
00514                                    GtkTreeIter *iter)
00515 {
00516     GncTreeModelCommodity *model;
00517     GncTreeModelCommodityPrivate *priv;
00518     GtkTreePath *path;
00519     gnc_commodity_table *ct;
00520     gnc_commodity_namespace *namespace;
00521     GList *ns_list;
00522 
00523     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), NULL);
00524     model = GNC_TREE_MODEL_COMMODITY (tree_model);
00525     g_return_val_if_fail (iter != NULL, NULL);
00526     g_return_val_if_fail (iter->user_data != NULL, NULL);
00527     g_return_val_if_fail (iter->user_data2 != NULL, NULL);
00528     g_return_val_if_fail (iter->stamp == model->stamp, NULL);
00529     ENTER("model %p, iter %p (%s)", tree_model, iter, iter_to_string(iter));
00530 
00531     /* Make sure this model has a commodity db. */
00532     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00533     ct = priv->commodity_table;
00534     if (ct == NULL)
00535     {
00536         LEAVE("no commodity table");
00537         return FALSE;
00538     }
00539 
00540     if (iter->user_data == ITER_IS_NAMESPACE)
00541     {
00542         /* Create a path to the namespace. This is just the index into
00543          * the namespace list, which we already stored in user_data3. */
00544         path = gtk_tree_path_new ();
00545         gtk_tree_path_append_index (path, GPOINTER_TO_INT(iter->user_data3));
00546         debug_path(LEAVE, path);
00547         return path;
00548     }
00549 
00550     /* Get the namespaces list. */
00551     ns_list = gnc_commodity_table_get_namespaces_list(ct);
00552     namespace = gnc_commodity_get_namespace_ds((gnc_commodity*)iter->user_data2);
00553 
00554     /* Create a path to the commodity. */
00555     path = gtk_tree_path_new ();
00556     gtk_tree_path_append_index (path, g_list_index (ns_list, namespace));
00557     gtk_tree_path_append_index (path, GPOINTER_TO_INT(iter->user_data3));
00558     debug_path(LEAVE, path);
00559     return path;
00560 }
00561 
00562 static void
00563 gnc_tree_model_commodity_get_value (GtkTreeModel *tree_model,
00564                                     GtkTreeIter *iter,
00565                                     int column,
00566                                     GValue *value)
00567 {
00568     GncTreeModelCommodity *model = GNC_TREE_MODEL_COMMODITY (tree_model);
00569     gnc_commodity_namespace *namespace;
00570     gnc_commodity *commodity;
00571     gnc_quote_source *source;
00572 
00573     g_return_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model));
00574     g_return_if_fail (iter != NULL);
00575     g_return_if_fail (iter->user_data != NULL);
00576     g_return_if_fail (iter->user_data2 != NULL);
00577     g_return_if_fail (iter->stamp == model->stamp);
00578 
00579     if (iter->user_data == ITER_IS_NAMESPACE)
00580     {
00581         namespace = (gnc_commodity_namespace *)iter->user_data2;
00582         switch (column)
00583         {
00584         case GNC_TREE_MODEL_COMMODITY_COL_NAMESPACE:
00585             g_value_init (value, G_TYPE_STRING);
00586             g_value_set_string (value, gnc_commodity_namespace_get_name (namespace));
00587             break;
00588         default:
00589             g_value_init (value, G_TYPE_STRING);
00590             g_value_set_string (value, "");
00591             break;
00592         case GNC_TREE_MODEL_COMMODITY_COL_FRACTION:
00593             g_value_init (value, G_TYPE_INT);
00594             g_value_set_int (value, 0);
00595             break;
00596         case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_FLAG:
00597             g_value_init (value, G_TYPE_BOOLEAN);
00598             g_value_set_boolean (value, FALSE);
00599             break;
00600         case GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY:
00601             g_value_init (value, G_TYPE_BOOLEAN);
00602             g_value_set_boolean (value, FALSE);
00603             break;
00604         }
00605         return;
00606     }
00607 
00608     commodity = (gnc_commodity *)iter->user_data2;
00609     switch (column)
00610     {
00611     case GNC_TREE_MODEL_COMMODITY_COL_MNEMONIC:
00612         g_value_init (value, G_TYPE_STRING);
00613 
00614         g_value_set_string (value, gnc_commodity_get_mnemonic (commodity));
00615         break;
00616     case GNC_TREE_MODEL_COMMODITY_COL_NAMESPACE:
00617         g_value_init (value, G_TYPE_STRING);
00618 
00619 //                      g_value_set_string (value, gnc_commodity_get_namespace (commodity));
00620         g_value_set_string (value, NULL);
00621         break;
00622     case GNC_TREE_MODEL_COMMODITY_COL_FULLNAME:
00623         g_value_init (value, G_TYPE_STRING);
00624 
00625         g_value_set_string (value, gnc_commodity_get_fullname (commodity));
00626         break;
00627     case GNC_TREE_MODEL_COMMODITY_COL_PRINTNAME:
00628         g_value_init (value, G_TYPE_STRING);
00629 
00630         g_value_set_string (value, gnc_commodity_get_printname (commodity));
00631         break;
00632     case GNC_TREE_MODEL_COMMODITY_COL_CUSIP:
00633         g_value_init (value, G_TYPE_STRING);
00634 
00635         g_value_set_string (value, gnc_commodity_get_cusip (commodity));
00636         break;
00637     case GNC_TREE_MODEL_COMMODITY_COL_UNIQUE_NAME:
00638         g_value_init (value, G_TYPE_STRING);
00639 
00640         g_value_set_string (value, gnc_commodity_get_unique_name (commodity));
00641         break;
00642     case GNC_TREE_MODEL_COMMODITY_COL_FRACTION:
00643         g_value_init (value, G_TYPE_INT);
00644 
00645         g_value_set_int (value, gnc_commodity_get_fraction (commodity));
00646         break;
00647     case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_FLAG:
00648         g_value_init (value, G_TYPE_BOOLEAN);
00649 
00650         g_value_set_boolean (value, gnc_commodity_get_quote_flag (commodity));
00651         break;
00652     case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_SOURCE:
00653         g_value_init (value, G_TYPE_STRING);
00654 
00655         if (gnc_commodity_get_quote_flag (commodity))
00656         {
00657             source = gnc_commodity_get_quote_source (commodity);
00658             g_value_set_string (value, gnc_quote_source_get_internal_name(source));
00659         }
00660         else
00661         {
00662             g_value_set_static_string (value, "");
00663         }
00664         break;
00665     case GNC_TREE_MODEL_COMMODITY_COL_QUOTE_TZ:
00666         g_value_init (value, G_TYPE_STRING);
00667 
00668         if (gnc_commodity_get_quote_flag (commodity))
00669         {
00670             g_value_set_string (value, gnc_commodity_get_quote_tz (commodity));
00671         }
00672         else
00673         {
00674             g_value_set_static_string (value, "");
00675         }
00676         break;
00677     case GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY:
00678         g_value_init (value, G_TYPE_BOOLEAN);
00679         g_value_set_boolean (value, TRUE);
00680         break;
00681     default:
00682         g_assert_not_reached ();
00683     }
00684 }
00685 
00686 static gboolean
00687 gnc_tree_model_commodity_iter_next (GtkTreeModel *tree_model,
00688                                     GtkTreeIter *iter)
00689 {
00690     GncTreeModelCommodity *model;
00691     GncTreeModelCommodityPrivate *priv;
00692     gnc_commodity_table *ct;
00693     gnc_commodity_namespace *namespace;
00694     GList *list;
00695     int n;
00696 
00697     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), FALSE);
00698     model = GNC_TREE_MODEL_COMMODITY (tree_model);
00699     g_return_val_if_fail (iter != NULL, FALSE);
00700     g_return_val_if_fail (iter->user_data != NULL, FALSE);
00701     g_return_val_if_fail (iter->user_data2 != NULL, FALSE);
00702     g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
00703 
00704     ENTER("model %p, iter %p(%s)", tree_model, iter, iter_to_string(iter));
00705     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00706     if (iter->user_data == ITER_IS_NAMESPACE)
00707     {
00708         ct = priv->commodity_table;
00709         list = gnc_commodity_table_get_namespaces_list(ct);
00710     }
00711     else if (iter->user_data == ITER_IS_COMMODITY)
00712     {
00713         namespace = gnc_commodity_get_namespace_ds((gnc_commodity *)iter->user_data2);
00714         list = gnc_commodity_namespace_get_commodity_list(namespace);
00715     }
00716     else
00717     {
00718         LEAVE("unknown iter type");
00719         return FALSE;
00720     }
00721 
00722     n = GPOINTER_TO_INT(iter->user_data3) + 1;
00723     iter->user_data2 = g_list_nth_data(list, n);
00724     if (iter->user_data2 == NULL)
00725     {
00726         LEAVE("no next iter");
00727         return FALSE;
00728     }
00729     iter->user_data3 = GINT_TO_POINTER(n);
00730     LEAVE("iter %p(%s)", iter, iter_to_string(iter));
00731     return TRUE;
00732 }
00733 
00734 
00735 static gboolean
00736 gnc_tree_model_commodity_iter_children (GtkTreeModel *tree_model,
00737                                         GtkTreeIter *iter,
00738                                         GtkTreeIter *parent)
00739 {
00740     GncTreeModelCommodity *model;
00741     GncTreeModelCommodityPrivate *priv;
00742     gnc_commodity_table *ct;
00743     gnc_commodity_namespace *namespace;
00744     GList *list;
00745 
00746     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), FALSE);
00747 
00748     ENTER("model %p, iter %p, parent %p (%s)",
00749           tree_model, iter, parent, iter_to_string(parent));
00750     model = GNC_TREE_MODEL_COMMODITY (tree_model);
00751     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00752 
00753     if (parent == NULL)
00754     {
00755         ct = priv->commodity_table;
00756         list = gnc_commodity_table_get_namespaces_list(ct);
00757         if (list == NULL)
00758         {
00759             LEAVE("no namespaces");
00760             return FALSE;
00761         }
00762 
00763         iter->stamp      = model->stamp;
00764         iter->user_data  = ITER_IS_NAMESPACE;
00765         iter->user_data2 = g_list_nth_data(list, 0);
00766         iter->user_data3 = GINT_TO_POINTER(0);
00767         LEAVE("ns iter %p (%s)", iter, iter_to_string(iter));
00768         return TRUE;
00769     }
00770 
00771     if (parent->user_data == ITER_IS_NAMESPACE)
00772     {
00773         namespace = (gnc_commodity_namespace *)parent->user_data2;
00774         list = gnc_commodity_namespace_get_commodity_list(namespace);
00775         if (list == NULL)
00776         {
00777             LEAVE("no commodities");
00778             return FALSE;
00779         }
00780 
00781         iter->stamp      = model->stamp;
00782         iter->user_data  = ITER_IS_COMMODITY;
00783         iter->user_data2 = g_list_nth_data(list, 0);
00784         iter->user_data3 = GINT_TO_POINTER(0);
00785         LEAVE("cm iter %p (%s)", iter, iter_to_string(iter));
00786         return TRUE;
00787     }
00788 
00789     LEAVE("FALSE");
00790     return FALSE;
00791 }
00792 
00793 static gboolean
00794 gnc_tree_model_commodity_iter_has_child (GtkTreeModel *tree_model,
00795         GtkTreeIter *iter)
00796 {
00797     gnc_commodity_namespace *namespace;
00798     GList *list;
00799 
00800     g_return_val_if_fail (iter != NULL, FALSE);
00801     ENTER("model %p, iter %p (%s)", tree_model,
00802           iter, iter_to_string(iter));
00803 
00804     if (iter->user_data != ITER_IS_NAMESPACE)
00805     {
00806         LEAVE("no children (not ns)");
00807         return FALSE;
00808     }
00809 
00810     namespace = (gnc_commodity_namespace *)iter->user_data2;
00811     list = gnc_commodity_namespace_get_commodity_list(namespace);
00812     LEAVE("%s children", list ? "has" : "no");
00813     return list != NULL;
00814 }
00815 
00816 static int
00817 gnc_tree_model_commodity_iter_n_children (GtkTreeModel *tree_model,
00818         GtkTreeIter *iter)
00819 {
00820     GncTreeModelCommodity *model;
00821     GncTreeModelCommodityPrivate *priv;
00822     gnc_commodity_table *ct;
00823     gnc_commodity_namespace *namespace;
00824     GList *list;
00825 
00826     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), -1);
00827 
00828     ENTER("model %p, iter %p (%s)", tree_model, iter, iter_to_string(iter));
00829     model = GNC_TREE_MODEL_COMMODITY (tree_model);
00830     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00831 
00832     if (iter == NULL)
00833     {
00834         ct = priv->commodity_table;
00835         list = gnc_commodity_table_get_namespaces_list(ct);
00836         LEAVE("ns list length %d", g_list_length(list));
00837         return g_list_length (list);
00838     }
00839 
00840     if (iter->user_data == ITER_IS_NAMESPACE)
00841     {
00842         namespace = (gnc_commodity_namespace *)iter->user_data2;
00843         list = gnc_commodity_namespace_get_commodity_list(namespace);
00844         LEAVE("cm list length %d", g_list_length(list));
00845         return g_list_length (list);
00846     }
00847 
00848     LEAVE("0");
00849     return 0;
00850 }
00851 
00852 static gboolean
00853 gnc_tree_model_commodity_iter_nth_child (GtkTreeModel *tree_model,
00854         GtkTreeIter *iter,
00855         GtkTreeIter *parent,
00856         int n)
00857 {
00858     GncTreeModelCommodity *model;
00859     GncTreeModelCommodityPrivate *priv;
00860     gnc_commodity_table *ct;
00861     gnc_commodity_namespace *namespace;
00862     GList *list;
00863 
00864     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), FALSE);
00865     g_return_val_if_fail (iter != NULL, FALSE);
00866 
00867     ENTER("model %p, iter %p, parent %p (%s)",
00868           tree_model, iter, parent, iter_to_string(parent));
00869     model = GNC_TREE_MODEL_COMMODITY (tree_model);
00870     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00871 
00872     if (parent == NULL)
00873     {
00874         ct = priv->commodity_table;
00875         list = gnc_commodity_table_get_namespaces_list(ct);
00876 
00877         iter->stamp      = model->stamp;
00878         iter->user_data  = ITER_IS_NAMESPACE;
00879         iter->user_data2 = g_list_nth_data(list, n);
00880         iter->user_data3 = GINT_TO_POINTER(n);
00881         LEAVE("ns iter %p (%s)", iter, iter_to_string(iter));
00882         return iter->user_data2 != NULL;
00883     }
00884 
00885     if (parent->user_data == ITER_IS_NAMESPACE)
00886     {
00887         namespace = (gnc_commodity_namespace *)parent->user_data2;
00888         list = gnc_commodity_namespace_get_commodity_list(namespace);
00889 
00890         iter->stamp      = model->stamp;
00891         iter->user_data  = ITER_IS_COMMODITY;
00892         iter->user_data2 = g_list_nth_data(list, n);
00893         iter->user_data3 = GINT_TO_POINTER(n);
00894         LEAVE("cm iter %p (%s)", iter, iter_to_string(iter));
00895         return iter->user_data2 != NULL;
00896     }
00897 
00898     iter->stamp = 0;
00899     LEAVE("FALSE");
00900     return FALSE;
00901 }
00902 
00903 static gboolean
00904 gnc_tree_model_commodity_iter_parent (GtkTreeModel *tree_model,
00905                                       GtkTreeIter *iter,
00906                                       GtkTreeIter *child)
00907 {
00908     GncTreeModelCommodity *model;
00909     GncTreeModelCommodityPrivate *priv;
00910     gnc_commodity_table *ct;
00911     gnc_commodity_namespace *namespace;
00912     GList *list;
00913 
00914     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (tree_model), FALSE);
00915     g_return_val_if_fail (iter != NULL, FALSE);
00916     g_return_val_if_fail (child != NULL, FALSE);
00917 
00918     ENTER("model %p, iter %p, child %p (%s)",
00919           tree_model, iter, child, iter_to_string(child));
00920     model = GNC_TREE_MODEL_COMMODITY (tree_model);
00921     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
00922 
00923     if (child->user_data == ITER_IS_NAMESPACE)
00924     {
00925         LEAVE("ns has no parent");
00926         return FALSE;
00927     }
00928 
00929     ct = priv->commodity_table;
00930     list = gnc_commodity_table_get_namespaces_list(ct);
00931     namespace = gnc_commodity_get_namespace_ds((gnc_commodity*)child->user_data2);
00932 
00933     iter->stamp      = model->stamp;
00934     iter->user_data  = ITER_IS_NAMESPACE;
00935     iter->user_data2 = namespace;
00936     iter->user_data3 = GINT_TO_POINTER(g_list_index(list, namespace));
00937     LEAVE("ns iter %p (%s)", iter, iter_to_string(iter));
00938     return TRUE;
00939 }
00940 
00941 /************************************************************/
00942 /*              Commodity Tree View Functions               */
00943 /************************************************************/
00944 
00945 /*
00946  * Convert a model/commodity pair into a gtk_tree_model_iter.  This
00947  * routine should only be called from the file
00948  * gnc-tree-view-commodity.c.
00949  */
00950 gboolean
00951 gnc_tree_model_commodity_get_iter_from_commodity (GncTreeModelCommodity *model,
00952         gnc_commodity *commodity,
00953         GtkTreeIter *iter)
00954 {
00955     gnc_commodity_namespace *namespace;
00956     GList *list;
00957     gint n;
00958 
00959     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), FALSE);
00960     g_return_val_if_fail ((commodity != NULL), FALSE);
00961     g_return_val_if_fail ((iter != NULL), FALSE);
00962 
00963     ENTER("model %p, commodity %p, iter %p", model, commodity, iter);
00964 
00965     namespace = gnc_commodity_get_namespace_ds(commodity);
00966     if (namespace == NULL)
00967     {
00968         LEAVE("no namespace");
00969         return FALSE;
00970     }
00971 
00972     list = gnc_commodity_namespace_get_commodity_list(namespace);
00973     if (list == NULL)
00974     {
00975         LEAVE("empty list");
00976         return FALSE;
00977     }
00978 
00979     n = g_list_index(list, commodity);
00980     if (n == -1)
00981     {
00982         LEAVE("not in list");
00983         return FALSE;
00984     }
00985 
00986     iter->stamp = model->stamp;
00987     iter->user_data  = ITER_IS_COMMODITY;
00988     iter->user_data2 = commodity;
00989     iter->user_data3 = GINT_TO_POINTER(n);
00990     LEAVE("iter %s", iter_to_string(iter));
00991     return TRUE;
00992 }
00993 
00994 /*
00995  * Convert a model/commodity pair into a gtk_tree_model_path.  This
00996  * routine should only be called from the file
00997  * gnc-tree-view-commodity.c.
00998  */
00999 GtkTreePath *
01000 gnc_tree_model_commodity_get_path_from_commodity (GncTreeModelCommodity *model,
01001         gnc_commodity *commodity)
01002 {
01003     GtkTreeIter tree_iter;
01004     GtkTreePath *tree_path;
01005 
01006     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), NULL);
01007     g_return_val_if_fail (commodity != NULL, NULL);
01008     ENTER("model %p, commodity %p", model, commodity);
01009 
01010     if (!gnc_tree_model_commodity_get_iter_from_commodity (model, commodity, &tree_iter))
01011     {
01012         LEAVE("no iter");
01013         return NULL;
01014     }
01015 
01016     tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &tree_iter);
01017     if (tree_path)
01018     {
01019         gchar *path_string = gtk_tree_path_to_string(tree_path);
01020         LEAVE("path (2) %s", path_string);
01021         g_free(path_string);
01022     }
01023     else
01024     {
01025         LEAVE("no path");
01026     }
01027     return tree_path;
01028 }
01029 
01030 /*
01031  * Convert a model/namespace pair into a gtk_tree_model_iter.  This
01032  * routine should only be called from the file
01033  * gnc-tree-view-commodity.c.
01034  */
01035 gboolean
01036 gnc_tree_model_commodity_get_iter_from_namespace (GncTreeModelCommodity *model,
01037         gnc_commodity_namespace *namespace,
01038         GtkTreeIter *iter)
01039 {
01040     GncTreeModelCommodityPrivate *priv;
01041     GList *list;
01042     gint n;
01043 
01044     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), FALSE);
01045     g_return_val_if_fail ((namespace != NULL), FALSE);
01046     g_return_val_if_fail ((iter != NULL), FALSE);
01047 
01048     ENTER("model %p, namespace %p, iter %p", model, namespace, iter);
01049 
01050     priv = GNC_TREE_MODEL_COMMODITY_GET_PRIVATE(model);
01051     list = gnc_commodity_table_get_namespaces_list(priv->commodity_table);
01052     if (list == NULL)
01053     {
01054         LEAVE("");
01055         return FALSE;
01056     }
01057 
01058     n = g_list_index(list, namespace);
01059     if (n == -1)
01060     {
01061         LEAVE("");
01062         return FALSE;
01063     }
01064 
01065     iter->stamp = model->stamp;
01066     iter->user_data  = ITER_IS_NAMESPACE;
01067     iter->user_data2 = namespace;
01068     iter->user_data3 = GINT_TO_POINTER(n);
01069     LEAVE("iter %s", iter_to_string(iter));
01070     return TRUE;
01071 }
01072 
01073 
01074 /************************************************************/
01075 /*  Commodity Tree Model - Engine Event Handling Functions  */
01076 /************************************************************/
01077 
01078 typedef struct _remove_data
01079 {
01080     GncTreeModelCommodity *model;
01081     GtkTreePath           *path;
01082 } remove_data;
01083 
01084 static GSList *pending_removals = NULL;
01085 
01097 static void
01098 gnc_tree_model_commodity_row_add (GncTreeModelCommodity *model,
01099                                   GtkTreeIter *iter)
01100 {
01101     GtkTreePath *path;
01102     GtkTreeModel *tree_model;
01103     GtkTreeIter tmp_iter;
01104 
01105     ENTER("model %p, iter (%p)%s", model, iter, iter_to_string(iter));
01106 
01107     /* We're adding a row, so the lists on which this model is based have
01108      * changed. Since existing iterators (except the one just passed in)
01109      * are all based on old indexes into those lists, we need to invalidate
01110      * them, which we can do by changing the model's stamp. */
01111     do
01112     {
01113         model->stamp++;
01114     }
01115     while (model->stamp == 0);
01116     iter->stamp = model->stamp;
01117 
01118     /* Tag the new row as inserted. */
01119     tree_model = GTK_TREE_MODEL(model);
01120     path = gnc_tree_model_commodity_get_path(tree_model, iter);
01121     gtk_tree_model_row_inserted(tree_model, path, iter);
01122 
01123     /* Inform all ancestors. */
01124     /*
01125      * Charles Day: I don't think calls to gtk_tree_model_row_changed() should
01126      * be necessary. It is just a workaround for bug #540201.
01127      */
01128     if (gtk_tree_path_up(path) &&
01129             gtk_tree_path_get_depth(path) > 0 &&
01130             gtk_tree_model_get_iter(tree_model, &tmp_iter, path))
01131     {
01132         /* Signal the change to the parent. */
01133         gtk_tree_model_row_changed(tree_model, path, &tmp_iter);
01134 
01135         /* Is this the parent's first child? */
01136         if (gtk_tree_model_iter_n_children(tree_model, &tmp_iter) == 1)
01137             gtk_tree_model_row_has_child_toggled(tree_model, path, &tmp_iter);
01138 
01139         /* Signal any other ancestors. */
01140         while (gtk_tree_path_up(path) &&
01141                 gtk_tree_path_get_depth(path) > 0 &&
01142                 gtk_tree_model_get_iter(tree_model, &tmp_iter, path))
01143         {
01144             gtk_tree_model_row_changed(tree_model, path, &tmp_iter);
01145         }
01146     }
01147     gtk_tree_path_free(path);
01148 
01149     /* If the new row already has children, signal that so the expander
01150      * can be shown. This can happen, for example, if a namespace is
01151      * changed in another place and gets removed and then re-added to
01152      * the commodity db. */
01153     if (gnc_tree_model_commodity_iter_has_child(tree_model, iter))
01154     {
01155         path = gnc_tree_model_commodity_get_path(tree_model, iter);
01156         gtk_tree_model_row_has_child_toggled(tree_model, path, iter);
01157         gtk_tree_path_free(path);
01158     }
01159 
01160     LEAVE(" ");
01161 }
01162 
01174 static void
01175 gnc_tree_model_commodity_row_delete (GncTreeModelCommodity *model,
01176                                      GtkTreePath *path)
01177 {
01178     GtkTreeModel *tree_model;
01179     GtkTreeIter iter;
01180 
01181     g_return_if_fail(GNC_IS_TREE_MODEL_COMMODITY(model));
01182     g_return_if_fail(path);
01183 
01184     debug_path(ENTER, path);
01185 
01186     tree_model = GTK_TREE_MODEL(model);
01187 
01188     /* We're removing a row, so the lists on which this model is based have
01189      * changed. Since existing iterators are all based on old indexes into
01190      * those lists, we need to invalidate them, which we can do by changing
01191      * the model's stamp. */
01192     do
01193     {
01194         model->stamp++;
01195     }
01196     while (model->stamp == 0);
01197 
01198     /* Signal that the path has been deleted. */
01199     gtk_tree_model_row_deleted(tree_model, path);
01200 
01201     /* Issue any appropriate signals to ancestors. */
01202     if (gtk_tree_path_up(path) &&
01203             gtk_tree_path_get_depth(path) > 0 &&
01204             gtk_tree_model_get_iter(tree_model, &iter, path) &&
01205             !gtk_tree_model_iter_has_child(tree_model, &iter))
01206     {
01207         DEBUG("parent toggled, iter %s", iter_to_string(&iter));
01208         gtk_tree_model_row_has_child_toggled(tree_model, path, &iter);
01209     }
01210 
01211     LEAVE(" ");
01212 }
01213 
01214 
01231 static gboolean
01232 gnc_tree_model_commodity_do_deletions (gpointer unused)
01233 {
01234     ENTER(" ");
01235 
01236     /* Go through the list of paths needing removal. */
01237     while (pending_removals)
01238     {
01239         remove_data *data = pending_removals->data;
01240         pending_removals = g_slist_delete_link(pending_removals, pending_removals);
01241 
01242         if (data)
01243         {
01244             debug_path(DEBUG, data->path);
01245 
01246             /* Remove the path. */
01247             gnc_tree_model_commodity_row_delete(data->model, data->path);
01248 
01249             gtk_tree_path_free(data->path);
01250             g_free(data);
01251         }
01252     }
01253 
01254     LEAVE(" ");
01255     /* Don't call me again. */
01256     return FALSE;
01257 }
01258 
01259 
01291 static void
01292 gnc_tree_model_commodity_event_handler (QofInstance *entity,
01293                                         QofEventId event_type,
01294                                         gpointer user_data,
01295                                         gpointer event_data)
01296 {
01297     GncTreeModelCommodity *model;
01298     GtkTreePath *path;
01299     GtkTreeIter iter;
01300     remove_data *data;
01301     const gchar *name;
01302 
01303     model = (GncTreeModelCommodity *)user_data;
01304 
01305     /* hard failures */
01306     g_return_if_fail(GNC_IS_TREE_MODEL_COMMODITY(model));
01307 
01308     ENTER("entity %p, event %d, model %p, event data %p",
01309           entity, event_type, user_data, event_data);
01310 
01311     /* Do deletions if any are pending. */
01312     if (pending_removals)
01313         gnc_tree_model_commodity_do_deletions(NULL);
01314 
01315     /* get type specific data */
01316     if (GNC_IS_COMMODITY(entity))
01317     {
01318         gnc_commodity *commodity;
01319 
01320         commodity = GNC_COMMODITY(entity);
01321         name = gnc_commodity_get_mnemonic(commodity);
01322         if (event_type != QOF_EVENT_DESTROY)
01323         {
01324             if (!gnc_tree_model_commodity_get_iter_from_commodity (model, commodity, &iter))
01325             {
01326                 LEAVE("no iter");
01327                 return;
01328             }
01329         }
01330     }
01331     else if (GNC_IS_COMMODITY_NAMESPACE(entity))
01332     {
01333         gnc_commodity_namespace *namespace;
01334 
01335         namespace = GNC_COMMODITY_NAMESPACE(entity);
01336         name = gnc_commodity_namespace_get_name(namespace);
01337         if (event_type != QOF_EVENT_DESTROY)
01338         {
01339             if (!gnc_tree_model_commodity_get_iter_from_namespace (model, namespace, &iter))
01340             {
01341                 LEAVE("no iter");
01342                 return;
01343             }
01344         }
01345     }
01346     else
01347     {
01348         LEAVE("");
01349         return;
01350     }
01351 
01352     switch (event_type)
01353     {
01354     case QOF_EVENT_ADD:
01355         /* Tell the filters/views where the new account was added. */
01356         DEBUG("add %s", name);
01357         gnc_tree_model_commodity_row_add (model, &iter);
01358         break;
01359 
01360     case QOF_EVENT_REMOVE:
01361         /* Record the path of this account for later use in destruction */
01362         DEBUG("remove %s", name);
01363         path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &iter);
01364         if (path == NULL)
01365         {
01366             LEAVE("not in model");
01367             return;
01368         }
01369 
01370         data = g_new0 (remove_data, 1);
01371         data->model = model;
01372         data->path = path;
01373         pending_removals = g_slist_append (pending_removals, data);
01374         g_idle_add_full(G_PRIORITY_HIGH_IDLE,
01375                         gnc_tree_model_commodity_do_deletions, NULL, NULL);
01376 
01377         LEAVE(" ");
01378         return;
01379 
01380     case QOF_EVENT_MODIFY:
01381         DEBUG("change %s", name);
01382         path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &iter);
01383         if (path == NULL)
01384         {
01385             LEAVE("not in model");
01386             return;
01387         }
01388         gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter);
01389         gtk_tree_path_free(path);
01390         LEAVE(" ");
01391         return;
01392 
01393     default:
01394         LEAVE("ignored event for %s", name);
01395         return;
01396     }
01397     LEAVE(" new stamp %u", model->stamp);
01398 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines