gpe-expenses  0.1.9
expenses-gtk.c
00001 /***************************************************************************
00002  *            expenses-gtk.c
00003  *
00004  *  Mon Nov 21 22:56:18 2005
00005  *  Copyright  2005  Neil Williams <linux@codehelp.co.uk>
00006  *  Copyright (C) 2002, 2003, 2004 Philip Blundell <philb@gnu.org>
00007  *  Copyright (C) 2005, 2006 Florian Boor <florian@kernelconcepts.de>
00008  ****************************************************************************/
00009 /*
00010     This package is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 3 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019 
00020     You should have received a copy of the GNU General Public License
00021     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00022  */
00023  
00024 #include "config.h"
00025 #include <stdlib.h>
00026 #include <glib.h>
00027 #include <glib/gi18n.h>
00028 #include <glib/gprintf.h>
00029 #include <qof.h>
00030 #include <math.h>
00031 #include <locale.h>
00032  /* GTK and GPE includes */
00033 #include <gtk/gtkmain.h>
00034 #include <gpe/pixmaps.h>
00035 #include <gpe/init.h>
00036 #include <gpe/pim-categories.h>
00037 #include <gpe/pim-categories-ui.h>
00038 #include <gpe/spacing.h>
00039 #include "expenses-gtk.h"
00040 #include "qof-main.h"
00041 #include "gpe-expenses.h"
00042 #include "qof-expenses.h"
00043 
00044 #define _(String) gettext (String)
00045 
00047 #define SHOW_DECIMAL_PLACES 2
00048 
00049 static QofLogModule log_module = GPE_MOD_GUI;
00050 
00051 enum { 
00052         COL_EXP_DATE, 
00053         COL_EXP_TYPE, 
00054         COL_EXP_SYMBOL, 
00055         COL_EXP_AMOUNT,
00056         COL_ENTITY,
00057         COL_MAX
00058 };
00059 static void exp_refresh_list (GpeExpenseData *context);
00060 
00074 static inline void
00075 compare_cache (gchar * text_entry, QofEntity * ent, const QofParam * param)
00076 {
00077         gchar * check;
00078         check = qof_util_param_to_string (ent, param);
00079         g_return_if_fail (check);
00080         if (safe_strcmp(check, text_entry))
00081         {
00082                 qof_util_param_edit ((QofInstance*)ent, param);
00083                 qof_util_param_set_string (ent, param, text_entry);
00084                 qof_util_param_commit ((QofInstance*)ent, param);
00085         }
00086         if (text_entry)
00087                 g_free (text_entry);
00088         text_entry = NULL;
00089 }
00090 
00097 static void
00098 edit_ok_clicked(GtkWidget G_GNUC_UNUSED *widget, gpointer data)
00099 {
00100         GpeExpenseData *context;
00101         QofCurrency * currency;
00102         GtkTextBuffer *buf;
00103         GtkTextIter start, end;
00104         QofEntity *ent;
00105         gchar * mnemonic;
00106 
00107         context = (GpeExpenseData*)data;
00108         g_return_if_fail(context);
00109         ent = context->entity;
00110 
00111         buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (context->text_view));
00112         gtk_text_buffer_get_bounds (buf, &start, &end);
00113         /* exp_note */
00114         compare_cache (g_strdup(gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buf), 
00115                 &start, &end, FALSE)), ent, 
00116                 qof_class_get_parameter (GPE_QOF_EXPENSES, EXP_NOTE));
00117         /* exp_vendor */
00118         compare_cache ( g_strdup (gtk_entry_get_text
00119                 (GTK_ENTRY (context->vendor_entry))), ent, 
00120                 qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_VENDOR));
00121         /* exp_city */
00122         compare_cache (g_strdup (gtk_entry_get_text
00123                 (GTK_ENTRY (context->city_entry))), ent, 
00124         qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_CITY));
00125         /* exp_attendees */
00126         compare_cache (g_strdup (gtk_entry_get_text
00127                 (GTK_ENTRY (context->attendees_entry))), ent,
00128         qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_ATTENDEES));
00129         /* exp_type */
00130         compare_cache (g_strdup (ExpenseTypeasString
00131                 (gtk_combo_box_get_active(context->edit_type_list))), ent, 
00132                 qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_TYPE));
00133         /* exp_payment */
00134         compare_cache (g_strdup (ExpensePaymentasString
00135                 (gtk_combo_box_get_active(context->payment_list))), ent, 
00136                 qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_PAYMENT));
00137         /* exp_category */
00138         compare_cache (g_strdup (gtk_label_get_text (GTK_LABEL(context->cat_label))),
00139                 ent, qof_class_get_parameter (GPE_QOF_EXPENSES, EXP_CATEGORY));
00140         /* exp_currency */
00141         mnemonic = gtk_combo_box_get_active_text (context->currency_list);
00142         currency = qof_currency_lookup_name ((QofInstance*)ent, mnemonic);
00143         /* if currency is not found, preserve the cache version. */
00144         if (currency)
00145                 compare_cache (g_strdup_printf ("%d", currency->pq_code), ent, 
00146                         qof_class_get_parameter (GPE_QOF_EXPENSES, EXP_CURRENCY));
00147         gtk_widget_destroy(context->window);
00148         context->entity = NULL;
00149         exp_refresh_list(context);
00150 }
00151 
00152 static void
00153 edit_cancel_clicked(GtkWidget G_GNUC_UNUSED *widget, gpointer data)
00154 {
00155         GpeExpenseData *context;
00156 
00157         context = (GpeExpenseData*)data;
00158         g_return_if_fail(context);
00159         exp_refresh_list(context);
00160         gtk_widget_destroy(context->window);
00161         context->entity = NULL;
00162 }
00163 
00164 static void
00165 edit_delete_clicked(GtkWidget G_GNUC_UNUSED *widget, gpointer data)
00166 {
00167         GpeExpenseData *context;
00168 
00169         context = (GpeExpenseData*)data;
00170         g_return_if_fail(context);
00171         qof_event_gen (context->entity, QOF_EVENT_DESTROY, NULL);
00172         qof_entity_release(context->entity);
00173         exp_refresh_list(context);
00174         gtk_widget_destroy(context->window);
00175         context->entity = NULL;
00176 }
00177 
00178 static void
00179 create_currency_list(gpointer G_GNUC_UNUSED key, gpointer value, gpointer user_data)
00180 {
00181         QofCurrency *curr;
00182         GpeExpenseData *context;
00183 
00184         curr = (QofCurrency*)value;
00185         context = (GpeExpenseData*)user_data;
00186         gtk_combo_box_insert_text (context->currency_list, curr->pq_code, 
00187                 curr->mnemonic);
00188 }
00189 
00190 /* ported from gpe-contacts */
00191 static gchar *
00192 build_categories_string (GSList * catlist)
00193 {
00194         guint id;
00195         GSList * iter;
00196         const gchar *cat;
00197         gchar *s = NULL;
00198 
00199         if (!catlist) { return g_strdup(""); }
00200         for (iter = catlist; iter; iter = iter->next)
00201         {
00202                 id = GPOINTER_TO_INT(iter->data);
00203                 cat = gpe_pim_category_name (id);
00204 
00205                 if (cat)
00206                 {
00207                         if (s)
00208                         {
00209                                 /* append as a comma-separated list */
00210                                 gchar *ns = g_strdup_printf ("%s, %s", s, cat);
00211                                 g_free (s);
00212                                 s = ns;
00213                         }
00214                         else
00215                                 s = g_strdup (cat);
00216                 }
00217         }
00218         return s;
00219 }
00220 
00221 static void
00222 set_selected_category (GtkWidget G_GNUC_UNUSED *ui, GSList *selected, gpointer user_data)
00223 {
00224         GpeExpenseData * context;
00225         gchar * str;
00226 
00227         context = (GpeExpenseData*)user_data;
00228         g_return_if_fail (context);
00229 
00230         str = build_categories_string (selected);
00231         if (str)
00232         {
00233                 gtk_label_set_markup (GTK_LABEL (context->cat_label), str);
00234                 g_free (str);
00235         }
00236 }
00237 
00238 /* based on gpe-contacts */
00239 static void
00240 on_categories_clicked (GtkButton G_GNUC_UNUSED *button, gpointer user_data)
00241 {
00242         GtkWidget * G_GNUC_UNUSED w;
00243 
00244         w = gpe_pim_categories_dialog (gpe_pim_categories_list (), 
00245                         G_CALLBACK (set_selected_category), user_data);
00246 }
00247 
00248 static gint
00249 cat_compare (gconstpointer gpe_cat, gconstpointer qof_name)
00250 {
00251         struct gpe_pim_category * c;
00252 
00253         c = (struct gpe_pim_category *) gpe_cat;
00254         return safe_strcasecmp (gpe_pim_category_name (c->id), qof_name);
00255 }
00256 
00257 /* merge the QOF category list into the GPE PIM category list */
00258 static void
00259 cat_populate (const gchar * cat_name)
00260 {
00261         GSList * cat_list, *match;
00262         gint max_list;
00263 
00264         match = NULL;
00265         cat_list = gpe_pim_categories_list();
00266         if (cat_list)
00267         {
00268                 /* if the category name exists, leave it alone */
00269                 match = g_slist_find_custom (cat_list, cat_name, cat_compare);
00270         }
00271         if (!match)
00272         {
00273                 DEBUG ("'%s' not found in GPE category list, adding.", cat_name);
00274                 gpe_pim_category_new (cat_name, &max_list);
00275         }
00276 }
00277 
00278 static void 
00279 edit_expense (GtkWidget G_GNUC_UNUSED *w, GpeExpenseData *context)
00280 {
00281         GtkWidget *table, *top_vbox;
00282         GtkWidget *viewport, *scrolled_window;
00283         GtkWidget *buttonbox, *buttonok, *buttoncancel, *buttondelete;
00284         GtkWidget *type_label, *payment_label, *currency_label;
00285         GtkWidget *city_label, *vendor_label, *note_label, *attendees_label;
00286         GtkTextBuffer *buf;
00287         guint gpe_spacing, pos, i;
00288         const QofParam *param;
00289         gboolean mileage;
00290         gchar *text;
00291 
00292         g_return_if_fail(context);
00293         if(!context->entity) { return; }
00294         ENTER (" ");
00295         gpe_spacing = 0;
00296         pos = 0;
00297         mileage = FALSE;
00298         buttonok = gtk_button_new_from_stock (GTK_STOCK_SAVE);
00299         buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
00300         buttondelete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
00301 
00302         table = gtk_table_new(10, 6, FALSE);
00303         top_vbox = gtk_vbox_new (FALSE, 0);
00304         context->text_view = gtk_text_view_new ();
00305         buttonbox = gtk_hbox_new (FALSE, 0);
00306         type_label = gtk_label_new (_("Type:"));
00307         payment_label = gtk_label_new (_("Payment:"));
00308         currency_label = gtk_label_new (_("Currency:"));
00309         vendor_label = gtk_label_new(_("Vendor:"));
00310         city_label = gtk_label_new(_("City:"));
00311         note_label = gtk_label_new(_("Note:"));
00312         attendees_label = gtk_label_new(_("Attendees"));
00313         context->categories = gtk_button_new_with_label (_("Category"));
00314         context->cat_label = gtk_label_new ("");
00315         context->edit_type_list = GTK_COMBO_BOX(gtk_combo_box_new_text());
00316         context->currency_list = GTK_COMBO_BOX(gtk_combo_box_new_text());
00317         context->payment_list = GTK_COMBO_BOX(gtk_combo_box_new_text());
00318         context->vendor_entry = GTK_ENTRY (gtk_entry_new());
00319         context->city_entry = GTK_ENTRY (gtk_entry_new());
00320         context->attendees_entry = GTK_ENTRY (gtk_entry_new());
00321         scrolled_window = gtk_scrolled_window_new (NULL, NULL);
00322         viewport = gtk_viewport_new(NULL, NULL);
00323 
00324         context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
00325 
00326         gtk_table_set_col_spacings (GTK_TABLE(table), gpe_spacing);
00327         gtk_table_set_row_spacings (GTK_TABLE(table), gpe_spacing);
00328         gtk_box_set_spacing (GTK_BOX(top_vbox), gpe_spacing);
00329 
00330         gtk_window_set_default_size (GTK_WINDOW (context->window), 240, 320);
00331         gtk_window_set_title (GTK_WINDOW (context->window), _("Expenses"));
00332 
00333         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
00334                                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
00335         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
00336         gtk_container_add (GTK_CONTAINER (viewport), table);
00337         gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
00338 
00339         gtk_container_set_border_width(GTK_CONTAINER(buttonbox), 0);
00340 
00341         gtk_table_set_col_spacings (GTK_TABLE(table), gpe_spacing);
00342         gtk_table_set_row_spacings (GTK_TABLE(table), gpe_spacing);
00343         gtk_box_set_spacing (GTK_BOX(top_vbox), gpe_spacing);
00344     
00345         gtk_signal_connect (GTK_OBJECT (buttonok), "clicked",
00346                           GTK_SIGNAL_FUNC (edit_ok_clicked), context);
00347         gtk_signal_connect (GTK_OBJECT (buttoncancel), "clicked",
00348                           GTK_SIGNAL_FUNC (edit_cancel_clicked), context);
00349         gtk_signal_connect (GTK_OBJECT (buttondelete), "clicked",
00350                           GTK_SIGNAL_FUNC (edit_delete_clicked), context);
00351 
00352         gtk_box_pack_start (GTK_BOX (buttonbox), buttondelete, TRUE, FALSE, 0);
00353         gtk_box_pack_start (GTK_BOX (buttonbox), buttoncancel, TRUE, FALSE, 0);
00354         gtk_box_pack_start (GTK_BOX (buttonbox), buttonok, TRUE, FALSE, 0);
00355 
00356         gtk_misc_set_alignment (GTK_MISC (context->cat_label), 0.0, 0.5);
00357         gtk_misc_set_alignment (GTK_MISC (type_label), 0.0, 0.5);
00358         gtk_misc_set_alignment (GTK_MISC (payment_label), 0.0, 0.5);
00359         gtk_misc_set_alignment (GTK_MISC (currency_label), 0.0, 0.5);
00360         gtk_misc_set_alignment (GTK_MISC (vendor_label), 0.0, 0.5);
00361         gtk_misc_set_alignment (GTK_MISC (city_label), 0.0, 0.5);
00362         gtk_misc_set_alignment (GTK_MISC (attendees_label), 0.0, 0.5);
00363   
00364         i = 0;
00365         param = qof_class_get_parameter(context->entity->e_type, EXP_TYPE);
00366         i = ExpenseTypefromString(param->param_getfcn(context->entity, param));
00367         gtk_combo_box_set_active(context->edit_type_list, i);
00368         /* Currency and PaymentType disabled for mileage */
00369         if(i == Mileage) { mileage = TRUE; }
00370 
00371         /* Category */
00372         pos++;
00373         gtk_table_attach (GTK_TABLE(table), context->categories, 0, 1, pos, pos+1, 
00374                                           GTK_FILL, GTK_FILL, 0, 0);
00375         /* the label comes after the button as the label *is* the data. */
00376         gtk_table_attach (GTK_TABLE(table), context->cat_label, 2, 3, pos, pos+1, 
00377                                           GTK_FILL, GTK_FILL, 0, 0);
00378         pos++;
00379         /* Type of expense */
00380         i = 0;
00381         gtk_table_attach(GTK_TABLE(table), type_label, 0, 1, pos, pos+1, 
00382                                    GTK_FILL, GTK_FILL, 0, 0);
00383         while(0 != safe_strcmp(ExpenseTypeasString(i), ""))
00384         {
00385                 gchar *check;
00386 
00387                 gtk_combo_box_append_text (context->edit_type_list, 
00388                         dgettext(LIBRARY_GETTEXT_PACKAGE, ExpenseTypeasString(i)));
00389                 check = qof_util_param_to_string(context->entity, param);
00390                 if(0 == safe_strcmp(check, ExpenseTypeasString(i)))
00391                 {
00392                         gtk_combo_box_set_active(context->edit_type_list, i);
00393                 }
00394                 g_free(check);
00395                 i++;
00396         }
00397         gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(context->edit_type_list), 1, 
00398                                 3, pos, pos+1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
00399 
00400         pos++;
00401         /* Payment method */
00402         i = 0;
00403         gtk_table_attach(GTK_TABLE(table), payment_label, 0, 1, pos, pos+1, 
00404                                 GTK_FILL, GTK_FILL, 0, 0);
00405         
00406         while((0 != safe_strcmp(ExpensePaymentasString(i), "")) &&
00407                 (!mileage))
00408         {
00409                 gtk_combo_box_append_text(context->payment_list, 
00410                         dgettext(LIBRARY_GETTEXT_PACKAGE, ExpensePaymentasString(i)));
00411                 i++;
00412         }
00413         gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(context->payment_list), 1, 
00414                                 3, pos, pos+1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
00415         pos++;
00416         /* Currency (to be replaced when using mileage) */
00417         if(!mileage)
00418         {
00419                 gtk_table_attach(GTK_TABLE(table), currency_label, 0, 1, pos, pos+1, 
00420                                         GTK_FILL, GTK_FILL, 0, 0);
00421                 qof_currency_foreach(create_currency_list, context);
00422                 gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(context->currency_list), 1, 
00423                                         3, pos, pos+1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
00424                 pos++;
00425         }
00426         /* Vendor */
00427         gtk_table_attach(GTK_TABLE(table), vendor_label, 0, 1, pos, pos+1, 
00428                                 GTK_FILL, GTK_FILL, 0, 0);
00429         gtk_table_attach(GTK_TABLE(table), GTK_WIDGET (context->vendor_entry), 
00430                 1, 5, pos, pos+1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
00431         pos++;
00432         /* City */
00433         gtk_table_attach(GTK_TABLE(table), city_label, 0, 1, pos, pos+1, 
00434                                 GTK_FILL, GTK_FILL, 0, 0);
00435         gtk_table_attach(GTK_TABLE(table), GTK_WIDGET (context->city_entry), 
00436                 1, 5, pos, pos+1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
00437         pos++;
00438         /* Attendees */
00439         gtk_table_attach(GTK_TABLE(table), attendees_label, 0, 1, pos, pos+1, 
00440                                 GTK_FILL, GTK_FILL, 0, 0);
00441         gtk_table_attach(GTK_TABLE(table), GTK_WIDGET (context->attendees_entry), 
00442                 1, 5, pos, pos+1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
00443         pos++;
00444         /* Note */
00445         gtk_table_attach(GTK_TABLE(table), note_label, 0, 1, pos, pos+1, 
00446                                 GTK_FILL, GTK_FILL, 0, 0);
00447         gtk_table_attach(GTK_TABLE(table), context->text_view, 1, 5, pos, pos+1,
00448                                 GTK_FILL, GTK_FILL | GTK_EXPAND, 0, 0);
00449         pos++;
00450 
00451         gtk_text_view_set_editable (GTK_TEXT_VIEW (context->text_view), TRUE);
00452         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (context->text_view), GTK_WRAP_WORD_CHAR);
00453 
00454         gtk_box_pack_start (GTK_BOX (top_vbox), scrolled_window, TRUE, TRUE, 0);
00455         gtk_box_pack_start (GTK_BOX (top_vbox), buttonbox, FALSE, FALSE, 0);
00456 
00457         gtk_container_add (GTK_CONTAINER (context->window), top_vbox);
00458 
00459         /* use entity values to preset the edit window  */
00460         i = 0;
00461         param = qof_class_get_parameter(context->entity->e_type, EXP_CATEGORY);
00462         text = param->param_getfcn(context->entity, param);
00463         if(text) {
00464                 /* check the QOF categories against the GPE categories
00465                  and add the OQF ones if they do not exist in GPE */
00466                 cat_populate (text);
00467                 PINFO ("setting cat_label=%s", text);
00468                 gtk_label_set_markup (GTK_LABEL(context->cat_label), text);
00469         }
00470 
00471         param = qof_class_get_parameter(context->entity->e_type, EXP_PAYMENT);
00472         i = ExpensePaymentfromString(param->param_getfcn(context->entity, param));
00473         gtk_combo_box_set_active(context->payment_list, i);
00474 
00475         param = qof_class_get_parameter(context->entity->e_type, EXP_VENDOR);
00476         text = param->param_getfcn(context->entity, param);
00477         if(text) { gtk_entry_set_text(context->vendor_entry, text); }
00478 
00479         param = qof_class_get_parameter(context->entity->e_type, EXP_CITY);
00480         text = param->param_getfcn(context->entity, param);
00481         if(text) { gtk_entry_set_text(context->city_entry, text); }
00482 
00483         param = qof_class_get_parameter(context->entity->e_type, EXP_CURRENCY);
00484         {
00485                 QofCurrency * currency;
00486                 gint32 check, (*int32_getter)   (QofEntity*, const QofParam*);
00487                 int32_getter = (gint32 (*)(QofEntity*, const QofParam*)) param->param_getfcn;
00488                 check = int32_getter(context->entity, param);
00489                 currency = qof_currency_lookup ((QofInstance*)context->entity, check);
00490                 if (currency)
00491                         PINFO (" currency=%d mnemonic=%s", check, currency->mnemonic);
00492                 gtk_combo_box_set_active(context->currency_list, check);
00493         }
00494 
00495         param = qof_class_get_parameter(context->entity->e_type, EXP_ATTENDEES);
00496         text = param->param_getfcn(context->entity, param);
00497         if(text) { gtk_entry_set_text(context->attendees_entry, text); }
00498 
00499         param = qof_class_get_parameter(context->entity->e_type, EXP_NOTE);
00500         buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (context->text_view));
00501         text = param->param_getfcn(context->entity, param);
00502         if(text) 
00503         { 
00504                 gtk_text_buffer_set_text(buf, text, strlen(text));
00505                 gtk_text_view_set_buffer(GTK_TEXT_VIEW (context->text_view), buf);
00506         }
00507 
00508         g_signal_connect (G_OBJECT (context->categories), "clicked",
00509                                           G_CALLBACK (on_categories_clicked), context);
00510         gpe_set_window_icon (context->window, "icon");
00511         gtk_widget_show_all(context->window);
00512         LEAVE (" ");
00513 }
00514 
00515 static void 
00516 open_about_dialog (void)
00517 {
00518         GtkAboutDialog* ab;
00519         /* If you modify gpe-expenses, add your details here. */
00520         const gchar * authors[4] = {"Neil Williams <linux@codehelp.co.uk>\n"
00521                 "Philip Blundell <philb@gnu.org>\n"
00522                 "Florian Boor <florian@kernelconcepts.de>\n"
00523                 , NULL };
00524 
00525         ab = GTK_ABOUT_DIALOG( gtk_about_dialog_new() );
00526         gtk_about_dialog_set_copyright(ab, 
00527                 "Copyright 2005-2007 Neil Williams <linux@codehelp.co.uk>");
00528         gtk_about_dialog_set_version(ab, VERSION);
00529         gtk_about_dialog_set_comments(ab,
00530                 /* Translators: line breaks allowed here. */
00531                 _("Expenses records for GPE. Supports payment types, "
00532                 "categories, expense types (mileage, meals, parking, etc.), "
00533                 "notes and currency selection."));
00534         gtk_about_dialog_set_license (ab,
00535                 " This package is free software; you can redistribute it and/or modify\n"
00536                 " it under the terms of the GNU General Public License as published by\n"
00537                 " the Free Software Foundation; either version 3 of the License, or\n"
00538                 " (at your option) any later version.\n"
00539                 "\n"
00540                 " This program is distributed in the hope that it will be useful,\n"
00541                 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00542                 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
00543                 " GNU General Public License for more details.\n"
00544                 "\n"
00545                 " You should have received a copy of the GNU General Public License\n"
00546                 " along with this program.  If not, see <http://www.gnu.org/licenses/>.\n");
00547         gtk_about_dialog_set_website (ab, "http://gpe-expenses.sourceforge.net/");
00548         gtk_about_dialog_set_authors (ab, authors);
00549         gtk_about_dialog_set_translator_credits (ab, _("translator-credits"));
00550         gtk_about_dialog_set_logo (ab, gpe_try_find_icon("icon", NULL));
00551         gpe_set_window_icon(GTK_WIDGET(ab), "icon");
00552         gtk_dialog_run(GTK_DIALOG(ab));
00553         gtk_widget_destroy (GTK_WIDGET(ab));
00554 }
00555 
00556 /*      Receives the selected expense, then list each
00557         column parameter. Use data selection for column1,
00558         string selection from list for column2, digit entry for column4.
00559         Column3 is set via selection of column2.
00560 */
00561 static void
00562 exp_show_entities(QofEntity *ent, gpointer data)
00563 {
00564         GpeExpenseData *context;
00565         QofTime     *qt;
00566         QofDate     *qd;
00567         QofNumeric amount, (*numeric_getter) (QofEntity*, const QofParam*);
00568         GtkTreeIter      ent_data;
00569         const QofParam   *param;
00570         gchar            *type, *symbol, *date_string, *dis_string;
00571         gdouble           d_amount;
00572 
00573         context = (GpeExpenseData*)data;
00574         g_return_if_fail(context);
00575         symbol = "";
00576         /* param_getfcn each parameter */
00577         param = qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_DATE);
00578         qt = (QofTime*)param->param_getfcn (ent, param);
00579         qd = qof_date_from_qtime (qt);
00580         date_string = qof_date_print (qd, QOF_DATE_FORMAT_CE);
00581         qof_date_free (qd);
00582         param = qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_TYPE);
00583         dis_string = param->param_getfcn(ent, param);
00584         type = dgettext(LIBRARY_GETTEXT_PACKAGE, dis_string);
00585         /* If Mileage, use ExpenseDistance,
00586         else use ExpenseCustomCurrency->symbol */
00587         if(0 == safe_strcmp(dis_string, "Mileage"))
00588         {
00589                 gint unit;
00590                 /* EXP_DISTANCE */
00591                 param = qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_DISTANCE);
00592                 unit = ExpenseDistancefromString(param->param_getfcn(ent, param));
00593                 switch (unit)
00594                 {
00595                         /* Translators: short form of 'miles' */
00596                         case 0 : { symbol = _("mi"); break; }
00597                         /* Translators: short form of 'kilometres' */
00598                         case 1 : { symbol = _("km"); break; }
00599                 }
00600         }
00601         else
00602         {
00603                 QofCurrency * pqc;
00604                 gint32 curr_code, (*int32_getter) (QofEntity *, const QofParam *);
00605                 param = qof_class_get_parameter (GPE_QOF_EXPENSES, EXP_CURRENCY);
00606                 int32_getter = (gint32 (*)(QofEntity *, const QofParam *))
00607                         param->param_getfcn;
00608                 curr_code = int32_getter (ent, param);
00609                 pqc = qof_currency_lookup ((QofInstance*)ent, curr_code);
00610                 if (pqc)
00611                         symbol = g_strdup(pqc->symbol);
00612         }
00613         param = qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_AMOUNT);
00614         numeric_getter = (QofNumeric (*)(QofEntity*, const QofParam*)) param->param_getfcn;
00615         amount = numeric_getter(ent, param);
00616         d_amount = qof_numeric_to_double(amount);
00617         /* Columns:  Date Type symbol Amount */
00618         gtk_list_store_append(context->list_store, &ent_data);
00619         gtk_list_store_set(context->list_store, &ent_data,
00620                 COL_EXP_DATE,   date_string,
00621                 COL_EXP_TYPE,   type,
00622                 COL_EXP_SYMBOL, symbol,
00623                 COL_EXP_AMOUNT, d_amount,
00624                 COL_ENTITY,     ent,
00625                 -1 );
00626         g_free(date_string);
00627 }
00628 
00629 /* button == 1 left mouse button, 3 = right click. */
00630 static gboolean
00631 button_press_event (GtkWidget *widget, GdkEventButton *b, gpointer data)
00632 {
00633         GtkTreeViewColumn *col;
00634         GtkTreePath *path;
00635         GtkTreeIter iter;
00636         QofEntity  *ent;
00637         gdouble amount;
00638         GpeExpenseData *context;
00639 
00640         context = (GpeExpenseData*)data;
00641         g_return_val_if_fail(context, FALSE);
00642         amount = 0.00;
00643         ent = NULL;
00644         switch (b->button) {
00645                 case 1 : {
00646                         if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
00647                                                 b->x, b->y, &path, &col, NULL, NULL))
00648                         {
00649                                 GtkTreeView * treeview;
00650 
00651                                 treeview = GTK_TREE_VIEW 
00652                                         (gtk_tree_view_new_with_model 
00653                                         (GTK_TREE_MODEL(context->list_store)));
00654                                 gtk_tree_view_set_cursor (treeview, path, NULL, TRUE);
00655                                 gtk_widget_grab_focus (GTK_WIDGET (treeview));
00656                                 gtk_tree_model_get_iter (GTK_TREE_MODEL (context->list_store), 
00657                                                 &iter, path);
00658                                 gtk_tree_model_get(GTK_TREE_MODEL (context->list_store),
00659                                                 &iter, COL_ENTITY, &ent, -1);
00660                                 gtk_tree_model_get(GTK_TREE_MODEL (context->list_store),
00661                                                 &iter, COL_EXP_AMOUNT, &amount, -1);
00662                                 context->entity = ent;
00663                                 gtk_tree_path_free (path);
00664                         }
00665                         break; 
00666                 }
00667                 default : { break; }
00668         }
00669         return FALSE;
00670 }
00671 
00681 static void 
00682 change_date (GtkCellRendererText G_GNUC_UNUSED *cell, 
00683                         gchar G_GNUC_UNUSED *path_string, gchar *new_text, gpointer data)
00684 {
00685         void (*time_setter) (QofEntity*, QofTime*);
00686         GpeExpenseData *context;
00687         const QofParam *param;
00688         QofTime *qt;
00689         QofDate *qd;
00690 
00691         context = (GpeExpenseData*)data;
00692         g_return_if_fail(context);
00693         ENTER (" new_text=%s", new_text);
00694         param = qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_DATE);
00695         time_setter = (void(*)(QofEntity*, QofTime*))param->param_setfcn;
00696         /* convert the string to a QofTime */
00697         qd = qof_date_parse (new_text, QOF_DATE_FORMAT_CE);
00698         qt = qof_date_to_qtime (qd);
00699         qof_util_param_edit ((QofInstance*)context->entity, param);
00700         if ((time_setter && qof_time_is_valid (qt)))
00701                 time_setter (context->entity, qt);
00702         qof_util_param_commit ((QofInstance*)context->entity, param);
00703         exp_refresh_list(context);
00704         LEAVE (" ");
00705 }
00706 
00707 static void 
00708 change_amount (GtkCellRendererText G_GNUC_UNUSED *cell, 
00709                            gchar G_GNUC_UNUSED *path_string, gchar *new_text, gpointer data)
00710 {
00711         GpeExpenseData *context;
00712         QofNumeric amount;
00713         void (*numeric_setter)   (QofEntity*, QofNumeric);
00714         void (*i32_setter)       (QofEntity*, gint32);
00715         const QofParam *param;
00716         gchar *numeric_char;
00717         gdouble d_amount;
00718         gint precision;
00719         /* detect local currency */
00720         QofCurrency * c;
00721         struct lconv lc;
00722         gchar * sy;
00723         guint def_pq_code;
00724 
00725         context = (GpeExpenseData*)data;
00726         g_return_if_fail(context);
00727         ENTER (" ");
00728         def_pq_code = -1;
00729         param = qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_CURRENCY);
00730         i32_setter = (void(*)(QofEntity*, gint32))param->param_setfcn;
00731         /* use locale currency */
00732         lc = *localeconv();
00733         DEBUG (" sym=%s", lc.currency_symbol);
00734         sy = g_strdup (lc.int_curr_symbol);
00735         sy = g_strstrip (sy);
00736         c = qof_currency_lookup_name ((QofInstance*)context->entity, sy);
00737         if (c)
00738                 def_pq_code = c->pq_code;
00739         g_free (sy);
00740         if(i32_setter != NULL) { i32_setter(context->entity, def_pq_code); }
00741         param = qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_AMOUNT);
00742         numeric_setter = (void(*)(QofEntity*, QofNumeric))param->param_setfcn;
00743         d_amount = 0.00;
00744         precision = pow(10, SHOW_DECIMAL_PLACES);
00745         amount = qof_numeric_zero();
00746         d_amount = strtod(new_text, NULL);
00747         amount = qof_numeric_from_double (d_amount, precision, 
00748                 QOF_HOW_DENOM_EXACT | QOF_HOW_RND_ROUND);
00749         numeric_char = qof_numeric_to_string(amount);
00750         DEBUG (" numeric_char=%s", numeric_char);
00751         g_free(numeric_char);
00752 
00753         if ((qof_numeric_check (amount) == QOF_ERROR_OK) && (numeric_setter))
00754         {
00755                 qof_util_param_edit ((QofInstance*)context->entity, param);
00756                 numeric_setter(context->entity, amount);
00757                 qof_util_param_commit ((QofInstance*)context->entity, param);
00758         }
00759         else 
00760         {
00761                 qof_util_param_edit ((QofInstance*)context->entity, param);
00762                 numeric_setter(context->entity, qof_numeric_zero ());
00763                 qof_util_param_commit ((QofInstance*)context->entity, param);
00764         }
00765         exp_refresh_list(context);
00766         LEAVE (" ");
00767 }
00768 
00769 static void
00770 rounding_func (GtkTreeViewColumn G_GNUC_UNUSED *tree_column,
00771         GtkCellRenderer *cell, GtkTreeModel *tree_model,
00772         GtkTreeIter *iter, gpointer data)
00773 {
00774         GtkCellRendererText *cell_text;
00775         gdouble d;
00776         gchar *s;
00777 
00778         cell_text = (GtkCellRendererText *)cell;
00779         d = 0.00;
00780         s = NULL;
00781         g_free(cell_text->text);
00782         gtk_tree_model_get(tree_model, iter, GPOINTER_TO_INT(data), &d, -1);
00783         s = g_strdup_printf("%%.%i", SHOW_DECIMAL_PLACES);
00784         s = g_strconcat(s, "f", NULL);
00785         cell_text->text = g_strdup_printf(s, d);
00786         g_free(s);
00787 }
00788 
00789 static gint
00790 type_compare (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
00791                 gpointer G_GNUC_UNUSED user_data)
00792 {
00793         gint result;
00794         gchar *str_a, *str_b;
00795 
00796         result = 0;
00797         gtk_tree_model_get(model, a, COL_EXP_TYPE, &str_a, -1);
00798         gtk_tree_model_get(model, b, COL_EXP_TYPE, &str_b, -1);
00799         result = safe_strcmp(str_a, str_b);
00800         g_free(str_a);
00801         g_free(str_b);
00802         return result;
00803 }
00804 
00811 static gint
00812 date_compare (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
00813                 gpointer G_GNUC_UNUSED user_data)
00814 {
00815         QofTime *qt_a, *qt_b;
00816         QofEntity * ent_a, * ent_b;
00817         const QofParam * param;
00818         gint result;
00819 
00820         ent_a = ent_b = NULL;
00821         result = 0;
00822         gtk_tree_model_get(model, a, COL_ENTITY, &ent_a, -1);
00823         gtk_tree_model_get(model, b, COL_ENTITY, &ent_b, -1);
00824         param = qof_class_get_parameter (GPE_QOF_EXPENSES, EXP_DATE);
00825         qt_a = param->param_getfcn (ent_a, param);
00826         qt_b = param->param_getfcn (ent_b, param);
00827         result = qof_time_cmp (qt_a, qt_b);
00828         qof_time_free (qt_a);
00829         qof_time_free (qt_b);
00830         return result;
00831 }
00832 
00833 static gint
00834 amount_compare (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
00835                 gpointer G_GNUC_UNUSED user_data)
00836 {
00837         gint result;
00838         gdouble *dbl_a, *dbl_b;
00839 
00840         result = 0;
00841         gtk_tree_model_get(model, a, COL_EXP_AMOUNT, &dbl_a, -1);
00842         gtk_tree_model_get(model, b, COL_EXP_AMOUNT, &dbl_b, -1);
00843         if(dbl_a != dbl_b)
00844                 result = (dbl_a > dbl_b) ? 1 : -1;
00845         return result;
00846 }
00847 
00848 static GtkWidget*
00849 set_list_view(GpeExpenseData *context)
00850 {
00851         GtkTreeView *view;
00852         GtkTreeSortable *sort;
00853         GtkWidget *scrolled;
00854         GtkCellRenderer *date_rend, *type_rend, *symbol_rend, *amount_rend;
00855         GtkTreeViewColumn *col;
00856 
00857         scrolled = gtk_scrolled_window_new (NULL, NULL);
00858         context->list_store = gtk_list_store_new(COL_MAX, G_TYPE_STRING, 
00859                 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_POINTER);
00860         sort = GTK_TREE_SORTABLE (context->list_store);
00861         view = GTK_TREE_VIEW (gtk_tree_view_new_with_model
00862                 (GTK_TREE_MODEL (sort)));
00863 
00864         date_rend = gtk_cell_renderer_text_new ();
00865         col = gtk_tree_view_column_new_with_attributes ((_("Date")), date_rend,
00866                         "text", COL_EXP_DATE, NULL);
00867         g_object_set(date_rend, "editable", TRUE, NULL);
00868         g_object_set(col, "reorderable", TRUE, NULL);
00869         g_object_set(col, "sort-indicator", TRUE, NULL);
00870         gtk_tree_view_column_set_sort_column_id(col, COL_EXP_DATE);
00871         gtk_tree_sortable_set_sort_func (sort, COL_EXP_DATE, date_compare, NULL, NULL);
00872         gtk_tree_view_column_set_expand(col, TRUE);
00873         gtk_tree_view_column_set_clickable(col, TRUE);
00874         gtk_tree_view_insert_column (GTK_TREE_VIEW (view), col, -1);
00875         g_signal_connect(date_rend, "edited", 
00876                 (GCallback) change_date, context);
00877 
00878         type_rend = gtk_cell_renderer_text_new ();
00879         col = gtk_tree_view_column_new_with_attributes (_("Type"), type_rend,
00880                         "text", COL_EXP_TYPE, NULL);
00881         gtk_tree_view_column_set_sort_column_id(col, COL_EXP_TYPE);
00882         gtk_tree_sortable_set_sort_func (sort, COL_EXP_TYPE, type_compare, NULL, NULL);
00883         gtk_tree_view_column_set_expand(col, TRUE);
00884         gtk_tree_view_column_set_clickable(col, TRUE);
00885         g_object_set(col, "reorderable", TRUE, NULL);
00886         g_object_set(col, "sort-indicator", TRUE, NULL);
00887         gtk_tree_view_insert_column (GTK_TREE_VIEW (view), col, -1);
00888 
00889         symbol_rend = gtk_cell_renderer_text_new ();
00890         col = gtk_tree_view_column_new_with_attributes ("", symbol_rend,
00891                         "text", COL_EXP_SYMBOL, NULL);
00892         gtk_tree_view_column_set_expand(col, TRUE);
00893         gtk_tree_view_column_set_clickable(col, TRUE);
00894         gtk_tree_view_insert_column (GTK_TREE_VIEW (view), col, -1);
00895 
00896         amount_rend = gtk_cell_renderer_text_new ();
00897         col = gtk_tree_view_column_new_with_attributes (_("Amount"), amount_rend,
00898                         "text", COL_EXP_AMOUNT, NULL);
00899         g_object_set(amount_rend, "editable", TRUE, NULL);
00900         g_object_set(col, "reorderable", TRUE, NULL);
00901         g_object_set(col, "sort-indicator", TRUE, NULL);
00902         gtk_tree_view_column_set_sort_column_id(col, COL_EXP_AMOUNT);
00903         gtk_tree_sortable_set_sort_func (sort, COL_EXP_AMOUNT, amount_compare, NULL, NULL);
00904         gtk_tree_view_column_set_expand(col, TRUE);
00905         gtk_tree_view_column_set_clickable(col, TRUE);
00906         gtk_tree_view_insert_column (GTK_TREE_VIEW (view), col, -1);
00907         gtk_tree_view_column_set_cell_data_func(col, amount_rend, 
00908                 rounding_func, GINT_TO_POINTER(COL_EXP_AMOUNT), NULL);
00909         g_signal_connect(amount_rend, "edited", 
00910                 (GCallback) change_amount, context);
00911 
00912         g_signal_connect (G_OBJECT (view), "button_press_event", 
00913                         G_CALLBACK (button_press_event), context);
00914 
00915         gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET(view));
00916         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
00917                           GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
00918         gtk_tree_sortable_set_sort_column_id (sort, COL_EXP_DATE, 
00919                 GTK_SORT_DESCENDING);
00920         return GTK_WIDGET(scrolled);
00921 }
00922 
00923 static void
00924 exp_refresh_list (GpeExpenseData *context)
00925 {
00926         gtk_list_store_clear(context->list_store);
00927         /* Populate the list from qof_object_foreach */
00928         qof_object_foreach(GPE_QOF_EXPENSES, context->book, exp_show_entities, context);
00929 }
00930 
00931 static void 
00932 open_new_expense (GtkWidget G_GNUC_UNUSED *w, GpeExpenseData *context)
00933 {
00934         GtkTreeIter  ent_data;
00935         QofInstance  *inst;
00936         QofBook      *book;
00937         const QofParam *param;
00938         void (*i32_setter)       (QofEntity*, gint32);
00939         /* detect local currency */
00940         QofCurrency * c;
00941         struct lconv lc;
00942         gchar * sy;
00943         guint def_pq_code;
00944 
00945         g_return_if_fail(context);
00946         def_pq_code = -1;
00947         book = qof_session_get_book(context->qof.input_session);
00948         inst = (QofInstance*)qof_object_new_instance(GPE_QOF_EXPENSES, book);
00949         context->entity = &inst->entity;
00950         /* use locale currency */
00951         lc = *localeconv();
00952         DEBUG (" sym=%s", lc.currency_symbol);
00953         sy = g_strdup (lc.int_curr_symbol);
00954         sy = g_strstrip (sy);
00955         c = qof_currency_lookup_name (inst, sy);
00956         if (c)
00957                 def_pq_code = c->pq_code;
00958         g_free (sy);
00959         param = qof_class_get_parameter (GPE_QOF_EXPENSES, EXP_CURRENCY);
00960         i32_setter = (void(*)(QofEntity*, gint32))param->param_setfcn;
00961         qof_util_param_edit ((QofInstance*)context->entity, param);
00962         i32_setter(context->entity, def_pq_code);
00963         qof_util_param_commit ((QofInstance*)context->entity, param);
00964         gtk_list_store_append(context->list_store, &ent_data);
00965         exp_refresh_list(context);
00966 }
00967 
00968 static GtkWidget*
00969 set_toolbar (GpeExpenseData *context)
00970 {
00971         GtkWidget *toolbar;
00972         GtkToolItem *new_exp, *quit_exp, *about_exp, *item, *edit_exp;
00973         toolbar = gtk_toolbar_new ();
00974         gtk_toolbar_set_orientation (GTK_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
00975 
00976         new_exp = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
00977         g_signal_connect(G_OBJECT(new_exp), "clicked", 
00978                 G_CALLBACK (open_new_expense), context);
00979         gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new_exp, -1);
00980 
00981         edit_exp = gtk_tool_button_new_from_stock(GTK_STOCK_PROPERTIES);
00982         g_signal_connect(G_OBJECT(edit_exp), "clicked",
00983                 G_CALLBACK (edit_expense), context);
00984         gtk_toolbar_insert(GTK_TOOLBAR(toolbar), edit_exp, -1);
00985 
00986         item = gtk_separator_tool_item_new();
00987         gtk_tool_item_set_expand(GTK_TOOL_ITEM(item), FALSE);
00988         gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
00989 
00990         about_exp = gtk_tool_button_new_from_stock(GTK_STOCK_ABOUT);
00991         g_signal_connect(G_OBJECT(about_exp), "clicked", 
00992                 G_CALLBACK (open_about_dialog), NULL);
00993         gtk_toolbar_insert(GTK_TOOLBAR(toolbar), about_exp, -1);
00994 
00995         item = gtk_separator_tool_item_new();
00996         gtk_tool_item_set_expand(GTK_TOOL_ITEM(item), FALSE);
00997         gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
00998 
00999         quit_exp = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
01000         gtk_toolbar_insert(GTK_TOOLBAR(toolbar), quit_exp, -1);
01001         g_signal_connect (G_OBJECT (quit_exp), "clicked",
01002                         G_CALLBACK (gtk_main_quit), NULL);
01003         return GTK_WIDGET(toolbar);
01004 }
01005 
01006 void
01007 open_expenses_window (GpeExpenseData *context)
01008 {
01009         GtkWidget *window;
01010         GtkWidget *vbox;
01011 
01012         g_return_if_fail(context);
01013         ENTER (" ");
01014         vbox = gtk_vbox_new (FALSE, 0);
01015 
01016         gpe_pim_categories_init ();
01017         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
01018         gtk_window_set_default_size (GTK_WINDOW (window), 240, 320);
01019         gtk_window_set_title (GTK_WINDOW (window), _("Expenses"));
01020         gpe_set_window_icon (window, "icon");
01021 
01022         gtk_box_pack_start (GTK_BOX (vbox), set_toolbar(context), FALSE, FALSE, 0);
01023         g_signal_connect (G_OBJECT (window), "delete-event",
01024                         G_CALLBACK (gtk_main_quit), NULL);
01025         
01026         gtk_box_pack_start (GTK_BOX (vbox), set_list_view(context), TRUE, TRUE, 0);
01027 
01028         gtk_container_add (GTK_CONTAINER (window), vbox);
01029         gtk_widget_show_all (window);
01030         /* Populate the list from qof_object_foreach */
01031         qof_object_foreach(GPE_QOF_EXPENSES, context->book, 
01032                 exp_show_entities, context);
01033         LEAVE (" ");
01034 }