/* 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 of
* 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-transaction.h"
#include "hb-transaction.h"
#include "gtk-dateentry.h"
#include "ui-payee.h"
#include "ui-category.h"
#include "ui-account.h"
#include "ui-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;
extern gchar *CYA_TYPE[];
gchar *CYA_OPERATION[] = {
N_("Add transaction"),
N_("Inherit transaction"),
N_("Modify transaction")
};
gchar *CYA_TXN_STATUS[] = {
N_("None"),
N_("Cleared"),
N_("Reconciled"),
N_("Remind"),
NULL
};
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void deftransaction_template_popover_populate(struct deftransaction_data *data, GList *srclist);
static void deftransaction_update(GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data;
gboolean sensitive;
DB( g_print("\n[ui-transaction] update\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
//# 1419476 empty category when no split either...
if( (data->ope->flags & (OF_SPLIT)) )
{
//# 1416624 empty category when split
ui_cat_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_grp), 0);
}
/* disable amount+category if split is set */
sensitive = (data->ope->flags & (OF_SPLIT)) ? FALSE : TRUE;
gtk_widget_set_sensitive(data->ST_amount, sensitive);
gtk_widget_set_sensitive(data->PO_grp, sensitive);
}
static void deftransaction_update_warnsign(GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data;
gboolean warning = FALSE;
gdouble amount;
gint amttype;
Category *cat;
DB( g_print("\n[ui-transaction] update warning sign\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
cat = ui_cat_comboboxentry_get(GTK_COMBO_BOX(data->PO_grp));
if(cat != NULL && cat->key > 0)
{
amount = hb_amount_round(gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount)), 2);
if(amount != 0.0)
{
amttype = (amount > 0) ? 1 : -1;
warning = (category_type_get(cat) != amttype) ? TRUE : FALSE;
}
}
if(warning)
gtk_widget_show_all(data->IB_warnsign);
else
gtk_widget_hide(data->IB_warnsign);
}
static void deftransaction_update_transfer(GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data;
gboolean sensitive;
guint kacc, kdst;
DB( g_print("\n[ui-transaction] update transfer\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
sensitive = TRUE;
kacc = ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data->PO_acc));
if(kacc == 0) { sensitive = FALSE; goto end; }
/* coherent seizure
* - target account selected
* - source != target
* - same currency
*/
if( gtk_combo_box_get_active(GTK_COMBO_BOX(data->NU_mode)) == PAYMODE_INTXFER )
{
Account *srcacc, *dstacc;
kdst = ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data->PO_accto));
if(kdst == 0) { sensitive = FALSE; goto end; }
if(kdst == kacc) {
sensitive = FALSE;
goto end;
}
srcacc = da_acc_get(kacc);
dstacc = da_acc_get(kdst);
if(srcacc->kcur != dstacc->kcur) {
sensitive = FALSE;
}
}
end:
DB( g_print(" sensitive %d\n", sensitive) );
//#1437551
//gtk_widget_set_sensitive(gtk_dialog_get_action_area(GTK_DIALOG (data->window)), sensitive);
gtk_dialog_set_response_sensitive(GTK_DIALOG (data->window), GTK_RESPONSE_ACCEPT, sensitive);
gtk_dialog_set_response_sensitive(GTK_DIALOG (data->window), GTK_RESPONSE_ADD, sensitive);
gtk_dialog_set_response_sensitive(GTK_DIALOG (data->window), GTK_RESPONSE_ADDKEEP, sensitive);
}
static void deftransaction_update_payee(GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data;
Category *cat;
gint paymode;
Payee *pay;
DB( g_print("\n[ui-transaction] update payee\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
// only set for empty category
// 1635053 and also paymode unset
cat = ui_cat_comboboxentry_get(GTK_COMBO_BOX(data->PO_grp));
paymode = gtk_combo_box_get_active(GTK_COMBO_BOX(data->NU_mode));
if( (cat == NULL || cat->key == 0) && (paymode == PAYMODE_NONE) )
{
pay = ui_pay_comboboxentry_get(GTK_COMBO_BOX(data->PO_pay));
if( pay != NULL )
{
g_signal_handlers_block_by_func (G_OBJECT (data->PO_grp), G_CALLBACK (deftransaction_update_warnsign), NULL);
ui_cat_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_grp), pay->kcat);
g_signal_handlers_unblock_by_func (G_OBJECT (data->PO_grp), G_CALLBACK (deftransaction_update_warnsign), NULL);
gtk_combo_box_set_active(GTK_COMBO_BOX(data->NU_mode), pay->paymode);
}
}
}
static void deftransaction_update_accto(GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data;
guint kacc;
DB( g_print("\n[ui-transaction] update accto\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
kacc = ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data->PO_acc));
DB( g_print(" acc is %d\n", kacc) );
//g_signal_handlers_block_by_func (G_OBJECT (data->PO_accto), G_CALLBACK (deftransaction_update_transfer), NULL);
//ui_acc_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_accto), 0);
//g_signal_handlers_unblock_by_func (G_OBJECT (data->PO_accto), G_CALLBACK (deftransaction_update_transfer), NULL);
ui_acc_comboboxentry_populate_except(GTK_COMBO_BOX(data->PO_accto), GLOBALS->h_acc, kacc, ACC_LST_INSERT_NORMAL);
deftransaction_update_transfer(widget, user_data);
}
void deftransaction_set_amount_from_split(GtkWidget *widget, gdouble amount)
{
struct deftransaction_data *data;
DB( g_print("\n[ui-transaction] set_amount_from_split\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
DB( g_print("- amount=%.2f\n", amount) );
data->ope->amount = amount;
gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_amount), amount);
deftransaction_update(widget, NULL);
}
static void deftransaction_set(GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data;
Transaction *entry;
gchar *tagstr, *txt;
DB( g_print("\n[ui-transaction] set\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
entry = data->ope;
DB( g_print(" - ope=%p data=%p tags:%p\n", data->ope, data, entry->tags) );
//DB( g_print(" set date to %d\n", entry->date) );
//g_object_set(GTK_DATE_ENTRY(data->PO_date), "date", (guint32)entry->ope_Date);
gtk_date_entry_set_date(GTK_DATE_ENTRY(data->PO_date), (guint)entry->date);
txt = (entry->wording != NULL) ? entry->wording : "";
gtk_entry_set_text(GTK_ENTRY(data->ST_word), txt);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_amount), entry->amount);
//gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_amount), (entry->ope_Flags & OF_INCOME) ? 1 : 0);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_cheque), (entry->flags & OF_CHEQ2) ? 1 : 0);
txt = (entry->info != NULL) ? entry->info : "";
gtk_entry_set_text(GTK_ENTRY(data->ST_info), txt);
ui_cat_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_grp), entry->kcat);
ui_pay_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_pay), entry->kpay);
tagstr = transaction_tags_tostring(entry);
DB( g_print(" - tags: '%s'\n", txt) );
txt = (tagstr != NULL) ? tagstr : "";
gtk_entry_set_text(GTK_ENTRY(data->ST_tags), txt);
g_free(tagstr);
radio_set_active(GTK_CONTAINER(data->RA_status), entry->status );
//as we trigger an event on this
//let's place it at the end to avoid misvalue on the trigger function
g_signal_handlers_block_by_func (G_OBJECT (data->PO_acc), G_CALLBACK (deftransaction_update_accto), NULL);
ui_acc_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_acc), entry->kacc);
ui_acc_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_accto), entry->kxferacc);
g_signal_handlers_unblock_by_func (G_OBJECT (data->PO_acc), G_CALLBACK (deftransaction_update_accto), NULL);
gtk_combo_box_set_active(GTK_COMBO_BOX(data->NU_mode), entry->paymode);
DB( g_print(" - acc is: %d\n", gtk_combo_box_get_active(GTK_COMBO_BOX(data->PO_acc)) ) );
}
void deftransaction_get(GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data;
Transaction *entry;
gchar *txt;
gdouble value;
gint active;
DB( g_print("\n[ui-transaction] get\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
entry = data->ope;
DB( g_print(" - ope = %p\n", entry) );
//DB( g_print(" get date to %d\n", entry->ope_Date) );
entry->date = gtk_date_entry_get_date(GTK_DATE_ENTRY(data->PO_date));
//g_object_get(GTK_DATE_ENTRY(data->PO_date), "date", entry->ope_Date);
//free any previous string
if( entry->wording )
{
g_free(entry->wording);
entry->wording = NULL;
}
txt = (gchar *)gtk_entry_get_text(GTK_ENTRY(data->ST_word));
// ignore if entry is empty
if (txt && *txt)
{
entry->wording = g_strdup(txt);
}
value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount));
entry->amount = value;
/* for internal transfer add, amount must be expense */
// #617936
/*
if( entry->paymode == PAYMODE_INTXFER && data->type == OPERATION_EDIT_ADD )
{
if( entry->amount > 0 )
entry->amount *= -1;
}
*/
//free any previous string
if( entry->info )
{
g_free(entry->info);
entry->info = NULL;
}
txt = (gchar *)gtk_entry_get_text(GTK_ENTRY(data->ST_info));
// ignore if entry is empty
if (txt && *txt)
{
entry->info = g_strdup(txt);
}
entry->paymode = gtk_combo_box_get_active(GTK_COMBO_BOX(data->NU_mode));
entry->kcat = ui_cat_comboboxentry_get_key_add_new(GTK_COMBO_BOX(data->PO_grp));
entry->kpay = ui_pay_comboboxentry_get_key_add_new(GTK_COMBO_BOX(data->PO_pay));
entry->kacc = ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data->PO_acc));
entry->kxferacc = ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data->PO_accto));
/* tags */
txt = (gchar *)gtk_entry_get_text(GTK_ENTRY(data->ST_tags));
DB( g_print(" - tags: '%s'\n", txt) );
transaction_tags_parse(entry, txt);
entry->status = radio_get_active(GTK_CONTAINER(data->RA_status));
//#1615245: moved here, after get combo entry key
if( entry->paymode != PAYMODE_INTXFER )
{
//#677351: revert kxferacc to 0
entry->kxferacc = 0;
}
/* flags */
//entry->flags = 0;
entry->flags &= (OF_SPLIT); //(split is set in hb_transaction)
if( data->type == TRANSACTION_EDIT_ADD || data->type == TRANSACTION_EDIT_INHERIT)
entry->flags |= OF_ADDED;
if( data->type == TRANSACTION_EDIT_MODIFY)
entry->flags |= OF_CHANGED;
active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_cheque));
if(active == 1) entry->flags |= OF_CHEQ2;
//active = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_amount));
active = entry->amount > 0 ? TRUE : FALSE;
if(active == TRUE) entry->flags |= OF_INCOME;
}
static gboolean deftransaction_amount_focusout(GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
{
struct deftransaction_data *data;
gushort paymode;
gdouble amount;
DB( g_print("\n[ui-transaction] amount focus-out-event %d\n", gtk_widget_is_focus(widget)) );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
paymode = gtk_combo_box_get_active(GTK_COMBO_BOX(data->NU_mode));
// for internal transfer add, amount must be expense by default
if( paymode == PAYMODE_INTXFER && data->type == TRANSACTION_EDIT_ADD )
{
amount = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount));
if(amount > 0)
gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_amount), amount *= -1);
}
deftransaction_update_warnsign(widget, NULL);
return FALSE;
}
static void deftransaction_toggleamount(GtkWidget *widget, GtkEntryIconPosition icon_pos, GdkEvent *event, gpointer user_data)
{
struct deftransaction_data *data;
guint count, i;
Split *split;
gdouble value;
DB( g_print("\n[ui-transaction] toggleamount\n") );
if(icon_pos == GTK_ENTRY_ICON_PRIMARY)
{
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
gtk_spin_button_update(GTK_SPIN_BUTTON(data->ST_amount));
value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount));
value *= -1;
gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_amount), value);
if( data->ope->flags & OF_SPLIT )
{
count = da_splits_count(data->ope->splits);
DB( g_print("- count = %d\n", count) );
for(i=0;iope->splits[i];
split->amount *= -1;
}
}
deftransaction_update_warnsign(widget, NULL);
}
}
static void deftransaction_button_split_cb(GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data;
Transaction *ope;
gdouble amount;
gint nbsplit;
DB( g_print("\n[ui-transaction] doing split\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
ope = data->ope;
amount = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount));
ui_split_dialog(data->window, ope->splits, amount, &deftransaction_set_amount_from_split);
//eval split to garantee disabled items
ope->flags &= ~(OF_SPLIT);
nbsplit = da_splits_count(ope->splits);
if(nbsplit > 0)
data->ope->flags |= (OF_SPLIT);
deftransaction_update(data->window, NULL);
}
/*
**
*/
static void deftransaction_paymode(GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data;
gint payment;
gint page;
gboolean sensitive;
DB( g_print("\n[ui-transaction] paymode change\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
payment = gtk_combo_box_get_active(GTK_COMBO_BOX(data->NU_mode));
page = 0;
/* todo: prefill the cheque number ? */
if( data->type != TRANSACTION_EDIT_MODIFY )
{
gboolean expense = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount)) > 0 ? FALSE : TRUE);
DB( g_print(" - payment: %d\n", PAYMODE_CHECK) );
DB( g_print(" - expense: %d\n", expense) );
DB( g_print(" - acc is: %d\n", ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data->PO_acc)) ) );
if(payment == PAYMODE_CHECK)
{
if(expense == TRUE)
{
Account *acc;
gint active = ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data->PO_acc));
guint cheque;
gchar *cheque_str;
DB( g_print(" - should fill cheque number for account %d\n", active) );
//#1410166
if( active > 0 )
{
acc = da_acc_get( active );
if(acc != NULL)
{
cheque = ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_cheque))==TRUE ? acc->cheque2 : acc->cheque1 );
cheque_str = g_strdup_printf("%d", cheque + 1);
gtk_entry_set_text(GTK_ENTRY(data->ST_info), cheque_str);
g_free(cheque_str);
}
}
}
}
}
if(payment == PAYMODE_CHECK)
page = 1;
sensitive = (payment == PAYMODE_INTXFER) ? FALSE : TRUE;
gtk_widget_set_sensitive(data->BT_split, sensitive);
sensitive = page == 1 ? TRUE : FALSE;
hb_widget_visible(data->CM_cheque, sensitive);
if(payment == PAYMODE_INTXFER)
{
page = 2;
// for internal transfer add, amount must be expense by default
gdouble amount = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount));
if( data->type == TRANSACTION_EDIT_ADD )
{
if(amount > 0)
gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_amount), amount *= -1);
}
//else //#1460370
//if( data->type == TRANSACTION_EDIT_MODIFY )
// {
if(amount > 0)
{
gtk_label_set_text_with_mnemonic (GTK_LABEL(data->LB_accto), _("From acc_ount:"));
}
else
{
gtk_label_set_text_with_mnemonic (GTK_LABEL(data->LB_accto), _("To acc_ount:"));
}
//}
}
deftransaction_update_accto(widget, user_data);
DB( g_print(" payment: %d, page: %d\n", payment, page) );
sensitive = page == 2 ? TRUE : FALSE;
hb_widget_visible(data->LB_accto, sensitive);
hb_widget_visible(data->PO_accto, sensitive);
}
/*
** called from outside
*/
gint deftransaction_external_edit(GtkWindow *parent, Transaction *old_txn, Transaction *new_txn)
{
GtkWidget *dialog;
gboolean result;
dialog = create_deftransaction_window(GTK_WINDOW(parent), TRANSACTION_EDIT_MODIFY, FALSE);
deftransaction_set_transaction(dialog, new_txn);
result = gtk_dialog_run (GTK_DIALOG (dialog));
if(result == GTK_RESPONSE_ACCEPT)
{
deftransaction_get(dialog, NULL);
account_balances_sub(old_txn);
account_balances_add(new_txn);
if( new_txn->paymode == PAYMODE_INTXFER )
{
//nota: if kxfer is 0, the user may have just changed the paymode to xfer
DB( g_print(" - kxfer = %d\n", new_txn->kxfer) );
if(new_txn->kxfer > 0) //1) search a strong linked child
{
Transaction *ltxn;
DB( g_print(" - old_txn: kacc=%d kxferacc=%d\n", old_txn->kacc, old_txn->kxferacc) );
//#1584342 was faultly old_txn
ltxn = transaction_xfer_child_strong_get(new_txn);
if(ltxn != NULL) //should never be the case
{
DB( g_print(" - strong link found, do sync\n") );
transaction_xfer_sync_child(new_txn, ltxn);
}
else
{
DB( g_print(" - no, somethin' went wrong here...\n") );
}
}
else
{
//2) any standard transaction that match ?
transaction_xfer_search_or_add_child(GTK_WINDOW(dialog), new_txn, FALSE);
}
}
//#1250061 : manage ability to break an internal xfer
if(old_txn->paymode == PAYMODE_INTXFER && new_txn->paymode != PAYMODE_INTXFER)
{
GtkWidget *p_dialog;
gboolean break_result;
DB( g_print(" - should break internal xfer\n") );
p_dialog = gtk_message_dialog_new
(
GTK_WINDOW(parent),
GTK_DIALOG_MODAL,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_YES_NO,
_("Do you want to break the internal transfer ?\n\n"
"Proceeding will delete the target transaction.")
);
break_result = gtk_dialog_run( GTK_DIALOG( p_dialog ) );
gtk_widget_destroy( p_dialog );
if(break_result == GTK_RESPONSE_YES)
{
transaction_xfer_remove_child(old_txn);
}
else //force paymode to internal xfer
{
new_txn->paymode = PAYMODE_INTXFER;
}
}
}
//1638035: manage account change
if( old_txn->kacc != new_txn->kacc )
{
//locked from ui, but test anyway: forbid change for internal transfer
if( new_txn->paymode == PAYMODE_INTXFER )
{
new_txn->kacc = old_txn->kacc;
}
else
{
//todo: maybe we should restrict this also to same currency account
account_balances_sub(new_txn);
transaction_acc_move(new_txn, old_txn->kacc, new_txn->kacc);
account_balances_add(new_txn);
}
}
deftransaction_dispose(dialog, NULL);
gtk_widget_destroy (dialog);
return result;
}
void deftransaction_set_transaction(GtkWidget *widget, Transaction *ope)
{
struct deftransaction_data *data;
DB( g_print("\n[ui-transaction] set transaction (from out)\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
data->ope = ope;
DB( g_print(" - ope=%p data=%p\n", data->ope, data) );
DB( g_print(" - call init\n") );
deftransaction_set(widget, NULL);
deftransaction_paymode(widget, NULL);
deftransaction_update(widget, NULL);
deftransaction_update_warnsign(widget, NULL);
}
void deftransaction_dispose(GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data;
DB( g_print("\n[ui-transaction] dispose\n") );
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
g_free(data);
}
static void deftransaction_setup(struct deftransaction_data *data)
{
DB( g_print("\n[ui-transaction] setup\n") );
ui_pay_comboboxentry_populate(GTK_COMBO_BOX(data->PO_pay), GLOBALS->h_pay);
ui_cat_comboboxentry_populate(GTK_COMBO_BOX(data->PO_grp), GLOBALS->h_cat);
ui_acc_comboboxentry_populate(GTK_COMBO_BOX(data->PO_acc), GLOBALS->h_acc, ACC_LST_INSERT_NORMAL);
ui_acc_comboboxentry_populate(GTK_COMBO_BOX(data->PO_accto), GLOBALS->h_acc, ACC_LST_INSERT_NORMAL);
if( data->showtemplate )
{
deftransaction_template_popover_populate (data, GLOBALS->arc_list);
gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(data->modelfilter));
}
}
static GtkWidget *
create_popover (GtkWidget *parent,
GtkWidget *child,
GtkPositionType pos)
{
GtkWidget *popover;
popover = gtk_popover_new (parent);
gtk_popover_set_position (GTK_POPOVER (popover), pos);
gtk_container_add (GTK_CONTAINER (popover), child);
gtk_container_set_border_width (GTK_CONTAINER (popover), SPACING_SMALL);
gtk_widget_show (child);
/* gtk_widget_set_margin_start (popover, SPACING_MEDIUM);
gtk_widget_set_margin_end (popover, SPACING_MEDIUM);
gtk_widget_set_margin_top (popover, SPACING_MEDIUM);
gtk_widget_set_margin_bottom (popover, SPACING_MEDIUM);*/
return popover;
}
static void deftransaction_template_popover_onRowActivated(GtkTreeView *treeview,
GtkTreePath *path,
GtkTreeViewColumn *col,
gpointer userdata)
{
struct deftransaction_data *data;
GtkTreeModel *model;
GtkTreeIter iter;
data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW)), "inst_data");
model = gtk_tree_view_get_model(treeview);
if (gtk_tree_model_get_iter(model, &iter, path))
{
Archive *arc;
Transaction *txn;
gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPTPL_DATAS, &arc, -1);
txn = data->ope;
da_transaction_init_from_template(txn, arc);
if( da_splits_clone(arc->splits, txn->splits) > 0)
txn->flags |= OF_SPLIT; //Flag that Splits are active
DB( g_print(" calls\n") );
deftransaction_set(GTK_WIDGET(treeview), NULL);
deftransaction_paymode(GTK_WIDGET(treeview), NULL);
deftransaction_update(GTK_WIDGET(treeview), NULL);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(data->MB_template), FALSE);
}
}
static void deftransaction_template_popover_populate(struct deftransaction_data *data, GList *srclist)
{
GtkTreeModel *model;
GtkTreeIter iter;
GList *list;
//insert all glist item into treeview
model = data->model;
gtk_list_store_clear(GTK_LIST_STORE(model));
list = g_list_first(srclist);
while (list != NULL)
{
Archive *entry = list->data;
gtk_list_store_append (GTK_LIST_STORE(model), &iter);
gtk_list_store_set (GTK_LIST_STORE(model), &iter,
LST_DSPTPL_DATAS, entry,
LST_DSPTPL_NAME, entry->wording,
-1);
//DB( g_print(" populate_treeview: %d %08x\n", i, list->data) );
list = g_list_next(list);
}
}
static void
deftransaction_template_popover_refilter (GtkWidget *widget, gpointer user_data)
{
struct deftransaction_data *data = user_data;
DB( g_print(" text changed\n") );
gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(data->modelfilter));
}
static gboolean deftransaction_template_popover_func_visible (GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
{
struct deftransaction_data *data = user_data;
Archive *entry;
gchar *str;
gboolean visible = TRUE;
gboolean showsched;
showsched = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(data->CM_showsched));
gchar *needle = g_ascii_strdown(gtk_entry_get_text(GTK_ENTRY(data->ST_search)), -1);
gtk_tree_model_get (model, iter,
LST_DSPTPL_DATAS, &entry,
LST_DSPTPL_NAME, &str, -1);
if( entry )
{
if( (entry->flags & OF_AUTO) && !showsched)
{
visible = FALSE;
}
else
{
gchar *haystack = g_ascii_strdown(str, -1);
if (str && g_strrstr (haystack, needle) == NULL )
{
visible = FALSE;
}
DB( g_print("filter: '%s' '%s' %d\n", str, needle, visible) );
g_free(haystack);
}
}
g_free(needle);
g_free (str);
return visible;
}
static GtkWidget *deftransaction_template_popover_create(struct deftransaction_data *data)
{
GtkListStore *store;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkWidget *box, *widget, *scrollwin, *treeview;
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, SPACING_SMALL);
widget = make_search(NULL);
data->ST_search = widget;
gtk_box_pack_start (GTK_BOX(box), widget, FALSE, FALSE, 0);
scrollwin = gtk_scrolled_window_new(NULL,NULL);
gtk_box_pack_start (GTK_BOX(box), scrollwin, TRUE, TRUE, 0);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_ETCHED_IN);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
store = gtk_list_store_new(NUM_LST_DSPTPL,
G_TYPE_POINTER,
G_TYPE_STRING);
data->model = GTK_TREE_MODEL(store);
data->modelfilter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(data->model), NULL));
gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(data->modelfilter), deftransaction_template_popover_func_visible, data, NULL);
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(data->modelfilter));
data->LV_arc = treeview;
gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
gtk_widget_grab_focus(treeview);
/* column for bug numbers */
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (NULL,
renderer,
"text",
LST_DSPTPL_NAME,
NULL);
//gtk_tree_view_column_set_resizable (column, TRUE);
gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE);
widget = gtk_check_button_new_with_mnemonic(_("Show _scheduled"));
data->CM_showsched = widget;
gtk_box_pack_start (GTK_BOX(box), widget, FALSE, FALSE, 0);
gtk_widget_show_all (box);
//signals
g_signal_connect (data->CM_showsched, "toggled", G_CALLBACK (deftransaction_template_popover_refilter), data);
g_signal_connect (data->ST_search, "search-changed", G_CALLBACK (deftransaction_template_popover_refilter), data);
return box;
}
static GtkWidget *deftransaction_make_block1(struct deftransaction_data *data)
{
GtkWidget *group_grid, *hbox, *label, *widget, *image;
gint row;
group_grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
row = 0;
label = make_label_widget(_("_Date:"));
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
widget = gtk_date_entry_new();
data->PO_date = widget;
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
gtk_widget_set_halign (widget, GTK_ALIGN_START);
gtk_widget_set_tooltip_text(widget, _("Date accepted here are:\nday,\nday/month or month/day,\nand complete date into your locale"));
row++;
label = make_label_widget(_("_Amount:"));
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_grid_attach (GTK_GRID (group_grid), hbox, 1, row, 1, 1);
widget = make_amount(label);
data->ST_amount = widget;
gtk_entry_set_icon_from_icon_name(GTK_ENTRY(widget), GTK_ENTRY_ICON_PRIMARY, ICONNAME_HB_TOGGLE_SIGN);
gtk_entry_set_icon_tooltip_text(GTK_ENTRY(widget), GTK_ENTRY_ICON_PRIMARY, _("Toggle amount sign"));
gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
image = gtk_image_new_from_icon_name (ICONNAME_HB_BUTTON_SPLIT, GTK_ICON_SIZE_BUTTON);
widget = gtk_button_new();
g_object_set (widget, "image", image, NULL);
data->BT_split = widget;
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_set_tooltip_text(widget, _("Transaction splits"));
row++;
label = make_label_widget(_("Pa_yment:"));
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
widget = make_paymode(label);
data->NU_mode = widget;
gtk_widget_set_halign (widget, GTK_ALIGN_START);
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
row++;
widget = gtk_check_button_new_with_mnemonic(_("Of notebook _2"));
data->CM_cheque = widget;
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
row++;
label = make_label_widget(_("_Info:"));
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
widget = make_string(label);
data->ST_info = widget;
gtk_widget_set_hexpand (widget, TRUE);
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
row++;
label = make_label_widget(_("A_ccount:"));
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
widget = ui_acc_comboboxentry_new(label);
data->PO_acc = widget;
gtk_widget_set_hexpand (widget, TRUE);
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
row++;
label = make_label_widget(_("To acc_ount:"));
data->LB_accto = label;
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
widget = ui_acc_comboboxentry_new(label);
data->PO_accto = widget;
gtk_widget_set_hexpand (widget, TRUE);
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
row++;
label = make_label_widget(_("_Payee:"));
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
widget = ui_pay_comboboxentry_new(label);
data->PO_pay = widget;
gtk_widget_set_hexpand (widget, TRUE);
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
gtk_widget_set_tooltip_text(widget, _("Autocompletion and direct seizure\nis available"));
row++;
label = make_label_widget(_("_Category:"));
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
widget = ui_cat_comboboxentry_new(label);
data->PO_grp = widget;
gtk_widget_set_hexpand (widget, TRUE);
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
gtk_widget_set_tooltip_text(widget, _("Autocompletion and direct seizure\nis available"));
row++;
label = make_label_widget(_("_Status:"));
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
widget = make_radio(CYA_TXN_STATUS, TRUE, GTK_ORIENTATION_HORIZONTAL);
data->RA_status = widget;
gtk_widget_set_halign (widget, GTK_ALIGN_START);
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
row++;
label = make_label_widget(_("M_emo:"));
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
widget = make_memo_entry(label);
data->ST_word = widget;
gtk_widget_set_hexpand (widget, TRUE);
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
row++;
label = make_label_widget(_("Ta_gs:"));
gtk_grid_attach (GTK_GRID (group_grid), label, 0, row, 1, 1);
widget = make_string(label);
data->ST_tags = widget;
gtk_widget_set_hexpand (widget, TRUE);
gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
return group_grid;
}
static gboolean
deftransaction_getgeometry(GtkWidget *widget, GdkEventConfigure *event, gpointer user_data)
{
struct WinGeometry *wg;
DB( g_print("\n[ui-transaction] get geometry\n") );
//store size
wg = &PREFS->txn_wg;
gtk_window_get_size(GTK_WINDOW(widget), &wg->w, NULL);
DB( g_print(" window: w=%d\n", wg->w) );
return FALSE;
}
GtkWidget *create_deftransaction_window (GtkWindow *parent, gint type, gboolean postmode)
{
struct deftransaction_data *data;
struct WinGeometry *wg;
GtkWidget *dialog, *content_area, *content_grid, *group_grid;
GtkWidget *label, *bar;
gint crow;
DB( g_print("\n[ui-transaction] new\n") );
data = g_malloc0(sizeof(struct deftransaction_data));
/*
dialog = gtk_dialog_new_with_buttons (_(CYA_OPERATION[data->type]),
GTK_WINDOW (parent),
0,
NULL,
NULL);
*/
dialog = gtk_dialog_new();
gtk_window_set_title (GTK_WINDOW(dialog), _(CYA_OPERATION[type]));
gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(parent));
//store our window private data
g_object_set_data(G_OBJECT(dialog), "inst_data", (gpointer)data);
DB( g_print(" - window=%p, inst_data=%p\n", dialog, data) );
data->window = dialog;
data->type = type;
// if you add/remove response_id also change into deftransaction_update_transfer
if(type == TRANSACTION_EDIT_MODIFY)
{
gtk_dialog_add_buttons (GTK_DIALOG(dialog),
_("_Cancel"), GTK_RESPONSE_REJECT,
_("_OK"), GTK_RESPONSE_ACCEPT,
NULL);
}
else
{
if(!postmode)
{
gtk_dialog_add_buttons (GTK_DIALOG(dialog),
_("_Close"), GTK_RESPONSE_REJECT,
_("_Add & keep"), GTK_RESPONSE_ADDKEEP,
_("_Add"), GTK_RESPONSE_ADD,
NULL);
}
else
{
gtk_dialog_add_buttons (GTK_DIALOG(dialog),
_("_Close"), GTK_RESPONSE_REJECT,
_("_Post"), GTK_RESPONSE_ADD,
NULL);
}
}
switch(type)
{
case TRANSACTION_EDIT_ADD:
gtk_window_set_icon_name(GTK_WINDOW (dialog), ICONNAME_HB_OPE_ADD);
break;
case TRANSACTION_EDIT_INHERIT:
gtk_window_set_icon_name(GTK_WINDOW (dialog), ICONNAME_HB_OPE_HERIT);
break;
case TRANSACTION_EDIT_MODIFY:
gtk_window_set_icon_name(GTK_WINDOW (dialog), ICONNAME_HB_OPE_EDIT);
break;
}
//gtk_window_set_decorated(GTK_WINDOW(dialog), TRUE);
//window contents
content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog));
content_grid = gtk_grid_new();
gtk_grid_set_row_spacing (GTK_GRID (content_grid), SPACING_LARGE);
gtk_grid_set_column_spacing (GTK_GRID (content_grid), SPACING_LARGE);
//gtk_grid_set_column_homogeneous(GTK_GRID (content_grid), TRUE);
gtk_orientable_set_orientation(GTK_ORIENTABLE(content_grid), GTK_ORIENTATION_VERTICAL);
gtk_container_set_border_width (GTK_CONTAINER(content_grid), SPACING_MEDIUM);
gtk_container_add (GTK_CONTAINER (content_area), content_grid);
gtk_widget_show_all(content_grid);
crow = 0;
data->showtemplate = FALSE;
if( data->type != TRANSACTION_EDIT_MODIFY && da_archive_length() > 0 && !postmode )
{
GtkWidget *box, *menubutton, *image;
data->showtemplate = TRUE;
menubutton = gtk_menu_button_new ();
data->MB_template = menubutton;
box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
label = gtk_label_new_with_mnemonic (_("Use a _template"));
gtk_box_pack_start (GTK_BOX(box), label, FALSE, FALSE, 0);
image = gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX(box), image, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(menubutton), box);
gtk_menu_button_set_direction (GTK_MENU_BUTTON(menubutton), GTK_ARROW_DOWN );
gtk_widget_set_halign (menubutton, GTK_ALIGN_END);
gtk_grid_attach (GTK_GRID (content_grid), menubutton, 0, crow, 1, 1);
gtk_widget_show_all(menubutton);
GtkWidget *template = deftransaction_template_popover_create(data);
GtkWidget *popover = create_popover (menubutton, template, GTK_POS_BOTTOM);
gtk_widget_set_size_request (popover, HB_MINWIDTH_LIST, HB_MINHEIGHT_LIST);
gtk_widget_set_vexpand (popover, TRUE);
gtk_widget_set_hexpand (popover, TRUE);
/*gtk_widget_set_margin_start (popover, 10);
gtk_widget_set_margin_end (popover, 10);
gtk_widget_set_margin_bottom (popover, 10);*/
gtk_menu_button_set_popover(GTK_MENU_BUTTON(menubutton), popover);
g_signal_connect (GTK_TREE_VIEW(data->LV_arc), "row-activated", G_CALLBACK (deftransaction_template_popover_onRowActivated), NULL);
}
crow++;
group_grid = deftransaction_make_block1(data);
//gtk_widget_set_hexpand (GTK_WIDGET(group_grid), TRUE);
gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow, 1, 1);
gtk_widget_show_all(group_grid);
/*crow++;
group_grid = deftransaction_make_block2(data);
gtk_widget_set_hexpand (GTK_WIDGET(group_grid), TRUE);
gtk_grid_attach (GTK_GRID (content_grid), group_grid, 1, crow, 1, 1);
gtk_widget_show_all(group_grid);*/
crow++;
bar = gtk_info_bar_new ();
data->IB_warnsign = bar;
gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_WARNING);
label = gtk_label_new (_("Warning: amount and category sign don't match"));
gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label, TRUE, TRUE, 0);
gtk_grid_attach (GTK_GRID (content_grid), bar, 0, crow, 1, 1);
//connect all our signals
g_signal_connect (dialog, "configure-event", G_CALLBACK (deftransaction_getgeometry), (gpointer)data);
g_signal_connect (G_OBJECT (data->ST_amount), "focus-out-event", G_CALLBACK (deftransaction_amount_focusout), NULL);
g_signal_connect (G_OBJECT (data->ST_amount), "icon-release", G_CALLBACK (deftransaction_toggleamount), NULL);
g_signal_connect (G_OBJECT (data->BT_split), "clicked", G_CALLBACK (deftransaction_button_split_cb), NULL);
g_signal_connect (data->NU_mode , "changed", G_CALLBACK (deftransaction_paymode), NULL);
g_signal_connect (data->CM_cheque, "toggled", G_CALLBACK (deftransaction_paymode), NULL);
g_signal_connect (data->PO_pay , "changed", G_CALLBACK (deftransaction_update_payee), NULL);
g_signal_connect (data->PO_acc , "changed", G_CALLBACK (deftransaction_update_accto), NULL);
g_signal_connect (data->PO_accto, "changed", G_CALLBACK (deftransaction_update_transfer), NULL);
g_signal_connect (data->PO_grp , "changed", G_CALLBACK (deftransaction_update_warnsign), NULL);
//setup, init and show window
deftransaction_setup(data);
wg = &PREFS->txn_wg;
gtk_window_set_default_size(GTK_WINDOW(dialog), wg->w, -1);
//gtk_widget_show_all (dialog);
//gtk_widget_hide(data->IB_warnsign);
return dialog;
}