expenses-gtk.c

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

Generated on Mon Jun 4 11:24:16 2007 for gpe-expenses by  doxygen 1.5.2