GnuCash 2.4.99
gnc-tree-view-commodity.c
00001 /********************************************************************\
00002  * gnc-tree-view-commodity.c -- GtkTreeView implementation to       *
00003  *                            display commodities in a GtkTreeView. *
00004  * Copyright (C) 2003,2005 David Hampton <hampton@employees.org>    *
00005  *                                                                  *
00006  * This program is free software; you can redistribute it and/or    *
00007  * modify it under the terms of the GNU General Public License as   *
00008  * published by the Free Software Foundation; either version 2 of   *
00009  * the License, or (at your option) any later version.              *
00010  *                                                                  *
00011  * This program is distributed in the hope that it will be useful,  *
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00014  * GNU General Public License for more details.                     *
00015  *                                                                  *
00016  * You should have received a copy of the GNU General Public License*
00017  * along with this program; if not, contact:                        *
00018  *                                                                  *
00019  * Free Software Foundation           Voice:  +1-617-542-5942       *
00020  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00021  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00022  *                                                                  *
00023 \********************************************************************/
00024 
00025 #include "config.h"
00026 
00027 #include <gtk/gtk.h>
00028 #include <glib/gi18n.h>
00029 #include <string.h>
00030 
00031 #include "gnc-tree-view.h"
00032 #include "gnc-tree-model-commodity.h"
00033 #include "gnc-tree-view-commodity.h"
00034 
00035 #include "gnc-commodity.h"
00036 #include "gnc-component-manager.h"
00037 #include "gnc-engine.h"
00038 #include "gnc-gconf-utils.h"
00039 #include "gnc-glib-utils.h"
00040 #include "gnc-gnome-utils.h"
00041 #include "gnc-icons.h"
00042 #include "gnc-ui-util.h"
00043 
00044 
00047 /* This static indicates the debugging module that this .o belongs to.  */
00048 static QofLogModule log_module = GNC_MOD_GUI;
00049 
00051 static void gnc_tree_view_commodity_class_init (GncTreeViewCommodityClass *klass);
00052 static void gnc_tree_view_commodity_init (GncTreeViewCommodity *view);
00053 static void gnc_tree_view_commodity_finalize (GObject *object);
00054 static void gnc_tree_view_commodity_destroy (GtkObject *object);
00055 
00056 typedef struct GncTreeViewCommodityPrivate
00057 {
00058     gpointer dummy;
00059 } GncTreeViewCommodityPrivate;
00060 
00061 #define GNC_TREE_VIEW_COMMODITY_GET_PRIVATE(o)  \
00062    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_TREE_VIEW_COMMODITY, GncTreeViewCommodityPrivate))
00063 
00064 
00065 /************************************************************/
00066 /*               g_object required functions                */
00067 /************************************************************/
00068 
00069 static GObjectClass *parent_class = NULL;
00070 
00071 GType
00072 gnc_tree_view_commodity_get_type (void)
00073 {
00074     static GType gnc_tree_view_commodity_type = 0;
00075 
00076     if (gnc_tree_view_commodity_type == 0)
00077     {
00078         static const GTypeInfo our_info =
00079         {
00080             sizeof (GncTreeViewCommodityClass),
00081             NULL,
00082             NULL,
00083             (GClassInitFunc) gnc_tree_view_commodity_class_init,
00084             NULL,
00085             NULL,
00086             sizeof (GncTreeViewCommodity),
00087             0,
00088             (GInstanceInitFunc) gnc_tree_view_commodity_init
00089         };
00090 
00091         gnc_tree_view_commodity_type = g_type_register_static (GNC_TYPE_TREE_VIEW,
00092                                        "GncTreeViewCommodity",
00093                                        &our_info, 0);
00094     }
00095 
00096     return gnc_tree_view_commodity_type;
00097 }
00098 
00099 static void
00100 gnc_tree_view_commodity_class_init (GncTreeViewCommodityClass *klass)
00101 {
00102     GObjectClass *o_class;
00103     GtkObjectClass *object_class;
00104 
00105     parent_class = g_type_class_peek_parent (klass);
00106 
00107     o_class = G_OBJECT_CLASS (klass);
00108     object_class = GTK_OBJECT_CLASS (klass);
00109 
00110     /* GObject signals */
00111     o_class->finalize = gnc_tree_view_commodity_finalize;
00112 
00113     /* GtkObject signals */
00114     object_class->destroy = gnc_tree_view_commodity_destroy;
00115 
00116     g_type_class_add_private(klass, sizeof(GncTreeViewCommodityPrivate));
00117 }
00118 
00119 static void
00120 gnc_tree_view_commodity_init (GncTreeViewCommodity *view)
00121 {
00122 }
00123 
00124 static void
00125 gnc_tree_view_commodity_finalize (GObject *object)
00126 {
00127     GncTreeViewCommodity *view;
00128     GncTreeViewCommodityPrivate *priv;
00129 
00130     g_return_if_fail (object != NULL);
00131     g_return_if_fail (GNC_IS_TREE_VIEW_COMMODITY (object));
00132 
00133     ENTER("view %p", object);
00134     view = GNC_TREE_VIEW_COMMODITY (object);
00135     priv = GNC_TREE_VIEW_COMMODITY_GET_PRIVATE (view);
00136 
00137     if (G_OBJECT_CLASS (parent_class)->finalize)
00138         (* G_OBJECT_CLASS (parent_class)->finalize) (object);
00139     LEAVE(" ");
00140 }
00141 
00142 static void
00143 gnc_tree_view_commodity_destroy (GtkObject *object)
00144 {
00145     GncTreeViewCommodity *view;
00146 
00147     g_return_if_fail (object != NULL);
00148     g_return_if_fail (GNC_IS_TREE_VIEW_COMMODITY (object));
00149 
00150     ENTER("view %p", object);
00151     view = GNC_TREE_VIEW_COMMODITY (object);
00152 
00153     if (GTK_OBJECT_CLASS (parent_class)->destroy)
00154         (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
00155     LEAVE(" ");
00156 }
00157 
00158 
00159 /************************************************************/
00160 /*                      sort functions                      */
00161 /************************************************************/
00162 
00163 static gboolean
00164 get_commodities_w_iters (GtkTreeModel *f_model,
00165                          GtkTreeIter *f_iter_a,
00166                          GtkTreeIter *f_iter_b,
00167                          GtkTreeModel **model_p,
00168                          GtkTreeIter *iter_a,
00169                          GtkTreeIter *iter_b,
00170                          gnc_commodity **comm_a,
00171                          gnc_commodity **comm_b)
00172 {
00173     GncTreeModelCommodity *model;
00174     GtkTreeModel *tree_model;
00175 
00176     tree_model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
00177     model = GNC_TREE_MODEL_COMMODITY(tree_model);
00178 
00179     gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
00180             iter_a,
00181             f_iter_a);
00182 
00183     gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
00184             iter_b,
00185             f_iter_b);
00186 
00187     /* Both iters must point to commodities for this to be meaningful */
00188     if (!gnc_tree_model_commodity_iter_is_commodity (model, iter_a))
00189         return FALSE;
00190     if (!gnc_tree_model_commodity_iter_is_commodity (model, iter_b))
00191         return FALSE;
00192 
00193     *comm_a = gnc_tree_model_commodity_get_commodity (model, iter_a);
00194     *comm_b = gnc_tree_model_commodity_get_commodity (model, iter_b);
00195     if (model_p)
00196         *model_p = tree_model;
00197     return TRUE;
00198 }
00199 
00200 static gboolean
00201 get_commodities (GtkTreeModel *f_model,
00202                  GtkTreeIter *f_iter_a,
00203                  GtkTreeIter *f_iter_b,
00204                  GtkTreeModel **model_p,
00205                  gnc_commodity **comm_a,
00206                  gnc_commodity **comm_b)
00207 {
00208     GtkTreeIter iter_a, iter_b;
00209 
00210     return get_commodities_w_iters(f_model, f_iter_a, f_iter_b, model_p,
00211                                    &iter_a, &iter_b, comm_a, comm_b);
00212 }
00213 
00214 static gint
00215 sort_namespace (GtkTreeModel *f_model,
00216                 GtkTreeIter *f_iter_a,
00217                 GtkTreeIter *f_iter_b)
00218 {
00219     GncTreeModelCommodity *model;
00220     GtkTreeModel *tree_model;
00221     GtkTreeIter iter_a, iter_b;
00222     gnc_commodity_namespace *ns_a, *ns_b;
00223 
00224     tree_model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
00225     model = GNC_TREE_MODEL_COMMODITY(tree_model);
00226 
00227     gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
00228             &iter_a,
00229             f_iter_a);
00230     gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(f_model),
00231             &iter_b,
00232             f_iter_b);
00233 
00234     ns_a = gnc_tree_model_commodity_get_namespace (model, &iter_a);
00235     ns_b = gnc_tree_model_commodity_get_namespace (model, &iter_b);
00236     return safe_utf8_collate (gnc_commodity_namespace_get_name (ns_a),
00237                               gnc_commodity_namespace_get_name (ns_b));
00238 }
00239 
00240 static gint
00241 default_sort (gnc_commodity *comm_a, gnc_commodity *comm_b)
00242 {
00243     gint fraction_a, fraction_b, result;
00244 
00245     result = safe_utf8_collate (gnc_commodity_get_namespace (comm_a),
00246                                 gnc_commodity_get_namespace (comm_b));
00247     if (result != 0) return result;
00248 
00249     result = safe_utf8_collate (gnc_commodity_get_mnemonic (comm_a),
00250                                 gnc_commodity_get_mnemonic (comm_b));
00251     if (result != 0) return result;
00252 
00253     result = safe_utf8_collate (gnc_commodity_get_fullname (comm_a),
00254                                 gnc_commodity_get_fullname (comm_b));
00255     if (result != 0) return result;
00256 
00257     result = safe_utf8_collate (gnc_commodity_get_cusip (comm_a),
00258                                 gnc_commodity_get_cusip (comm_b));
00259     if (result != 0) return result;
00260 
00261     fraction_a = gnc_commodity_get_fraction (comm_a);
00262     fraction_b = gnc_commodity_get_fraction (comm_b);
00263 
00264     if (fraction_a < fraction_b)
00265         return -1;
00266 
00267     if (fraction_b < fraction_a)
00268         return 1;
00269 
00270     return 0;
00271 }
00272 
00273 static gint
00274 sort_by_commodity_string (GtkTreeModel *f_model,
00275                           GtkTreeIter *f_iter_a,
00276                           GtkTreeIter *f_iter_b,
00277                           gpointer user_data)
00278 {
00279     GtkTreeModel *model;
00280     GtkTreeIter iter_a, iter_b;
00281     gnc_commodity *comm_a, *comm_b;
00282     gchar *str1, *str2;
00283     gint column = GPOINTER_TO_INT(user_data);
00284     gint result;
00285 
00286     if (!get_commodities_w_iters(f_model, f_iter_a, f_iter_b,
00287                                  &model, &iter_a, &iter_b, &comm_a, &comm_b))
00288         return sort_namespace (f_model, f_iter_a, f_iter_b);
00289 
00290     /* Get the strings. */
00291     gtk_tree_model_get(GTK_TREE_MODEL(model), &iter_a,  column, &str1, -1);
00292     gtk_tree_model_get(GTK_TREE_MODEL(model), &iter_b,  column, &str2, -1);
00293 
00294     result = safe_utf8_collate(str1, str2);
00295     g_free(str1);
00296     g_free(str2);
00297     if (result != 0)
00298         return result;
00299     return default_sort(comm_a, comm_b);
00300 }
00301 
00302 
00303 static gint
00304 sort_by_fraction (GtkTreeModel *f_model,
00305                   GtkTreeIter *f_iter_a,
00306                   GtkTreeIter *f_iter_b,
00307                   gpointer user_data)
00308 {
00309     gnc_commodity *comm_a, *comm_b;
00310     gint fraction_a, fraction_b;
00311 
00312     if (!get_commodities (f_model, f_iter_a, f_iter_b, NULL, &comm_a, &comm_b))
00313         return sort_namespace (f_model, f_iter_a, f_iter_b);
00314 
00315     fraction_a = gnc_commodity_get_fraction (comm_a);
00316     fraction_b = gnc_commodity_get_fraction (comm_b);
00317 
00318     if (fraction_a < fraction_b)
00319         return -1;
00320 
00321     if (fraction_b < fraction_a)
00322         return 1;
00323 
00324     return default_sort(comm_a, comm_b);
00325 }
00326 
00327 static gint
00328 sort_by_quote_flag (GtkTreeModel *f_model,
00329                     GtkTreeIter *f_iter_a,
00330                     GtkTreeIter *f_iter_b,
00331                     gpointer user_data)
00332 {
00333     gnc_commodity *comm_a, *comm_b;
00334     gboolean flag_a, flag_b;
00335 
00336     if (!get_commodities (f_model, f_iter_a, f_iter_b, NULL, &comm_a, &comm_b))
00337         return sort_namespace (f_model, f_iter_a, f_iter_b);
00338 
00339     flag_a = gnc_commodity_get_quote_flag(comm_a);
00340     flag_b = gnc_commodity_get_quote_flag(comm_b);
00341 
00342     if (flag_a < flag_b)
00343         return -1;
00344     else if (flag_a > flag_b)
00345         return 1;
00346     return default_sort(comm_a, comm_b);
00347 }
00348 
00349 /************************************************************/
00350 /*                    New View Creation                     */
00351 /************************************************************/
00352 
00353 /*
00354  * Create a new commodity tree view with (optional) top level root node.
00355  * This view will be based on a model that is common to all view of
00356  * the same set of books, but will have its own private filter on that
00357  * model.
00358  */
00359 GtkTreeView *
00360 gnc_tree_view_commodity_new (QofBook *book,
00361                              const gchar *first_property_name,
00362                              ...)
00363 {
00364     GncTreeView *view;
00365     GtkTreeModel *model, *f_model, *s_model;
00366     GtkTreeViewColumn *col;
00367     gnc_commodity_table *ct;
00368     va_list var_args;
00369 
00370     ENTER(" ");
00371     /* Create/get a pointer to the existing model for this set of books. */
00372     ct = gnc_commodity_table_get_table (book);
00373     model = gnc_tree_model_commodity_new (book, ct);
00374 
00375     /* Set up the view private filter on the common model. */
00376     f_model = gtk_tree_model_filter_new (model, NULL);
00377     g_object_unref(G_OBJECT(model));
00378     s_model = gtk_tree_model_sort_new_with_model (f_model);
00379     g_object_unref(G_OBJECT(f_model));
00380 
00381     /* Create our view */
00382     view = g_object_new (GNC_TYPE_TREE_VIEW_COMMODITY,
00383                          "name", "commodity_tree", NULL);
00384     gnc_tree_view_set_model (view, s_model);
00385     g_object_unref(G_OBJECT(s_model));
00386 
00387     DEBUG("model ref count is %d",   G_OBJECT(model)->ref_count);
00388     DEBUG("f_model ref count is %d", G_OBJECT(f_model)->ref_count);
00389     DEBUG("s_model ref count is %d", G_OBJECT(s_model)->ref_count);
00390 
00391     /* Set default visibilities */
00392     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(view), FALSE);
00393 
00394     col = gnc_tree_view_add_text_column (
00395               view, _("Namespace"), "namespace", NULL, "NASDAQ",
00396               GNC_TREE_MODEL_COMMODITY_COL_NAMESPACE,
00397               GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
00398               sort_by_commodity_string);
00399     col = gnc_tree_view_add_text_column (
00400               view, _("Symbol"), "symbol", NULL, "ACMEACME",
00401               GNC_TREE_MODEL_COMMODITY_COL_MNEMONIC,
00402               GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY,
00403               sort_by_commodity_string);
00404     g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
00405     col = gnc_tree_view_add_text_column (
00406               view, _("Name"), "name", NULL, "Acme Corporation, Inc.",
00407               GNC_TREE_MODEL_COMMODITY_COL_FULLNAME,
00408               GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY,
00409               sort_by_commodity_string);
00410     g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
00411     col = gnc_tree_view_add_text_column (
00412               view, _("Print Name"), "printname", NULL,
00413               "ACMEACME (Acme Corporation, Inc.)",
00414               GNC_TREE_MODEL_COMMODITY_COL_PRINTNAME,
00415               GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY,
00416               sort_by_commodity_string);
00417     col = gnc_tree_view_add_text_column (
00418               view, _("Unique Name"), "uniquename", NULL,
00419               "NASDAQ::ACMEACME", GNC_TREE_MODEL_COMMODITY_COL_UNIQUE_NAME,
00420               GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY,
00421               sort_by_commodity_string);
00422     col = gnc_tree_view_add_text_column (
00423               /* Translators: Again replace CUSIP by the name of your
00424                  National Securities Identifying Number. */
00425               view, _("ISIN/CUSIP"), "cusip_code", NULL, "QWERTYUIOP",
00426               GNC_TREE_MODEL_COMMODITY_COL_CUSIP,
00427               GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY,
00428               sort_by_commodity_string);
00429     g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
00430     col = gnc_tree_view_add_numeric_column (
00431               view, _("Fraction"), "fraction", "10000",
00432               GNC_TREE_MODEL_COMMODITY_COL_FRACTION,
00433               GNC_TREE_VIEW_COLUMN_COLOR_NONE,
00434               GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY,
00435               sort_by_fraction);
00436     g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
00437     col = gnc_tree_view_add_toggle_column(
00438               view, _("Get Quotes"),
00439               /* Translators: This string has a context prefix; the translation
00440                  must only contain the part after the | character. */
00441               Q_("Column letter for 'Get Quotes'|Q"), "quote_flag",
00442               GNC_TREE_MODEL_COMMODITY_COL_QUOTE_FLAG,
00443               GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY,
00444               sort_by_quote_flag,
00445               NULL);
00446     col = gnc_tree_view_add_text_column (
00447               view, _("Source"), "quote_source", NULL, "yahoo",
00448               GNC_TREE_MODEL_COMMODITY_COL_QUOTE_SOURCE,
00449               GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY,
00450               sort_by_commodity_string);
00451     col = gnc_tree_view_add_text_column (
00452               view, _("Timezone"), "quote_timezone", NULL, "America/New_York",
00453               GNC_TREE_MODEL_COMMODITY_COL_QUOTE_TZ,
00454               GNC_TREE_MODEL_COMMODITY_COL_VISIBILITY,
00455               sort_by_commodity_string);
00456     g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
00457 
00458     gnc_tree_view_configure_columns(view);
00459 
00460     /* Set properties */
00461     va_start (var_args, first_property_name);
00462     g_object_set_valist (G_OBJECT(view), first_property_name, var_args);
00463     va_end (var_args);
00464 
00465     /* Sort on the name column by default. This allows for a consistent
00466      * sort if commodities are briefly removed and re-added. */
00467     if (!gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(s_model),
00468             NULL, NULL))
00469     {
00470         gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model),
00471                                              GNC_TREE_MODEL_COMMODITY_COL_FULLNAME,
00472                                              GTK_SORT_ASCENDING);
00473     }
00474 
00475     gtk_widget_show(GTK_WIDGET(view));
00476     LEAVE(" %p", view);
00477     return GTK_TREE_VIEW(view);
00478 }
00479 
00480 /************************************************************/
00481 /*                   Auxiliary Functions                    */
00482 /************************************************************/
00483 
00484 #define debug_path(fn, path) {                          \
00485     gchar *path_string = gtk_tree_path_to_string(path); \
00486     fn("tree path %s", path_string);                    \
00487     g_free(path_string);                                \
00488   }
00489 
00490 static gboolean
00491 gnc_tree_view_commodity_get_iter_from_commodity (GncTreeViewCommodity *view,
00492         gnc_commodity *commodity,
00493         GtkTreeIter *s_iter)
00494 {
00495     GtkTreeModel *model, *f_model, *s_model;
00496     GtkTreeIter iter, f_iter;
00497 
00498     g_return_val_if_fail(GNC_IS_TREE_VIEW_COMMODITY(view), FALSE);
00499     g_return_val_if_fail(commodity != NULL, FALSE);
00500     g_return_val_if_fail(s_iter != NULL, FALSE);
00501 
00502     ENTER("view %p, commodity %p (%s)", view, commodity, gnc_commodity_get_mnemonic(commodity));
00503 
00504     /* Reach down to the real model and get an iter for this commodity */
00505     s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
00506     f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
00507     model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
00508     if (!gnc_tree_model_commodity_get_iter_from_commodity (GNC_TREE_MODEL_COMMODITY(model), commodity, &iter))
00509     {
00510         LEAVE("model_get_iter_from_commodity failed");
00511         return FALSE;
00512     }
00513 
00514     /* convert back to a sort iter */
00515     gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER(f_model),
00516             &f_iter, &iter);
00517     gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT(s_model),
00518             s_iter, &f_iter);
00519     LEAVE(" ");
00520     return TRUE;
00521 }
00522 
00523 /************************************************************/
00524 /*          Commodity Tree View Visibility Filter           */
00525 /************************************************************/
00526 
00527 typedef struct
00528 {
00529     gnc_tree_view_commodity_ns_filter_func user_ns_fn;
00530     gnc_tree_view_commodity_cm_filter_func user_cm_fn;
00531     gpointer                               user_data;
00532     GtkDestroyNotify                       user_destroy;
00533 } filter_user_data;
00534 
00535 static void
00536 gnc_tree_view_commodity_filter_destroy (gpointer data)
00537 {
00538     filter_user_data *fd = data;
00539 
00540     if (fd->user_destroy)
00541         fd->user_destroy(fd->user_data);
00542     g_free(fd);
00543 }
00544 
00545 static gboolean
00546 gnc_tree_view_commodity_filter_helper (GtkTreeModel *model,
00547                                        GtkTreeIter *iter,
00548                                        gpointer data)
00549 {
00550     gnc_commodity_namespace *namespace;
00551     gnc_commodity *commodity;
00552     filter_user_data *fd = data;
00553 
00554     g_return_val_if_fail (GNC_IS_TREE_MODEL_COMMODITY (model), FALSE);
00555     g_return_val_if_fail (iter != NULL, FALSE);
00556 
00557     if (gnc_tree_model_commodity_iter_is_namespace (GNC_TREE_MODEL_COMMODITY(model), iter))
00558     {
00559         if (fd->user_ns_fn)
00560         {
00561             namespace = gnc_tree_model_commodity_get_namespace (GNC_TREE_MODEL_COMMODITY(model), iter);
00562             return fd->user_ns_fn(namespace, fd->user_data);
00563         }
00564         return TRUE;
00565     }
00566 
00567     if (gnc_tree_model_commodity_iter_is_commodity (GNC_TREE_MODEL_COMMODITY(model), iter))
00568     {
00569         if (fd->user_cm_fn)
00570         {
00571             commodity = gnc_tree_model_commodity_get_commodity (GNC_TREE_MODEL_COMMODITY(model), iter);
00572             return fd->user_cm_fn(commodity, fd->user_data);
00573         }
00574         return TRUE;
00575     }
00576 
00577     return FALSE;
00578 }
00579 
00580 /*
00581  * Set an GtkTreeModel visible filter on this commodity.  This filter will be
00582  * called for each commodity that the tree is about to show, and the
00583  * commodity will be passed to the callback function.
00584  */
00585 void
00586 gnc_tree_view_commodity_set_filter (GncTreeViewCommodity *view,
00587                                     gnc_tree_view_commodity_ns_filter_func ns_func,
00588                                     gnc_tree_view_commodity_cm_filter_func cm_func,
00589                                     gpointer data,
00590                                     GtkDestroyNotify destroy)
00591 {
00592     GtkTreeModel *f_model, *s_model;
00593     filter_user_data *fd = data;
00594 
00595     g_return_if_fail(GNC_IS_TREE_VIEW_COMMODITY(view));
00596     g_return_if_fail((ns_func != NULL) || (cm_func != NULL));
00597 
00598     ENTER("view %p, ns func %p, cm func %p, data %p, destroy %p",
00599           view, ns_func, cm_func, data, destroy);
00600 
00601     fd = g_malloc(sizeof(filter_user_data));
00602     fd->user_ns_fn   = ns_func;
00603     fd->user_cm_fn   = cm_func;
00604     fd->user_data    = data;
00605     fd->user_destroy = destroy;
00606 
00607     s_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
00608     f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
00609     gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (f_model),
00610                                             gnc_tree_view_commodity_filter_helper,
00611                                             fd,
00612                                             gnc_tree_view_commodity_filter_destroy);
00613 
00614     /* Whack any existing levels. The top two levels have been created
00615      * before this routine can be called. */
00616     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (f_model));
00617     LEAVE(" ");
00618 }
00619 
00620 /*
00621  * Forces the entire commodity tree to be re-evaluated for visibility.
00622  */
00623 void
00624 gnc_tree_view_commodity_refilter (GncTreeViewCommodity *view)
00625 {
00626     GtkTreeModel *f_model, *s_model;
00627 
00628     g_return_if_fail(GNC_IS_TREE_VIEW_COMMODITY(view));
00629 
00630     ENTER("view %p", view);
00631     s_model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
00632     f_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (s_model));
00633     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (f_model));
00634     LEAVE(" ");
00635 }
00636 
00637 
00638 /************************************************************/
00639 /*           Commodity Tree View Get/Set Functions            */
00640 /************************************************************/
00641 
00642 /*
00643  * Retrieve the selected commodity from an commodity tree view.  The
00644  * commodity tree must be in single selection mode.
00645  */
00646 gnc_commodity *
00647 gnc_tree_view_commodity_get_selected_commodity (GncTreeViewCommodity *view)
00648 {
00649     GtkTreeSelection *selection;
00650     GtkTreeModel *model, *f_model, *s_model;
00651     GtkTreeIter iter, f_iter, s_iter;
00652     gnc_commodity *commodity;
00653 
00654     g_return_val_if_fail (GNC_IS_TREE_VIEW_COMMODITY (view), NULL);
00655 
00656     ENTER("view %p", view);
00657 
00658     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
00659     if (!gtk_tree_selection_get_selected (selection, &s_model, &s_iter))
00660     {
00661         LEAVE("no commodity, get_selected failed");
00662         return FALSE;
00663     }
00664 
00665     gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model),
00666             &f_iter, &s_iter);
00667 
00668     f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
00669     gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (f_model),
00670             &iter, &f_iter);
00671 
00672     model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
00673     commodity = gnc_tree_model_commodity_get_commodity (GNC_TREE_MODEL_COMMODITY(model),
00674                 &iter);
00675     LEAVE("commodity %p (%s)", commodity,
00676           commodity ? gnc_commodity_get_mnemonic(commodity) : "");
00677     return commodity;
00678 }
00679 
00680 
00681 /*
00682  * This helper function is called once for each row in the tree view
00683  * that is currently selected.  Its task is to an the corresponding
00684  * commodity to the end of a glist.
00685  */
00686 static void
00687 get_selected_commodities_helper (GtkTreeModel *s_model,
00688                                  GtkTreePath *s_path,
00689                                  GtkTreeIter *s_iter,
00690                                  gpointer data)
00691 {
00692     GList **return_list = data;
00693     GtkTreeModel *model, *f_model;
00694     GtkTreeIter iter, f_iter;
00695     gnc_commodity *commodity;
00696 
00697     gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model),
00698             &f_iter, s_iter);
00699 
00700     f_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(s_model));
00701     gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (f_model),
00702             &iter, &f_iter);
00703 
00704     model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(f_model));
00705     commodity = gnc_tree_model_commodity_get_commodity (GNC_TREE_MODEL_COMMODITY(model),
00706                 &iter);
00707     *return_list = g_list_append(*return_list, commodity);
00708 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines