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

Generated on Tue Dec 11 05:37:30 2007 for gpe-expenses by  doxygen 1.5.4