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