GnuCash 2.4.99
gnc-tree-model-owner.c
00001 /*
00002  * gnc-tree-model-owner.c -- GtkTreeModel implementation to
00003  *      display owners in a GtkTreeView.
00004  *
00005  * Copyright (C) 2011 Geert Janssens <geert@kobaltwit.be>
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License as
00009  * published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, contact:
00019  *
00020  * Free Software Foundation           Voice:  +1-617-542-5942
00021  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00022  * Boston, MA  02110-1301,  USA       gnu@gnu.org
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-model-owner.h"
00032 #include "gnc-component-manager.h"
00033 #include "gncOwner.h"
00034 #include "gnc-commodity.h"
00035 #include "gnc-gconf-utils.h"
00036 #include "gnc-engine.h"
00037 #include "gnc-event.h"
00038 #include "gnc-gobject-utils.h"
00039 #include "gnc-ui-balances.h"
00040 #include "gnc-ui-util.h"
00041 
00042 #define TREE_MODEL_OWNER_CM_CLASS "tree-model-owner"
00043 
00045 static QofLogModule log_module = GNC_MOD_GUI;
00046 
00048 static void gnc_tree_model_owner_class_init (GncTreeModelOwnerClass *klass);
00049 static void gnc_tree_model_owner_init (GncTreeModelOwner *model);
00050 static void gnc_tree_model_owner_finalize (GObject *object);
00051 static void gnc_tree_model_owner_dispose (GObject *object);
00052 
00054 static void gnc_tree_model_owner_tree_model_init (GtkTreeModelIface *iface);
00055 static GtkTreeModelFlags gnc_tree_model_owner_get_flags (GtkTreeModel *tree_model);
00056 static int gnc_tree_model_owner_get_n_columns (GtkTreeModel *tree_model);
00057 static GType gnc_tree_model_owner_get_column_type (GtkTreeModel *tree_model,
00058         int index);
00059 static gboolean gnc_tree_model_owner_get_iter (GtkTreeModel *tree_model,
00060         GtkTreeIter *iter,
00061         GtkTreePath *path);
00062 static GtkTreePath *gnc_tree_model_owner_get_path (GtkTreeModel *tree_model,
00063         GtkTreeIter *iter);
00064 static void gnc_tree_model_owner_get_value (GtkTreeModel *tree_model,
00065         GtkTreeIter *iter,
00066         int column,
00067         GValue *value);
00068 static gboolean gnc_tree_model_owner_iter_next (GtkTreeModel *tree_model,
00069         GtkTreeIter *iter);
00070 static gboolean gnc_tree_model_owner_iter_children (GtkTreeModel *tree_model,
00071         GtkTreeIter *iter,
00072         GtkTreeIter *parent);
00073 static gboolean gnc_tree_model_owner_iter_has_child (GtkTreeModel *tree_model,
00074         GtkTreeIter *iter);
00075 static int gnc_tree_model_owner_iter_n_children (GtkTreeModel *tree_model,
00076         GtkTreeIter *iter);
00077 static gboolean gnc_tree_model_owner_iter_nth_child (GtkTreeModel *tree_model,
00078         GtkTreeIter *iter,
00079         GtkTreeIter *parent,
00080         int n);
00081 static gboolean gnc_tree_model_owner_iter_parent (GtkTreeModel *tree_model,
00082         GtkTreeIter *iter,
00083         GtkTreeIter *child);
00084 
00086 static void gnc_tree_model_owner_event_handler (QofInstance *entity,
00087         QofEventId event_type,
00088         GncTreeModelOwner *model,
00089         GncEventData *ed);
00090 
00092 typedef struct GncTreeModelOwnerPrivate
00093 {
00094     QofBook *book;
00095     GncOwnerType owner_type;
00096     OwnerList *owner_list;
00097     gint event_handler_id;
00098     const gchar *negative_color;
00099 } GncTreeModelOwnerPrivate;
00100 
00101 #define GNC_TREE_MODEL_OWNER_GET_PRIVATE(o)  \
00102    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_TREE_MODEL_OWNER, GncTreeModelOwnerPrivate))
00103 
00104 
00105 /************************************************************/
00106 /*           Owner Tree Model - Misc Functions            */
00107 /************************************************************/
00108 
00115 static void
00116 gnc_tree_model_owner_update_color (GConfEntry *entry, gpointer user_data)
00117 {
00118     GncTreeModelOwnerPrivate *priv;
00119     GncTreeModelOwner *model;
00120     GConfValue *value;
00121     gboolean use_red;
00122 
00123     g_return_if_fail(GNC_IS_TREE_MODEL_OWNER(user_data));
00124     model = user_data;
00125     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00126     value = gconf_entry_get_value(entry);
00127     use_red = gconf_value_get_bool(value);
00128     priv->negative_color = use_red ? "red" : "black";
00129 }
00130 /************************************************************/
00131 /*               g_object required functions                */
00132 /************************************************************/
00133 
00135 static GtkObjectClass *parent_class = NULL;
00136 
00137 GType
00138 gnc_tree_model_owner_get_type (void)
00139 {
00140     static GType gnc_tree_model_owner_type = 0;
00141 
00142     if (gnc_tree_model_owner_type == 0)
00143     {
00144         static const GTypeInfo our_info =
00145         {
00146             sizeof (GncTreeModelOwnerClass), /* class_size */
00147             NULL,                            /* base_init */
00148             NULL,                            /* base_finalize */
00149             (GClassInitFunc) gnc_tree_model_owner_class_init,
00150             NULL,                            /* class_finalize */
00151             NULL,                            /* class_data */
00152             sizeof (GncTreeModelOwner),      /* */
00153             0,                               /* n_preallocs */
00154             (GInstanceInitFunc) gnc_tree_model_owner_init
00155         };
00156 
00157         static const GInterfaceInfo tree_model_info =
00158         {
00159             (GInterfaceInitFunc) gnc_tree_model_owner_tree_model_init,
00160             NULL,
00161             NULL
00162         };
00163 
00164         gnc_tree_model_owner_type = g_type_register_static (GNC_TYPE_TREE_MODEL,
00165                                     GNC_TREE_MODEL_OWNER_NAME,
00166                                     &our_info, 0);
00167 
00168         g_type_add_interface_static (gnc_tree_model_owner_type,
00169                                      GTK_TYPE_TREE_MODEL,
00170                                      &tree_model_info);
00171     }
00172 
00173     return gnc_tree_model_owner_type;
00174 }
00175 
00176 static void
00177 gnc_tree_model_owner_class_init (GncTreeModelOwnerClass *klass)
00178 {
00179     GObjectClass *o_class;
00180 
00181     parent_class = g_type_class_peek_parent (klass);
00182 
00183     o_class = G_OBJECT_CLASS (klass);
00184 
00185     /* GObject signals */
00186     o_class->finalize = gnc_tree_model_owner_finalize;
00187     o_class->dispose = gnc_tree_model_owner_dispose;
00188 
00189     g_type_class_add_private(klass, sizeof(GncTreeModelOwnerPrivate));
00190 }
00191 
00192 static void
00193 gnc_tree_model_owner_init (GncTreeModelOwner *model)
00194 {
00195     GncTreeModelOwnerPrivate *priv;
00196     gboolean red;
00197 
00198     ENTER("model %p", model);
00199     while (model->stamp == 0)
00200     {
00201         model->stamp = g_random_int ();
00202     }
00203 
00204     red = gnc_gconf_get_bool(GCONF_GENERAL, KEY_NEGATIVE_IN_RED, NULL);
00205 
00206     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00207     priv->book       = NULL;
00208     priv->owner_list = NULL;
00209     priv->owner_type = GNC_OWNER_NONE;
00210     priv->negative_color = red ? "red" : "black";
00211 
00212     gnc_gconf_general_register_cb(KEY_NEGATIVE_IN_RED,
00213                                   gnc_tree_model_owner_update_color,
00214                                   model);
00215 
00216     LEAVE(" ");
00217 }
00218 
00219 static void
00220 gnc_tree_model_owner_finalize (GObject *object)
00221 {
00222     GncTreeModelOwnerPrivate *priv;
00223     GncTreeModelOwner *model;
00224 
00225     g_return_if_fail (object != NULL);
00226     g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (object));
00227 
00228     ENTER("model %p", object);
00229 
00230     model = GNC_TREE_MODEL_OWNER (object);
00231     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00232 
00233     gnc_gconf_general_remove_cb(KEY_NEGATIVE_IN_RED,
00234                                 gnc_tree_model_owner_update_color,
00235                                 model);
00236 
00237     priv->book       = NULL;
00238     priv->owner_list = NULL;
00239 
00240     if (G_OBJECT_CLASS (parent_class)->finalize)
00241         G_OBJECT_CLASS(parent_class)->finalize (object);
00242     LEAVE(" ");
00243 }
00244 
00245 static void
00246 gnc_tree_model_owner_dispose (GObject *object)
00247 {
00248     GncTreeModelOwnerPrivate *priv;
00249     GncTreeModelOwner *model;
00250 
00251     g_return_if_fail (object != NULL);
00252     g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (object));
00253 
00254     ENTER("model %p", object);
00255 
00256     model = GNC_TREE_MODEL_OWNER (object);
00257     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00258 
00259     if (priv->event_handler_id)
00260     {
00261         qof_event_unregister_handler (priv->event_handler_id);
00262         priv->event_handler_id = 0;
00263     }
00264 
00265     gnc_gconf_general_remove_cb(KEY_NEGATIVE_IN_RED,
00266                                 gnc_tree_model_owner_update_color,
00267                                 model);
00268 
00269     if (G_OBJECT_CLASS (parent_class)->dispose)
00270         G_OBJECT_CLASS (parent_class)->dispose (object);
00271     LEAVE(" ");
00272 }
00273 
00274 
00275 /************************************************************/
00276 /*                   New Model Creation                     */
00277 /************************************************************/
00278 
00279 GtkTreeModel *
00280 gnc_tree_model_owner_new (GncOwnerType owner_type)
00281 {
00282     GncTreeModelOwner *model;
00283     GncTreeModelOwnerPrivate *priv;
00284     const GList *item;
00285 
00286     ENTER("owner_type %d", owner_type);
00287     item = gnc_gobject_tracking_get_list(GNC_TREE_MODEL_OWNER_NAME);
00288     for ( ; item; item = g_list_next(item))
00289     {
00290         model = (GncTreeModelOwner *)item->data;
00291         priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00292         if (priv->owner_type == owner_type)
00293         {
00294             g_object_ref(G_OBJECT(model));
00295             LEAVE("returning existing model %p", model);
00296             return GTK_TREE_MODEL(model);
00297         }
00298     }
00299 
00300     model = g_object_new (GNC_TYPE_TREE_MODEL_OWNER,
00301                           NULL);
00302 
00303     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00304     priv->book = gnc_get_current_book();
00305     priv->owner_type = owner_type;
00306     priv->owner_list = gncBusinessGetOwnerList (priv->book, gncOwnerTypeToQofIdType(owner_type), TRUE);
00307 
00308     priv->event_handler_id = qof_event_register_handler
00309                              ((QofEventHandler)gnc_tree_model_owner_event_handler, model);
00310 
00311     LEAVE("model %p", model);
00312     return GTK_TREE_MODEL (model);
00313 }
00314 
00315 
00316 /************************************************************/
00317 /*        Gnc Tree Model Debugging Utility Function         */
00318 /************************************************************/
00319 
00320 #define ITER_STRING_LEN 128
00321 
00322 static const gchar *
00323 iter_to_string (GtkTreeIter *iter)
00324 {
00325 #ifdef G_THREADS_ENABLED
00326     static GStaticPrivate gtmits_buffer_key = G_STATIC_PRIVATE_INIT;
00327     gchar *string;
00328 
00329     string = g_static_private_get (&gtmits_buffer_key);
00330     if (string == NULL)
00331     {
00332         string = g_malloc(ITER_STRING_LEN + 1);
00333         g_static_private_set (&gtmits_buffer_key, string, g_free);
00334     }
00335 #else
00336     static char string[ITER_STRING_LEN + 1];
00337 #endif
00338 
00339     if (iter)
00340         snprintf(string, ITER_STRING_LEN,
00341                  "[stamp:%x data:%p (%s), %p, %d]",
00342                  iter->stamp, iter->user_data,
00343                  gncOwnerGetName ((GncOwner *) iter->user_data),
00344                  iter->user_data2, GPOINTER_TO_INT(iter->user_data3));
00345     else
00346         strcpy(string, "(null)");
00347     return string;
00348 }
00349 
00350 
00351 /************************************************************/
00352 /*       Gtk Tree Model Required Interface Functions        */
00353 /************************************************************/
00354 
00355 static void
00356 gnc_tree_model_owner_tree_model_init (GtkTreeModelIface *iface)
00357 {
00358     iface->get_flags       = gnc_tree_model_owner_get_flags;
00359     iface->get_n_columns   = gnc_tree_model_owner_get_n_columns;
00360     iface->get_column_type = gnc_tree_model_owner_get_column_type;
00361     iface->get_iter        = gnc_tree_model_owner_get_iter;
00362     iface->get_path        = gnc_tree_model_owner_get_path;
00363     iface->get_value       = gnc_tree_model_owner_get_value;
00364     iface->iter_next       = gnc_tree_model_owner_iter_next;
00365     iface->iter_children   = gnc_tree_model_owner_iter_children;
00366     iface->iter_has_child  = gnc_tree_model_owner_iter_has_child;
00367     iface->iter_n_children = gnc_tree_model_owner_iter_n_children;
00368     iface->iter_nth_child  = gnc_tree_model_owner_iter_nth_child;
00369     iface->iter_parent     = gnc_tree_model_owner_iter_parent;
00370 }
00371 
00372 static GtkTreeModelFlags
00373 gnc_tree_model_owner_get_flags (GtkTreeModel *tree_model)
00374 {
00375     return 0;
00376 }
00377 
00378 static int
00379 gnc_tree_model_owner_get_n_columns (GtkTreeModel *tree_model)
00380 {
00381     g_return_val_if_fail(GNC_IS_TREE_MODEL_OWNER(tree_model), -1);
00382 
00383     return GNC_TREE_MODEL_OWNER_NUM_COLUMNS;
00384 }
00385 
00386 static GType
00387 gnc_tree_model_owner_get_column_type (GtkTreeModel *tree_model,
00388                                       int index)
00389 {
00390     g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), G_TYPE_INVALID);
00391     g_return_val_if_fail ((index < GNC_TREE_MODEL_OWNER_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
00392 
00393     switch (index)
00394     {
00395     case GNC_TREE_MODEL_OWNER_COL_NAME:
00396     case GNC_TREE_MODEL_OWNER_COL_TYPE:
00397     case GNC_TREE_MODEL_OWNER_COL_CURRENCY:
00398     case GNC_TREE_MODEL_OWNER_COL_ID:
00399     case GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME:
00400     case GNC_TREE_MODEL_OWNER_COL_ADDRESS_1:
00401     case GNC_TREE_MODEL_OWNER_COL_ADDRESS_2:
00402     case GNC_TREE_MODEL_OWNER_COL_ADDRESS_3:
00403     case GNC_TREE_MODEL_OWNER_COL_ADDRESS_4:
00404     case GNC_TREE_MODEL_OWNER_COL_PHONE:
00405     case GNC_TREE_MODEL_OWNER_COL_FAX:
00406     case GNC_TREE_MODEL_OWNER_COL_EMAIL:
00407     case GNC_TREE_MODEL_OWNER_COL_BALANCE:
00408     case GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT:
00409     case GNC_TREE_MODEL_OWNER_COL_NOTES:
00410 
00411     case GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE:
00412         return G_TYPE_STRING;
00413 
00414     case GNC_TREE_MODEL_OWNER_COL_ACTIVE:
00415         return G_TYPE_BOOLEAN;
00416 
00417     default:
00418         g_assert_not_reached ();
00419         return G_TYPE_INVALID;
00420     }
00421 }
00422 
00423 static gboolean
00424 gnc_tree_model_owner_get_iter (GtkTreeModel *tree_model,
00425                                GtkTreeIter *iter,
00426                                GtkTreePath *path)
00427 {
00428     GncTreeModelOwnerPrivate *priv;
00429     GncTreeModelOwner *model;
00430     GncOwner *owner;
00431     gint *indices;
00432 
00433     g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
00434 
00435     {
00436         gchar *path_string = gtk_tree_path_to_string(path);
00437         ENTER("model %p, iter %p, path %s", tree_model, iter, path_string);
00438         g_free(path_string);
00439     }
00440 
00441     model = GNC_TREE_MODEL_OWNER (tree_model);
00442     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00443 
00444     /* We keep a simple list of owners, not a tree, so only depth 1 is valid */
00445     if (gtk_tree_path_get_depth (path) != 1)
00446     {
00447         LEAVE("bad depth");
00448         return FALSE;
00449     }
00450 
00451     indices = gtk_tree_path_get_indices (path);
00452 
00453     owner = g_list_nth_data (priv->owner_list, indices[0]);
00454     if (owner == NULL)
00455     {
00456         iter->stamp = 0;
00457         LEAVE("bad index");
00458         return FALSE;
00459     }
00460 
00461     iter->stamp = model->stamp;
00462     iter->user_data = owner;
00463     iter->user_data2 = GINT_TO_POINTER (indices[0]);
00464     iter->user_data3 = NULL;
00465 
00466     LEAVE("iter %s", iter_to_string (iter));
00467     return TRUE;
00468 }
00469 
00470 static GtkTreePath *
00471 gnc_tree_model_owner_get_path (GtkTreeModel *tree_model,
00472                                GtkTreeIter *iter)
00473 {
00474     GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
00475     GncTreeModelOwnerPrivate *priv;
00476     GncOwner *owner;
00477     GtkTreePath *path;
00478     gint i;
00479 
00480     g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
00481     g_return_val_if_fail (iter != NULL, NULL);
00482     g_return_val_if_fail (iter->user_data != NULL, NULL);
00483     g_return_val_if_fail (iter->stamp == model->stamp, NULL);
00484 
00485     ENTER("model %p, iter %s", model, iter_to_string(iter));
00486 
00487     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00488     if (priv->owner_list == NULL)
00489     {
00490         LEAVE("failed (1)");
00491         return NULL;
00492     }
00493 
00494     owner = (GncOwner *) iter->user_data;
00495 
00496     path = gtk_tree_path_new ();
00497     i = g_list_index (priv->owner_list, owner);
00498     if (i == -1)
00499     {
00500         gtk_tree_path_free (path);
00501         LEAVE("failed (3)");
00502         return NULL;
00503     }
00504     gtk_tree_path_prepend_index (path, i);
00505 
00506     {
00507         gchar *path_string = gtk_tree_path_to_string(path);
00508         LEAVE("path (4) %s", path_string);
00509         g_free(path_string);
00510     }
00511     return path;
00512 }
00513 
00514 static void
00515 gnc_tree_model_owner_set_color(GncTreeModelOwner *model,
00516                                gboolean negative,
00517                                GValue *value)
00518 {
00519     GncTreeModelOwnerPrivate *priv;
00520 
00521     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00522     if (negative)
00523         g_value_set_static_string (value, priv->negative_color);
00524     else
00525         g_value_set_static_string (value, "black");
00526 }
00527 
00528 static void
00529 gnc_tree_model_owner_get_value (GtkTreeModel *tree_model,
00530                                 GtkTreeIter *iter,
00531                                 int column,
00532                                 GValue *value)
00533 {
00534     GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
00535     GncTreeModelOwnerPrivate *priv;
00536     GncOwner *owner;
00537     gboolean negative; /* used to set "deficit style" also known as red numbers */
00538     gchar *string = NULL;
00539     time_t last_date;
00540 
00541     g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (model));
00542     g_return_if_fail (iter != NULL);
00543     g_return_if_fail (iter->user_data != NULL);
00544     g_return_if_fail (iter->stamp == model->stamp);
00545 
00546     ENTER("model %p, iter %s, col %d", tree_model,
00547           iter_to_string(iter), column);
00548 
00549     owner = (GncOwner *) iter->user_data;
00550     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00551 
00552     switch (column)
00553     {
00554     case GNC_TREE_MODEL_OWNER_COL_NAME:
00555         g_value_init (value, G_TYPE_STRING);
00556         g_value_set_string (value, gncOwnerGetName (owner));
00557         break;
00558     case GNC_TREE_MODEL_OWNER_COL_TYPE:
00559         g_value_init (value, G_TYPE_STRING);
00560         g_value_set_string (value,
00561                             gncOwnerTypeToQofIdType (gncOwnerGetType (owner)));
00562         break;
00563     case GNC_TREE_MODEL_OWNER_COL_ID:
00564         g_value_init (value, G_TYPE_STRING);
00565         g_value_set_string (value, gncOwnerGetID (owner));
00566         break;
00567     case GNC_TREE_MODEL_OWNER_COL_CURRENCY:
00568         g_value_init (value, G_TYPE_STRING);
00569         g_value_set_string (value,
00570                             gnc_commodity_get_fullname(gncOwnerGetCurrency (owner)));
00571         break;
00572     case GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME:
00573         g_value_init (value, G_TYPE_STRING);
00574         string = g_strdup (gncAddressGetName (gncOwnerGetAddr (owner)));
00575         if (string)
00576             g_value_take_string (value, string);
00577         else
00578             g_value_set_static_string (value, "");
00579         break;
00580     case GNC_TREE_MODEL_OWNER_COL_ADDRESS_1:
00581         g_value_init (value, G_TYPE_STRING);
00582         string = g_strdup (gncAddressGetAddr1 (gncOwnerGetAddr (owner)));
00583         if (string)
00584             g_value_take_string (value, string);
00585         else
00586             g_value_set_static_string (value, "");
00587         break;
00588     case GNC_TREE_MODEL_OWNER_COL_ADDRESS_2:
00589         g_value_init (value, G_TYPE_STRING);
00590         string = g_strdup (gncAddressGetAddr2 (gncOwnerGetAddr (owner)));
00591         if (string)
00592             g_value_take_string (value, string);
00593         else
00594             g_value_set_static_string (value, "");
00595         break;
00596     case GNC_TREE_MODEL_OWNER_COL_ADDRESS_3:
00597         g_value_init (value, G_TYPE_STRING);
00598         string = g_strdup (gncAddressGetAddr3 (gncOwnerGetAddr (owner)));
00599         if (string)
00600             g_value_take_string (value, string);
00601         else
00602             g_value_set_static_string (value, "");
00603         break;
00604     case GNC_TREE_MODEL_OWNER_COL_ADDRESS_4:
00605         g_value_init (value, G_TYPE_STRING);
00606         string = g_strdup (gncAddressGetAddr4 (gncOwnerGetAddr (owner)));
00607         if (string)
00608             g_value_take_string (value, string);
00609         else
00610             g_value_set_static_string (value, "");
00611         break;
00612     case GNC_TREE_MODEL_OWNER_COL_PHONE:
00613         g_value_init (value, G_TYPE_STRING);
00614         string = g_strdup (gncAddressGetPhone (gncOwnerGetAddr (owner)));
00615         if (string)
00616             g_value_take_string (value, string);
00617         else
00618             g_value_set_static_string (value, "");
00619         break;
00620     case GNC_TREE_MODEL_OWNER_COL_FAX:
00621         g_value_init (value, G_TYPE_STRING);
00622         string = g_strdup (gncAddressGetFax (gncOwnerGetAddr (owner)));
00623         if (string)
00624             g_value_take_string (value, string);
00625         else
00626             g_value_set_static_string (value, "");
00627         break;
00628     case GNC_TREE_MODEL_OWNER_COL_EMAIL:
00629         g_value_init (value, G_TYPE_STRING);
00630         string = g_strdup (gncAddressGetEmail (gncOwnerGetAddr (owner)));
00631         if (string)
00632             g_value_take_string (value, string);
00633         else
00634             g_value_set_static_string (value, "");
00635         break;
00636 
00637     case GNC_TREE_MODEL_OWNER_COL_BALANCE:
00638         g_value_init (value, G_TYPE_STRING);
00639         string = gnc_ui_owner_get_print_balance(owner, &negative);
00640         g_value_take_string (value, string);
00641         break;
00642 
00643     case GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT:
00644         g_value_init (value, G_TYPE_STRING);
00645         string = gnc_ui_owner_get_print_report_balance(owner, &negative);
00646         g_value_take_string (value, string);
00647         break;
00648     case GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE:
00649         g_value_init (value, G_TYPE_STRING);
00650         string = gnc_ui_owner_get_print_balance(owner, &negative);
00651         gnc_tree_model_owner_set_color(model, negative, value);
00652         g_free(string);
00653         break;
00654 
00655     case GNC_TREE_MODEL_OWNER_COL_NOTES:
00656         g_value_init (value, G_TYPE_STRING);
00657         switch (gncOwnerGetType (owner))
00658         {
00659         case GNC_OWNER_NONE:
00660         case GNC_OWNER_UNDEFINED:
00661         case GNC_OWNER_EMPLOYEE:
00662         case GNC_OWNER_JOB:
00663         default:
00664             g_value_set_static_string (value, "");
00665             break;
00666         case GNC_OWNER_VENDOR:
00667             g_value_set_string (value, gncVendorGetNotes (gncOwnerGetVendor (owner)));
00668             break;
00669         case GNC_OWNER_CUSTOMER:
00670             g_value_set_string (value, gncCustomerGetNotes (gncOwnerGetCustomer (owner)));
00671             break;
00672         }
00673         break;
00674 
00675     case GNC_TREE_MODEL_OWNER_COL_ACTIVE:
00676         g_value_init (value, G_TYPE_BOOLEAN);
00677         g_value_set_boolean (value, gncOwnerGetActive (owner));
00678         break;
00679 
00680     default:
00681         g_assert_not_reached ();
00682     }
00683     LEAVE(" ");
00684 }
00685 
00686 static gboolean
00687 gnc_tree_model_owner_iter_next (GtkTreeModel *tree_model,
00688                                 GtkTreeIter *iter)
00689 {
00690     GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model);
00691     GncTreeModelOwnerPrivate *priv;
00692     GncOwner *owner;
00693     gint i;
00694 
00695     g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), FALSE);
00696     g_return_val_if_fail (iter != NULL, FALSE);
00697     g_return_val_if_fail (iter->user_data != NULL, FALSE);
00698     g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
00699 
00700     ENTER("model %p, iter %s", tree_model, iter_to_string (iter));
00701 
00702     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00703 
00704     /* Get the *next* sibling owner. */
00705     i = GPOINTER_TO_INT (iter->user_data2);
00706     owner = g_list_nth_data (priv->owner_list, i + 1);
00707     if (owner == NULL)
00708     {
00709         iter->stamp = 0;
00710         LEAVE("failed (3)");
00711         return FALSE;
00712     }
00713 
00714     iter->user_data = owner;
00715     iter->user_data2 = GINT_TO_POINTER (i + 1);
00716     iter->user_data3 = NULL;
00717 
00718     LEAVE("iter %s", iter_to_string(iter));
00719     return TRUE;
00720 }
00721 
00722 static gboolean
00723 gnc_tree_model_owner_iter_children (GtkTreeModel *tree_model,
00724                                     GtkTreeIter *iter,
00725                                     GtkTreeIter *parent_iter)
00726 {
00727     GncTreeModelOwnerPrivate *priv;
00728     GncTreeModelOwner *model;
00729 
00730     g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
00731     ENTER("model %p, iter %p (to be filed in), parent %s",
00732           tree_model, iter, (parent_iter ? iter_to_string(parent_iter) : "(null)"));
00733 
00734     model = GNC_TREE_MODEL_OWNER (tree_model);
00735     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00736 
00737     /* Owner lists don't have children, so this function call only
00738      * makes sense if no parent_iter was supplied. In that case,
00739      * return the first owner in the list */
00740     if (!parent_iter)
00741     {
00742         iter->user_data = g_list_nth_data (priv->owner_list, 0);
00743         iter->user_data2 = GINT_TO_POINTER (0);
00744         iter->user_data3 = NULL;
00745         iter->stamp = model->stamp;
00746         LEAVE("iter (2) %s", iter_to_string(iter));
00747         return TRUE;
00748     }
00749     else
00750     {
00751         iter->stamp = 0;
00752         LEAVE("failed (owners don't have children)");
00753         return FALSE;
00754     }
00755 }
00756 
00757 static gboolean
00758 gnc_tree_model_owner_iter_has_child (GtkTreeModel *tree_model,
00759                                      GtkTreeIter *iter)
00760 {
00761     /* Owner lists don't have children, so always return false */
00762     return FALSE;
00763 }
00764 
00765 static int
00766 gnc_tree_model_owner_iter_n_children (GtkTreeModel *tree_model,
00767                                       GtkTreeIter *iter)
00768 {
00769     GncTreeModelOwner *model;
00770     GncTreeModelOwnerPrivate *priv;
00771 
00772     g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), -1);
00773 
00774     model = GNC_TREE_MODEL_OWNER (tree_model);
00775     priv  = GNC_TREE_MODEL_OWNER_GET_PRIVATE (model);
00776 
00777     /* Owner lists don't have children, so always return 0, except for
00778      * the special case this request comes for the special "root" iter
00779      * (NULL). For that exception we return the size of the ower list.
00780      */
00781     if (iter == NULL)
00782         return (gint) g_list_length (priv->owner_list);
00783 
00784     g_return_val_if_fail (
00785         GNC_TREE_MODEL_OWNER (tree_model)->stamp == iter->stamp, -1);
00786 
00787     return 0;
00788 }
00789 
00790 static gboolean
00791 gnc_tree_model_owner_iter_nth_child (GtkTreeModel *tree_model,
00792                                      GtkTreeIter *iter,
00793                                      GtkTreeIter *parent_iter,
00794                                      int n)
00795 {
00796     GncTreeModelOwner *model;
00797     GncTreeModelOwnerPrivate *priv;
00798 
00799     if (parent_iter)
00800     {
00801         gchar *parent_string;
00802         parent_string = g_strdup(iter_to_string(parent_iter));
00803         ENTER("model %p, iter %s, parent_iter %s, n %d",
00804               tree_model, iter_to_string(iter),
00805               parent_string, n);
00806         g_free(parent_string);
00807     }
00808     else
00809     {
00810         ENTER("model %p, iter %s, parent_iter (null), n %d",
00811               tree_model, iter_to_string(iter), n);
00812     }
00813     gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (tree_model), FALSE);
00814 
00815     model = GNC_TREE_MODEL_OWNER (tree_model);
00816     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00817 
00818     /* Owner lists don't have children, so this function call only
00819      * makes sense if no parent_iter was supplied. In that case,
00820      * return the first owner in the list */
00821     if (!parent_iter)
00822     {
00823         iter->user_data = g_list_nth_data (priv->owner_list, n);
00824         iter->user_data2 = GINT_TO_POINTER (n);
00825         iter->user_data3 = NULL;
00826         iter->stamp = model->stamp;
00827         LEAVE("iter (2) %s", iter_to_string(iter));
00828         return TRUE;
00829     }
00830     else
00831     {
00832         iter->stamp = 0;
00833         LEAVE("failed (owners don't have children)");
00834         return FALSE;
00835     }
00836 }
00837 
00838 static gboolean
00839 gnc_tree_model_owner_iter_parent (GtkTreeModel *tree_model,
00840                                   GtkTreeIter *iter,
00841                                   GtkTreeIter *child)
00842 {
00843     /* Owner lists don't have children, so always return false */
00844     iter->stamp = 0;
00845     return FALSE;
00846 }
00847 
00848 
00849 /************************************************************/
00850 /*            Owner Tree View Filter Functions            */
00851 /************************************************************/
00852 
00853 /*
00854  * Convert a model/iter pair to a gnucash owner.  This routine should
00855  * only be called from an owner tree view filter function.
00856  */
00857 GncOwner *
00858 gnc_tree_model_owner_get_owner (GncTreeModelOwner *model,
00859                                 GtkTreeIter *iter)
00860 {
00861     g_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
00862     g_return_val_if_fail (iter != NULL, NULL);
00863     g_return_val_if_fail (iter->user_data != NULL, NULL);
00864     g_return_val_if_fail (iter->stamp == model->stamp, NULL);
00865 
00866     return (GncOwner *) iter->user_data;
00867 }
00868 
00869 /*
00870  * Convert a model/owner pair into a gtk_tree_model_iter.  This
00871  * routine should only be called from the file
00872  * gnc-tree-view-owner.c.
00873  */
00874 gboolean
00875 gnc_tree_model_owner_get_iter_from_owner (GncTreeModelOwner *model,
00876         GncOwner *owner,
00877         GtkTreeIter *iter)
00878 {
00879     GncTreeModelOwnerPrivate *priv;
00880     GList *owner_in_list;
00881 
00882     ENTER("model %p, owner %p, iter %p", model, owner, iter);
00883     gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), FALSE);
00884     gnc_leave_return_val_if_fail ((owner != NULL), FALSE);
00885     gnc_leave_return_val_if_fail ((iter != NULL), FALSE);
00886 
00887 
00888     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
00889     owner_in_list = g_list_find_custom (priv->owner_list, (gconstpointer)owner, (GCompareFunc)gncOwnerGCompareFunc);
00890     if (owner_in_list)
00891     {
00892         iter->stamp = model->stamp;
00893         iter->user_data = owner_in_list->data;
00894         iter->user_data2 = GINT_TO_POINTER (g_list_position (priv->owner_list, owner_in_list));
00895         iter->user_data3 = NULL;
00896         LEAVE("iter %s", iter_to_string (iter));
00897         return TRUE;
00898     }
00899     else
00900     {
00901         iter->stamp = 0;
00902         iter->user_data = NULL;
00903         LEAVE("Owner not found in list");
00904         return FALSE;
00905     }
00906 }
00907 
00908 /*
00909  * Convert a model/owner pair into a gtk_tree_model_path.  This
00910  * routine should only be called from the file
00911  * gnc-tree-view-owner.c.
00912  */
00913 GtkTreePath *
00914 gnc_tree_model_owner_get_path_from_owner (GncTreeModelOwner *model,
00915         GncOwner *owner)
00916 {
00917     GtkTreeIter tree_iter;
00918     GtkTreePath *tree_path;
00919 
00920     ENTER("model %p, owner %p", model, owner);
00921     gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_OWNER (model), NULL);
00922     gnc_leave_return_val_if_fail (owner != NULL, NULL);
00923 
00924     if (!gnc_tree_model_owner_get_iter_from_owner (model, owner,
00925             &tree_iter))
00926     {
00927         LEAVE("no iter");
00928         return NULL;
00929     }
00930 
00931     tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &tree_iter);
00932     if (tree_path)
00933     {
00934         gchar *path_string = gtk_tree_path_to_string(tree_path);
00935         LEAVE("path (2) %s", path_string);
00936         g_free(path_string);
00937     }
00938     else
00939     {
00940         LEAVE("no path");
00941     }
00942     return tree_path;
00943 }
00944 
00945 /************************************************************/
00946 /*   Owner Tree Model - Engine Event Handling Functions   */
00947 /************************************************************/
00948 
00949 static void
00950 increment_stamp(GncTreeModelOwner *model)
00951 {
00952     do model->stamp++;
00953     while (!model->stamp);
00954 }
00955 
00984 static void
00985 gnc_tree_model_owner_event_handler (QofInstance *entity,
00986                                     QofEventId event_type,
00987                                     GncTreeModelOwner *model,
00988                                     GncEventData *ed)
00989 {
00990     GncTreeModelOwnerPrivate *priv;
00991     GtkTreePath *path = NULL;
00992     GtkTreeIter iter;
00993     GncOwner owner;
00994 
00995     g_return_if_fail(model);         /* Required */
00996 
00997     if (!GNC_IS_OWNER(entity))
00998         return;
00999 
01000     ENTER("entity %p of type %d, model %p, event_data %p",
01001           entity, event_type, model, ed);
01002     priv = GNC_TREE_MODEL_OWNER_GET_PRIVATE(model);
01003 
01004     qofOwnerSetEntity (&owner, entity);
01005     if (gncOwnerGetType(&owner) != priv->owner_type)
01006     {
01007         LEAVE("model type and owner type differ");
01008         return;
01009     }
01010 
01011     if (qof_instance_get_book (entity) != priv->book)
01012     {
01013         LEAVE("not in this book");
01014         return;
01015     }
01016 
01017     /* What to do, that to do. */
01018     switch (event_type)
01019     {
01020     case QOF_EVENT_ADD:
01021         /* Tell the filters/views where the new owner was added. */
01022         DEBUG("add owner %p (%s)", &owner, gncOwnerGetName(&owner));
01023         /* First update our copy of the owner list. This isn't done automatically */
01024         priv->owner_list = gncBusinessGetOwnerList (priv->book,
01025                            gncOwnerTypeToQofIdType(priv->owner_type), TRUE);
01026         increment_stamp(model);
01027         if (!gnc_tree_model_owner_get_iter_from_owner (model, &owner, &iter))
01028         {
01029             LEAVE("can't generate iter");
01030             break;
01031         }
01032         path = gnc_tree_model_owner_get_path(GTK_TREE_MODEL(model), &iter);
01033         if (!path)
01034         {
01035             DEBUG("can't generate path");
01036             break;
01037         }
01038         gtk_tree_model_row_inserted (GTK_TREE_MODEL(model), path, &iter);
01039         break;
01040 
01041     case QOF_EVENT_REMOVE:
01042         if (!ed) /* Required for a remove. */
01043             break;
01044         DEBUG("remove owner %d (%s) from owner_list %p", ed->idx,
01045               gncOwnerGetName(&owner), priv->owner_list);
01046         path = gtk_tree_path_new();
01047         if (!path)
01048         {
01049             DEBUG("can't generate path");
01050             break;
01051         }
01052         increment_stamp(model);
01053         gtk_tree_path_append_index (path, ed->idx);
01054         gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), path);
01055         break;
01056 
01057     case QOF_EVENT_MODIFY:
01058         DEBUG("modify  owner %p (%s)", &owner, gncOwnerGetName(&owner));
01059         if (!gnc_tree_model_owner_get_iter_from_owner (model, &owner, &iter))
01060         {
01061             LEAVE("can't generate iter");
01062             return;
01063         }
01064         path = gnc_tree_model_owner_get_path(GTK_TREE_MODEL(model), &iter);
01065         if (!path)
01066         {
01067             DEBUG("can't generate path");
01068             break;
01069         }
01070         gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter);
01071         break;
01072 
01073     default:
01074         LEAVE("unknown event type");
01075         return;
01076     }
01077 
01078     if (path)
01079         gtk_tree_path_free(path);
01080     LEAVE(" ");
01081     return;
01082 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines