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