00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
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
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
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
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
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
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
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
00140 mnemonic = gtk_combo_box_get_active_text (context->currency_list);
00141 currency = gpe_currency_lookup_name ((QofInstance*)ent, mnemonic);
00142
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
00289 if(i == Mileage) { mileage = TRUE; }
00290
00291
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
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
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
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
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
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
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
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
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
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
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
00467
00468
00469
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
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
00496
00497
00498 if(0 == safe_strcmp(dis_string, "Mileage"))
00499 {
00500 gint unit;
00501
00502 param = qof_class_get_parameter(GPE_QOF_EXPENSES, EXP_DISTANCE);
00503 unit = ExpenseDistancefromString(param->param_getfcn(ent, param));
00504 switch (unit)
00505 {
00506
00507 case 0 : { symbol = _("mi"); break; }
00508
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
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
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
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
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
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
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
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
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
00932 qof_object_foreach(GPE_QOF_EXPENSES, context->book,
00933 exp_show_entities, context);
00934 LEAVE (" ");
00935 }