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