diff --git a/src/gnome-utils/gnc-account-sel.c b/src/gnome-utils/gnc-account-sel.c index 6f86cfb85a..bcda4e1709 100644 --- a/src/gnome-utils/gnc-account-sel.c +++ b/src/gnome-utils/gnc-account-sel.c @@ -200,6 +200,8 @@ gas_populate_list( GNCAccountSel *gas ) currentSel = gtk_editable_get_chars( GTK_EDITABLE(entry), 0, -1 ); + g_signal_handlers_block_by_func( gas->combo, combo_changed_cb , gas ); + root = gnc_book_get_root_account( gnc_get_current_book() ); accts = gnc_account_get_descendants_sorted( root ); @@ -232,6 +234,8 @@ gas_populate_list( GNCAccountSel *gas ) if (active != -1) gtk_combo_box_set_active(GTK_COMBO_BOX(gas->combo), active); + g_signal_handlers_unblock_by_func( gas->combo, combo_changed_cb , gas ); + g_list_free( filteredAccts ); if ( currentSel ) { @@ -313,6 +317,7 @@ gnc_account_sel_find_account (GtkTreeModel *model, void gnc_account_sel_set_account( GNCAccountSel *gas, Account *acct, gboolean set_default_acct ) { + GtkEntry *entry; gas_find_data data; if (set_default_acct) @@ -324,8 +329,11 @@ gnc_account_sel_set_account( GNCAccountSel *gas, Account *acct, gboolean set_def gtk_combo_box_set_active( GTK_COMBO_BOX(gas->combo), -1 ); } if ( acct == NULL ) + { + entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gas->combo))); + gtk_editable_delete_text(GTK_EDITABLE(entry),0,-1); return; - + } data.gas = gas; data.acct = acct; gtk_tree_model_foreach(GTK_TREE_MODEL(gas->store), diff --git a/src/gnome/Makefile.am b/src/gnome/Makefile.am index 18eef82d8d..fdc11975e1 100644 --- a/src/gnome/Makefile.am +++ b/src/gnome/Makefile.am @@ -26,6 +26,7 @@ libgnc_gnome_la_SOURCES = \ swig-gnome.c \ assistant-acct-period.c \ assistant-hierarchy.c \ + assistant-loan.c \ assistant-stock-split.c \ dialog-commodities.c \ dialog-fincalc.c \ @@ -39,7 +40,6 @@ libgnc_gnome_la_SOURCES = \ dialog-sx-from-trans.c \ dialog-sx-since-last-run.c \ dialog-tax-info.c \ - druid-loan.c \ gnc-plugin-account-tree.c \ gnc-plugin-basic-commands.c \ gnc-plugin-budget.c \ @@ -66,6 +66,7 @@ appicondir = $(datadir)/pixmaps noinst_HEADERS = \ assistant-acct-period.h \ assistant-hierarchy.h \ + assistant-loan.h \ assistant-stock-split.h \ dialog-fincalc.h \ dialog-find-transactions.h \ @@ -75,7 +76,6 @@ noinst_HEADERS = \ dialog-sx-editor.h \ dialog-sx-from-trans.h \ dialog-sx-since-last-run.h \ - druid-loan.h \ gnc-plugin-account-tree.h \ gnc-plugin-basic-commands.h \ gnc-plugin-budget.h \ diff --git a/src/gnome/druid-loan.c b/src/gnome/assistant-loan.c similarity index 68% rename from src/gnome/druid-loan.c rename to src/gnome/assistant-loan.c index 2156776115..fb57e95a13 100644 --- a/src/gnome/druid-loan.c +++ b/src/gnome/assistant-loan.c @@ -1,8 +1,9 @@ /********************************************************************\ - * druid-loan.c : A Gnome Druid for setting up loan-repayment * + * assistant-loan.c : An Assistant for setting up loan-repayment * * scheduled transactions. * * Copyright (C) 2002,2007 Joshua Sled * * Copyright (C) 2006 David Hampton * + * Copyright (C) 2011 Robert Fewell * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * @@ -23,19 +24,17 @@ \********************************************************************/ #include "config.h" - #include +#include #include #include #include #include - -#include "druid-loan.h" - +#include "assistant-loan.h" #include "SchedXaction.h" #include "SX-book.h" #include "SX-ttinfo.h" -#include "druid-utils.h" +#include "assistant-utils.h" #include "gnc-amount-edit.h" #include "gnc-account-sel.h" #include "gnc-date.h" @@ -50,52 +49,9 @@ #include "gnc-frequency.h" #include "gnc-engine.h" -#define DIALOG_LOAN_DRUID_CM_CLASS "druid-loan-setup" +#define DIALOG_LOAN_ASSISTANT_CM_CLASS "assistant-loan-setup" -#define SX_GLADE_FILE "sched-xact.glade" -#define LOAN_DRUID_WIN_GLADE_NAME "loan_druid_win" -#define LOAN_DRUID_GLADE_NAME "loan_druid" - -#define PG_INTRO "loan_intro_pg" -#define PG_INFO "loan_info_pg" -# define PARAM_TABLE "param_table" -# define ORIG_PRINC_ENTRY "orig_princ_ent" -# define IRATE_SPIN "irate_spin" -# define IRATE_TYPE_COMBOBOX "irate_type_combobox" -# define TYPE_COMBOBOX "type_combobox" -# define VAR_CONTAINER "type_freq_frame" -# define LENGTH_SPIN "len_spin" -# define LENGTH_OPT "len_opt" -# define REMAIN_SPIN "rem_spin" -#define PG_OPTS "loan_opts_pg" -# define OPT_CONTAINER "opt_vbox" -# define OPT_ESCROW "opt_escrow_cb" -# define OPT_ESCROW_CONTAINER "opt_escrow_hbox" -#define PG_REPAYMENT "repayment_pg" -# define TXN_NAME "txn_title" -# define REPAY_TABLE "repay_table" -# define AMOUNT_ENTRY "amount_ent" -# define FREQ_CONTAINER "freq_frame" -#define PG_PAYMENT "payment_pg" -# define PAY_TXN_TITLE "pay_txn_title" -# define PAY_AMT_ENTRY "pay_amt_ent" -# define PAY_TABLE "pay_table" -# define PAY_USE_ESCROW "pay_use_escrow" -# define PAY_SPEC_SRC_ACCT "pay_specify_source" -# define PAY_FROM_ACCT_LBL "pay_from_account_label" -# define PAY_ESC_TO_LBL "pay_escrow_to_label" -# define PAY_ESC_FROM_LBL "pay_escrow_from_label" -# define PAY_TXN_PART_RB "pay_txn_part_rb" -# define PAY_UNIQ_FREQ_RB "pay_uniq_freq_rb" -# define PAY_FREQ_CONTAINER "pay_freq_align" -#define PG_REVIEW "review_pg" -# define REV_SCROLLWIN "rev_scrollwin" -# define REV_DATE_FRAME "rev_date_frame" -# define REV_RANGE_OPT "rev_range_opt" -# define REV_RANGE_TABLE "rev_date_range_table" -#define PG_COMMIT "commit_pg" - -#define OPT_VBOX_SPACING 2 +static QofLogModule log_module = GNC_MOD_ASSISTANT; enum loan_cols { @@ -114,18 +70,7 @@ typedef enum CUSTOM } REV_RANGE_OPTS; -static QofLogModule log_module = GNC_MOD_SX; - -/** - * TODO/fixme: - * . param account selection should fill in orig/cur principal amounts from - * the books. - * . initialize type freq to monthly. - * . if LoanType <- !GNC_FIXED - * . Frequency <- sensitive - **/ - -struct LoanDruidData_; +struct LoanAssistantData_; /** * The data relating to a single "repayment option" -- a potential @@ -134,6 +79,8 @@ struct LoanDruidData_; typedef struct RepayOptData_ { gboolean enabled; + gboolean optValid; + gboolean FreqUniq; char *name; /* { "insurance", "pmi", "taxes", ... } */ char *txnMemo; float amount; @@ -175,9 +122,9 @@ static RepayOptDataDefault REPAY_DEFAULTS[] = **/ typedef struct RepayOptUI_ { - /* must be stated this way [instead of 'LoanDruidData*'] because of + /* must be stated this way [instead of 'LoanAssistantData*'] because of * forward decl. */ - struct LoanDruidData_ *ldd; + struct LoanAssistantData_ *ldd; GtkCheckButton *optCb; GtkCheckButton *escrowCb; RepayOptData *optData; @@ -199,6 +146,7 @@ typedef enum GNC_MONTHS = 0, GNC_YEARS } PeriodSize; + /*type of interest rate entered*/ typedef enum { @@ -261,11 +209,10 @@ typedef struct LoanData_ /** * The UI-side storage of the loan druid data. **/ -typedef struct LoanDruidData_ +typedef struct LoanAssistantData_ { - GladeXML *gxml; - GtkWidget *dialog; - GnomeDruid *druid; + GtkWidget *window; + GtkWidget *assistant; LoanData ld; /* The UI-side storage of repayment data; this is 1:1 with the array @@ -333,7 +280,7 @@ typedef struct LoanDruidData_ GNCDateEdit *revEndDate; GtkScrolledWindow *revScrollWin; GtkTreeView *revView; -} LoanDruidData; +} LoanAssistantData; /** * A transient structure to contain SX details during the creation process. @@ -354,100 +301,237 @@ typedef struct toCreateSX_ TTInfo *escrowTxn; } toCreateSX; -static void gnc_loan_druid_data_init( LoanDruidData *ldd ); -static void gnc_loan_druid_get_widgets( LoanDruidData *ldd ); +/**************************************************************************/ -static void ld_close_handler( LoanDruidData *ldd ); -static void ld_destroy( GtkObject *o, gpointer ud ); +static void loan_assistant_window_destroy_cb( GtkObject *object, gpointer user_data ); +static void loan_assistant_close_handler( gpointer user_data ); +static void loan_assistant_data_init( LoanAssistantData *ldd ); -static void ld_cancel_check( GnomeDruid *gd, LoanDruidData *ldd ); -static void ld_prm_type_changed( GtkWidget *w, gpointer ud ); -static void ld_calc_upd_rem_payments( GtkWidget *w, gpointer ud ); +static void loan_info_prep( GtkAssistant *assistant, gpointer user_data ); +static void loan_info_prm_type_cb( GtkWidget *w, gpointer user_data ); +static void loan_info_calc_update_cb( GtkWidget *widget, gpointer user_data ); +void loan_info_page_valid_cb( GtkWidget *widget, gpointer user_data ); +static gboolean loan_info_page_complete( GtkAssistant *assistant, gpointer user_data ); +static void loan_info_page_save( GtkAssistant *assistant, gpointer user_data ); -static void ld_escrow_toggle( GtkToggleButton *tb, gpointer ud ); -static void ld_opt_toggled( GtkToggleButton *tb, gpointer ud ); -static void ld_opt_consistency( GtkToggleButton *tb, gpointer ud ); -static void ld_escrow_toggled( GtkToggleButton *tb, gpointer ud ); +static void loan_opt_prep( GtkAssistant *assistant, gpointer user_data ); +static void loan_opt_toggled_cb( GtkToggleButton *tb, gpointer user_data ); +static void loan_opt_consistency_cb( GtkToggleButton *tb, gpointer user_data ); +static void loan_opt_escrow_toggle_cb( GtkToggleButton *tb, gpointer user_data ); +static void loan_opt_escrow_toggled_cb( GtkToggleButton *tb, gpointer user_data ); +void loan_opt_page_valid_cb (GtkWidget *widget, gpointer user_data ); +static gboolean loan_opt_page_complete( GtkAssistant *assistant, gpointer user_data ); -static void ld_pay_freq_toggle( GtkToggleButton *tb, gpointer ud ); +static void loan_rep_prep ( GtkAssistant *assistant, gpointer user_data ); +void loan_rep_page_valid_cb (GtkWidget *widget, gpointer user_data ); +static gboolean loan_rep_page_complete( GtkAssistant *assistant, gpointer user_data ); +static void loan_rep_page_save( GtkAssistant *assistant, gpointer user_data ); -static void ld_pay_use_esc_setup( LoanDruidData *ldd, gboolean newState ); -static void ld_pay_use_esc_toggle( GtkToggleButton *tb, gpointer ud ); -static void ld_pay_spec_src_setup( LoanDruidData *ldd, gboolean newState ); -static void ld_pay_spec_src_toggle( GtkToggleButton *tb, gpointer ud ); +static void loan_pay_prep ( GtkAssistant *assistant, gpointer user_data ); +static void loan_pay_use_esc_setup( LoanAssistantData *ldd, gboolean newState ); +static void loan_pay_use_esc_toggle_cb( GtkToggleButton *tb, gpointer user_data ); +static void loan_pay_spec_src_setup( LoanAssistantData *ldd, gboolean newState ); +static void loan_pay_spec_src_toggle_cb( GtkToggleButton *tb, gpointer user_data ); +static void loan_pay_freq_toggle_cb( GtkToggleButton *tb, gpointer user_data ); +static void loan_pay_page_valid_cb (GtkWidget *widget, gpointer user_data ); +static gboolean loan_pay_complete( GtkAssistant *assistant, gpointer user_data ); +static gboolean loan_pay_all_opt_valid ( GtkAssistant *assistant, gpointer user_data ); +static void loan_pay_back_button_cb( GtkButton *button, gpointer user_data ); +static void loan_pay_next_button_cb( GtkButton *button, gpointer user_data ); -static void ld_get_loan_range( LoanDruidData *ldd, - GDate *start, - GDate *end ); +static void loan_rev_prep ( GtkAssistant *assistant, gpointer user_data ); +static void loan_rev_recalc_schedule( LoanAssistantData *ldd ); +static void loan_rev_range_opt_changed_cb( GtkComboBox *combo, gpointer user_data ); +static void loan_rev_range_changed_cb( GNCDateEdit *gde, gpointer user_data ); +static void loan_rev_get_loan_range( LoanAssistantData *ldd, GDate *start, GDate *end ); +static void loan_rev_get_dates( LoanAssistantData *ldd, GDate *start, GDate *end ); +static void loan_rev_update_view( LoanAssistantData *ldd, GDate *start, GDate *end ); +static void loan_rev_sched_list_free( gpointer data, gpointer user_data ); +static void loan_rev_hash_to_list( gpointer key, gpointer val, gpointer user_data ); +static void loan_rev_hash_free_date_keys( gpointer key, gpointer val, gpointer user_data ); -static void ld_rev_recalc_schedule( LoanDruidData *ldd ); -static void ld_rev_range_opt_changed( GtkComboBox *combo, gpointer ud ); -static void ld_rev_range_changed( GNCDateEdit *gde, gpointer ud ); -static void ld_rev_get_dates( LoanDruidData *ldd, - GDate *start, - GDate *end ); -static void ld_rev_update_view( LoanDruidData *ldd, - GDate *start, - GDate *end ); -static void ld_rev_sched_list_free( gpointer data, gpointer user_data ); -static void ld_rev_hash_to_list( gpointer key, - gpointer val, - gpointer user_data ); -static void ld_rev_hash_free_date_keys( gpointer key, - gpointer val, - gpointer user_data ); +static void loan_get_pmt_formula( LoanAssistantData *ldd, GString *gstr ); +static void loan_get_ppmt_formula( LoanAssistantData *ldd, GString *gstr ); +static void loan_get_ipmt_formula( LoanAssistantData *ldd, GString *gstr ); +static float loan_apr_to_simple_formula (float rate, float compounding_periods); -static void ld_get_pmt_formula( LoanDruidData *ldd, GString *gstr ); -static void ld_get_ppmt_formula( LoanDruidData *ldd, GString *gstr ); -static void ld_get_ipmt_formula( LoanDruidData *ldd, GString *gstr ); +static void loan_create_sxes( LoanAssistantData *ldd ); +static gint loan_find_ttsplit_with_acct( gconstpointer elt, gconstpointer crit ); +static void loan_create_sx_from_tcSX( LoanAssistantData *ldd, toCreateSX *tcSX ); +static void loan_tcSX_free( gpointer data, gpointer user_data ); -static gboolean ld_info_save( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static void ld_info_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static gboolean ld_opts_tran( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static void ld_opts_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static gboolean ld_rep_next ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static void ld_rep_prep ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static gboolean ld_rep_back ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static gboolean ld_pay_next ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static void ld_pay_prep ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static gboolean ld_pay_back ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static gboolean ld_rev_next ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static void ld_rev_prep ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static gboolean ld_rev_back ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static gboolean ld_com_next ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static void ld_com_prep ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static gboolean ld_com_back ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); -static void ld_com_fin ( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ); +void loan_assistant_prepare( GtkAssistant *assistant, GtkWidget *page, gpointer user_data ); +void loan_assistant_finish( GtkAssistant *gtkassistant, gpointer user_data ); +void loan_assistant_cancel( GtkAssistant *gtkassistant, gpointer user_data ); +void loan_assistant_close( GtkAssistant *gtkassistant, gpointer user_data ); -static void ld_create_sxes( LoanDruidData *ldd ); -static gint ld_find_ttsplit_with_acct( gconstpointer elt, - gconstpointer crit ); -static void ld_create_sx_from_tcSX( LoanDruidData *ldd, toCreateSX *tcSX ); -static void ld_tcSX_free( gpointer data, gpointer user_data ); -static float ld_apr_to_simple_formula (float rate, float compounding_periods); +/*****************************************************************************/ -struct LoanDruidData_* -gnc_ui_sx_loan_druid_create(void) + +static +void +loan_assistant_close_handler( gpointer user_data ) { - int i; - LoanDruidData *ldd; + LoanAssistantData *ldd = user_data; + gtk_widget_destroy( ldd->window ); +} - ldd = g_new0( LoanDruidData, 1 ); - gnc_loan_druid_data_init( ldd ); +static +void +loan_assistant_window_destroy_cb( GtkObject *object, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; - ldd->gxml = gnc_glade_xml_new( SX_GLADE_FILE, LOAN_DRUID_WIN_GLADE_NAME ); - ldd->dialog = glade_xml_get_widget( ldd->gxml, LOAN_DRUID_WIN_GLADE_NAME ); - ldd->druid = GNOME_DRUID(glade_xml_get_widget( ldd->gxml, - LOAN_DRUID_GLADE_NAME )); - gnc_druid_set_colors (ldd->druid); + g_assert( ldd ); - /* get pointers to the various widgets */ - gnc_loan_druid_get_widgets( ldd ); + gnc_unregister_gui_component_by_data (DIALOG_LOAN_ASSISTANT_CM_CLASS, ldd); - /* non-gladeable widget setup */ + /* free alloc'd mem; cleanup */ + + /* repay opts */ { int i; + + g_date_free( ldd->ld.startDate ); + g_date_free( ldd->ld.varStartDate ); + recurrenceListFree(&ldd->ld.loan_schedule); + + if ( ldd->ld.repMemo ) + g_free( ldd->ld.repMemo ); + + for ( i = 0; i < ldd->ld.repayOptCount; i++ ) + { + RepayOptData *rod = ldd->ld.repayOpts[i]; + if ( rod->name ) + g_free( rod->name ); + if ( rod->txnMemo ) + g_free( rod->txnMemo ); + + if ( rod->startDate ) + g_date_free( rod->startDate ); + + if (rod->schedule != NULL) + recurrenceListFree(&rod->schedule); + + g_free( ldd->ld.repayOpts[i] ); + g_free( ldd->repayOptsUI[i] ); + } + g_free( ldd->ld.repayOpts ); + g_free( ldd->repayOptsUI ); + + if ( ldd->ld.repAmount ) + g_free( ldd->ld.repAmount ); + + g_date_free( ldd->ld.repStartDate ); + } + + /* review */ + { + if ( ldd->ld.revSchedule ) + { + g_list_foreach( ldd->ld.revSchedule, + loan_rev_sched_list_free, + NULL ); + g_list_free( ldd->ld.revSchedule ); + ldd->ld.revSchedule = NULL; + } + } + + g_free( ldd ); +} + + +static GtkWidget * +gnc_loan_assistant_create( LoanAssistantData *ldd ) +{ + GtkBuilder *builder; + GtkWidget *window; + + loan_assistant_data_init( ldd ); + + builder = gtk_builder_new(); + + gnc_builder_add_from_file (builder ,"assistant-loan.glade", "len_liststore"); + gnc_builder_add_from_file (builder ,"assistant-loan.glade", "range_liststore"); + gnc_builder_add_from_file (builder ,"assistant-loan.glade", "type_liststore"); + gnc_builder_add_from_file (builder ,"assistant-loan.glade", "rate_liststore"); + + gnc_builder_add_from_file (builder ,"assistant-loan.glade", "Loan-Mortgage Assistant"); + window = GTK_WIDGET(gtk_builder_get_object (builder, "Loan-Mortgage Assistant")); + ldd->window = window; + + + /* Set the assistant colors */ + gnc_assistant_set_colors (GTK_ASSISTANT (ldd->window)); + + /* Enable buttons on complete pages. */ + gtk_assistant_set_page_complete (GTK_ASSISTANT (window), + GTK_WIDGET(gtk_builder_get_object(builder, "loan_intro_page")), + TRUE); + gtk_assistant_set_page_complete (GTK_ASSISTANT (window), + GTK_WIDGET(gtk_builder_get_object(builder, "loan_options_page")), + TRUE); + gtk_assistant_set_page_complete (GTK_ASSISTANT (window), + GTK_WIDGET(gtk_builder_get_object(builder, "loan_review_page")), + TRUE); + + /* Information Page */ + { + ldd->prmTable = GTK_TABLE(gtk_builder_get_object(builder, "param_table")); + ldd->prmVarFrame = GTK_FRAME(gtk_builder_get_object(builder, "type_freq_frame")); + ldd->prmIrateSpin = GTK_SPIN_BUTTON (gtk_builder_get_object(builder, "irate_spin")); + ldd->prmType = GTK_COMBO_BOX (gtk_builder_get_object(builder, "type_combobox")); + gtk_combo_box_set_active( GTK_COMBO_BOX( ldd->prmType), 0 ); + ldd->prmLengthSpin = GTK_SPIN_BUTTON (gtk_builder_get_object(builder, "len_spin")); + ldd->prmLengthType = GTK_COMBO_BOX (gtk_builder_get_object(builder, "len_opt")); + gtk_combo_box_set_active( GTK_COMBO_BOX( ldd->prmLengthType), 0 ); + ldd->prmRemainSpin = GTK_SPIN_BUTTON (gtk_builder_get_object(builder, "rem_spin")); + ldd->prmIrateType = GTK_COMBO_BOX (gtk_builder_get_object(builder, "irate_type_combobox")); + gtk_combo_box_set_active( GTK_COMBO_BOX( ldd->prmIrateType), 0 ); + /* ldd->prmStartDateGDE */ + } + /* Repayment Page */ + { + ldd->repTable = GTK_TABLE(gtk_builder_get_object(builder, "repay_table")); + ldd->repTxnName = GTK_ENTRY(gtk_builder_get_object(builder, "txn_title")); + ldd->repAmtEntry = GTK_ENTRY(gtk_builder_get_object(builder, "amount_ent")); + ldd->repFreqFrame = GTK_FRAME(gtk_builder_get_object(builder, "freq_frame")); + } + /* Options Page */ + { + ldd->optVBox = GTK_VBOX(gtk_builder_get_object(builder, "loan_options_page")); + ldd->optEscrowCb = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "opt_escrow_cb")); + ldd->optEscrowHBox = GTK_HBOX(gtk_builder_get_object(builder, "opt_escrow_hbox")); + } + /* Payment Page */ + { + ldd->payTable = GTK_TABLE(gtk_builder_get_object(builder, "pay_table")); + ldd->payTxnName = GTK_ENTRY(gtk_builder_get_object(builder, "pay_txn_title")); + ldd->payAmtEntry = GTK_ENTRY(gtk_builder_get_object(builder, "pay_amt_ent")); + ldd->payUseEscrow = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "pay_use_escrow")); + ldd->paySpecSrcAcct = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "pay_specify_source")); + ldd->payAcctFromLabel = GTK_LABEL(gtk_builder_get_object(builder, "pay_from_account_label")); + ldd->payEscToLabel = GTK_LABEL(gtk_builder_get_object(builder, "pay_escrow_to_label")); + ldd->payEscFromLabel = GTK_LABEL(gtk_builder_get_object(builder, "pay_escrow_from_label")); + ldd->payTxnFreqPartRb = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "pay_txn_part_rb")); + ldd->payTxnFreqUniqRb = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "pay_uniq_freq_rb")); + ldd->payFreqAlign = GTK_ALIGNMENT(gtk_builder_get_object(builder, "pay_freq_align")); + } + /* Review Page */ + { + ldd->revTable = GTK_TABLE(gtk_builder_get_object(builder, "rev_date_range_table")); + ldd->revRangeOpt = GTK_COMBO_BOX(gtk_builder_get_object(builder, "rev_range_opt")); + ldd->revDateFrame = GTK_FRAME(gtk_builder_get_object(builder, "rev_date_frame")); + ldd->revScrollWin = GTK_SCROLLED_WINDOW(gtk_builder_get_object(builder, "rev_scrollwin")); + /* GNCDateEdit *revStartDate */ + /* GNCDateEdit *revEndDate */ + } + + /* non-buildable widget setup */ + { + GtkWidget *butt; + int i; // ACCT_TYPE_LIABILITY GList *liabilityAcct; // ACCT_TYPE_BANK, ACCT_TYPE_CASH, ACCT_TYPE_CREDIT, @@ -589,7 +673,7 @@ gnc_ui_sx_loan_druid_create(void) gtk_widget_set_sensitive( GTK_WIDGET(ldd->prmVarFrame), FALSE ); { g_signal_connect( ldd->prmType, "changed", - G_CALLBACK( ld_prm_type_changed ), + G_CALLBACK( loan_info_prm_type_cb ), ldd ); } @@ -599,37 +683,36 @@ gnc_ui_sx_loan_druid_create(void) /* 8.0 [%], range of 0.005..100.0 with ticks at 0.001[%]. */ a = GTK_ADJUSTMENT(gtk_adjustment_new( 8.0, 0.001, 100.0, 0.001, - 1.0, 1.0 )); + 1.0, 0.0 )); gtk_spin_button_set_adjustment( ldd->prmIrateSpin, a ); gtk_spin_button_set_value( ldd->prmIrateSpin, 8.00 ); - gtk_spin_button_set_snap_to_ticks( ldd->prmIrateSpin, - TRUE ); + gtk_spin_button_set_snap_to_ticks( ldd->prmIrateSpin, TRUE ); a = GTK_ADJUSTMENT(gtk_adjustment_new( 360, 1, 9999, 1, - 12, 12 )); + 12, 0.0 )); gtk_spin_button_set_adjustment( ldd->prmLengthSpin, a ); g_signal_connect( ldd->prmLengthSpin, "changed", - G_CALLBACK( ld_calc_upd_rem_payments ), + G_CALLBACK( loan_info_calc_update_cb ), ldd ); g_signal_connect( ldd->prmStartDateGDE, "date-changed", - G_CALLBACK( ld_calc_upd_rem_payments ), + G_CALLBACK( loan_info_calc_update_cb ), ldd ); - g_signal_connect( ldd->prmLengthSpin, "changed", - G_CALLBACK( ld_calc_upd_rem_payments ), + g_signal_connect( ldd->prmLengthSpin, "value-changed", + G_CALLBACK( loan_info_calc_update_cb ), ldd ); g_signal_connect( ldd->prmLengthType, "changed", - G_CALLBACK( ld_calc_upd_rem_payments ), + G_CALLBACK( loan_info_calc_update_cb ), ldd ); a = GTK_ADJUSTMENT(gtk_adjustment_new( 360, 1, 9999, 1, - 12, 12 )); + 12, 0.0 )); gtk_spin_button_set_adjustment( ldd->prmRemainSpin, a ); } g_signal_connect( ldd->optEscrowCb, "toggled", - G_CALLBACK(ld_escrow_toggle), ldd ); + G_CALLBACK(loan_opt_escrow_toggle_cb), ldd ); gtk_widget_set_sensitive( GTK_WIDGET(ldd->optEscrowHBox), FALSE ); ldd->optEscrowGAS = GNC_ACCOUNT_SEL(gnc_account_sel_new()); gnc_account_sel_set_new_account_ability( ldd->optEscrowGAS, TRUE ); @@ -655,7 +738,7 @@ gnc_ui_sx_loan_druid_create(void) for ( i = 0; i < ldd->ld.repayOptCount; i++ ) { rouid = ldd->repayOptsUI[i]; - vb = GTK_VBOX(gtk_vbox_new( FALSE, OPT_VBOX_SPACING )); + vb = GTK_VBOX(gtk_vbox_new( FALSE, 2 )); /* Add payment checkbox. */ @@ -687,13 +770,13 @@ gnc_ui_sx_loan_druid_create(void) FALSE, FALSE, 2 ); g_signal_connect( rouid->optCb, "toggled", - G_CALLBACK(ld_opt_toggled), + G_CALLBACK(loan_opt_toggled_cb), rouid ); g_signal_connect( rouid->optCb, "toggled", - G_CALLBACK(ld_opt_consistency), + G_CALLBACK(loan_opt_consistency_cb), rouid ); g_signal_connect( rouid->escrowCb, "toggled", - G_CALLBACK(ld_escrow_toggled), + G_CALLBACK(loan_opt_escrow_toggled_cb), rouid ); optAlign = GTK_ALIGNMENT(gtk_alignment_new( 0.5, 0.5, 0.75, 1.0 )); @@ -707,124 +790,105 @@ gnc_ui_sx_loan_druid_create(void) } g_signal_connect( ldd->payUseEscrow, "toggled", - G_CALLBACK(ld_pay_use_esc_toggle), ldd ); + G_CALLBACK(loan_pay_use_esc_toggle_cb), ldd ); g_signal_connect( ldd->paySpecSrcAcct, "toggled", - G_CALLBACK(ld_pay_spec_src_toggle), ldd ); - g_signal_connect( ldd->payTxnFreqPartRb, "toggled", - G_CALLBACK(ld_pay_freq_toggle), ldd ); + G_CALLBACK(loan_pay_spec_src_toggle_cb), ldd ); g_signal_connect( ldd->payTxnFreqUniqRb, "toggled", - G_CALLBACK(ld_pay_freq_toggle), ldd ); + G_CALLBACK(loan_pay_freq_toggle_cb), ldd ); - ldd->prmVarGncFreq = - GNC_FREQUENCY(gnc_frequency_new( NULL, NULL )); - gtk_container_add( GTK_CONTAINER(ldd->prmVarFrame), - GTK_WIDGET(ldd->prmVarGncFreq) ); + { + GtkHBox *hbox; + hbox = GTK_HBOX(gtk_builder_get_object(builder, "type_freq_hbox")); + ldd->prmVarGncFreq = GNC_FREQUENCY(gnc_frequency_new( NULL, NULL )); + gtk_box_pack_start( GTK_BOX(hbox) , GTK_WIDGET(ldd->prmVarGncFreq), TRUE, FALSE, 0 ); + g_signal_connect (ldd->prmVarGncFreq, "changed", + G_CALLBACK (loan_info_page_valid_cb), ldd); + } + { + GtkHBox *hbox; + hbox = GTK_HBOX(gtk_builder_get_object(builder, "freq_frame_hbox")); + ldd->repGncFreq = GNC_FREQUENCY(gnc_frequency_new( NULL, NULL )); + gtk_box_pack_start( GTK_BOX(hbox) , GTK_WIDGET(ldd->repGncFreq), TRUE, FALSE, 0 ); + g_signal_connect (ldd->repGncFreq, "changed", + G_CALLBACK (loan_rep_page_valid_cb), ldd); + } - ldd->repGncFreq = - GNC_FREQUENCY(gnc_frequency_new( NULL, NULL )); - gtk_container_add( GTK_CONTAINER(ldd->repFreqFrame), - GTK_WIDGET(ldd->repGncFreq) ); + ldd->payGncFreq = GNC_FREQUENCY(gnc_frequency_new( NULL, NULL )); + gtk_container_add( GTK_CONTAINER(ldd->payFreqAlign), GTK_WIDGET(ldd->payGncFreq) ); + g_signal_connect (ldd->payGncFreq, "changed", + G_CALLBACK (loan_pay_page_valid_cb), ldd); + + butt = GTK_WIDGET(gtk_builder_get_object(builder, "pay_back_button")); + g_signal_connect (butt, "clicked", + G_CALLBACK (loan_pay_back_button_cb), ldd); + + butt = GTK_WIDGET(gtk_builder_get_object(builder, "pay_next_button")); + g_signal_connect (butt, "clicked", + G_CALLBACK (loan_pay_next_button_cb), ldd); - ldd->payGncFreq = - GNC_FREQUENCY(gnc_frequency_new( NULL, NULL )); - gtk_container_add( GTK_CONTAINER(ldd->payFreqAlign), - GTK_WIDGET(ldd->payGncFreq) ); } - /* Review page widget setup. */ + /* Info page Call Back */ + { + g_signal_connect (ldd->prmAccountGAS, "account_sel_changed", + G_CALLBACK (loan_info_page_valid_cb), ldd); + g_signal_connect( ldd->prmIrateType, "changed", + G_CALLBACK( loan_info_page_valid_cb ), ldd ); + } + /* Opts page Call Back */ + { + g_signal_connect (ldd->optEscrowGAS, "account_sel_changed", + G_CALLBACK (loan_opt_page_valid_cb), ldd); + } + /* Rep page Call Back */ + { + g_signal_connect (ldd->repAssetsFromGAS, "account_sel_changed", + G_CALLBACK (loan_rep_page_valid_cb), ldd); + g_signal_connect (ldd->repIntToGAS, "account_sel_changed", + G_CALLBACK (loan_rep_page_valid_cb), ldd); + g_signal_connect (ldd->repPrincToGAS, "account_sel_changed", + G_CALLBACK (loan_rep_page_valid_cb), ldd); + } + /* Pay page Call Back */ + { + g_signal_connect (ldd->payAcctFromGAS, "account_sel_changed", + G_CALLBACK (loan_pay_page_valid_cb), ldd); + g_signal_connect (ldd->payAcctToGAS, "account_sel_changed", + G_CALLBACK (loan_pay_page_valid_cb), ldd); + g_signal_connect (ldd->payAcctEscFromGAS, "account_sel_changed", + G_CALLBACK (loan_pay_page_valid_cb), ldd); + g_signal_connect (ldd->payAcctEscToGAS, "account_sel_changed", + G_CALLBACK (loan_pay_page_valid_cb), ldd); + } + /* Review page Call Back */ { gtk_combo_box_set_active( ldd->revRangeOpt, 0 ); g_signal_connect( ldd->revRangeOpt, "changed", - G_CALLBACK( ld_rev_range_opt_changed ), + G_CALLBACK( loan_rev_range_opt_changed_cb ), ldd ); g_signal_connect( ldd->revStartDate, "date-changed", - G_CALLBACK( ld_rev_range_changed ), + G_CALLBACK( loan_rev_range_changed_cb ), ldd ); g_signal_connect( ldd->revEndDate, "date-changed", - G_CALLBACK( ld_rev_range_changed ), + G_CALLBACK( loan_rev_range_changed_cb ), ldd ); } - { - static struct - { - char *pageName; - gboolean (*nextFn)(); - void (*prepFn)(); - gboolean (*backFn)(); - void (*finishFn)(); - /* cancel is handled by the druid itself. */ - } DRUID_HANDLERS[] = - { - { PG_INFO, ld_info_save, ld_info_prep, ld_info_save, NULL }, - { PG_OPTS, ld_opts_tran, ld_opts_prep, ld_opts_tran, NULL }, - { PG_REPAYMENT, ld_rep_next, ld_rep_prep, ld_rep_back, NULL }, - { PG_PAYMENT, ld_pay_next, ld_pay_prep, ld_pay_back, NULL }, - { PG_REVIEW, ld_rev_next, ld_rev_prep, ld_rev_back, NULL }, - { PG_COMMIT, ld_com_next, ld_com_prep, ld_com_back, ld_com_fin }, - { NULL } - }; - - /* setup page-transition handlers */ - /* setup druid-global handler for cancel */ - g_signal_connect( ldd->druid, "cancel", - G_CALLBACK(ld_cancel_check), ldd ); - /* FIXME: this is substantially similar to the code in - * dialog-sxsincelast.c ... it should probably be factored out - * somewhere. */ - for ( i = 0; DRUID_HANDLERS[i].pageName != NULL; i++ ) - { - GtkWidget *pg; - - pg = glade_xml_get_widget( ldd->gxml, - DRUID_HANDLERS[i].pageName ); - if ( DRUID_HANDLERS[i].prepFn ) - { - g_signal_connect( pg, "prepare", - G_CALLBACK(DRUID_HANDLERS[i]. - prepFn), - ldd); - } - if ( DRUID_HANDLERS[i].backFn ) - { - g_signal_connect( pg, "back", - G_CALLBACK(DRUID_HANDLERS[i]. - backFn), - ldd); - } - if ( DRUID_HANDLERS[i].nextFn ) - { - g_signal_connect( pg, "next", - G_CALLBACK(DRUID_HANDLERS[i]. - nextFn), - ldd); - } - if ( DRUID_HANDLERS[i].finishFn ) - { - g_signal_connect( pg, "finish", - G_CALLBACK(DRUID_HANDLERS[i]. - finishFn), - ldd); - } - } - } - - gnc_register_gui_component( DIALOG_LOAN_DRUID_CM_CLASS, - NULL, /* no refresh handler */ - (GNCComponentCloseHandler)ld_close_handler, - ldd ); - - g_signal_connect( ldd->dialog, "destroy", - G_CALLBACK(ld_destroy), + g_signal_connect( ldd->window, "destroy", + G_CALLBACK(loan_assistant_window_destroy_cb), ldd ); - gtk_widget_show_all( ldd->dialog ); - return ldd; + gtk_builder_connect_signals(builder, ldd); + g_object_unref(G_OBJECT(builder)); + + gtk_widget_show_all( ldd->window ); + return window; } + static void -gnc_loan_druid_data_init( LoanDruidData *ldd ) +loan_assistant_data_init( LoanAssistantData *ldd ) { int i, optCount; RepayOptData *optData; @@ -866,6 +930,8 @@ gnc_loan_druid_data_init( LoanDruidData *ldd ) = g_new0( RepayOptData, 1 ); optData->enabled = FALSE; + optData->optValid = FALSE; + optData->FreqUniq = FALSE; optData->name = g_strdup( _(REPAY_DEFAULTS[i].name) ); optData->txnMemo = g_strdup( _(REPAY_DEFAULTS[i]. defaultTxnMemo) ); @@ -877,560 +943,128 @@ gnc_loan_druid_data_init( LoanDruidData *ldd ) } } +/************************ Page functions in order ***********************/ + static void -gnc_loan_druid_get_widgets( LoanDruidData *ldd ) +loan_info_prep( GtkAssistant *assistant, gpointer user_data ) { - g_assert( ldd != NULL ); - g_assert( ldd->gxml != NULL ); + LoanAssistantData *ldd = user_data; - /* Get all widgets */ -#define GET_CASTED_WIDGET( cast, name ) \ - (cast( glade_xml_get_widget( ldd->gxml, name ) )) + gnc_amount_edit_set_amount( ldd->prmOrigPrincGAE, ldd->ld.principal ); + gtk_spin_button_set_value( ldd->prmIrateSpin, ldd->ld.interestRate ); + gtk_combo_box_set_active( ldd->prmIrateType, ldd->ld.rateType ); + gtk_combo_box_set_active( ldd->prmType, ldd->ld.type ); + if ( ldd->ld.type != GNC_FIXED ) + { + g_signal_handlers_block_by_func( GNC_FREQUENCY( ldd->prmVarGncFreq), loan_info_page_valid_cb , ldd ); + gnc_frequency_setup_recurrence(ldd->prmVarGncFreq, ldd->ld.loan_schedule, ldd->ld.varStartDate); + g_signal_handlers_unblock_by_func( GNC_FREQUENCY( ldd->prmVarGncFreq), loan_info_page_valid_cb , ldd ); + } - /* prm = params */ - ldd->prmTable = - GET_CASTED_WIDGET( GTK_TABLE, PARAM_TABLE ); - ldd->prmIrateSpin = - GET_CASTED_WIDGET( GTK_SPIN_BUTTON, IRATE_SPIN ); - ldd->prmType = - GET_CASTED_WIDGET( GTK_COMBO_BOX, TYPE_COMBOBOX ); - ldd->prmVarFrame = - GET_CASTED_WIDGET( GTK_FRAME, VAR_CONTAINER ); - /* ldd->prmStartDateGDE */ - ldd->prmLengthSpin = - GET_CASTED_WIDGET( GTK_SPIN_BUTTON, LENGTH_SPIN ); - ldd->prmLengthType = - GET_CASTED_WIDGET( GTK_COMBO_BOX, LENGTH_OPT ); - ldd->prmRemainSpin = - GET_CASTED_WIDGET( GTK_SPIN_BUTTON, REMAIN_SPIN ); - ldd->prmIrateType = - GET_CASTED_WIDGET( GTK_COMBO_BOX, IRATE_TYPE_COMBOBOX ); + /* start date */ + { + struct tm *tmpTm; - /* opt = options */ - ldd->optVBox = - GET_CASTED_WIDGET( GTK_VBOX, OPT_CONTAINER ); - ldd->optEscrowCb = - GET_CASTED_WIDGET( GTK_CHECK_BUTTON, OPT_ESCROW ); - ldd->optEscrowHBox = - GET_CASTED_WIDGET( GTK_HBOX, OPT_ESCROW_CONTAINER ); + tmpTm = g_new0( struct tm, 1 ); - /* rep = repayment */ - ldd->repTxnName = - GET_CASTED_WIDGET( GTK_ENTRY, TXN_NAME ); - ldd->repTable = - GET_CASTED_WIDGET( GTK_TABLE, REPAY_TABLE ); - ldd->repAmtEntry = - GET_CASTED_WIDGET( GTK_ENTRY, AMOUNT_ENTRY ); - ldd->repFreqFrame = - GET_CASTED_WIDGET( GTK_FRAME, FREQ_CONTAINER ); + g_date_to_struct_tm( ldd->ld.startDate, tmpTm ); + gnc_date_edit_set_time( ldd->prmStartDateGDE, + mktime(tmpTm) ); + g_free( tmpTm ); + } - /* pay = payment[s] */ - ldd->payTxnName = - GET_CASTED_WIDGET( GTK_ENTRY, PAY_TXN_TITLE ); - ldd->payAmtEntry = - GET_CASTED_WIDGET( GTK_ENTRY, PAY_AMT_ENTRY ); - ldd->payTable = - GET_CASTED_WIDGET( GTK_TABLE, PAY_TABLE ); - ldd->payUseEscrow = - GET_CASTED_WIDGET( GTK_CHECK_BUTTON, PAY_USE_ESCROW ); - ldd->paySpecSrcAcct = - GET_CASTED_WIDGET( GTK_CHECK_BUTTON, PAY_SPEC_SRC_ACCT ); - ldd->payAcctFromLabel = - GET_CASTED_WIDGET( GTK_LABEL, PAY_FROM_ACCT_LBL ); - ldd->payEscToLabel = - GET_CASTED_WIDGET( GTK_LABEL, PAY_ESC_TO_LBL ); - ldd->payEscFromLabel = - GET_CASTED_WIDGET( GTK_LABEL, PAY_ESC_FROM_LBL ); - ldd->payTxnFreqPartRb = - GET_CASTED_WIDGET( GTK_RADIO_BUTTON, PAY_TXN_PART_RB ); - ldd->payTxnFreqUniqRb = - GET_CASTED_WIDGET( GTK_RADIO_BUTTON, PAY_UNIQ_FREQ_RB ); - ldd->payFreqAlign = - GET_CASTED_WIDGET( GTK_ALIGNMENT, PAY_FREQ_CONTAINER ); - - /* rev = review */ - ldd->revRangeOpt = - GET_CASTED_WIDGET( GTK_COMBO_BOX, REV_RANGE_OPT ); - ldd->revDateFrame = - GET_CASTED_WIDGET( GTK_FRAME, REV_DATE_FRAME ); - ldd->revTable = - GET_CASTED_WIDGET( GTK_TABLE, REV_RANGE_TABLE ); - /* GNCDateEdit *revStartDate */ - /* GNCDateEdit *revEndDate */ - ldd->revScrollWin = - GET_CASTED_WIDGET( GTK_SCROLLED_WINDOW, REV_SCROLLWIN ); - -} - -/* convert APR rate to simple rate based on formula r=q((1+i)^(1/q)-1) (r=interest rate, i=apr, q=compounding periods) */ - -gfloat ld_apr_to_simple_formula (gfloat rate, gfloat compounding_periods) -{ - /* float percent_to_frac; - redundant */ - gfloat simple_rate; - /* percent_to_frac= compounding_periods/100; - redundant */ - simple_rate = compounding_periods * ((pow((1 + rate), (1 / compounding_periods))) - 1); - return (simple_rate); + /* length: total and remaining */ + { + gtk_spin_button_set_value( ldd->prmLengthSpin, ldd->ld.numPer ); + gtk_combo_box_set_active( ldd->prmLengthType, ldd->ld.perSize ); + gtk_spin_button_set_value( ldd->prmRemainSpin, ldd->ld.numMonRemain ); + } } static void -ld_get_pmt_formula( LoanDruidData *ldd, GString *gstr ) +loan_info_prm_type_cb( GtkWidget *w, gpointer user_data ) { - gint rate_case; - gfloat pass_thru_rate; - g_assert( ldd != NULL ); - g_assert( gstr != NULL ); - rate_case = ldd->ld.rateType; - pass_thru_rate = ldd->ld.interestRate / 100; - switch (rate_case) - { - case GNC_IRATE_SIMPLE: - { - g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", - pass_thru_rate, 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal) ); - } - break; - case GNC_IRATE_APR_DAILY: - { - g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 365), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal) ); - } - break; - case GNC_IRATE_APR_WEEKLY: - { - g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 52), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal) ); - } - break; - case GNC_IRATE_APR_MONTHLY: - { - g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 12), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal) ); - } - break; - case GNC_IRATE_APR_QUARTERLY: - { - g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 4), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal) ); - } - break; - case GNC_IRATE_APR_ANNUALLY: - { - g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 1), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal) ); - } - break; - default: - g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", - (ldd->ld.interestRate / 100), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal) ); - break; - } -} - -static -void -ld_get_ppmt_formula( LoanDruidData *ldd, GString *gstr ) -{ - gint rate_case; - gfloat pass_thru_rate; - g_assert( ldd != NULL ); - g_assert( gstr != NULL ); - rate_case = ldd->ld.rateType; - pass_thru_rate = ldd->ld.interestRate / 100; - switch (rate_case) - { - case GNC_IRATE_SIMPLE: - { - g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - pass_thru_rate, - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - case GNC_IRATE_APR_DAILY: - { - g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 365), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - case GNC_IRATE_APR_WEEKLY: - { - g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 52), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - case GNC_IRATE_APR_MONTHLY: - { - g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 12), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - case GNC_IRATE_APR_QUARTERLY: - { - g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 4), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - case GNC_IRATE_APR_ANNUALLY: - { - g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 1), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - default: - g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - (ldd->ld.interestRate / 100), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - break; - } -} - -static -void -ld_get_ipmt_formula( LoanDruidData *ldd, GString *gstr ) -{ - gint rate_case; - gfloat pass_thru_rate; - g_assert( ldd != NULL ); - g_assert( gstr != NULL ); - rate_case = ldd->ld.rateType; - pass_thru_rate = ldd->ld.interestRate / 100; - switch (rate_case) - { - case GNC_IRATE_SIMPLE: - { - g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - pass_thru_rate, - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - case GNC_IRATE_APR_DAILY: - { - g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 365), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - case GNC_IRATE_APR_WEEKLY: - { - g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 52), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - case GNC_IRATE_APR_MONTHLY: - { - g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 12), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - case GNC_IRATE_APR_QUARTERLY: - { - g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 4), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - case GNC_IRATE_APR_ANNUALLY: - { - g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - ld_apr_to_simple_formula(pass_thru_rate, 1), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - } - break; - default: - g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", - (ldd->ld.interestRate / 100), - 12.0, - ( ldd->ld.numPer - * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., - gnc_numeric_to_double(ldd->ld.principal)); - break; - } -} - -static -void -ld_close_handler( LoanDruidData *ldd ) -{ - gtk_widget_hide( ldd->dialog ); - gtk_widget_destroy( ldd->dialog ); -} - -static -void -ld_destroy( GtkObject *o, gpointer ud ) -{ - LoanDruidData *ldd; - - ldd = (LoanDruidData*)ud; - - g_assert( ldd ); - - gnc_unregister_gui_component_by_data - (DIALOG_LOAN_DRUID_CM_CLASS, ldd); - - /* free alloc'd mem; cleanup */ - - /* repay opts */ - { - int i; - - g_date_free( ldd->ld.startDate ); - g_date_free( ldd->ld.varStartDate ); - recurrenceListFree(&ldd->ld.loan_schedule); - - if ( ldd->ld.repMemo ) - g_free( ldd->ld.repMemo ); - - for ( i = 0; i < ldd->ld.repayOptCount; i++ ) - { - RepayOptData *rod = ldd->ld.repayOpts[i]; - if ( rod->name ) - g_free( rod->name ); - if ( rod->txnMemo ) - g_free( rod->txnMemo ); - - if ( rod->startDate ) - g_date_free( rod->startDate ); - - if (rod->schedule != NULL) - recurrenceListFree(&rod->schedule); - - g_free( ldd->ld.repayOpts[i] ); - g_free( ldd->repayOptsUI[i] ); - } - g_free( ldd->ld.repayOpts ); - g_free( ldd->repayOptsUI ); - - if ( ldd->ld.repAmount ) - g_free( ldd->ld.repAmount ); - - g_date_free( ldd->ld.repStartDate ); - } - - /* review */ - { - if ( ldd->ld.revSchedule ) - { - g_list_foreach( ldd->ld.revSchedule, - ld_rev_sched_list_free, - NULL ); - g_list_free( ldd->ld.revSchedule ); - ldd->ld.revSchedule = NULL; - } - } - - g_free( ldd ); -} - - -static -void -ld_cancel_check( GnomeDruid *gd, LoanDruidData *ldd ) -{ - const char *cancelMsg = _( "Are you sure you want to cancel " - "the Mortgage/Loan Setup Assistant?" ); - if ( gnc_verify_dialog( ldd->dialog, FALSE, "%s", cancelMsg ) ) - { - gnc_close_gui_component_by_data( DIALOG_LOAN_DRUID_CM_CLASS, - ldd ); - } -} - -static -void -ld_prm_type_changed( GtkWidget *w, gpointer ud ) -{ - LoanDruidData *ldd; + LoanAssistantData *ldd = user_data; gint index; - ldd = (LoanDruidData*)ud; index = gtk_combo_box_get_active( ldd->prmType ); gtk_widget_set_sensitive( GTK_WIDGET(ldd->prmVarFrame), index != GNC_FIXED ); } + static void -ld_escrow_toggle( GtkToggleButton *tb, gpointer ud ) +loan_info_calc_update_cb( GtkWidget *w, gpointer user_data ) { - int i; - gboolean newState; - RepayOptUIData *rouid; - LoanDruidData *ldd; + LoanAssistantData *ldd = user_data; + GDate start, now; + int i, totalVal, total, remain; - ldd = (LoanDruidData*)ud; - newState = gtk_toggle_button_get_active(tb); - gtk_widget_set_sensitive( GTK_WIDGET(ldd->optEscrowHBox), newState ); - /* deal with escrow options. */ - for ( i = 0; i < ldd->ld.repayOptCount; i++ ) + g_date_clear( &start, 1 ); + g_date_clear( &now, 1 ); + g_date_set_time_t( &start, gnc_date_edit_get_date( ldd->prmStartDateGDE ) ); + g_date_set_time_t( &now, time(NULL) ); + for ( i = 0; g_date_compare( &start, &now ) < 0; i++ ) { - rouid = ldd->repayOptsUI[i]; - /* If we're going off, then uncheck and desensitize all escrow opts. */ - /* If we're going on, then sensitize all escrow opts. */ - - /* prevent the toggle handler from running and "trashing" the - * state of the throughEscrowP selection */ - g_signal_handlers_block_by_func( rouid->escrowCb, - ld_escrow_toggled, - rouid ); - gtk_toggle_button_set_active( - GTK_TOGGLE_BUTTON(rouid->escrowCb), - ( newState - && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(rouid->optCb) ) - && rouid->optData->throughEscrowP ) ); - gtk_widget_set_sensitive( - GTK_WIDGET(rouid->escrowCb), - newState - && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(rouid->optCb) ) ); - g_signal_handlers_unblock_by_func( rouid->escrowCb, - ld_escrow_toggled, - rouid ); - if ( newState ) - { - rouid->optData->from = ldd->ld.escrowAcct; - } - else - { - rouid->optData->from = NULL; - } + g_date_add_months( &start, 1 ); } + + /* Get the correct, current value of the length spin. */ + { + gchar *valueStr = gtk_editable_get_chars( GTK_EDITABLE(ldd->prmLengthSpin), + 0, -1 ); + totalVal = strtol( valueStr, NULL, 10 ); + g_free( valueStr ); + } + total = totalVal + * ( gtk_combo_box_get_active( ldd->prmLengthType ) + == 1 ? 12 : 1 ); + remain = total - i; + gtk_spin_button_set_value( ldd->prmRemainSpin, remain ); + gtk_widget_show( GTK_WIDGET(ldd->prmRemainSpin) ); } -static + void -ld_opt_toggled( GtkToggleButton *tb, gpointer ud ) +loan_info_page_valid_cb (GtkWidget *widget, gpointer user_data ) { - RepayOptUIData *rouid; + LoanAssistantData *ldd = user_data; + GtkAssistant *assistant = GTK_ASSISTANT(ldd->window); + gint num = gtk_assistant_get_current_page (assistant); + GtkWidget *page = gtk_assistant_get_nth_page (assistant, num); - rouid = (RepayOptUIData*)ud; - rouid->optData->enabled = gtk_toggle_button_get_active(tb); + gtk_assistant_set_page_complete (assistant, page, + loan_info_page_complete (assistant, ldd)); } -static -void -ld_opt_consistency( GtkToggleButton *tb, gpointer ud ) -{ - GtkToggleButton *escrowCb; - RepayOptUIData *rouid; - - rouid = (RepayOptUIData*)ud; - escrowCb = GTK_TOGGLE_BUTTON(rouid->escrowCb); - /* make sure the escrow option is only selected if we're active. */ - gtk_toggle_button_set_active( escrowCb, - gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON( - rouid->ldd->optEscrowCb) ) - && rouid->optData->throughEscrowP - && gtk_toggle_button_get_active(tb) ); - /* make sure the escrow option is only sensitive if we're active, and - * the escrow account is enabled */ - gtk_widget_set_sensitive( GTK_WIDGET(escrowCb), - gtk_toggle_button_get_active(tb) - && gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(rouid->ldd->optEscrowCb)) ); -} - -static -void -ld_escrow_toggled( GtkToggleButton *tb, gpointer ud ) -{ - RepayOptUIData *rouid; - - rouid = (RepayOptUIData*)ud; - rouid->optData->throughEscrowP = gtk_toggle_button_get_active( tb ); -} static gboolean -ld_info_save( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) +loan_info_page_complete( GtkAssistant *assistant, gpointer user_data ) { - LoanDruidData *ldd; - - ldd = (LoanDruidData*)ud; + LoanAssistantData *ldd = user_data; ldd->ld.primaryAcct = gnc_account_sel_get_account( ldd->prmAccountGAS ); + /* Test for valid Account */ if ( ldd->ld.primaryAcct == NULL ) - { - gnc_info_dialog( ldd->dialog, "%s", - _("Please select a valid loan account.") ); - return TRUE; - } + return FALSE; + + return TRUE; +} + + +static +void +loan_info_page_save( GtkAssistant *assistant, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + + ldd->ld.primaryAcct = gnc_account_sel_get_account( ldd->prmAccountGAS ); + if ( ! ldd->ld.repPriAcct ) { ldd->ld.repPriAcct = ldd->ld.primaryAcct; @@ -1439,6 +1073,7 @@ ld_info_save( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) ldd->ld.interestRate = gtk_spin_button_get_value( ldd->prmIrateSpin ); ldd->ld.rateType = gtk_combo_box_get_active (ldd->prmIrateType ); ldd->ld.type = gtk_combo_box_get_active( ldd->prmType ); + if ( ldd->ld.type != GNC_FIXED ) { recurrenceListFree(&ldd->ld.loan_schedule); @@ -1470,91 +1105,24 @@ ld_info_save( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) ldd->ld.numMonRemain = gtk_spin_button_get_value_as_int( ldd->prmRemainSpin ); } - return FALSE; } +/************************************************************************/ + static void -ld_info_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - LoanDruidData *ldd; - - ldd = (LoanDruidData*)ud; - gnc_amount_edit_set_amount( ldd->prmOrigPrincGAE, ldd->ld.principal ); - gtk_spin_button_set_value( ldd->prmIrateSpin, ldd->ld.interestRate ); - gtk_combo_box_set_active( ldd->prmIrateType, ldd ->ld.rateType ); - gtk_combo_box_set_active( ldd->prmType, ldd->ld.type ); - if ( ldd->ld.type != GNC_FIXED ) - { - gnc_frequency_setup_recurrence(ldd->prmVarGncFreq, - ldd->ld.loan_schedule, - ldd->ld.varStartDate); - } - - /* start date */ - { - struct tm *tmpTm; - - tmpTm = g_new0( struct tm, 1 ); - - g_date_to_struct_tm( ldd->ld.startDate, tmpTm ); - gnc_date_edit_set_time( ldd->prmStartDateGDE, - mktime(tmpTm) ); - g_free( tmpTm ); - } - - /* length: total and remaining */ - { - gtk_spin_button_set_value( ldd->prmLengthSpin, ldd->ld.numPer ); - gtk_combo_box_set_active( ldd->prmLengthType, ldd->ld.perSize ); - gtk_spin_button_set_value( ldd->prmRemainSpin, ldd->ld.numMonRemain ); - } -} - -static -gboolean -ld_opts_save_state( LoanDruidData *ldd ) -{ - if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(ldd->optEscrowCb) ) ) - { - ldd->ld.escrowAcct = - gnc_account_sel_get_account( ldd->optEscrowGAS ); - if ( ldd->ld.escrowAcct == NULL ) - { - gnc_info_dialog( ldd->dialog, "%s", - _("Please select a valid " - "Escrow Account.") ); - return TRUE; - } - - } - else - { - ldd->ld.escrowAcct = NULL; - } - return FALSE; -} - -static -gboolean -ld_opts_tran( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - return ld_opts_save_state( (LoanDruidData*)ud ); -} - -static -void -ld_opts_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) +loan_opt_prep( GtkAssistant *assistant, gpointer user_data ) { int i; RepayOptUIData *rouid; - LoanDruidData *ldd; + LoanAssistantData *ldd = user_data; + + /* Save Previous Page ( Information ) */ + loan_info_page_save(assistant, ldd); - ldd = (LoanDruidData*)ud; if ( ldd->ld.escrowAcct ) { - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->optEscrowCb), - TRUE ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->optEscrowCb), TRUE ); gnc_account_sel_set_account( ldd->optEscrowGAS, ldd->ld.escrowAcct, FALSE ); } for ( i = 0; i < ldd->ld.repayOptCount; i++ ) @@ -1572,10 +1140,249 @@ ld_opts_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) } } + +static +void +loan_opt_toggled_cb( GtkToggleButton *tb, gpointer user_data ) +{ + RepayOptUIData *rouid; + + rouid = (RepayOptUIData*)user_data; + rouid->optData->enabled = gtk_toggle_button_get_active(tb); +} + + +static +void +loan_opt_consistency_cb( GtkToggleButton *tb, gpointer user_data ) +{ + GtkToggleButton *escrowCb; + RepayOptUIData *rouid; + + rouid = (RepayOptUIData*)user_data; + escrowCb = GTK_TOGGLE_BUTTON(rouid->escrowCb); + /* make sure the escrow option is only selected if we're active. */ + gtk_toggle_button_set_active( escrowCb, + gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON( + rouid->ldd->optEscrowCb) ) + && rouid->optData->throughEscrowP + && gtk_toggle_button_get_active(tb) ); + /* make sure the escrow option is only sensitive if we're active, and + * the escrow account is enabled */ + gtk_widget_set_sensitive( GTK_WIDGET(escrowCb), + gtk_toggle_button_get_active(tb) + && gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(rouid->ldd->optEscrowCb)) ); +} + + +static +void +loan_opt_escrow_toggle_cb( GtkToggleButton *tb, gpointer user_data ) +{ + int i; + gboolean newState; + RepayOptUIData *rouid; + LoanAssistantData *ldd = user_data; + GtkAssistant *assistant = GTK_ASSISTANT(ldd->window); + gint num = gtk_assistant_get_current_page (assistant); + GtkWidget *page = gtk_assistant_get_nth_page (assistant, num); + + newState = gtk_toggle_button_get_active(tb); + gtk_widget_set_sensitive( GTK_WIDGET(ldd->optEscrowHBox), newState ); + /* Check for Valid Account if enabled */ + if (newState) + { + if (GNC_ACCOUNT_SEL( ldd->ld.escrowAcct) == NULL) + gtk_assistant_set_page_complete (assistant, page, FALSE); + } + else + { + ldd->ld.escrowAcct = NULL; + gnc_account_sel_set_account( GNC_ACCOUNT_SEL( ldd->optEscrowGAS), NULL , FALSE ); + gtk_assistant_set_page_complete (assistant, page, TRUE); + } + + + /* deal with escrow options. */ + for ( i = 0; i < ldd->ld.repayOptCount; i++ ) + { + rouid = ldd->repayOptsUI[i]; + /* If we're going off, then uncheck and desensitize all escrow opts. */ + /* If we're going on, then sensitize all escrow opts. */ + + /* prevent the toggle handler from running and "trashing" the + * state of the throughEscrowP selection */ + g_signal_handlers_block_by_func( rouid->escrowCb, + loan_opt_escrow_toggled_cb, + rouid ); + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(rouid->escrowCb), + ( newState + && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(rouid->optCb) ) + && rouid->optData->throughEscrowP ) ); + gtk_widget_set_sensitive( + GTK_WIDGET(rouid->escrowCb), + newState + && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(rouid->optCb) ) ); + g_signal_handlers_unblock_by_func( rouid->escrowCb, + loan_opt_escrow_toggled_cb, + rouid ); + if ( newState ) + { + rouid->optData->from = ldd->ld.escrowAcct; + } + else + { + rouid->optData->from = NULL; + } + } +} + + +static +void +loan_opt_escrow_toggled_cb( GtkToggleButton *tb, gpointer user_data ) +{ + RepayOptUIData *rouid; + + rouid = (RepayOptUIData*)user_data; + rouid->optData->throughEscrowP = gtk_toggle_button_get_active( tb ); +} + + +void +loan_opt_page_valid_cb (GtkWidget *widget, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + + GtkAssistant *assistant = GTK_ASSISTANT(ldd->window); + gint num = gtk_assistant_get_current_page (assistant); + GtkWidget *page = gtk_assistant_get_nth_page (assistant, num); + + gtk_assistant_set_page_complete (assistant, page, + loan_opt_page_complete (assistant, ldd)); +} + + static gboolean -ld_rep_save( LoanDruidData *ldd ) +loan_opt_page_complete( GtkAssistant *assistant, gpointer user_data ) { + LoanAssistantData *ldd = user_data; + + if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(ldd->optEscrowCb) ) ) + { + ldd->ld.escrowAcct = + gnc_account_sel_get_account( ldd->optEscrowGAS ); + /* Test for valid Account */ + if ( ldd->ld.escrowAcct == NULL ) + return FALSE; + } + else + { + ldd->ld.escrowAcct = NULL; + } + return TRUE; +} + +/************************************************************************/ + +static +void +loan_rep_prep( GtkAssistant *assistant, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + GString *str; + + if ( ldd->ld.repAmount ) + { + g_free( ldd->ld.repAmount ); + } + + str = g_string_sized_new( 64 ); + loan_get_pmt_formula( ldd, str); + ldd->ld.repAmount = str->str; + g_string_free( str, FALSE ); + + if ( ldd->ld.repMemo ) + gtk_entry_set_text( ldd->repTxnName, ldd->ld.repMemo ); + + if ( ldd->ld.repAmount ) + gtk_entry_set_text( ldd->repAmtEntry, ldd->ld.repAmount ); + + gnc_account_sel_set_account( ldd->repAssetsFromGAS, ldd->ld.repFromAcct, FALSE ); + gnc_account_sel_set_account( ldd->repPrincToGAS, ldd->ld.repPriAcct, FALSE ); + gnc_account_sel_set_account( ldd->repIntToGAS, ldd->ld.repIntAcct, FALSE ); + + g_signal_handlers_block_by_func( ldd->repGncFreq, loan_rep_page_valid_cb , ldd ); + gnc_frequency_setup_recurrence(ldd->repGncFreq, ldd->ld.repayment_schedule, ldd->ld.repStartDate); + g_signal_handlers_unblock_by_func( ldd->repGncFreq, loan_rep_page_valid_cb , ldd ); + + /* Find the first enabled option */ + { + int i; + for ( i = 0; // we can always start at 0, here. + (i < ldd->ld.repayOptCount) + && !ldd->ld.repayOpts[i]->enabled; + i++ ) + ; + if ( i < ldd->ld.repayOptCount ) + ldd->currentIdx = i; + else + ldd->currentIdx = -1; + } +} + + +void +loan_rep_page_valid_cb (GtkWidget *widget, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + GtkAssistant *assistant = GTK_ASSISTANT(ldd->window); + gint num = gtk_assistant_get_current_page (assistant); + GtkWidget *page = gtk_assistant_get_nth_page (assistant, num); + + gtk_assistant_set_page_complete (assistant, page, + loan_rep_page_complete (assistant, ldd)); +} + + +static +gboolean +loan_rep_page_complete( GtkAssistant *assistant, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + int i; + + ldd->ld.repFromAcct = + gnc_account_sel_get_account( ldd->repAssetsFromGAS ); + /* Test for valid Account */ + if ( ldd->ld.repFromAcct == NULL ) + return FALSE; + + ldd->ld.repPriAcct = + gnc_account_sel_get_account( ldd->repPrincToGAS ); + /* Test for valid Account */ + if ( ldd->ld.repPriAcct == NULL ) + return FALSE; + + ldd->ld.repIntAcct = + gnc_account_sel_get_account( ldd->repIntToGAS ); + /* Test for valid Account */ + if ( ldd->ld.repIntAcct == NULL ) + return FALSE; + + return TRUE; +} + + +static +void +loan_rep_page_save( GtkAssistant *assistant, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; int i; if ( ldd->ld.repMemo ) @@ -1590,209 +1397,322 @@ ld_rep_save( LoanDruidData *ldd ) ldd->ld.repFromAcct = gnc_account_sel_get_account( ldd->repAssetsFromGAS ); - if ( ldd->ld.repFromAcct == NULL ) - { - gnc_info_dialog( ldd->dialog, "%s", - _("Please select a valid \"from\" account.")); - return TRUE; - } + ldd->ld.repPriAcct = gnc_account_sel_get_account( ldd->repPrincToGAS ); - if ( ldd->ld.repPriAcct == NULL ) - { - gnc_info_dialog( ldd->dialog, "%s", - _("Please select a valid \"to\" account.") ); - return TRUE; - } + ldd->ld.repIntAcct = gnc_account_sel_get_account( ldd->repIntToGAS ); - if ( ldd->ld.repIntAcct == NULL ) - { - gnc_info_dialog( ldd->dialog, "%s", - _("Please select a valid " - "\"interest\" account.") ); - return TRUE; - } + recurrenceListFree(&ldd->ld.repayment_schedule); gnc_frequency_save_to_recurrence(ldd->repGncFreq, &ldd->ld.repayment_schedule, ldd->ld.repStartDate); - - /* Set the 'from' accounts of the various options to be the - * Assets-From account, if they're not already something else. */ - for ( i = 0; i < ldd->ld.repayOptCount; i++ ) - { - RepayOptData *rod = ldd->ld.repayOpts[i]; - if ( ! rod->from ) - { - rod->from = ldd->ld.repFromAcct; - } - } - return FALSE; } -static -gboolean -ld_rep_next( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - LoanDruidData *ldd; - - ldd = (LoanDruidData*)ud; - - if ( ld_rep_save( ldd ) != FALSE ) - { - DEBUG( "Couldn't save, stopping here." ); - return TRUE; - } - - { - int i; - for ( i = 0; // we can always start at 0, here. - (i < ldd->ld.repayOptCount) - && !ldd->ld.repayOpts[i]->enabled; - i++ ) - ; - if ( i < ldd->ld.repayOptCount ) - { - ldd->currentIdx = i; - return FALSE; - } - } - gnome_druid_set_page( ldd->druid, - GNOME_DRUID_PAGE( - glade_xml_get_widget( ldd->gxml, - PG_REVIEW ) ) ); - return TRUE; -} - -static -gboolean -ld_rep_back( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - LoanDruidData *ldd; - - ldd = (LoanDruidData*)ud; - return ld_rep_save(ldd); -} +/************************************************************************/ static void -ld_rep_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) +loan_pay_prep( GtkAssistant *assistant, gpointer user_data ) { - LoanDruidData *ldd; - GString *str; - - - ldd = (LoanDruidData*)ud; - - if ( ldd->ld.repAmount ) - { - g_free( ldd->ld.repAmount ); - } - - str = g_string_sized_new( 64 ); - ld_get_pmt_formula( ldd, str); - ldd->ld.repAmount = str->str; - g_string_free( str, FALSE ); - - if ( ldd->ld.repMemo ) - gtk_entry_set_text( ldd->repTxnName, ldd->ld.repMemo ); - - if ( ldd->ld.repAmount ) - gtk_entry_set_text( ldd->repAmtEntry, ldd->ld.repAmount ); - - gnc_account_sel_set_account( ldd->repAssetsFromGAS, - ldd->ld.repFromAcct, FALSE ); - gnc_account_sel_set_account( ldd->repPrincToGAS, - ldd->ld.repPriAcct, FALSE ); - gnc_account_sel_set_account( ldd->repIntToGAS, - ldd->ld.repIntAcct, FALSE ); - gnc_frequency_setup_recurrence(ldd->repGncFreq, - ldd->ld.repayment_schedule, - ldd->ld.repStartDate); -} - -static -void -ld_pay_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - LoanDruidData *ldd; + LoanAssistantData *ldd = user_data; RepayOptData *rod; GString *str; - gboolean uniq; - ldd = (LoanDruidData*)ud; + + gint num = gtk_assistant_get_current_page (assistant); + GtkWidget *page = gtk_assistant_get_nth_page (assistant, num); + + /* Save Previous Page (Repayment) */ + loan_rep_page_save(assistant, ldd); + + /* Step over page if no options enabled */ + if (ldd->currentIdx == -1 ) + { + gtk_assistant_set_current_page (assistant, num + 1); + } + else + { + g_assert( ldd->currentIdx >= 0 ); + g_assert( ldd->currentIdx <= ldd->ld.repayOptCount ); + + rod = ldd->ld.repayOpts[ldd->currentIdx]; + str = g_string_sized_new( 32 ); + /* Translators: %s is "Taxes", or "Insurance", or similar */ + g_string_printf( str, _("Loan Repayment Option: \"%s\""), rod->name ); + gtk_assistant_set_page_title (assistant, page, str->str ); + + /* copy in the relevant data from the currently-indexed option. */ + gtk_entry_set_text( ldd->payTxnName, rod->txnMemo ); + g_string_printf( str, "%0.2f", rod->amount ); + gtk_entry_set_text( ldd->payAmtEntry, str->str ); + + gtk_widget_set_sensitive( GTK_WIDGET(ldd->payUseEscrow), + (ldd->ld.escrowAcct != NULL) ); + + { + g_signal_handlers_block_by_func( ldd->payUseEscrow, + loan_pay_use_esc_toggle_cb, + ldd ); + + loan_pay_use_esc_setup( ldd, + (ldd->ld.escrowAcct != NULL) + && rod->throughEscrowP ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payUseEscrow), + (rod->throughEscrowP + && ldd->ld.escrowAcct != NULL) ); + + g_signal_handlers_unblock_by_func( ldd->payUseEscrow, + loan_pay_use_esc_toggle_cb, + ldd ); + } + + { + g_signal_handlers_block_by_func( ldd->paySpecSrcAcct, + loan_pay_spec_src_toggle_cb, + ldd ); + loan_pay_spec_src_setup( ldd, rod->specSrcAcctP ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->paySpecSrcAcct), + rod->specSrcAcctP ); + + g_signal_handlers_unblock_by_func( ldd->paySpecSrcAcct, + loan_pay_spec_src_toggle_cb, + ldd ); + } + + g_signal_handlers_block_by_func(ldd->payAcctToGAS, loan_pay_page_valid_cb, ldd ); + gnc_account_sel_set_account( ldd->payAcctToGAS, rod->to, FALSE ); + g_signal_handlers_unblock_by_func(ldd->payAcctToGAS, loan_pay_page_valid_cb, ldd ); + + + g_signal_handlers_block_by_func(ldd->payTxnFreqUniqRb, loan_pay_freq_toggle_cb, ldd ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqPartRb), !rod->FreqUniq ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb), rod->FreqUniq ); + g_signal_handlers_unblock_by_func(ldd->payTxnFreqUniqRb, loan_pay_freq_toggle_cb, ldd ); + + gtk_widget_set_sensitive( GTK_WIDGET(ldd->payFreqAlign), rod->FreqUniq ); + + if ( rod->FreqUniq ) + { + g_signal_handlers_disconnect_by_func( ldd->payGncFreq, loan_pay_page_valid_cb, ldd ); + gtk_container_remove( GTK_CONTAINER(ldd->payFreqAlign), GTK_WIDGET(ldd->payGncFreq) ); + ldd->payGncFreq = NULL; + ldd->payGncFreq = GNC_FREQUENCY(gnc_frequency_new_from_recurrence( rod->schedule, rod->startDate )); + gtk_container_add( GTK_CONTAINER(ldd->payFreqAlign), GTK_WIDGET(ldd->payGncFreq) ); + g_signal_connect (ldd->payGncFreq, "changed", + G_CALLBACK (loan_pay_page_valid_cb), ldd); + } + g_string_free( str, TRUE ); + loan_pay_page_valid_cb(GTK_WIDGET(ldd->window), ldd); + } +} + + +void +loan_pay_page_valid_cb (GtkWidget *widget, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + GtkAssistant *assistant = GTK_ASSISTANT(ldd->window); + gint num = gtk_assistant_get_current_page (assistant); + GtkWidget *page = gtk_assistant_get_nth_page (assistant, num); + + gtk_assistant_set_page_complete (assistant, page, + ( loan_pay_complete (assistant, ldd) && + loan_pay_all_opt_valid (assistant, ldd ))); +} + + +static +void +loan_pay_use_esc_setup( LoanAssistantData *ldd, gboolean newState ) +{ + gtk_widget_set_sensitive( GTK_WIDGET(ldd->payEscToLabel), newState ); + gtk_widget_set_sensitive( GTK_WIDGET(ldd->payEscFromLabel), newState ); + if ( newState ) + { + g_signal_handlers_block_by_func( ldd->payAcctEscToGAS, loan_pay_page_valid_cb, ldd ); + g_signal_handlers_block_by_func( ldd->payAcctEscFromGAS, loan_pay_page_valid_cb, ldd ); + gnc_account_sel_set_account( ldd->payAcctEscToGAS, ldd->ld.escrowAcct, FALSE ); + gnc_account_sel_set_account( ldd->payAcctEscFromGAS, ldd->ld.escrowAcct, FALSE ); + g_signal_handlers_unblock_by_func( ldd->payAcctEscToGAS, loan_pay_page_valid_cb, ldd ); + g_signal_handlers_unblock_by_func( ldd->payAcctEscFromGAS, loan_pay_page_valid_cb, ldd ); + } +} + + +static +void +loan_pay_use_esc_toggle_cb( GtkToggleButton *tb, gpointer user_data ) +{ + gboolean newState; + LoanAssistantData *ldd = user_data; + + newState = gtk_toggle_button_get_active( tb ); + loan_pay_use_esc_setup( ldd, newState ); +} + + +static +void +loan_pay_spec_src_setup( LoanAssistantData *ldd, gboolean newState ) +{ + gtk_widget_set_sensitive( GTK_WIDGET(ldd->payAcctFromLabel), newState ); + gtk_widget_set_sensitive( GTK_WIDGET(ldd->payAcctFromGAS), newState ); + if ( newState ) + { + g_signal_handlers_block_by_func( ldd->payAcctFromGAS, loan_pay_page_valid_cb, ldd ); + gnc_account_sel_set_account( ldd->payAcctFromGAS, ldd->ld.repayOpts[ldd->currentIdx]->from, FALSE ); + g_signal_handlers_unblock_by_func( ldd->payAcctFromGAS, loan_pay_page_valid_cb, ldd ); + } + else + { + g_signal_handlers_block_by_func( ldd->payAcctFromGAS, loan_pay_page_valid_cb, ldd ); + gnc_account_sel_set_account( ldd->payAcctFromGAS, NULL, FALSE ); + ldd->ld.repayOpts[ldd->currentIdx]->from = NULL; + g_signal_handlers_unblock_by_func( ldd->payAcctFromGAS, loan_pay_page_valid_cb, ldd ); + } +} + + +static +void +loan_pay_spec_src_toggle_cb( GtkToggleButton *tb, gpointer user_data ) +{ + gboolean newState; + LoanAssistantData *ldd = user_data; + + newState = gtk_toggle_button_get_active( tb ); + loan_pay_spec_src_setup( ldd, newState ); +} + + +static +void +loan_pay_freq_toggle_cb( GtkToggleButton *tb, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + RepayOptData *rod; + g_assert( ldd->currentIdx >= 0 ); g_assert( ldd->currentIdx <= ldd->ld.repayOptCount ); rod = ldd->ld.repayOpts[ldd->currentIdx]; - str = g_string_sized_new( 32 ); - /* Translators: %s is "Taxes", or "Insurance", or similar */ - g_string_printf( str, _("Payment: \"%s\""), rod->name ); - gnome_druid_page_standard_set_title( GNOME_DRUID_PAGE_STANDARD(gdp), - str->str ); - /* copy in the relevant data from the currently-indexed - * option. */ - gtk_entry_set_text( ldd->payTxnName, rod->txnMemo ); - g_string_printf( str, "%0.2f", rod->amount ); - gtk_entry_set_text( ldd->payAmtEntry, str->str ); - gtk_widget_set_sensitive( GTK_WIDGET(ldd->payUseEscrow), - (ldd->ld.escrowAcct != NULL) ); + rod->FreqUniq = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb) ); + gtk_widget_set_sensitive( GTK_WIDGET(ldd->payFreqAlign), rod->FreqUniq ); + if ( rod->FreqUniq ) { - g_signal_handlers_block_by_func( ldd->payUseEscrow, - ld_pay_use_esc_toggle, - ldd ); + if ( rod->schedule == NULL ) + { + Recurrence *r = g_new0(Recurrence, 1); - ld_pay_use_esc_setup( ldd, - (ldd->ld.escrowAcct != NULL) - && rod->throughEscrowP ); - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payUseEscrow), - (rod->throughEscrowP - && ldd->ld.escrowAcct != NULL) ); - - g_signal_handlers_unblock_by_func( ldd->payUseEscrow, - ld_pay_use_esc_toggle, - ldd ); + recurrenceSet(r, 1, PERIOD_MONTH, ldd->ld.startDate, WEEKEND_ADJ_NONE); + rod->schedule = g_list_append(rod->schedule, r); + } + if ( rod->startDate == NULL ) + { + rod->startDate = g_date_new(); + *rod->startDate = *ldd->ld.startDate; + } + g_signal_handlers_block_by_func( ldd->payGncFreq, loan_pay_page_valid_cb, ldd ); + gnc_frequency_setup_recurrence(ldd->payGncFreq, rod->schedule, rod->startDate); + g_signal_handlers_unblock_by_func( ldd->payGncFreq, loan_pay_page_valid_cb, ldd ); } - + else { - g_signal_handlers_block_by_func( ldd->paySpecSrcAcct, - ld_pay_spec_src_toggle, - ldd ); - - ld_pay_spec_src_setup( ldd, rod->specSrcAcctP ); - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->paySpecSrcAcct), - rod->specSrcAcctP ); - - g_signal_handlers_unblock_by_func( ldd->paySpecSrcAcct, - ld_pay_spec_src_toggle, - ldd ); + if (rod->schedule) + { + recurrenceListFree(&rod->schedule); + } + if ( rod->startDate ) + { + g_date_free( rod->startDate ); + rod->startDate = NULL; + } } - - gnc_account_sel_set_account( ldd->payAcctToGAS, rod->to, FALSE ); - - uniq = (rod->schedule != NULL); - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqPartRb), - !uniq ); - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb), - uniq ); - gtk_widget_set_sensitive( GTK_WIDGET(ldd->payFreqAlign), - uniq ); - if ( uniq ) - { - gnc_frequency_setup_recurrence( ldd->payGncFreq, rod->schedule, rod->startDate ); - } - - g_string_free( str, TRUE ); } + +static +void +loan_pay_next_button_cb( GtkButton *button, gpointer user_data ) +{ + int i; + LoanAssistantData *ldd = user_data; + + /* save current data */ + if ( loan_pay_complete ( GTK_ASSISTANT(ldd->window), user_data ) != FALSE ) + { + /* Go through opts list and select next enabled option. */ + for ( i = ldd->currentIdx + 1; + (i < ldd->ld.repayOptCount) + && !ldd->ld.repayOpts[i]->enabled; i++ ) + ; + if ( i < ldd->ld.repayOptCount ) + { + ldd->currentIdx = i; + loan_pay_prep( GTK_ASSISTANT(ldd->window), user_data ); + } + } +} + + +static +void +loan_pay_back_button_cb( GtkButton *button, gpointer user_data ) +{ + int i; + LoanAssistantData *ldd = user_data; + + /* save current data */ + if ( loan_pay_complete ( GTK_ASSISTANT(ldd->window), user_data ) != FALSE) + { + /* go back through opts list and select next enabled options. */ + for ( i = ldd->currentIdx - 1; + (i > -1) && !ldd->ld.repayOpts[i]->enabled; + i-- ) + ; + if ( i >= 0 ) + { + ldd->currentIdx = i; + loan_pay_prep( GTK_ASSISTANT(ldd->window), user_data ); + } + } +} + + static gboolean -ld_pay_save_current( LoanDruidData *ldd ) +loan_pay_all_opt_valid ( GtkAssistant *assistant, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + int i; + gboolean all_valid; + all_valid = FALSE; + + /* Go through all option pages checking for valid enabled pages */ + for ( i = 0; (i < ldd->ld.repayOptCount); i++ ) + { + if (ldd->ld.repayOpts[i]->enabled) + { + if (ldd->ld.repayOpts[i]->optValid) + all_valid = TRUE; + else + all_valid = FALSE; + } + } + return all_valid; +} + + +static +gboolean +loan_pay_complete( GtkAssistant *assistant, gpointer user_data ) { gchar *tmpStr; + LoanAssistantData *ldd = user_data; RepayOptData *rod; g_assert( ldd->currentIdx >= 0 ); @@ -1817,249 +1737,59 @@ ld_pay_save_current( LoanDruidData *ldd ) gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(ldd->paySpecSrcAcct) ); - rod->from = NULL; + /* Test for Valid From Account */ if ( rod->specSrcAcctP ) { rod->from = gnc_account_sel_get_account( ldd->payAcctFromGAS ); if ( rod->from == NULL ) - { - gnc_info_dialog( ldd->dialog, "%s", - _("Please select a valid " - "\"from\" account.") ); - return TRUE; - } + return FALSE; } - rod->to = gnc_account_sel_get_account( ldd->payAcctToGAS ); + /* Test for Valid To Account */ + rod->to = gnc_account_sel_get_account( ldd->payAcctToGAS ); if ( rod->to == NULL ) - { - gnc_info_dialog( ldd->dialog, "%s", - _("Please select a valid " - "\"to\" account.") ); - return TRUE; - } + return FALSE; - /* if ( rb toggled ) - * ensure schedule/startdate setup - * save - * else - * if (freqspec setup) - * remove schedule/startdate - */ + /* Set Page Valid */ + rod->optValid = TRUE; - /* neither of these should happen. */ - g_assert( ! (rod->schedule && !rod->startDate) ); - g_assert( ! (!rod->schedule && rod->startDate) ); - - if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb)) ) + /* If Uniq Freq, then save to recurrence */ + if ( rod->FreqUniq ) { if ( rod->startDate == NULL ) { rod->startDate = g_date_new(); } recurrenceListFree(&rod->schedule); - gnc_frequency_save_to_recurrence(ldd->payGncFreq, - &rod->schedule, - rod->startDate); + gnc_frequency_save_to_recurrence(ldd->payGncFreq, &rod->schedule, rod->startDate); + + if(! rod->schedule ) + { + return FALSE; + } } - else - { - if (rod->schedule) - { - recurrenceListFree(&rod->schedule); - } - if ( rod->startDate ) - { - g_date_free( rod->startDate ); - rod->startDate = NULL; - } - } - return FALSE; -} - -static -gboolean -ld_pay_next( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - int i; - LoanDruidData *ldd; - - ldd = (LoanDruidData*)ud; - /* save current data */ - if ( ld_pay_save_current( ldd ) != FALSE ) - { - return TRUE; - } - - /* Go through opts list and select next enabled option. */ - for ( i = ldd->currentIdx + 1; - (i < ldd->ld.repayOptCount) - && !ldd->ld.repayOpts[i]->enabled; i++ ) - ; - - if ( i < ldd->ld.repayOptCount ) - { - ldd->currentIdx = i; - ld_pay_prep( gdp, arg1, ud ); - return TRUE; - } - - /* If there's no repayment options enabled, then go immediately to - * the review page. */ - gnome_druid_set_page( ldd->druid, - GNOME_DRUID_PAGE( - glade_xml_get_widget( ldd->gxml, - PG_REVIEW ) ) ); return TRUE; } -static -gboolean -ld_pay_back( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - int i; - LoanDruidData *ldd; - - ldd = (LoanDruidData*)ud; - - /* save current data */ - if ( ld_pay_save_current( ldd ) != FALSE ) - { - return TRUE; - } - - /* go back through opts list and select next enabled options. */ - for ( i = ldd->currentIdx - 1; - (i > -1) && !ldd->ld.repayOpts[i]->enabled; - i-- ) - ; - if ( i >= 0 ) - { - ldd->currentIdx = i; - ld_pay_prep( gdp, arg1, ud ); - return TRUE; - } - ldd->currentIdx = -1; - return FALSE; -} +/************************************************************************/ static void -ld_pay_freq_toggle( GtkToggleButton *tb, gpointer ud ) -{ - LoanDruidData *ldd; - gboolean uniq; - - ldd = (LoanDruidData*)ud; - - g_assert( ldd->currentIdx >= 0 ); - g_assert( ldd->currentIdx <= ldd->ld.repayOptCount ); - - uniq = gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(ldd->payTxnFreqUniqRb) ); - gtk_widget_set_sensitive( GTK_WIDGET(ldd->payFreqAlign), uniq ); - - if ( uniq ) - { - RepayOptData *rod; - rod = ldd->ld.repayOpts[ ldd->currentIdx ]; - - if ( rod->schedule == NULL ) - { - Recurrence *r = g_new0(Recurrence, 1); - recurrenceSet(r, 1, PERIOD_MONTH, ldd->ld.startDate, WEEKEND_ADJ_NONE); - rod->schedule = g_list_append(rod->schedule, r); - } - if ( rod->startDate == NULL ) - { - rod->startDate = g_date_new(); - *rod->startDate = *ldd->ld.startDate; - } - gnc_frequency_setup_recurrence(ldd->payGncFreq, - rod->schedule, - rod->startDate); - } -} - -static -void -ld_pay_use_esc_setup( LoanDruidData *ldd, gboolean newState ) -{ - gtk_widget_set_sensitive( GTK_WIDGET(ldd->payEscToLabel), newState ); - gtk_widget_set_sensitive( GTK_WIDGET(ldd->payEscFromLabel), newState ); - if ( newState ) - { - gnc_account_sel_set_account( ldd->payAcctEscToGAS, - ldd->ld.escrowAcct, FALSE ); - gnc_account_sel_set_account( ldd->payAcctEscFromGAS, - ldd->ld.escrowAcct, FALSE ); - } -} - -static -void -ld_pay_use_esc_toggle( GtkToggleButton *tb, gpointer ud ) -{ - gboolean newState; - LoanDruidData *ldd = (LoanDruidData*)ud; - - newState = gtk_toggle_button_get_active( tb ); - ld_pay_use_esc_setup( ldd, newState ); -} - -static -void -ld_pay_spec_src_setup( LoanDruidData *ldd, gboolean newState ) -{ - gtk_widget_set_sensitive( GTK_WIDGET(ldd->payAcctFromLabel), newState ); - gtk_widget_set_sensitive( GTK_WIDGET(ldd->payAcctFromGAS), newState ); - if ( newState ) - { - gnc_account_sel_set_account( ldd->payAcctFromGAS, - ldd->ld.repayOpts[ldd->currentIdx] - ->from, FALSE ); - } -} - -static -void -ld_pay_spec_src_toggle( GtkToggleButton *tb, gpointer ud ) -{ - gboolean newState; - LoanDruidData *ldd = (LoanDruidData*)ud; - - newState = gtk_toggle_button_get_active( tb ); - ld_pay_spec_src_setup( ldd, newState ); -} - -static -gboolean -ld_rev_next( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - LoanDruidData *ldd; - - ldd = (LoanDruidData*)ud; - gnome_druid_set_page( ldd->druid, - GNOME_DRUID_PAGE( - glade_xml_get_widget( ldd->gxml, - PG_COMMIT ) ) ); - return TRUE; -} - -static -void -ld_rev_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) +loan_rev_prep( GtkAssistant *assistant, gpointer user_data ) { /* 3, here, does not include the Date column. */ const static int BASE_COLS = 3; - LoanDruidData *ldd; + LoanAssistantData *ldd = user_data; GtkListStore *store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GType *types; int i; + int col=1; - ldd = (LoanDruidData*)ud; + /* Make sure we saved last Payment Option */ + if (ldd->currentIdx != -1) + loan_pay_complete(assistant, ldd); /* Cleanup old view */ if ( ldd->revView != NULL ) @@ -2082,7 +1812,6 @@ ld_rev_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) ldd->ld.revRepayOptToColMap[i] = ldd->ld.revNumPmts; ldd->ld.revNumPmts += 1; } - /* '+1' for leading date col */ types = g_new( GType, ldd->ld.revNumPmts + 1 ); for ( i = 0; i < ldd->ld.revNumPmts + 1; i++ ) @@ -2126,13 +1855,13 @@ ld_rev_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) { continue; } - renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes (ldd->ld.repayOpts[i]->name, renderer, - "text", LOAN_COL_INTEREST + i, + "text", LOAN_COL_INTEREST + col, NULL); gtk_tree_view_append_column(ldd->revView, column); + col++; } } @@ -2140,713 +1869,23 @@ ld_rev_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) GTK_WIDGET(ldd->revView) ); gtk_widget_show( GTK_WIDGET(ldd->revView) ); - ld_rev_recalc_schedule( ldd ); + loan_rev_recalc_schedule( ldd ); { GDate start, end; g_date_clear( &start, 1 ); g_date_clear( &end, 1 ); - ld_rev_get_dates( ldd, &start, &end ); - ld_rev_update_view( ldd, &start, &end ); + loan_rev_get_dates( ldd, &start, &end ); + loan_rev_update_view( ldd, &start, &end ); } } -static -gboolean -ld_rev_back( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - LoanDruidData *ldd = (LoanDruidData*)ud; - int i; - - /* Get the correct page based on the repayment state. */ - /* go back through opts list and select next enabled options. */ - for ( i = ldd->currentIdx; - (i > -1) && !ldd->ld.repayOpts[i]->enabled; - i-- ) - ; - if ( i >= 0 ) - { - ldd->currentIdx = i; - /* natural transition to the payments page */ - return FALSE; - } - - /* If there are no payment options, then go directly to the main - * repayment page. */ - gnome_druid_set_page( ldd->druid, - GNOME_DRUID_PAGE( - glade_xml_get_widget( ldd->gxml, - PG_REPAYMENT ) ) ); - return TRUE; -} - -static -gboolean -ld_com_next( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - g_assert( FALSE ); - return TRUE; -} static void -ld_com_prep( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) +loan_rev_range_opt_changed_cb( GtkComboBox *combo, gpointer user_data ) { -} - -static -gboolean -ld_com_back( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - LoanDruidData *ldd = (LoanDruidData*)ud; - gnome_druid_set_page( ldd->druid, - GNOME_DRUID_PAGE( - glade_xml_get_widget( ldd->gxml, - PG_REVIEW ) ) ); - return TRUE; -} - -static -void -ld_com_fin( GnomeDruidPage *gdp, gpointer arg1, gpointer ud ) -{ - LoanDruidData *ldd = (LoanDruidData*)ud; - ld_create_sxes( ldd ); - ld_close_handler( ldd ); - -} - -static int -ld_calc_sx_instance_num(GDate *start_date, GList *schedule) -{ - int instance_count; - GDate next_date, today; - - g_date_clear(&next_date, 1); - g_date_clear(&today, 1); - g_date_set_time_t(&today, time(NULL)); - - if (g_date_compare(start_date, &today) > 0) - return 0; - - instance_count = -1; - do - { - instance_count++; - recurrenceListNextInstance(schedule, start_date, &next_date); - } - while (g_date_compare(&next_date, &today) < 0); - - return instance_count; -} - -static -void -ld_tcSX_free( gpointer data, gpointer user_data ) -{ - toCreateSX *tcSX = (toCreateSX*)data; - g_free( tcSX->name ); - if ( tcSX->mainTxn ) - gnc_ttinfo_free( tcSX->mainTxn ); - if ( tcSX->escrowTxn ) - gnc_ttinfo_free( tcSX->escrowTxn ); - g_free( tcSX ); -} - -/** - * Custom GCompareFunc to find the element of a GList of TTSplitInfo's which - * has the given [Account*] criteria. - * @return 0 if match, as per GCompareFunc in the g_list_find_custom context. - **/ -static -gint -ld_find_ttsplit_with_acct( gconstpointer elt, - gconstpointer crit ) -{ - TTSplitInfo *ttsi = (TTSplitInfo*)elt; - return ( (gnc_ttsplitinfo_get_account( ttsi ) - == (Account*)crit) ? 0 : 1 ); -} - -/** - * Enters into the books a Scheduled Transaction from the given toCreateSX. - **/ -static -void -ld_create_sx_from_tcSX( LoanDruidData *ldd, toCreateSX *tcSX ) -{ - SchedXaction *sx; - SchedXactions *sxes; - GList *ttxnList; - - sx = xaccSchedXactionMalloc( gnc_get_current_book() ); - xaccSchedXactionSetName( sx, tcSX->name ); - gnc_sx_set_schedule(sx, tcSX->schedule); - xaccSchedXactionSetStartDate( sx, &tcSX->start ); - xaccSchedXactionSetLastOccurDate( sx, &tcSX->last ); - xaccSchedXactionSetEndDate( sx, &tcSX->end ); - gnc_sx_set_instance_count( sx, tcSX->instNum ); - - ttxnList = NULL; - if ( tcSX->mainTxn ) - ttxnList = g_list_append( ttxnList, tcSX->mainTxn ); - if ( tcSX->escrowTxn ) - ttxnList = g_list_append( ttxnList, tcSX->escrowTxn ); - - g_assert( ttxnList != NULL ); - - xaccSchedXactionSetTemplateTrans( sx, ttxnList, - gnc_get_current_book() ); - - sxes = gnc_book_get_schedxactions(gnc_get_current_book()); - gnc_sxes_add_sx(sxes, sx); - - g_list_free( ttxnList ); - ttxnList = NULL; -} - -/** - * Does the work to setup the given toCreateSX structure for a specific - * repayment. Note that if the RepayOptData doesn't specify a unique - * schedule, the paymentSX and the tcSX parameters will be the same. - **/ -static -void -ld_setup_repayment_sx( LoanDruidData *ldd, - RepayOptData *rod, - toCreateSX *paymentSX, - toCreateSX *tcSX ) -{ - /* In DoubleEntryAccounting-ease, this is what we're going to do, - * below... - * - * if ( rep->escrow ) { - * if ( rep->from ) { - * a: paymentSX.main.splits += split( rep->fromAcct, repAmt ) - * b: paymentSX.main.split( ldd->ld.escrowAcct ).debCred += repAmt - * tcSX.escrow.split( rep->escrow ).debCred += repAmt - * c1: tcSX.escrow.splits += split( rep->toAcct, +repAmt ) - * } else { - * d: paymentSX.main.split( ldd->ld.repFromAcct ).debcred += -repAmt - * b: paymentSX.main.split( ldd->ld.escrowAcct ).debCred += repAmt - * tcSX.escrow.splits += split( rep->escrow, -repAmt ) - * c1: tcSX.escrow.splits += split( rep->toAcct, +repAmt ) - * } - * } else { - * if ( rep->from ) { - * a: paymentSX.main.splits += split( rep->fromAcct, -repAmt ) - * c2: paymentSX.main.splits += split( rep->toAcct, +repAmt ) - * } else { - * d: paymentSX.main.split( ldd->ld.payFromAcct ).debcred += -repAmt - * c2: paymentSX.main.splits += split( rep->toAcct, +repAmt ) - * } - * } - */ - - /* Now, we refactor the common operations from the above out... - * - * fromSplit = NULL; - * if ( rep->escrow ) { - * b: paymentSX.main.split( ldd->ld.escrowAcct ).debCred += repAmt - * c1: ( toTTI = tcSX.escrow ) - * if ( rep->from ) { - * a1: (fromSplit = NULL) paymentSX.main.splits += split( rep->fromAcct, repAmt ) - * b: - * tcSX.escrow.split( rep->escrow ).debCred += repAmt - * c1: - * } else { - * a2: (fromSplit = paymentSX.main.split( ldd->ld.repFromAcct )) .debcred += -repAmt - * b: - * tcSX.escrow.splits += split( rep->escrow, -repAmt ) - * c1: - * } - * } else { - * c2: ( toTTI = paymentSX.main ) - * if ( rep->from ) { - * a1: (fromSplit = NULL) paymentSX.main.splits += split( rep->fromAcct, -repAmt ) - * c2: - * } else { - * a2: (fromSplit = paymentSX.main.split( ldd->ld.payFromAcct )).debcred += -repAmt - * c2: - * } - * } - * if ( fromSplit ) { - * fromSplit.debCred += (-repAmt); - * } else { - * fromSplit = split( rep->fromAcct, -repAmt ) - * paymentSX.main.splits += fromSplit - * } - * toTTI.splits += split( rep->toAcct, +repAmt ); - */ - - /** Now, the actual implementation... */ - - GString *gstr; - GList *elt; - TTSplitInfo *fromSplit = NULL; - TTSplitInfo *ttsi; - TTInfo *toTxn = NULL; - GNCPrintAmountInfo pricePAI = gnc_default_price_print_info(); -#define AMTBUF_LEN 64 - gchar amtBuf[AMTBUF_LEN]; - gint GNCN_HOW = (GNC_HOW_DENOM_SIGFIGS(2) | GNC_HOW_RND_ROUND_HALF_UP); - - /* We're going to use this a lot, below, so just create it once. */ - xaccSPrintAmount( amtBuf, - double_to_gnc_numeric( rod->amount, 100, - GNCN_HOW ), - pricePAI ); - - if ( rod->throughEscrowP && ldd->ld.escrowAcct ) - { - toTxn = tcSX->escrowTxn; - - /* Add the repayment amount into the string of the existing - * ttsplit. */ - { - elt = g_list_find_custom( - gnc_ttinfo_get_template_splits( paymentSX->mainTxn ), - ldd->ld.escrowAcct, - ld_find_ttsplit_with_acct ); - g_assert( elt ); - ttsi = (TTSplitInfo*)elt->data; - g_assert( ttsi ); - gstr = g_string_new( gnc_ttsplitinfo_get_debit_formula( ttsi ) ); - g_string_append_printf( gstr, " + %s", amtBuf ); - gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str ); - g_string_free( gstr, TRUE ); - gstr = NULL; - ttsi = NULL; - } - - if ( rod->from != NULL ) - { - gchar *str; - - fromSplit = NULL; - - /* tcSX.escrow.split( rep->escrow ).debCred += repAmt */ - elt = g_list_find_custom( - gnc_ttinfo_get_template_splits( tcSX->escrowTxn ), - ldd->ld.escrowAcct, - ld_find_ttsplit_with_acct ); - ttsi = NULL; - if ( elt ) - { - ttsi = (TTSplitInfo*)elt->data; - } - if ( !ttsi ) - { - /* create split */ - ttsi = gnc_ttsplitinfo_malloc(); - gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo ); - gnc_ttsplitinfo_set_account( ttsi, ldd->ld.escrowAcct ); - gnc_ttinfo_append_template_split( tcSX->escrowTxn, ttsi ); - } - if ( (str = (gchar*)gnc_ttsplitinfo_get_credit_formula( ttsi )) - == NULL ) - { - gstr = g_string_sized_new( 16 ); - } - else - { - /* If we did get a split/didn't have to - * create a split, then we need to add our - * amount in rather than replace. */ - gstr = g_string_new( str ); - g_string_append_printf( gstr, " + " ); - } - g_string_append_printf( gstr, "%s", amtBuf ); - gnc_ttsplitinfo_set_credit_formula( ttsi, gstr->str ); - g_string_free( gstr, TRUE ); - gstr = NULL; - ttsi = NULL; - } - else - { - /* (fromSplit = paymentSX.main.split( ldd->ld.repFromAcct )) */ - elt = g_list_find_custom( - gnc_ttinfo_get_template_splits( paymentSX->mainTxn ), - ldd->ld.repFromAcct, - ld_find_ttsplit_with_acct ); - g_assert( elt ); - fromSplit = (TTSplitInfo*)elt->data; - - /* tcSX.escrow.splits += split( rep->escrow, -repAmt ) */ - ttsi = gnc_ttsplitinfo_malloc(); - gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo ); - gnc_ttsplitinfo_set_account( ttsi, ldd->ld.escrowAcct ); - gnc_ttsplitinfo_set_credit_formula( ttsi, amtBuf ); - gnc_ttinfo_append_template_split( tcSX->escrowTxn, ttsi ); - ttsi = NULL; - } - } - else - { - toTxn = tcSX->mainTxn; - - if ( rod->from != NULL ) - { - fromSplit = NULL; - } - else - { - /* (fromSplit = paymentSX.main.split( ldd->ld.repFromAcct )) */ - elt = g_list_find_custom( - gnc_ttinfo_get_template_splits( tcSX->mainTxn ), - ldd->ld.repFromAcct, - ld_find_ttsplit_with_acct ); - fromSplit = NULL; - if ( elt ) - { - /* This is conditionally true in the case of - * a repayment on it's own schedule. */ - fromSplit = (TTSplitInfo*)elt->data; - } - } - } - - if ( fromSplit != NULL ) - { - /* Update the existing from-split. */ - gstr = g_string_new( gnc_ttsplitinfo_get_credit_formula( fromSplit ) ); - g_string_append_printf( gstr, " + %s", amtBuf ); - gnc_ttsplitinfo_set_credit_formula( fromSplit, gstr->str ); - g_string_free( gstr, TRUE ); - gstr = NULL; - - } - else - { - TTInfo *tti; - /* Create a new from-split. */ - ttsi = gnc_ttsplitinfo_malloc(); - gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo ); - if ( rod->from ) - { - gnc_ttsplitinfo_set_account( ttsi, rod->from ); - } - else - { - gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repFromAcct ); - } - gnc_ttsplitinfo_set_credit_formula( ttsi, amtBuf ); - tti = tcSX->mainTxn; - if ( rod->throughEscrowP ) - { - tti = paymentSX->mainTxn; - } - gnc_ttinfo_append_template_split( tti, ttsi ); - ttsi = NULL; - tti = NULL; - } - - /* Add to-account split. */ - { - ttsi = gnc_ttsplitinfo_malloc(); - gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo ); - gnc_ttsplitinfo_set_account( ttsi, rod->to ); - gnc_ttsplitinfo_set_debit_formula( ttsi, amtBuf ); - gnc_ttinfo_append_template_split( toTxn, ttsi ); - ttsi = NULL; - } -} - -/** - * Actually does the heavy-lifting of creating the SXes from the - * LoanDruidData. - * - * Rules: - * - There is at least one SX created, with at least one txn, for the loan - * payment itself. - * - A new SX is created for each repayment with a different frequency. - * - Non-unique repayment From-accounts cause a "summed (src-)split", unique - * repayment From-accounts cause new (src-)splits. - * - Each repayment causes a new (dst-)split [the To-account]. - * - Escrow-diverted repayments cause new Txns w/in their - * SX. [Assets->Escrow, Escrow->(Expense|Liability)] - **/ -static -void -ld_create_sxes( LoanDruidData *ldd ) -{ - /* The main loan-payment SX.*/ - toCreateSX *paymentSX = NULL; - /* A GList of any other repayment SXes with different schedule. */ - GList *repaySXes = NULL; - /* The currently-being-referenced toCreateSX. */ - toCreateSX *tcSX; - int i; - TTInfo *ttxn; - TTSplitInfo *ttsi; - GString *gstr; - - paymentSX = g_new0( toCreateSX, 1 ); - paymentSX->name = g_strdup(ldd->ld.repMemo); - paymentSX->start = *ldd->ld.startDate; - paymentSX->last = *ldd->ld.repStartDate; - g_date_subtract_months( &paymentSX->last, 1 ); - { - paymentSX->end = *ldd->ld.repStartDate; - g_date_add_months( &paymentSX->end, ldd->ld.numMonRemain - 1); - } - paymentSX->schedule = ldd->ld.repayment_schedule; - /* Figure out the correct current instance-count for the txns in the - * SX. */ - paymentSX->instNum = - (ldd->ld.numPer * ( ldd->ld.perSize == GNC_YEARS ? 12 : 1 )) - - ldd->ld.numMonRemain + 1; - - paymentSX->mainTxn = gnc_ttinfo_malloc(); - gnc_ttinfo_set_currency( paymentSX->mainTxn, - gnc_default_currency() ); - { - GString *payMainTxnDesc = g_string_sized_new( 32 ); - g_string_printf( payMainTxnDesc, - "%s - %s", - ldd->ld.repMemo, - ( ldd->ld.escrowAcct == NULL - ? _("Payment") - : _("Escrow Payment") ) - ); - - gnc_ttinfo_set_description( paymentSX->mainTxn, - payMainTxnDesc->str ); - g_string_free( payMainTxnDesc, TRUE ); - } - - /* Create the basic txns and splits... - * - * ttxn <- mainTxn - * srcAcct <- assets - * if ( escrow ) { - * realSrcAcct <- srcAcct - * srcAcct <- escrow; - * ttxn <- escrowTxn - * main.splits += split( realSrcAcct, -pmt ) - * main.splits += split( escrow, pmt ) - * } - * ttxn.splits += split( escrow, -pmt) - * ttxn.splits += split( liability, ppmt ) - * ttxn.splits += split( expenses:interest, ipmt ) */ - - { - Account *srcAcct; - - ttxn = paymentSX->mainTxn; - srcAcct = ldd->ld.repFromAcct; - - if ( ldd->ld.escrowAcct != NULL ) - { - Account *realSrcAcct = srcAcct; - srcAcct = ldd->ld.escrowAcct; - - gstr = g_string_sized_new( 32 ); - ld_get_pmt_formula( ldd, gstr ); - /* ttxn.splits += split( realSrcAcct, -pmt ); */ - { - ttsi = gnc_ttsplitinfo_malloc(); - gnc_ttsplitinfo_set_memo( ttsi, ldd->ld.repMemo ); - gnc_ttsplitinfo_set_account( ttsi, realSrcAcct ); - gnc_ttsplitinfo_set_credit_formula( ttsi, gstr->str ); - gnc_ttinfo_append_template_split( ttxn, ttsi ); - ttsi = NULL; - } - - /* ttxn.splits += split( escrowAcct, +pmt ); */ - { - ttsi = gnc_ttsplitinfo_malloc(); - gnc_ttsplitinfo_set_memo( ttsi, ldd->ld.repMemo ); - gnc_ttsplitinfo_set_account( ttsi, ldd->ld.escrowAcct ); - gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str ); - gnc_ttinfo_append_template_split( ttxn, ttsi ); - ttsi = NULL; - } - g_string_free( gstr, TRUE ); - gstr = NULL; - - paymentSX->escrowTxn = gnc_ttinfo_malloc(); - gnc_ttinfo_set_currency( paymentSX->escrowTxn, - gnc_default_currency() ); - - { - GString *escrowTxnDesc; - escrowTxnDesc = g_string_new( ldd->ld.repMemo ); - g_string_append_printf( escrowTxnDesc, " - %s", _("Payment") ); - gnc_ttinfo_set_description( paymentSX->escrowTxn, - escrowTxnDesc->str ); - g_string_free( escrowTxnDesc, TRUE ); - } - ttxn = paymentSX->escrowTxn; - } - - /* ttxn.splits += split( srcAcct, -pmt ); */ - { - ttsi = gnc_ttsplitinfo_malloc(); - { - gstr = g_string_new( ldd->ld.repMemo ); - g_string_append_printf( gstr, " - %s", - _("Payment") ); - gnc_ttsplitinfo_set_memo( ttsi, gstr->str ); - g_string_free( gstr, TRUE ); - gstr = NULL; - } - gnc_ttsplitinfo_set_account( ttsi, srcAcct ); - gstr = g_string_sized_new( 32 ); - ld_get_pmt_formula( ldd, gstr ); - gnc_ttsplitinfo_set_credit_formula( ttsi, gstr->str ); - gnc_ttinfo_append_template_split( ttxn, ttsi ); - g_string_free( gstr, TRUE ); - gstr = NULL; - ttsi = NULL; - } - - /* ttxn.splits += split( ldd->ld.repPriAcct, +ppmt ); */ - { - ttsi = gnc_ttsplitinfo_malloc(); - { - gstr = g_string_new( ldd->ld.repMemo ); - g_string_append_printf( gstr, " - %s", - _("Principal") ); - gnc_ttsplitinfo_set_memo( ttsi, gstr->str ); - g_string_free( gstr, TRUE ); - gstr = NULL; - } - gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repPriAcct ); - gstr = g_string_sized_new( 32 ); - ld_get_ppmt_formula( ldd, gstr ); - gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str ); - gnc_ttinfo_append_template_split( ttxn, ttsi ); - g_string_free( gstr, TRUE ); - gstr = NULL; - ttsi = NULL; - } - - /* ttxn.splits += split( ldd->ld.repIntAcct, +ipmt ); */ - { - ttsi = gnc_ttsplitinfo_malloc(); - { - gstr = g_string_new( ldd->ld.repMemo ); - g_string_append_printf( gstr, " - %s", - _("Interest") ); - gnc_ttsplitinfo_set_memo( ttsi, gstr->str ); - g_string_free( gstr, TRUE ); - gstr = NULL; - } - gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repIntAcct ); - gstr = g_string_sized_new( 32 ); - ld_get_ipmt_formula( ldd, gstr ); - gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str ); - gnc_ttinfo_append_template_split( ttxn, ttsi ); - g_string_free( gstr, TRUE ); - gstr = NULL; - ttsi = NULL; - } - } - - for ( i = 0; i < ldd->ld.repayOptCount; i++ ) - { - RepayOptData *rod = ldd->ld.repayOpts[i]; - if ( ! rod->enabled ) - continue; - - tcSX = paymentSX; - if ( rod->schedule != NULL ) - { - tcSX = g_new0( toCreateSX, 1 ); - gstr = g_string_new( ldd->ld.repMemo ); - g_string_append_printf( gstr, " - %s", - rod->name ); - tcSX->name = g_strdup(gstr->str); - tcSX->start = *ldd->ld.startDate; - tcSX->last = *ldd->ld.repStartDate; - { - tcSX->end = tcSX->last; - g_date_add_months( &tcSX->end, ldd->ld.numMonRemain ); - } - tcSX->schedule = rod->schedule; - /* So it won't get destroyed when the close the - * Druid. */ - tcSX->instNum = - ld_calc_sx_instance_num(&tcSX->start, rod->schedule); - rod->schedule = NULL; - tcSX->mainTxn = gnc_ttinfo_malloc(); - gnc_ttinfo_set_currency( tcSX->mainTxn, - gnc_default_currency() ); - gnc_ttinfo_set_description( tcSX->mainTxn, - gstr->str ); - tcSX->escrowTxn = gnc_ttinfo_malloc(); - gnc_ttinfo_set_currency( tcSX->escrowTxn, - gnc_default_currency() ); - gnc_ttinfo_set_description( tcSX->escrowTxn, - gstr->str ); - - g_string_free( gstr, TRUE ); - gstr = NULL; - - repaySXes = g_list_append( repaySXes, tcSX ); - - } - - /* repayment */ - ld_setup_repayment_sx( ldd, rod, paymentSX, tcSX ); - } - - /* Create the SXes */ - { - GList *l; - - ld_create_sx_from_tcSX( ldd, paymentSX ); - - for ( l = repaySXes; l; l = l->next ) - { - ld_create_sx_from_tcSX( ldd, (toCreateSX*)l->data ); - } - } - - /* Clean up. */ - ld_tcSX_free( paymentSX, NULL ); - g_list_foreach( repaySXes, ld_tcSX_free, NULL ); - g_list_free( repaySXes ); -} - -static -void -ld_calc_upd_rem_payments( GtkWidget *w, gpointer ud ) -{ - LoanDruidData *ldd = (LoanDruidData*)ud; - GDate start, now; - int i, totalVal, total, remain; - - g_date_clear( &start, 1 ); - g_date_clear( &now, 1 ); - g_date_set_time_t( &start, gnc_date_edit_get_date( ldd->prmStartDateGDE ) ); - g_date_set_time_t( &now, time(NULL) ); - for ( i = 0; g_date_compare( &start, &now ) < 0; i++ ) - { - g_date_add_months( &start, 1 ); - } - - /* Get the correct, current value of the length spin. */ - { - gchar *valueStr = gtk_editable_get_chars( GTK_EDITABLE(ldd->prmLengthSpin), - 0, -1 ); - totalVal = strtol( valueStr, NULL, 10 ); - g_free( valueStr ); - } - total = totalVal - * ( gtk_combo_box_get_active( ldd->prmLengthType ) - == 1 ? 12 : 1 ); - remain = total - i; - gtk_spin_button_set_value( ldd->prmRemainSpin, remain ); - gtk_widget_show( GTK_WIDGET(ldd->prmRemainSpin) ); -} - -static -void -ld_rev_range_opt_changed( GtkComboBox *combo, gpointer ud ) -{ - LoanDruidData *ldd = (LoanDruidData*)ud; + LoanAssistantData *ldd = user_data; int opt; opt = gtk_combo_box_get_active( ldd->revRangeOpt ); @@ -2856,28 +1895,30 @@ ld_rev_range_opt_changed( GtkComboBox *combo, gpointer ud ) GDate start, end; g_date_clear( &start, 1 ); g_date_clear( &end, 1 ); - ld_rev_get_dates( ldd, &start, &end ); - ld_rev_update_view( ldd, &start, &end ); + loan_rev_get_dates( ldd, &start, &end ); + loan_rev_update_view( ldd, &start, &end ); } } + static void -ld_rev_range_changed( GNCDateEdit *gde, gpointer ud ) +loan_rev_range_changed_cb( GNCDateEdit *gde, gpointer user_data ) { - LoanDruidData *ldd = (LoanDruidData*)ud; + LoanAssistantData *ldd = user_data; { GDate start, end; g_date_clear( &start, 1 ); g_date_clear( &end, 1 ); - ld_rev_get_dates( ldd, &start, &end ); - ld_rev_update_view( ldd, &start, &end ); + loan_rev_get_dates( ldd, &start, &end ); + loan_rev_update_view( ldd, &start, &end ); } } + static void -ld_get_loan_range( LoanDruidData *ldd, GDate *start, GDate *end ) +loan_rev_get_loan_range( LoanAssistantData *ldd, GDate *start, GDate *end ) { int monthsTotal; struct tm *endDateMath; @@ -2893,9 +1934,10 @@ ld_get_loan_range( LoanDruidData *ldd, GDate *start, GDate *end ) g_free( endDateMath ); } + static void -ld_rev_get_dates( LoanDruidData *ldd, GDate *start, GDate *end ) +loan_rev_get_dates( LoanAssistantData *ldd, GDate *start, GDate *end ) { int range = gtk_combo_box_get_active( ldd->revRangeOpt ); switch ( range ) @@ -2911,7 +1953,7 @@ ld_rev_get_dates( LoanDruidData *ldd, GDate *start, GDate *end ) g_date_add_years( end, 1 ); break; case WHOLE_LOAN: - ld_get_loan_range( ldd, start, end ); + loan_rev_get_loan_range( ldd, start, end ); break; case CUSTOM: g_date_set_time_t( start, @@ -2926,18 +1968,20 @@ ld_rev_get_dates( LoanDruidData *ldd, GDate *start, GDate *end ) } + static void -ld_rev_sched_list_free( gpointer data, gpointer user_data ) +loan_rev_sched_list_free( gpointer data, gpointer user_data ) { RevRepaymentRow *rrr = (RevRepaymentRow*)data; g_free( rrr->numCells ); g_free( rrr ); } + static void -ld_rev_hash_to_list( gpointer key, gpointer val, gpointer user_data ) +loan_rev_hash_to_list( gpointer key, gpointer val, gpointer user_data ) { GList **l = (GList**)user_data; RevRepaymentRow *rrr = g_new0( RevRepaymentRow, 1 ); @@ -2953,16 +1997,18 @@ ld_rev_hash_to_list( gpointer key, gpointer val, gpointer user_data ) *l = g_list_append( *l, (gpointer)rrr ); } + static void -ld_rev_hash_free_date_keys( gpointer key, gpointer val, gpointer user_data ) +loan_rev_hash_free_date_keys( gpointer key, gpointer val, gpointer user_data ) { g_free( (GDate*)key ); } + static void -ld_rev_recalc_schedule( LoanDruidData *ldd ) +loan_rev_recalc_schedule( LoanAssistantData *ldd ) { GDate start, end; gnc_numeric *rowNumData; @@ -2970,7 +2016,7 @@ ld_rev_recalc_schedule( LoanDruidData *ldd ) g_date_clear( &start, 1 ); g_date_clear( &end, 1 ); - ld_get_loan_range( ldd, &start, &end ); + loan_rev_get_loan_range( ldd, &start, &end ); /* The repayment_schedule is a hash of GDates to * row-of-gnc_numeric[N] data, where N is the number of columns as @@ -2986,11 +2032,11 @@ ld_rev_recalc_schedule( LoanDruidData *ldd ) GHashTable *ivar; pmtFormula = g_string_sized_new( 64 ); - ld_get_pmt_formula( ldd, pmtFormula ); + loan_get_pmt_formula( ldd, pmtFormula ); ppmtFormula = g_string_sized_new( 64 ); - ld_get_ppmt_formula( ldd, ppmtFormula ); + loan_get_ppmt_formula( ldd, ppmtFormula ); ipmtFormula = g_string_sized_new( 64 ); - ld_get_ipmt_formula( ldd, ipmtFormula ); + loan_get_ipmt_formula( ldd, ipmtFormula ); ivar = g_hash_table_new( g_str_hash, g_str_equal ); g_date_clear( &curDate, 1 ); @@ -3134,14 +2180,14 @@ ld_rev_recalc_schedule( LoanDruidData *ldd ) if ( ldd->ld.revSchedule != NULL ) { g_list_foreach( ldd->ld.revSchedule, - ld_rev_sched_list_free, + loan_rev_sched_list_free, NULL ); g_list_free( ldd->ld.revSchedule ); ldd->ld.revSchedule = NULL; } - g_hash_table_foreach( repayment_schedule, ld_rev_hash_to_list, + g_hash_table_foreach( repayment_schedule, loan_rev_hash_to_list, &ldd->ld.revSchedule ); - g_hash_table_foreach( repayment_schedule, ld_rev_hash_free_date_keys, + g_hash_table_foreach( repayment_schedule, loan_rev_hash_free_date_keys, NULL ); g_hash_table_destroy( repayment_schedule ); ldd->ld.revSchedule = @@ -3149,9 +2195,10 @@ ld_rev_recalc_schedule( LoanDruidData *ldd ) } } + static void -ld_rev_update_view( LoanDruidData *ldd, GDate *start, GDate *end ) +loan_rev_update_view( LoanAssistantData *ldd, GDate *start, GDate *end ) { static gchar *NO_AMT_CELL_TEXT = " "; GList *l; @@ -3205,3 +2252,948 @@ ld_rev_update_view( LoanDruidData *ldd, GDate *start, GDate *end ) } } + +/************************* Worker functions *****************************/ + +/* convert APR rate to simple rate based on formula r=q((1+i)^(1/q)-1) (r=interest rate, i=apr, q=compounding periods) */ + +gfloat loan_apr_to_simple_formula (gfloat rate, gfloat compounding_periods) +{ + /* float percent_to_frac; - redundant */ + gfloat simple_rate; + /* percent_to_frac= compounding_periods/100; - redundant */ + simple_rate = compounding_periods * ((pow((1 + rate), (1 / compounding_periods))) - 1); + return (simple_rate); +} + + +static +void +loan_get_pmt_formula( LoanAssistantData *ldd, GString *gstr ) +{ + gint rate_case; + gfloat pass_thru_rate; + g_assert( ldd != NULL ); + g_assert( gstr != NULL ); + rate_case = ldd->ld.rateType; + pass_thru_rate = ldd->ld.interestRate / 100; + switch (rate_case) + { + case GNC_IRATE_SIMPLE: + { + g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", + pass_thru_rate, 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal) ); + } + break; + case GNC_IRATE_APR_DAILY: + { + g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 365), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal) ); + } + break; + case GNC_IRATE_APR_WEEKLY: + { + g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 52), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal) ); + } + break; + case GNC_IRATE_APR_MONTHLY: + { + g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 12), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal) ); + } + break; + case GNC_IRATE_APR_QUARTERLY: + { + g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 4), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal) ); + } + break; + case GNC_IRATE_APR_ANNUALLY: + { + g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 1), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal) ); + } + break; + default: + g_string_append_printf( gstr, "pmt( %.5f / %0.2f : %0.2f : %0.2f : 0 : 0 )", + (ldd->ld.interestRate / 100), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal) ); + break; + } +} + + +static +void +loan_get_ppmt_formula( LoanAssistantData *ldd, GString *gstr ) +{ + gint rate_case; + gfloat pass_thru_rate; + g_assert( ldd != NULL ); + g_assert( gstr != NULL ); + rate_case = ldd->ld.rateType; + pass_thru_rate = ldd->ld.interestRate / 100; + switch (rate_case) + { + case GNC_IRATE_SIMPLE: + { + g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + pass_thru_rate, + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + case GNC_IRATE_APR_DAILY: + { + g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 365), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + case GNC_IRATE_APR_WEEKLY: + { + g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 52), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + case GNC_IRATE_APR_MONTHLY: + { + g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 12), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + case GNC_IRATE_APR_QUARTERLY: + { + g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 4), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + case GNC_IRATE_APR_ANNUALLY: + { + g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 1), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + default: + g_string_printf( gstr, "ppmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + (ldd->ld.interestRate / 100), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + break; + } +} + + +static +void +loan_get_ipmt_formula( LoanAssistantData *ldd, GString *gstr ) +{ + gint rate_case; + gfloat pass_thru_rate; + g_assert( ldd != NULL ); + g_assert( gstr != NULL ); + rate_case = ldd->ld.rateType; + pass_thru_rate = ldd->ld.interestRate / 100; + switch (rate_case) + { + case GNC_IRATE_SIMPLE: + { + g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + pass_thru_rate, + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + case GNC_IRATE_APR_DAILY: + { + g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 365), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + case GNC_IRATE_APR_WEEKLY: + { + g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 52), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + case GNC_IRATE_APR_MONTHLY: + { + g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 12), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + case GNC_IRATE_APR_QUARTERLY: + { + g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 4), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + case GNC_IRATE_APR_ANNUALLY: + { + g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + loan_apr_to_simple_formula(pass_thru_rate, 1), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + } + break; + default: + g_string_printf( gstr, "ipmt( %.5f / %0.2f : i : %0.2f : %0.2f : 0 : 0 )", + (ldd->ld.interestRate / 100), + 12.0, + ( ldd->ld.numPer + * ( ldd->ld.perSize == GNC_MONTHS ? 1 : 12 ) ) * 1., + gnc_numeric_to_double(ldd->ld.principal)); + break; + } +} + +/******************* Scheduled Transaction Functions ********************/ + +static int +ld_calc_sx_instance_num(GDate *start_date, GList *schedule) +{ + int instance_count; + GDate next_date, today; + + g_date_clear(&next_date, 1); + g_date_clear(&today, 1); + g_date_set_time_t(&today, time(NULL)); + + if (g_date_compare(start_date, &today) > 0) + return 0; + + instance_count = -1; + do + { + instance_count++; + recurrenceListNextInstance(schedule, start_date, &next_date); + } + while (g_date_compare(&next_date, &today) < 0); + + return instance_count; +} + + +static +void +loan_tcSX_free( gpointer data, gpointer user_data ) +{ + toCreateSX *tcSX = (toCreateSX*)data; + g_free( tcSX->name ); + if ( tcSX->mainTxn ) + gnc_ttinfo_free( tcSX->mainTxn ); + if ( tcSX->escrowTxn ) + gnc_ttinfo_free( tcSX->escrowTxn ); + g_free( tcSX ); +} + + +/** + * Custom GCompareFunc to find the element of a GList of TTSplitInfo's which + * has the given [Account*] criteria. + * @return 0 if match, as per GCompareFunc in the g_list_find_custom context. + **/ +static +gint +loan_find_ttsplit_with_acct( gconstpointer elt, + gconstpointer crit ) +{ + TTSplitInfo *ttsi = (TTSplitInfo*)elt; + return ( (gnc_ttsplitinfo_get_account( ttsi ) + == (Account*)crit) ? 0 : 1 ); +} + + +/** + * Enters into the books a Scheduled Transaction from the given toCreateSX. + **/ +static +void +loan_create_sx_from_tcSX( LoanAssistantData *ldd, toCreateSX *tcSX ) +{ + SchedXaction *sx; + SchedXactions *sxes; + GList *ttxnList; + + sx = xaccSchedXactionMalloc( gnc_get_current_book() ); + xaccSchedXactionSetName( sx, tcSX->name ); + gnc_sx_set_schedule(sx, tcSX->schedule); + xaccSchedXactionSetStartDate( sx, &tcSX->start ); + xaccSchedXactionSetLastOccurDate( sx, &tcSX->last ); + xaccSchedXactionSetEndDate( sx, &tcSX->end ); + gnc_sx_set_instance_count( sx, tcSX->instNum ); + + ttxnList = NULL; + if ( tcSX->mainTxn ) + ttxnList = g_list_append( ttxnList, tcSX->mainTxn ); + if ( tcSX->escrowTxn ) + ttxnList = g_list_append( ttxnList, tcSX->escrowTxn ); + + g_assert( ttxnList != NULL ); + + xaccSchedXactionSetTemplateTrans( sx, ttxnList, + gnc_get_current_book() ); + + sxes = gnc_book_get_schedxactions(gnc_get_current_book()); + gnc_sxes_add_sx(sxes, sx); + g_list_free( ttxnList ); + ttxnList = NULL; +} + + +/** + * Does the work to setup the given toCreateSX structure for a specific + * repayment. Note that if the RepayOptData doesn't specify a unique + * schedule, the paymentSX and the tcSX parameters will be the same. + **/ +static +void +ld_setup_repayment_sx( LoanAssistantData *ldd, + RepayOptData *rod, + toCreateSX *paymentSX, + toCreateSX *tcSX ) +{ + /* In DoubleEntryAccounting-ease, this is what we're going to do, + * below... + * + * if ( rep->escrow ) { + * if ( rep->from ) { + * a: paymentSX.main.splits += split( rep->fromAcct, repAmt ) + * b: paymentSX.main.split( ldd->ld.escrowAcct ).debCred += repAmt + * tcSX.escrow.split( rep->escrow ).debCred += repAmt + * c1: tcSX.escrow.splits += split( rep->toAcct, +repAmt ) + * } else { + * d: paymentSX.main.split( ldd->ld.repFromAcct ).debcred += -repAmt + * b: paymentSX.main.split( ldd->ld.escrowAcct ).debCred += repAmt + * tcSX.escrow.splits += split( rep->escrow, -repAmt ) + * c1: tcSX.escrow.splits += split( rep->toAcct, +repAmt ) + * } + * } else { + * if ( rep->from ) { + * a: paymentSX.main.splits += split( rep->fromAcct, -repAmt ) + * c2: paymentSX.main.splits += split( rep->toAcct, +repAmt ) + * } else { + * d: paymentSX.main.split( ldd->ld.payFromAcct ).debcred += -repAmt + * c2: paymentSX.main.splits += split( rep->toAcct, +repAmt ) + * } + * } + */ + + /* Now, we refactor the common operations from the above out... + * + * fromSplit = NULL; + * if ( rep->escrow ) { + * b: paymentSX.main.split( ldd->ld.escrowAcct ).debCred += repAmt + * c1: ( toTTI = tcSX.escrow ) + * if ( rep->from ) { + * a1: (fromSplit = NULL) paymentSX.main.splits += split( rep->fromAcct, repAmt ) + * b: + * tcSX.escrow.split( rep->escrow ).debCred += repAmt + * c1: + * } else { + * a2: (fromSplit = paymentSX.main.split( ldd->ld.repFromAcct )) .debcred += -repAmt + * b: + * tcSX.escrow.splits += split( rep->escrow, -repAmt ) + * c1: + * } + * } else { + * c2: ( toTTI = paymentSX.main ) + * if ( rep->from ) { + * a1: (fromSplit = NULL) paymentSX.main.splits += split( rep->fromAcct, -repAmt ) + * c2: + * } else { + * a2: (fromSplit = paymentSX.main.split( ldd->ld.payFromAcct )).debcred += -repAmt + * c2: + * } + * } + * if ( fromSplit ) { + * fromSplit.debCred += (-repAmt); + * } else { + * fromSplit = split( rep->fromAcct, -repAmt ) + * paymentSX.main.splits += fromSplit + * } + * toTTI.splits += split( rep->toAcct, +repAmt ); + */ + + /** Now, the actual implementation... */ + + GString *gstr; + GList *elt; + TTSplitInfo *fromSplit = NULL; + TTSplitInfo *ttsi; + TTInfo *toTxn = NULL; + GNCPrintAmountInfo pricePAI = gnc_default_price_print_info(); +#define AMTBUF_LEN 64 + gchar amtBuf[AMTBUF_LEN]; + gint GNCN_HOW = (GNC_HOW_DENOM_SIGFIGS(2) | GNC_HOW_RND_ROUND_HALF_UP); + + /* We're going to use this a lot, below, so just create it once. */ + xaccSPrintAmount( amtBuf, + double_to_gnc_numeric( rod->amount, 100, + GNCN_HOW ), + pricePAI ); + + if ( rod->throughEscrowP && ldd->ld.escrowAcct ) + { + toTxn = tcSX->escrowTxn; + + /* Add the repayment amount into the string of the existing + * ttsplit. */ + { + elt = g_list_find_custom( + gnc_ttinfo_get_template_splits( paymentSX->mainTxn ), + ldd->ld.escrowAcct, + loan_find_ttsplit_with_acct ); + g_assert( elt ); + ttsi = (TTSplitInfo*)elt->data; + g_assert( ttsi ); + gstr = g_string_new( gnc_ttsplitinfo_get_debit_formula( ttsi ) ); + g_string_append_printf( gstr, " + %s", amtBuf ); + gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str ); + g_string_free( gstr, TRUE ); + gstr = NULL; + ttsi = NULL; + } + + if ( rod->from != NULL ) + { + gchar *str; + + fromSplit = NULL; + + /* tcSX.escrow.split( rep->escrow ).debCred += repAmt */ + elt = g_list_find_custom( + gnc_ttinfo_get_template_splits( tcSX->escrowTxn ), + ldd->ld.escrowAcct, + loan_find_ttsplit_with_acct ); + ttsi = NULL; + if ( elt ) + { + ttsi = (TTSplitInfo*)elt->data; + } + if ( !ttsi ) + { + /* create split */ + ttsi = gnc_ttsplitinfo_malloc(); + gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo ); + gnc_ttsplitinfo_set_account( ttsi, ldd->ld.escrowAcct ); + gnc_ttinfo_append_template_split( tcSX->escrowTxn, ttsi ); + } + if ( (str = (gchar*)gnc_ttsplitinfo_get_credit_formula( ttsi )) + == NULL ) + { + gstr = g_string_sized_new( 16 ); + } + else + { + /* If we did get a split/didn't have to + * create a split, then we need to add our + * amount in rather than replace. */ + gstr = g_string_new( str ); + g_string_append_printf( gstr, " + " ); + } + g_string_append_printf( gstr, "%s", amtBuf ); + gnc_ttsplitinfo_set_credit_formula( ttsi, gstr->str ); + g_string_free( gstr, TRUE ); + gstr = NULL; + ttsi = NULL; + } + else + { + /* (fromSplit = paymentSX.main.split( ldd->ld.repFromAcct )) */ + elt = g_list_find_custom( + gnc_ttinfo_get_template_splits( paymentSX->mainTxn ), + ldd->ld.repFromAcct, + loan_find_ttsplit_with_acct ); + g_assert( elt ); + fromSplit = (TTSplitInfo*)elt->data; + + /* tcSX.escrow.splits += split( rep->escrow, -repAmt ) */ + ttsi = gnc_ttsplitinfo_malloc(); + gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo ); + gnc_ttsplitinfo_set_account( ttsi, ldd->ld.escrowAcct ); + gnc_ttsplitinfo_set_credit_formula( ttsi, amtBuf ); + gnc_ttinfo_append_template_split( tcSX->escrowTxn, ttsi ); + ttsi = NULL; + } + } + else + { + toTxn = tcSX->mainTxn; + + if ( rod->from != NULL ) + { + fromSplit = NULL; + } + else + { + /* (fromSplit = paymentSX.main.split( ldd->ld.repFromAcct )) */ + elt = g_list_find_custom( + gnc_ttinfo_get_template_splits( tcSX->mainTxn ), + ldd->ld.repFromAcct, + loan_find_ttsplit_with_acct ); + fromSplit = NULL; + if ( elt ) + { + /* This is conditionally true in the case of + * a repayment on it's own schedule. */ + fromSplit = (TTSplitInfo*)elt->data; + } + } + } + + if ( fromSplit != NULL ) + { + /* Update the existing from-split. */ + gstr = g_string_new( gnc_ttsplitinfo_get_credit_formula( fromSplit ) ); + g_string_append_printf( gstr, " + %s", amtBuf ); + gnc_ttsplitinfo_set_credit_formula( fromSplit, gstr->str ); + g_string_free( gstr, TRUE ); + gstr = NULL; + + } + else + { + TTInfo *tti; + /* Create a new from-split. */ + ttsi = gnc_ttsplitinfo_malloc(); + gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo ); + if ( rod->from ) + { + gnc_ttsplitinfo_set_account( ttsi, rod->from ); + } + else + { + gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repFromAcct ); + } + gnc_ttsplitinfo_set_credit_formula( ttsi, amtBuf ); + tti = tcSX->mainTxn; + if ( rod->throughEscrowP ) + { + tti = paymentSX->mainTxn; + } + gnc_ttinfo_append_template_split( tti, ttsi ); + ttsi = NULL; + tti = NULL; + } + + /* Add to-account split. */ + { + ttsi = gnc_ttsplitinfo_malloc(); + gnc_ttsplitinfo_set_memo( ttsi, rod->txnMemo ); + gnc_ttsplitinfo_set_account( ttsi, rod->to ); + gnc_ttsplitinfo_set_debit_formula( ttsi, amtBuf ); + gnc_ttinfo_append_template_split( toTxn, ttsi ); + ttsi = NULL; + } +} + + +/** + * Actually does the heavy-lifting of creating the SXes from the + * LoanAssistantData. + * + * Rules: + * - There is at least one SX created, with at least one txn, for the loan + * payment itself. + * - A new SX is created for each repayment with a different frequency. + * - Non-unique repayment From-accounts cause a "summed (src-)split", unique + * repayment From-accounts cause new (src-)splits. + * - Each repayment causes a new (dst-)split [the To-account]. + * - Escrow-diverted repayments cause new Txns w/in their + * SX. [Assets->Escrow, Escrow->(Expense|Liability)] + **/ +static +void +loan_create_sxes( LoanAssistantData *ldd ) +{ + /* The main loan-payment SX.*/ + toCreateSX *paymentSX = NULL; + /* A GList of any other repayment SXes with different schedule. */ + GList *repaySXes = NULL; + /* The currently-being-referenced toCreateSX. */ + toCreateSX *tcSX; + int i; + TTInfo *ttxn; + TTSplitInfo *ttsi; + GString *gstr; + + paymentSX = g_new0( toCreateSX, 1 ); + paymentSX->name = g_strdup(ldd->ld.repMemo); + paymentSX->start = *ldd->ld.startDate; + paymentSX->last = *ldd->ld.repStartDate; + g_date_subtract_months( &paymentSX->last, 1 ); + { + paymentSX->end = *ldd->ld.repStartDate; + g_date_add_months( &paymentSX->end, ldd->ld.numMonRemain - 1); + } + + paymentSX->schedule = ldd->ld.repayment_schedule; + /* Figure out the correct current instance-count for the txns in the + * SX. */ + paymentSX->instNum = + (ldd->ld.numPer * ( ldd->ld.perSize == GNC_YEARS ? 12 : 1 )) + - ldd->ld.numMonRemain + 1; + + paymentSX->mainTxn = gnc_ttinfo_malloc(); + gnc_ttinfo_set_currency( paymentSX->mainTxn, + gnc_default_currency() ); + + { + GString *payMainTxnDesc = g_string_sized_new( 32 ); + g_string_printf( payMainTxnDesc, + "%s - %s", + ldd->ld.repMemo, + ( ldd->ld.escrowAcct == NULL + ? _("Payment") + : _("Escrow Payment") ) + ); + + gnc_ttinfo_set_description( paymentSX->mainTxn, + payMainTxnDesc->str ); + g_string_free( payMainTxnDesc, TRUE ); + } + + /* Create the basic txns and splits... + * + * ttxn <- mainTxn + * srcAcct <- assets + * if ( escrow ) { + * realSrcAcct <- srcAcct + * srcAcct <- escrow; + * ttxn <- escrowTxn + * main.splits += split( realSrcAcct, -pmt ) + * main.splits += split( escrow, pmt ) + * } + * ttxn.splits += split( escrow, -pmt) + * ttxn.splits += split( liability, ppmt ) + * ttxn.splits += split( expenses:interest, ipmt ) */ + + { + Account *srcAcct; + + ttxn = paymentSX->mainTxn; + srcAcct = ldd->ld.repFromAcct; + if ( ldd->ld.escrowAcct != NULL ) + { + Account *realSrcAcct = srcAcct; + srcAcct = ldd->ld.escrowAcct; + gstr = g_string_sized_new( 32 ); + loan_get_pmt_formula( ldd, gstr ); + /* ttxn.splits += split( realSrcAcct, -pmt ); */ + { + ttsi = gnc_ttsplitinfo_malloc(); + gnc_ttsplitinfo_set_memo( ttsi, ldd->ld.repMemo ); + gnc_ttsplitinfo_set_account( ttsi, realSrcAcct ); + gnc_ttsplitinfo_set_credit_formula( ttsi, gstr->str ); + gnc_ttinfo_append_template_split( ttxn, ttsi ); + ttsi = NULL; + } + /* ttxn.splits += split( escrowAcct, +pmt ); */ + { + ttsi = gnc_ttsplitinfo_malloc(); + gnc_ttsplitinfo_set_memo( ttsi, ldd->ld.repMemo ); + gnc_ttsplitinfo_set_account( ttsi, ldd->ld.escrowAcct ); + gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str ); + gnc_ttinfo_append_template_split( ttxn, ttsi ); + ttsi = NULL; + } + g_string_free( gstr, TRUE ); + gstr = NULL; + paymentSX->escrowTxn = gnc_ttinfo_malloc(); + gnc_ttinfo_set_currency( paymentSX->escrowTxn, + gnc_default_currency() ); + + { + GString *escrowTxnDesc; + escrowTxnDesc = g_string_new( ldd->ld.repMemo ); + g_string_append_printf( escrowTxnDesc, " - %s", _("Payment") ); + gnc_ttinfo_set_description( paymentSX->escrowTxn, + escrowTxnDesc->str ); + g_string_free( escrowTxnDesc, TRUE ); + } + ttxn = paymentSX->escrowTxn; + } + /* ttxn.splits += split( srcAcct, -pmt ); */ + { + ttsi = gnc_ttsplitinfo_malloc(); + { + gstr = g_string_new( ldd->ld.repMemo ); + g_string_append_printf( gstr, " - %s", + _("Payment") ); + gnc_ttsplitinfo_set_memo( ttsi, gstr->str ); + g_string_free( gstr, TRUE ); + gstr = NULL; + } + gnc_ttsplitinfo_set_account( ttsi, srcAcct ); + gstr = g_string_sized_new( 32 ); + loan_get_pmt_formula( ldd, gstr ); + gnc_ttsplitinfo_set_credit_formula( ttsi, gstr->str ); + gnc_ttinfo_append_template_split( ttxn, ttsi ); + g_string_free( gstr, TRUE ); + gstr = NULL; + ttsi = NULL; + } + /* ttxn.splits += split( ldd->ld.repPriAcct, +ppmt ); */ + { + ttsi = gnc_ttsplitinfo_malloc(); + { + gstr = g_string_new( ldd->ld.repMemo ); + g_string_append_printf( gstr, " - %s", + _("Principal") ); + gnc_ttsplitinfo_set_memo( ttsi, gstr->str ); + g_string_free( gstr, TRUE ); + gstr = NULL; + } + gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repPriAcct ); + gstr = g_string_sized_new( 32 ); + loan_get_ppmt_formula( ldd, gstr ); + gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str ); + gnc_ttinfo_append_template_split( ttxn, ttsi ); + g_string_free( gstr, TRUE ); + gstr = NULL; + ttsi = NULL; + } + /* ttxn.splits += split( ldd->ld.repIntAcct, +ipmt ); */ + { + ttsi = gnc_ttsplitinfo_malloc(); + { + gstr = g_string_new( ldd->ld.repMemo ); + g_string_append_printf( gstr, " - %s", + _("Interest") ); + gnc_ttsplitinfo_set_memo( ttsi, gstr->str ); + g_string_free( gstr, TRUE ); + gstr = NULL; + } + gnc_ttsplitinfo_set_account( ttsi, ldd->ld.repIntAcct ); + gstr = g_string_sized_new( 32 ); + loan_get_ipmt_formula( ldd, gstr ); + gnc_ttsplitinfo_set_debit_formula( ttsi, gstr->str ); + gnc_ttinfo_append_template_split( ttxn, ttsi ); + g_string_free( gstr, TRUE ); + gstr = NULL; + ttsi = NULL; + } + } + for ( i = 0; i < ldd->ld.repayOptCount; i++ ) + { + RepayOptData *rod = ldd->ld.repayOpts[i]; + if ( ! rod->enabled ) + continue; + + tcSX = paymentSX; + if ( rod->schedule != NULL ) + { + tcSX = g_new0( toCreateSX, 1 ); + gstr = g_string_new( ldd->ld.repMemo ); + g_string_append_printf( gstr, " - %s", + rod->name ); + tcSX->name = g_strdup(gstr->str); + tcSX->start = *ldd->ld.startDate; + tcSX->last = *ldd->ld.repStartDate; + { + tcSX->end = tcSX->last; + g_date_add_months( &tcSX->end, ldd->ld.numMonRemain ); + } + tcSX->schedule = rod->schedule; + /* So it won't get destroyed when the close the + * Druid. */ + tcSX->instNum = + ld_calc_sx_instance_num(&tcSX->start, rod->schedule); + rod->schedule = NULL; + tcSX->mainTxn = gnc_ttinfo_malloc(); + gnc_ttinfo_set_currency( tcSX->mainTxn, + gnc_default_currency() ); + gnc_ttinfo_set_description( tcSX->mainTxn, + gstr->str ); + tcSX->escrowTxn = gnc_ttinfo_malloc(); + gnc_ttinfo_set_currency( tcSX->escrowTxn, + gnc_default_currency() ); + gnc_ttinfo_set_description( tcSX->escrowTxn, + gstr->str ); + + g_string_free( gstr, TRUE ); + gstr = NULL; + + repaySXes = g_list_append( repaySXes, tcSX ); + + } + + /* repayment */ + ld_setup_repayment_sx( ldd, rod, paymentSX, tcSX ); + } + /* Create the SXes */ + { + GList *l; + + loan_create_sx_from_tcSX( ldd, paymentSX ); + + for ( l = repaySXes; l; l = l->next ) + { + loan_create_sx_from_tcSX( ldd, (toCreateSX*)l->data ); + } + } + /* Clean up. */ + loan_tcSX_free( paymentSX, NULL ); + g_list_foreach( repaySXes, loan_tcSX_free, NULL ); + g_list_free( repaySXes ); +} + +/************************ Assistant Functions ***************************/ + +void +loan_assistant_finish ( GtkAssistant *gtkassistant, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + loan_create_sxes( ldd ); + +} + + +void +loan_assistant_cancel( GtkAssistant *gtkassistant, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + gnc_close_gui_component_by_data( DIALOG_LOAN_ASSISTANT_CM_CLASS,ldd ); +} + + +void +loan_assistant_close( GtkAssistant *gtkassistant, gpointer user_data ) +{ + LoanAssistantData *ldd = user_data; + gnc_close_gui_component_by_data( DIALOG_LOAN_ASSISTANT_CM_CLASS,ldd ); +} + + +void +loan_assistant_prepare (GtkAssistant *assistant, GtkWidget *page, + gpointer user_data) +{ + LoanAssistantData *ldd = user_data; + gint currentpage = gtk_assistant_get_current_page(assistant); + + switch (currentpage) + { + case 1: + /* Current page is info page */ + loan_info_prep (assistant, user_data); + break; + case 2: + /* Current page is Options page */ + loan_opt_prep (assistant, user_data); + break; + case 3: + /* Current page is Repayments page */ + loan_rep_prep (assistant, user_data); + break; + case 4: + /* Current page is Repayments Options page */ + loan_pay_prep (assistant, user_data); + break; + case 5: + /* Current page is Review page */ + loan_rev_prep (assistant, user_data); + break; + } +} + + +/********************************************************************\ + * gnc_ui_sx_loan_assistant_create * + * opens up a window to start the loan Assistant * + * * +\********************************************************************/ +void +gnc_ui_sx_loan_assistant_create (void) +{ + LoanAssistantData *ldd; + gint component_id; + + ldd = g_new0 (LoanAssistantData, 1); + + gnc_loan_assistant_create (ldd); + + component_id = gnc_register_gui_component (DIALOG_LOAN_ASSISTANT_CM_CLASS, + NULL, loan_assistant_close_handler, + ldd); + + gnc_gui_component_watch_entity_type (component_id, + GNC_ID_ACCOUNT, + QOF_EVENT_MODIFY | QOF_EVENT_DESTROY); + + gtk_widget_show_all (ldd->window); + + gnc_window_adjust_for_screen (GTK_WINDOW(ldd->window)); +} + diff --git a/src/gnome/druid-loan.h b/src/gnome/assistant-loan.h similarity index 89% rename from src/gnome/druid-loan.h rename to src/gnome/assistant-loan.h index f0bc0e20a7..3e5062e8a7 100644 --- a/src/gnome/druid-loan.h +++ b/src/gnome/assistant-loan.h @@ -1,7 +1,8 @@ /********************************************************************\ - * druid-loan.h : A Gnome Druid for setting up loan-repayment * + * assistant-loan.h : An Assistant for setting up loan-repayment * * scheduled transactions. * * Copyright (C) 2002 Joshua Sled * + * Copyright (C) 2011 Robert Fewell * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * @@ -21,4 +22,4 @@ * Boston, MA 02110-1301, USA gnu@gnu.org * \********************************************************************/ -struct LoanDruidData_* gnc_ui_sx_loan_druid_create(void); +void gnc_ui_sx_loan_assistant_create(void); diff --git a/src/gnome/glade/sched-xact.glade b/src/gnome/glade/sched-xact.glade index a3b9b27905..943b497759 100644 --- a/src/gnome/glade/sched-xact.glade +++ b/src/gnome/glade/sched-xact.glade @@ -1898,1104 +1898,6 @@ Yearly - - True - Mortgage/Loan Assistant - - - True - 4 - - - True - Edge Start - Mortgage/Loan Repayment Setup - This is a step-by-step method of creating a loan repayment setup within GnuCash. In this assistant, you can input the parameters of your loan and its repayment and give the details of its payback. Using that information, the appropriate Scheduled Transactions will be created. - -If you make a mistake or want to make changes later, you can edit the created Scheduled Transactions directly. - - - - - True - Loan Information - #ffffffffffff - #666666669998 - #666666669998 - - - True - 5 - vertical - - - True - 5 - 6 - 4 - 5 - 5 - - - True - 1 - Interest Rate: - center - - - 2 - 3 - GTK_FILL - - - - - - True - 1 - Start Date: - center - - - 4 - 5 - GTK_FILL - - - - - - True - 1 - Length: - center - - - 5 - 6 - GTK_FILL - - - - - - True - 1 - Amount: - right - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - 1 - Loan Account: - center - - - GTK_FILL - - - - - - True - True - 1 0 100 1 10 0 - 1 - - - 3 - 4 - 5 - 6 - - - - - - True - - - True - True - 1 0 100 1 10 0 - 1 - - - 0 - - - - - True - months -years - - - False - False - 1 - - - - - 1 - 2 - 5 - 6 - - - - - - True - 0 - 0.25 - - - - - - 1 - 4 - 4 - 5 - - - - - - True - 0 - 0.5 - - - True - - - True - True - 1 0 100 1 10 0 - 1 - 3 - True - True - - - 0 - - - - - True - % - center - - - False - False - 1 - - - - - - - 1 - 2 - 2 - 3 - - - - - - True - 1 - 0 - Type: - center - - - 2 - 3 - 2 - 3 - - - - - - True - 1 - Months Remaining: - center - - - 2 - 3 - 5 - 6 - - - - - - True - 0.5 - 0.75 - - - True - 3 - 0.5 - - - - - - True - Interest Rate Change Frequency - - - label_item - - - - - - - 1 - 4 - 3 - 4 - GTK_EXPAND | GTK_SHRINK | GTK_FILL - GTK_EXPAND | GTK_SHRINK | GTK_FILL - - - - - True - Fixed Rate -3/1 Year ARM -5/1 Year ARM -7/1 Year ARM -10/1 Year ARM - - - 3 - 4 - 2 - 3 - GTK_FILL - GTK_FILL - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - True - Options - #ffffffffffff - #666666669998 - #666666669998 - - - True - 16 - vertical - - - True - 10 - Do you... - center - - - False - False - 0 - - - - - True - 0.75 - - - True - vertical - - - ... utilize an escrow account for payments? - True - True - False - True - True - - - False - False - 0 - - - - - True - 0.75 - - - True - - - True - Escrow Account: - center - - - False - False - 0 - - - - - - - - - - False - False - 1 - - - - - - - False - False - 1 - - - - - True - 0.89999997615814209 - - - True - - - - - False - False - 5 - 2 - - - - - - - - - True - Repayment - #ffffffffffff - #666666669998 - #666666669998 - - - True - 16 - vertical - - - True - 5 - 5 - 4 - 5 - 5 - - - True - 1 - Payment From: - right - - - 2 - 3 - GTK_FILL - - - - - - True - 1 - Principal To: - right - - - 3 - 4 - GTK_FILL - - - - - - True - 1 - Name: - right - - - GTK_FILL - - - - - - True - 1 - Amount: - right - - - 1 - 2 - GTK_FILL - - - - - - True - 1 - Interest To: - right - - - 2 - 3 - 3 - 4 - GTK_FILL - - - - - - True - 0 - - - True - True - - - - - 1 - 4 - - - - - - True - 0 - - - True - True - - - - - 1 - 4 - 1 - 2 - GTK_FILL - - - - - - True - 0.5 - 0.89999997615814209 - - - True - 3 - 0.5 - - - - - - True - Repayment Frequency - - - label_item - - - - - - - 4 - 4 - 5 - GTK_SHRINK | GTK_FILL - GTK_EXPAND | GTK_SHRINK | GTK_FILL - - - - - - - - - - - - - - - - - - - - 5 - 0 - - - - - - - - - True - Repayment Type - #ffffffffffff - #666666669998 - #666666669998 - - - True - 16 - vertical - - - True - - - True - vertical - - - True - 5 - 6 - 4 - 5 - 5 - - - True - 1 - Amount: - center - - - 1 - 2 - GTK_FILL - - - - - - True - 1 - Payment From: - center - - - 4 - 5 - GTK_FILL - - - - - - True - 1 - Name: - center - - - GTK_FILL - - - - - - True - 1 - Payment To (Escrow): - right - - - 2 - 3 - 4 - 5 - GTK_FILL - - - - - - True - 0 - - - True - True - - - - - 1 - 4 - - - - - - True - 0 - - - True - True - - - - - 1 - 4 - 1 - 2 - - - - - - True - 1 - Payment From (Escrow): - center - - - 5 - 6 - GTK_FILL - - - - - - True - 1 - Payment To: - center - - - 2 - 3 - 5 - 6 - GTK_FILL - - - - - - Specify Source Account - True - True - False - True - True - - - 1 - 4 - 3 - 4 - GTK_FILL - - - - - - Use Escrow Account - True - True - False - True - True - - - 1 - 4 - 2 - 3 - GTK_FILL - - - - - - - - - - - - - - - - - - - - - - - - False - 0 - - - - - True - 0.5 - 0.75 - - - True - 5 - 0.5 - - - True - vertical - - - Part of Payment Transaction - True - True - False - True - True - - - False - False - 0 - - - - - True - vertical - - - Other - True - True - False - True - True - pay_txn_part_rb - - - False - False - 0 - - - - - True - 1 - 0.94999998807907104 - - - - - - False - False - 1 - - - - - False - False - 1 - - - - - - - True - Payment Frequency - - - label_item - - - - - - - False - False - 1 - - - - - - - 0 - - - - - - - - - True - Review - #ffffffffffff - #666666669998 - #666666669998 - - - True - 16 - vertical - - - True - vertical - - - True - - - True - - - True - 1 - 5 - 5 - Range: - center - - - False - False - 0 - - - - - True - vertical - - - True - Current Year -Now + 1 Year -Whole Loan -Custom - - - False - 0 - - - - - 1 - - - - - False - False - 0 - - - - - True - False - 2 - 0.5 - - - True - 2 - - - True - 1 - 5 - 5 - Start Date: - center - - - GTK_FILL - - - - - - True - 1 - 5 - 5 - End Date: - center - - - 1 - 2 - GTK_FILL - - - - - - - - True - Date Range - - - label_item - - - - - 2 - 1 - - - - - False - False - 0 - - - - - True - False - automatic - automatic - - - - - - 1 - - - - - 0 - - - - - - - - - True - GNOME_EDGE_FINISH - Press apply to commit these changes. - - - - - True diff --git a/src/gnome/gnc-plugin-basic-commands.c b/src/gnome/gnc-plugin-basic-commands.c index f6ff909199..8e42b5d092 100644 --- a/src/gnome/gnc-plugin-basic-commands.c +++ b/src/gnome/gnc-plugin-basic-commands.c @@ -46,7 +46,7 @@ #include "dialog-sx-since-last-run.h" #include "dialog-totd.h" #include "assistant-acct-period.h" -#include "druid-loan.h" +#include "assistant-loan.h" #include "gnc-engine.h" #include "gnc-file.h" #include "gnc-gui-query.h" @@ -501,7 +501,7 @@ gnc_main_window_cmd_actions_since_last_run (GtkAction *action, GncMainWindowActi static void gnc_main_window_cmd_actions_mortgage_loan (GtkAction *action, GncMainWindowActionData *data) { - gnc_ui_sx_loan_druid_create (); + gnc_ui_sx_loan_assistant_create (); } static void diff --git a/src/gnome/gtkbuilder/Makefile.am b/src/gnome/gtkbuilder/Makefile.am index 7651d9819d..ec58045a2f 100644 --- a/src/gnome/gtkbuilder/Makefile.am +++ b/src/gnome/gtkbuilder/Makefile.am @@ -2,6 +2,7 @@ gtkbuilderdir = $(GNC_GTKBUILDER_DIR) gtkbuilder_DATA = \ account.glade \ acctperiod.glade \ + assistant-loan.glade \ autoclear.glade \ budget.glade \ commodities.glade \ diff --git a/src/gnome/gtkbuilder/assistant-loan.glade b/src/gnome/gtkbuilder/assistant-loan.glade new file mode 100644 index 0000000000..999d99d88a --- /dev/null +++ b/src/gnome/gtkbuilder/assistant-loan.glade @@ -0,0 +1,1417 @@ + + + + + + False + 12 + + + + + + + True + False + This is a step-by-step method for creating a loan repayment within GnuCash. In this assistant, you can input the details of your loan and its repayment along with the details of its payback. Using that information, the appropriate Scheduled Transactions will be created. + +If you make a mistake or want to make changes later, you can edit the created Scheduled Transactions directly. + center + True + + + intro + Loan / Mortgage Repayment Setup + True + + + + + True + False + 5 + + + True + False + Enter the Loan Details, as a minimum enter a valid Loan Account and Amount. + + center + True + + + True + False + 0 + + + + + True + False + 5 + 6 + 4 + 5 + 5 + + + True + False + 1 + Interest Rate: + center + + + 2 + 3 + GTK_FILL + + + + + + True + False + 1 + Start Date: + center + + + 4 + 5 + GTK_FILL + + + + + + True + False + 1 + Length: + center + + + 5 + 6 + GTK_FILL + + + + + + True + False + 1 + Amount: + right + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + False + 1 + Loan Account: + center + + + GTK_FILL + + + + + + True + True + + True + False + False + True + True + 1 + + + 3 + 4 + 5 + 6 + + + + + + True + False + + + True + True + + True + False + False + True + True + 1 + + + True + True + 0 + + + + + True + False + len_liststore + + + + 0 + + + + + False + False + 1 + + + + + 1 + 2 + 5 + 6 + + + + + + True + False + 0 + 0.25 + + + + + + 1 + 4 + 4 + 5 + + + + + + True + False + 0 + 0.5 + + + True + False + + + True + False + rate_liststore + + + + 0 + + + + + True + True + 0 + + + + + True + True + + True + False + False + True + True + 1 + 3 + True + True + + + True + True + 1 + + + + + True + False + % + center + + + False + False + 2 + + + + + + + 1 + 2 + 2 + 3 + + + + + + True + False + 1 + 0 + Type: + center + + + 2 + 3 + 2 + 3 + + + + + + True + False + 1 + Months Remaining: + center + + + 2 + 3 + 5 + 6 + + + + + + True + False + 0.5 + 0.75 + + + True + False + 0.5 + + + True + False + 10 + + + + + + + + True + False + Interest Rate Change Frequency + + + + + + + 4 + 3 + 4 + GTK_EXPAND | GTK_SHRINK | GTK_FILL + GTK_EXPAND | GTK_SHRINK | GTK_FILL + + + + + True + False + type_liststore + + + + 0 + + + + + 3 + 4 + 2 + 3 + GTK_FILL + GTK_FILL + + + + + + + + + + + + + + + + + + + + + + + True + False + 1 + + + + + Loan Details + + + + + True + False + + + True + False + 10 + +Do you utilise an escrow account, if so an account must be specified... + center + True + + + False + False + 0 + + + + + True + False + 0.75 + + + True + False + + + ... utilize an escrow account for payments? + True + True + False + False + True + True + + + False + False + 0 + + + + + True + False + 0.75 + + + True + False + + + True + False + Escrow Account: + center + + + False + False + 0 + + + + + + + + + + False + False + 1 + + + + + + + False + False + 1 + + + + + True + False + 0.89999997615814209 + + + True + False + + + + + False + False + 5 + 2 + + + + + Loan Repayment Options + + + + + True + False + + + True + False + +All accounts must have valid entries to continue. + + center + True + + + False + False + 0 + + + + + True + False + 5 + 5 + 4 + 5 + 5 + + + True + False + 1 + Payment From: + right + + + 2 + 3 + GTK_FILL + + + + + + True + False + 1 + Principal To: + right + + + 3 + 4 + GTK_FILL + + + + + + True + False + 1 + Name: + right + + + GTK_FILL + + + + + + True + False + 1 + Amount: + right + + + 1 + 2 + GTK_FILL + + + + + + True + False + 1 + Interest To: + right + + + 2 + 3 + 3 + 4 + GTK_FILL + + + + + + True + False + 0 + + + True + True + + True + False + False + True + True + + + + + 1 + 4 + + + + + + True + False + 0 + + + True + True + + True + False + False + True + True + + + + + 1 + 4 + 1 + 2 + GTK_FILL + + + + + + True + False + 0.5 + 0.89999997615814209 + + + True + False + 0.5 + + + True + False + 10 + + + + + + + + True + False + Repayment Frequency + + + + + + + 4 + 4 + 5 + GTK_SHRINK | GTK_FILL + GTK_EXPAND | GTK_SHRINK | GTK_FILL + + + + + + + + + + + + + + + + + + + + False + False + 5 + 1 + + + + + Loan Repayment + + + + + True + False + + + True + False + +All enabled option pages must contain valid entries to continue. + + center + + + True + False + 0 + + + + + True + False + + + True + False + + + True + False + 5 + 6 + 4 + 5 + 5 + + + True + False + 1 + Amount: + center + + + 1 + 2 + GTK_FILL + + + + + + True + False + 1 + Payment From: + center + + + 4 + 5 + GTK_FILL + + + + + + True + False + 1 + Name: + center + + + GTK_FILL + + + + + + True + False + 1 + Payment To (Escrow): + right + + + 2 + 3 + 4 + 5 + GTK_FILL + + + + + + True + False + 0 + + + True + True + + True + False + False + True + True + + + + + 1 + 4 + + + + + + True + False + 0 + + + True + True + + True + False + False + True + True + + + + + 1 + 4 + 1 + 2 + + + + + + True + False + 1 + Payment From (Escrow): + center + + + 5 + 6 + GTK_FILL + + + + + + True + False + 1 + Payment To: + center + + + 2 + 3 + 5 + 6 + GTK_FILL + + + + + + Specify Source Account + True + True + False + False + True + True + + + 1 + 4 + 3 + 4 + GTK_FILL + + + + + + Use Escrow Account + True + True + False + False + True + True + + + 1 + 4 + 2 + 3 + GTK_FILL + + + + + + + + + + + + + + + + + + + + + + + + False + True + 0 + + + + + True + False + 0.5 + 0.75 + + + True + False + 0.5 + + + True + False + + + Part of Payment Transaction + True + True + False + False + True + True + True + + + False + False + 0 + + + + + True + False + 10 + + + Other + True + True + False + False + True + True + pay_txn_part_rb + + + False + False + 0 + + + + + True + False + 1 + 0.94999998807907104 + + + + + + False + False + 1 + + + + + False + False + 1 + + + + + + + True + False + Payment Frequency + + + + + + + False + False + 1 + + + + + + + True + True + 1 + + + + + True + False + + + Previous Option + True + True + True + False + + + True + True + 0 + + + + + Next Option + True + True + True + False + + + True + True + 1 + + + + + True + True + 2 + + + + + progress + Loan Payment + + + + + True + False + + + True + False + +Review the details below and if correct press Apply to create the schedule. + center + + + False + False + 0 + + + + + True + False + 10 + + + True + False + + + True + False + + + True + False + 1 + 5 + 5 + Range: + center + + + False + False + 0 + + + + + True + False + 10 + + + True + False + range_liststore + + + + 0 + + + + + True + False + 0 + + + + + True + True + 1 + + + + + False + False + 0 + + + + + True + False + False + 5 + 0.5 + + + True + False + 10 + 2 + + + True + False + 1 + 5 + 5 + Start Date: + center + + + GTK_FILL + + + + + + True + False + 1 + 5 + 5 + End Date: + center + + + 1 + 2 + GTK_FILL + + + + + + + + True + False + Date Range + + + + + True + True + 2 + 1 + + + + + False + False + 0 + + + + + True + True + automatic + automatic + + + + + + True + True + 1 + + + + + True + True + 1 + + + + + confirm + Loan Review + + + + + True + False + Schedule added successfully. + center + True + + + summary + Loan Summary + True + + + + + + + + + + + Months + + + Years + + + + + + + + + + + Current Year + + + Now + 1 Year + + + Whole Loan + + + Custome + + + + + + + + + + + Interest Rate + + + APR (Compounded Daily) + + + APR (Compounded Weekly) + + + APR (Compounded Monthly) + + + APR (Compounded Quarterly) + + + APR (Compounded Annually) + + + + + + + + + + + Fixed Rate + + + 3/1 Year ARM + + + 5/1 Year ARM + + + 7/1 Year ARM + + + 10/1 Year ARM + + + + diff --git a/src/gnome/gtkbuilder/sched-xact.glade b/src/gnome/gtkbuilder/sched-xact.glade index e8c7097720..3ecb16093f 100644 --- a/src/gnome/gtkbuilder/sched-xact.glade +++ b/src/gnome/gtkbuilder/sched-xact.glade @@ -1764,13 +1764,6 @@ ok_button - - True - Mortgage/Loan Assistant - - - - True