X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fhomebank;a=blobdiff_plain;f=src%2Fui-split.c;fp=src%2Fui-split.c;h=da0438b7186b6c0b5da0c2a312561903b45139d9;hp=0000000000000000000000000000000000000000;hb=59c5e08a64798d4303ae7eb3a2713bc93d98fa7b;hpb=8988b3bef0760b4cab8144715cc3d8f55688861c diff --git a/src/ui-split.c b/src/ui-split.c new file mode 100644 index 0000000..da0438b --- /dev/null +++ b/src/ui-split.c @@ -0,0 +1,560 @@ +/* HomeBank -- Free, easy, personal accounting for everyone. + * Copyright (C) 1995-2016 Maxime DOYEN + * + * This file is part of HomeBank. + * + * HomeBank is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * HomeBank is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty ofdeftransaction_amountchanged + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "homebank.h" + +#include "ui-split.h" +#include "ui-transaction.h" +#include "ui-archive.h" +#include "gtk-dateentry.h" +#include "ui-payee.h" +#include "ui-category.h" +#include "ui-account.h" +#include "hb-split.h" + + + + +/****************************************************************************/ +/* Debug macros */ +/****************************************************************************/ +#define MYDEBUG 0 + +#if MYDEBUG +#define DB(x) (x); +#else +#define DB(x); +#endif + +/* our global datas */ +extern struct HomeBank *GLOBALS; +extern struct Preferences *PREFS; + + +#define GTK_RESPONSE_SPLIT_SUM 10880 +#define GTK_RESPONSE_SPLIT_REM 10888 + + +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +static void ui_split_dialog_filter_text_handler (GtkEntry *entry, + const gchar *text, + gint length, + gint *position, + gpointer data) +{ +GtkEditable *editable = GTK_EDITABLE(entry); +gint i, count=0; +gchar *result = g_new0 (gchar, length+1); + + for (i=0; i < length; i++) + { + if (text[i]=='|') + continue; + result[count++] = text[i]; + } + + + if (count > 0) { + g_signal_handlers_block_by_func (G_OBJECT (editable), + G_CALLBACK (ui_split_dialog_filter_text_handler), + data); + gtk_editable_insert_text (editable, result, count, position); + g_signal_handlers_unblock_by_func (G_OBJECT (editable), + G_CALLBACK (ui_split_dialog_filter_text_handler), + data); + } + g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text"); + + g_free (result); +} + + +void ui_split_dialog_line_sensitive(guint line, gboolean sensitive, gpointer user_data) +{ +struct ui_split_dialog_data *data = user_data; + + if( line > TXN_MAX_SPLIT ) + return; + + if( line == 0 ) // line 0 always active ! + sensitive = TRUE; + + + gtk_widget_set_sensitive(data->PO_cat[line], sensitive); + gtk_widget_set_sensitive(data->ST_amount[line], sensitive); + gtk_widget_set_sensitive(data->ST_memo[line], sensitive); + if(data->BT_rem[line]) + gtk_widget_set_sensitive(data->BT_rem[line], sensitive); + if(data->BT_add[line]) + gtk_widget_set_sensitive(data->BT_add[line], sensitive); + + if(sensitive == FALSE) + { + ui_cat_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_cat[line]), 0); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_amount[line]), 0.0); + gtk_entry_set_text(GTK_ENTRY(data->ST_memo[line]), ""); + } + + if(sensitive == TRUE) + data->activeline = line; + +} + + +void ui_split_dialog_compute(GtkWidget *widget, gpointer user_data) +{ +struct ui_split_dialog_data *data = user_data; +gint i, count, nbvalid; +//gint j; +gchar buf[48]; +gboolean sensitive, active; +//guint32 cat[TXN_MAX_SPLIT]; +gdouble amt[TXN_MAX_SPLIT]; +gboolean valid[TXN_MAX_SPLIT]; + + DB( g_print("\n(ui_split_dialog_compute)\n") ); + + data->sumsplit = data->remsplit = 0.0; + nbvalid = 0; + for(i=0;iPO_cat[i]); + if(!active) break; + + //cat[i] = ui_cat_comboboxentry_get_key(GTK_COMBO_BOX(data->PO_cat[i])); + amt[i] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount[i])); + data->sumsplit += amt[i]; + valid[i] = TRUE; + + if(!amt[i]) + valid[i] = FALSE; + + /* disable use same category several time + for(j=0;jnbsplit) ); + + if(data->nbsplit == i) + { + DB( g_print("- set last split %d\n", i) ); + + if(data->BT_add[i]) + gtk_widget_set_sensitive(data->BT_add[i], valid[i]); + + if(data->BT_rem[i]) + gtk_widget_set_sensitive(data->BT_rem[i], TRUE); + } + else + { + DB( g_print("- set off to %d\n", i) ); + + if(data->BT_add[i]) + gtk_widget_set_sensitive(data->BT_add[i], FALSE); + + if(data->BT_rem[i]) + gtk_widget_set_sensitive(data->BT_rem[i], FALSE); + } + } + + count = i; + DB( g_print("- count=%d, nbvalid=%d\n", count, nbvalid ) ); + + + if(data->splittype == TXN_SPLIT_AMOUNT) + { + data->remsplit = data->amount - data->sumsplit; + } + + //rules validation + sensitive = ((count == nbvalid) && (count > 1)) ? TRUE : FALSE; + if(data->splittype == TXN_SPLIT_NEW) + gtk_dialog_set_response_sensitive(GTK_DIALOG(data->dialog), GTK_RESPONSE_SPLIT_SUM, sensitive); + + if(data->splittype == TXN_SPLIT_AMOUNT) + { + sensitive = hb_amount_round(data->remsplit, 2) != 0.0 ? FALSE : sensitive; + gtk_dialog_set_response_sensitive(GTK_DIALOG(data->dialog), GTK_RESPONSE_ACCEPT, sensitive); + + if(!data->remsplit) + g_sprintf(buf, "----"); + else + g_snprintf(buf, 48, "%.2f", data->remsplit); + + gtk_label_set_label(GTK_LABEL(data->LB_remain), buf); + + g_snprintf(buf, 48, "%.2f", data->amount); + gtk_label_set_label(GTK_LABEL(data->LB_txnamount), buf); + } + + g_snprintf(buf, 48, "%.2f", data->sumsplit); + gtk_label_set_text(GTK_LABEL(data->LB_sumsplit), buf); + +} + + +void ui_split_dialog_inactiveline(GtkWidget *widget, gpointer user_data) +{ +struct ui_split_dialog_data *data; +gint line; + + DB( g_print("\n(ui_split_dialog_inactiveline)\n") ); + + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); + + if(data->nbsplit <= 0) //1st split always active + return; + + line = data->nbsplit--; + + DB( g_print("- nbsplit:%d off:%d\n", data->nbsplit, line) ); + + ui_split_dialog_line_sensitive(line, FALSE, data); + ui_split_dialog_compute(widget, data); +} + + +void ui_split_dialog_activeline(GtkWidget *widget, gpointer user_data) +{ +struct ui_split_dialog_data *data; +gint line; + + DB( g_print("\n(ui_split_dialog_activeline)\n") ); + + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); + + line = data->nbsplit; + if(line >= (TXN_MAX_SPLIT-1)) //bound + return; + + line = ++data->nbsplit; + + DB( g_print("- nbsplit:%d off:%d\n", data->nbsplit-1, line) ); + + + ui_split_dialog_line_sensitive(line, TRUE, data); + + if(data->splittype == TXN_SPLIT_AMOUNT) + { + DB( g_print("- line %d :: affect remain\n", line) ); + g_signal_handler_block(data->ST_amount[line], data->handler_id[line]); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_amount[line]), data->remsplit); + g_signal_handler_unblock(data->ST_amount[line], data->handler_id[line]); + } + + ui_split_dialog_compute(widget, data); +} + + +void ui_split_dialog_get(struct ui_split_dialog_data *data) +{ +guint i; +Split *split; +guint32 kcat; +gchar *memo; +gdouble amount; + + DB( g_print("(ui_split_dialog_get)\n") ); + + da_splits_free(data->splits); + + for(i=0;iPO_cat[i])); + memo = (gchar *)gtk_entry_get_text(GTK_ENTRY(data->ST_memo[i])); + amount = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount[i])); + + if(amount) + { + split = da_split_new(kcat, amount, memo); + + DB( g_print("- get split %d : %d, %.2f, %s\n", i, split->kcat, split->amount, split->memo) ); + + da_splits_append (data->splits, split); + } + } +} + + +void ui_split_dialog_set(struct ui_split_dialog_data *data) +{ +guint count, i; +Split *split; +gchar *txt; + + DB( g_print("(ui_split_dialog_set)\n") ); + + for(i=0;iPO_cat[i]), GLOBALS->h_cat); + //#1258821 + //if( data->splittype == TXN_SPLIT_AMOUNT ) + //{ + //if(data->amount > 0.0) + // gtk_spin_button_set_range(GTK_SPIN_BUTTON(data->ST_amount[i]), 0.0, G_MAXDOUBLE); + //else + // gtk_spin_button_set_range(GTK_SPIN_BUTTON(data->ST_amount[i]), -G_MAXDOUBLE, 0.0); + //} + } + + + count = da_splits_count(data->splits); + data->nbsplit = count > 1 ? count-1 : 0; + + DB( g_print("- count = %d\n", count) ); + + + for(i=0;isplits[i]; + + DB( g_print("- set split %d : %d, %.2f, %s\n", i, split->kcat, split->amount, split->memo) ); + + ui_cat_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_cat[i]), split->kcat); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_amount[i]), split->amount); + txt = (split->memo != NULL) ? split->memo : ""; + gtk_entry_set_text(GTK_ENTRY(data->ST_memo[i]), txt); + ui_split_dialog_line_sensitive(i, TRUE, data); + } + +} + + + + +GtkWidget *ui_split_dialog (GtkWidget *parent, Split *ope_splits[], gdouble amount, void (update_callbackFunction(GtkWidget*, gdouble))) +{ +struct ui_split_dialog_data data; +GtkWidget *dialog, *content, *mainvbox, *label; +GtkWidget *table, *widget; +gint row, i; + + + dialog = gtk_dialog_new_with_buttons (_("Transaction splits"), + GTK_WINDOW(parent), + 0, + _("_Cancel"), + GTK_RESPONSE_CANCEL, + NULL); + + data.dialog = dialog; + data.splits = ope_splits; + data.amount = amount; + data.splittype = amount ? TXN_SPLIT_AMOUNT : TXN_SPLIT_NEW; + + gtk_dialog_add_button(GTK_DIALOG(dialog), _("_Remove"), GTK_RESPONSE_SPLIT_REM); + + /* sum button must appear only when new split add */ + //#1258821 + //if(data.splittype == TXN_SPLIT_NEW) + gtk_dialog_add_button(GTK_DIALOG(dialog), _("Sum"), GTK_RESPONSE_SPLIT_SUM); + + + if(data.splittype == TXN_SPLIT_AMOUNT) + gtk_dialog_add_button(GTK_DIALOG(dialog), _("_OK"), GTK_RESPONSE_ACCEPT); + + //store our dialog private data + g_object_set_data(G_OBJECT(dialog), "inst_data", (gpointer)&data); + DB( g_print("(ui_split_dialog) dialog=%p, inst_data=%p\n", dialog, &data) ); + + g_signal_connect (dialog, "destroy", + G_CALLBACK (gtk_widget_destroyed), &dialog); + + //dialog contents + content = gtk_dialog_get_content_area(GTK_DIALOG (dialog)); + mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_MEDIUM); + gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM); + + + table = gtk_grid_new (); + //gtk_container_set_border_width (GTK_CONTAINER (table), SP_BORDER); + gtk_grid_set_row_spacing (GTK_GRID (table), SPACING_SMALL/2); + gtk_grid_set_column_spacing (GTK_GRID (table), SPACING_MEDIUM/2); + gtk_box_pack_start (GTK_BOX (mainvbox), table, TRUE, TRUE, 0); + + row = 0; + label = gtk_label_new(_("Category")); + gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); + gtk_grid_attach (GTK_GRID (table), label, 2, row, 1, 1); + + label = gtk_label_new(_("Memo")); + gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); + gtk_grid_attach (GTK_GRID (table), label, 3, row, 1, 1); + + label = gtk_label_new(_("Amount")); + gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); + gtk_grid_attach (GTK_GRID (table), label, 4, row, 1, 1); + + for(i=0;i 0) + { + widget = gtk_button_new_with_label ("-"); + data.BT_rem[i] = widget; + gtk_grid_attach (GTK_GRID (table), widget, 0, row, 1, 1); + } + + if( (i < (TXN_MAX_SPLIT-1)) ) + { + widget = gtk_button_new_with_label ("+"); + data.BT_add[i] = widget; + gtk_grid_attach (GTK_GRID (table), widget, 1, row, 1, 1); + } + + widget = ui_cat_comboboxentry_new(NULL); + data.PO_cat[i] = widget; + gtk_widget_set_hexpand (widget, TRUE); + gtk_grid_attach (GTK_GRID (table), widget, 2, row, 1, 1); + + widget = make_string(NULL); + gtk_widget_set_hexpand (widget, TRUE); + data.ST_memo[i] = widget; + gtk_grid_attach (GTK_GRID (table), widget, 3, row, 1, 1); + + widget = make_amount(NULL); + data.ST_amount[i] = widget; + gtk_grid_attach (GTK_GRID (table), widget, 4, row, 1, 1); + + //connect all our signals + g_signal_connect (data.PO_cat[i], "changed", G_CALLBACK (ui_split_dialog_compute), &data); + g_signal_connect (data.ST_memo[i], "insert-text", G_CALLBACK(ui_split_dialog_filter_text_handler), NULL); + data.handler_id[i] = g_signal_connect (G_OBJECT (data.ST_amount[i]), "value-changed", G_CALLBACK (ui_split_dialog_compute), &data); + if(data.BT_rem[i]) + g_signal_connect (data.BT_rem[i], "clicked", G_CALLBACK (ui_split_dialog_inactiveline), GINT_TO_POINTER(i)); + if(data.BT_add[i]) + g_signal_connect (data.BT_add[i], "clicked", G_CALLBACK (ui_split_dialog_activeline), GINT_TO_POINTER(i)); + } + + row++; + label = gtk_label_new(_("Sum of splits:")); + gtk_widget_set_halign (label, GTK_ALIGN_END); + gtk_grid_attach (GTK_GRID (table), label, 3, row, 1, 1); + widget = gtk_label_new(NULL); + gtk_widget_set_halign (widget, GTK_ALIGN_END); + data.LB_sumsplit = widget; + gtk_grid_attach (GTK_GRID (table), widget, 4, row, 1, 1); + + if( data.splittype == TXN_SPLIT_AMOUNT ) + { + row++; + label = gtk_label_new(_("Unassigned:")); + gtk_widget_set_halign (label, GTK_ALIGN_END); + gtk_grid_attach (GTK_GRID (table), label, 3, row, 1, 1); + widget = gtk_label_new(NULL); + gtk_widget_set_halign (widget, GTK_ALIGN_END); + gtk_widget_set_margin_left(widget, 20); + gtk_widget_set_margin_right(widget, 20); + data.LB_remain = widget; + gtk_grid_attach (GTK_GRID (table), widget, 4, row, 1, 1); + + row++; + widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_grid_attach (GTK_GRID (table), widget, 4, row, 1, 1); + + row++; + label = gtk_label_new(_("Transaction amount:")); + gtk_widget_set_halign (label, GTK_ALIGN_END); + gtk_grid_attach (GTK_GRID (table), label, 3, row, 1, 1); + widget = gtk_label_new(NULL); + gtk_widget_set_halign (widget, GTK_ALIGN_END); + gtk_widget_set_margin_left(widget, 20); + gtk_widget_set_margin_right(widget, 20); + data.LB_txnamount = widget; + gtk_grid_attach (GTK_GRID (table), widget, 4, row, 1, 1); + } + + + //setup, init and show dialog + //ui_cur_manage_dialog_setup(&data); + + + ui_split_dialog_set(&data); + ui_split_dialog_compute(NULL, &data); + + + //ui_cur_manage_dialog_update(data.LV_cur, NULL); + + gtk_window_set_default_size(GTK_WINDOW(dialog), 480, -1); + + gtk_widget_show_all (dialog); + + //wait for the user + gint result = gtk_dialog_run (GTK_DIALOG (dialog)); + + switch (result) + { + case GTK_RESPONSE_ACCEPT: + //do_application_specific_something (); + ui_split_dialog_get(&data); + update_callbackFunction(parent,data.sumsplit); + break; + case GTK_RESPONSE_SPLIT_REM: + da_splits_free(ope_splits); + update_callbackFunction(parent,data.sumsplit); + break; + case GTK_RESPONSE_SPLIT_SUM: // sum split and alter txn amount + ui_split_dialog_get(&data); + update_callbackFunction(parent,data.sumsplit); + break; + default: + //do_nothing_since_dialog_was_cancelled (); + break; + } + + // debug + /*#if MYDEBUG == 1 + { + guint i; + + for(i=0;ikcat, split->amount, split->memo); + } + } + #endif*/ + + // cleanup and destroy + //GLOBALS->changes_count += data.change; + gtk_widget_destroy (dialog); + + return NULL; +} +