diff --git a/ChangeLog b/ChangeLog index f55aded2f4..3883cb8287 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2001-02-12 Bill Gribble + + * src/engine/gnc-numeric.{c,h}, src/scm/gnc-numeric.scm: add + support for a new auto-denom type, GNC_DENOM_SIGFIGS(x), where x + is the number of "significant figures" you want in the output. + This means that the output denominator will always be a poewr of + 10, but which power is determined by the magnitude of the + argument. + + * src/engine/Transaction.c, src/gnc-exp-parser.c, + src/gnc-ui-util.c: make minor changes to use GNC_DENOM_SIGFIGS + where appropriate. + + * src/gnome/dialog-account-picker.{c,h}: totally rewritten QIF + import account picker. this one is much less likely to get you + into trouble. Still some rough edges but MUCH better than + the old one. + + * src/gnome/druid-qif-import.c: fixes. Add memo/payee matching + (but it's not hooked up to the import yet so don't get that + excited). + + * src/scm/qif-import/qif-dialog-utils.scm: memo mapping stuff, + i18n fixes. + + * src/scm/qif-import/qif-to-gnc.scm: update error catching; print + backtrace on failure. + 2001-02-09 Christian Stimming * src/scm/commodity-utilities.scm: Functions to calculate exchange diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c index 446a38a922..3d2eb738bc 100644 --- a/src/engine/Transaction.c +++ b/src/engine/Transaction.c @@ -64,9 +64,7 @@ */ int force_double_entry = 0; -/* arbitrary price per share increment FIXME */ -#define PRICE_DENOM 1000000 - +#define PRICE_SIGFIGS 6 /* This static indicates the debugging module that this .o belongs to. */ static short module = MOD_ENGINE; @@ -377,7 +375,8 @@ DxaccSplitSetSharePriceAndAmount (Split *s, double price, double amt) { xaccSplitSetSharePriceAndAmount (s, - double_to_gnc_numeric(price, PRICE_DENOM, GNC_RND_ROUND), + double_to_gnc_numeric(price, GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(PRICE_SIGFIGS) | GNC_RND_ROUND), double_to_gnc_numeric(amt, get_security_denom(s), GNC_RND_ROUND)); } @@ -399,7 +398,9 @@ void DxaccSplitSetSharePrice (Split *s, double amt) { xaccSplitSetSharePrice - (s, double_to_gnc_numeric(amt, PRICE_DENOM, GNC_RND_ROUND)); + (s, double_to_gnc_numeric(amt, GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(PRICE_SIGFIGS) | + GNC_RND_ROUND)); } void @@ -428,7 +429,7 @@ DxaccSplitSetShareAmount (Split *s, double damt) GNC_DENOM_REDUCE); } else { - old_price = gnc_numeric_create(PRICE_DENOM, PRICE_DENOM); + old_price = gnc_numeric_create(1, 1); } s->damount = gnc_numeric_convert(amt, get_security_denom(s), @@ -465,7 +466,7 @@ DxaccSplitSetValue (Split *s, double damt) GNC_DENOM_REDUCE); } else { - old_price = gnc_numeric_create(PRICE_DENOM, PRICE_DENOM); + old_price = gnc_numeric_create(1, 1); } s->value = gnc_numeric_convert(amt, get_currency_denom(s), @@ -2185,11 +2186,13 @@ xaccSplitGetValue (Split * split) { gnc_numeric xaccSplitGetSharePrice (Split * split) { if(!split || gnc_numeric_zero_p(split->damount)) { - return gnc_numeric_create(PRICE_DENOM, PRICE_DENOM); + return gnc_numeric_create(1, 1); } return gnc_numeric_div(split->value, split->damount, - PRICE_DENOM, GNC_RND_ROUND); + GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(PRICE_SIGFIGS) | + GNC_RND_ROUND); } /********************************************************************\ diff --git a/src/engine/gnc-numeric.c b/src/engine/gnc-numeric.c index 200c300da3..e12fa07600 100644 --- a/src/engine/gnc-numeric.c +++ b/src/engine/gnc-numeric.c @@ -475,6 +475,8 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how) { gint64 remainder; gint64 sign; gint denom_neg=0; + double ratio, logratio; + double sigfigs; if(gnc_numeric_check(in)) { return gnc_numeric_error(GNC_ERROR_ARG); @@ -500,6 +502,23 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how) { } break; + case GNC_DENOM_SIGFIG: + ratio = gnc_numeric_to_double(in); + logratio = log10(ratio); + logratio = ((logratio > 0.0) ? + (floor(logratio)+1.0) : (ceil(logratio))); + sigfigs = GNC_NUMERIC_GET_SIGFIGS(how); + + if(sigfigs-logratio >= 0) { + denom = (gint64)(pow(10, sigfigs-logratio)); + } + else { + denom = -((gint64)(pow(10, logratio-sigfigs))); + } + + how = how & ~GNC_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; + break; + case GNC_DENOM_LCD: /* this is a no-op. */ default: @@ -573,7 +592,7 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how) { out.num = out.num + 1; } } - else if((2 * remainder * denom) > in.denom) { + else if((2 * remainder) > temp.denom) { out.num = out.num + 1; } break; @@ -584,7 +603,7 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how) { out.num = out.num + 1; } } - else if((2 * remainder * denom) >= in.denom) { + else if((2 * remainder ) >= temp.denom) { out.num = out.num + 1; } break; @@ -601,10 +620,10 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how) { } } else { - if((2 * remainder * denom) > in.denom) { + if((2 * remainder ) > temp.denom) { out.num = out.num + 1; } - else if((2 * remainder * denom) == in.denom) { + else if((2 * remainder) == temp.denom) { if(out.num % 2) { out.num = out.num + 1; } @@ -780,6 +799,23 @@ double_to_gnc_numeric(double in, gint64 denom, gint how) { gint64 int_part=0; double frac_part; gint64 frac_int=0; + double logval; + double sigfigs; + + if((denom == GNC_DENOM_AUTO) && (how & GNC_DENOM_SIGFIG)) { + logval = log10(in); + logval = ((logval > 0.0) ? + (floor(logval)+1.0) : (ceil(logval))); + sigfigs = GNC_NUMERIC_GET_SIGFIGS(how); + if(sigfigs-logval >= 0) { + denom = (gint64)(pow(10, sigfigs-logval)); + } + else { + denom = -((gint64)(pow(10, logval-sigfigs))); + } + + how = how & ~GNC_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; + } int_part = (gint64)(floor(fabs(in))); frac_part = in - (double)int_part; @@ -787,7 +823,7 @@ double_to_gnc_numeric(double in, gint64 denom, gint how) { int_part = int_part * denom; frac_part = frac_part * (double)denom; - switch(how) { + switch(how & GNC_NUMERIC_RND_MASK) { case GNC_RND_FLOOR: frac_int = (gint64)floor(frac_part); break; @@ -853,7 +889,7 @@ gnc_numeric_create(gint64 num, gint64 denom) { gnc_numeric gnc_numeric_error(int error_code) { if(abs(error_code) < 5) { - PERR("%s", _numeric_error_strings[ - error_code]); + // PERR("%s", _numeric_error_strings[ - error_code]); } return gnc_numeric_create(error_code, 0LL); } @@ -1180,7 +1216,35 @@ main(int argc, char ** argv) { gnc_numeric_print(b), gnc_numeric_print(d), gnc_numeric_print(gnc_numeric_add(b, d, GNC_DENOM_AUTO, GNC_DENOM_LCD))); + + printf("float to 6 sigfigs: %s\n", + gnc_numeric_print(double_to_gnc_numeric(1.1234567890123, + GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(6) | + GNC_RND_ROUND))); + printf("float to 6 sigfigs: %s\n", + gnc_numeric_print(double_to_gnc_numeric(.011234567890123, + GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(6) | + GNC_RND_ROUND))); + printf("float to 6 sigfigs: %s\n", + gnc_numeric_print(double_to_gnc_numeric(1123.4567890123, + GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(6) | + GNC_RND_ROUND))); + printf("float to 6 sigfigs: %s\n", + gnc_numeric_print(double_to_gnc_numeric(1.1234567890123e-5, + GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(6) | + GNC_RND_ROUND))); + printf("add to 4 sigfigs: %s + %s = %s\n", + gnc_numeric_print(a), gnc_numeric_print(b), + gnc_numeric_print(gnc_numeric_add(a, b, + GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(4) | + GNC_RND_ROUND))); + return 0; } #endif diff --git a/src/engine/gnc-numeric.h b/src/engine/gnc-numeric.h index 67107ea771..745960d6d9 100644 --- a/src/engine/gnc-numeric.h +++ b/src/engine/gnc-numeric.h @@ -34,8 +34,9 @@ struct _gnc_numeric { typedef struct _gnc_numeric gnc_numeric; /* bitmasks for HOW flags */ -#define GNC_NUMERIC_RND_MASK 0x0000000f -#define GNC_NUMERIC_DENOM_MASK 0x000000f0 +#define GNC_NUMERIC_RND_MASK 0x0000000f +#define GNC_NUMERIC_DENOM_MASK 0x000000f0 +#define GNC_NUMERIC_SIGFIGS_MASK 0x0000ff00 /* rounding/truncation modes for operations */ enum { @@ -54,9 +55,13 @@ enum { GNC_DENOM_EXACT = 0x10, GNC_DENOM_REDUCE = 0x20, GNC_DENOM_LCD = 0x30, - GNC_DENOM_FIXED = 0x40 + GNC_DENOM_FIXED = 0x40, + GNC_DENOM_SIGFIG = 0x50 }; +/* bits 8-15 of 'how' are reserved for the number of significant + * digits to use in the output with GNC_DENOM_SIGFIG */ + /* errors */ enum { GNC_ERROR_OK = 0, @@ -69,6 +74,8 @@ enum { #define GNC_DENOM_AUTO 0 #define GNC_DENOM_RECIPROCAL( a ) (- ( a )) +#define GNC_DENOM_SIGFIGS( a ) ( ((( a ) & 0xff) << 8) | GNC_DENOM_SIGFIG) +#define GNC_NUMERIC_GET_SIGFIGS( a ) ( (( a ) & 0xff00 ) >> 8) /* make a gnc_numeric from numerator and denominator */ gnc_numeric gnc_numeric_create(gint64 num, gint64 denom); diff --git a/src/gnc-exp-parser.c b/src/gnc-exp-parser.c index c09d4c75ae..c44cd9e2bc 100644 --- a/src/gnc-exp-parser.c +++ b/src/gnc-exp-parser.c @@ -88,7 +88,8 @@ gnc_exp_parser_init (void) double dvalue; dvalue = gh_scm2double (val_scm); - value = double_to_gnc_numeric (dvalue, 10000, GNC_RND_FLOOR); + value = double_to_gnc_numeric (dvalue, GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(6) | GNC_RND_ROUND); } else if (gh_string_p (val_scm)) { diff --git a/src/gnc-ui-util.c b/src/gnc-ui-util.c index b4c3bbb9bb..d53ad91841 100644 --- a/src/gnc-ui-util.c +++ b/src/gnc-ui-util.c @@ -1026,7 +1026,8 @@ DxaccPrintAmount (double dval, GNCPrintAmountInfo info) { gnc_numeric val; - val = double_to_gnc_numeric (dval, 10000, GNC_RND_ROUND); + val = double_to_gnc_numeric (dval, GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(6) | GNC_RND_ROUND); return xaccPrintAmount (val, info); } @@ -1036,7 +1037,8 @@ DxaccSPrintAmount (char * bufp, double dval, GNCPrintAmountInfo info) { gnc_numeric val; - val = double_to_gnc_numeric (dval, 10000, GNC_RND_ROUND); + val = double_to_gnc_numeric (dval, GNC_DENOM_AUTO, + GNC_DENOM_SIGFIGS(6) | GNC_RND_ROUND); return xaccSPrintAmount (bufp, val, info); } diff --git a/src/gnome/dialog-account-picker.c b/src/gnome/dialog-account-picker.c index a4f7b4886d..44fef4aa93 100644 --- a/src/gnome/dialog-account-picker.c +++ b/src/gnome/dialog-account-picker.c @@ -1,7 +1,7 @@ /********************************************************************\ - * dialog-account-picker.c -- window for picking a Gnucash account * - * (GnuCash) * - * Copyright (C) 2000 Bill Gribble * + * dialog-account-picker.c -- window for picking a Gnucash account * + * from the QIF importer. * + * Copyright (C) 2000-2001 Bill Gribble * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * @@ -25,243 +25,246 @@ #include #include - -#include "dialog-account-picker.h" - #include -#include "FileDialog.h" -#include "Group.h" -#include "Account.h" +#include "dialog-account-picker.h" +#include "druid-qif-import.h" +#include "gnc-ui-util.h" #include "dialog-utils.h" #include "query-user.h" +struct _accountpickerdialog { + GtkWidget * dialog; + GtkWidget * treeview; + QIFImportWindow * qif_wind; + SCM map_entry; + gchar * selected_name; +}; static void -build_acct_tree(AccountGroup * group, GtkWidget * tree, GtkWidget * picker) { - GList * accts; - GList * node; - AccountGroup * children; - GtkWidget * tree_item; - GtkWidget * sub_tree; +row_data_destroy_cb(gpointer data) { + g_free(data); +} + +static void +acct_tree_add_accts(SCM accts, GtkCTree * tree, GtkCTreeNode * parent, + char * base_name) { + char * acctinfo[2]; + char * acctname; + char sep[2] = " "; + GtkCTreeNode * node; + gboolean leafnode; + SCM current; - accts = xaccGroupGetSubAccounts(group); + sep[0] = gnc_get_account_separator(); - for (node = accts; node; node = node->next) { - Account *account = node->data; + while(!gh_null_p(accts)) { + current = gh_car(accts); - if(group == xaccAccountGetParent(account)) { - tree_item = gtk_tree_item_new_with_label(xaccAccountGetName(account)); - - gtk_object_set_user_data(GTK_OBJECT(tree_item), account); - - gtk_tree_append(GTK_TREE(tree), tree_item); - children = xaccAccountGetChildren(account); - - if(children && (xaccGroupGetNumAccounts(children) > 0)) { - sub_tree = gtk_tree_new(); - gtk_signal_connect(GTK_OBJECT(sub_tree), "select_child", - GTK_SIGNAL_FUNC(gnc_ui_account_picker_select_cb), - picker); - build_acct_tree(children, sub_tree, picker); - gtk_tree_item_set_subtree(GTK_TREE_ITEM(tree_item), - sub_tree); - } - gtk_widget_show(tree_item); + if(gh_null_p(current)) { + printf(" ** BUG in acct tree .. grib fix me! (everybody else ignore)\n"); + accts = gh_cdr(accts); + continue; } - } - g_list_free (accts); + acctinfo[0] = gh_scm2newstr(gh_car(current), NULL); + if(gh_cadr(current) == SCM_BOOL_T) { + acctinfo[1] = "*"; + } + else { + acctinfo[1] = " "; + } + + if(!gh_null_p(gh_caddr(current))) { + leafnode = FALSE; + } + else { + leafnode = TRUE; + } + + node = gtk_ctree_insert_node(tree, parent, NULL, + acctinfo, 2, + NULL, NULL, NULL, NULL, + leafnode, TRUE); + + /* set some row data */ + if(base_name && (strlen(base_name) > 0)) { + acctname = g_strjoin(sep, base_name, acctinfo[0], NULL); + } + else { + acctname = g_strdup(acctinfo[0]); + } + gtk_ctree_node_set_row_data_full(tree, node, + acctname, + row_data_destroy_cb); + if(!leafnode) { + acct_tree_add_accts(gh_caddr(current), tree, node, acctname); + } + + accts = gh_cdr(accts); + } } static gint -close_cb (GnomeDialog *dialog, gpointer data) -{ - gtk_main_quit (); - - return FALSE; +test_str_cmp(gconstpointer a, gconstpointer b) { + return strcmp(a, b); } -/****************************************************************\ - * accountPickerBox - * select an account from the ones that the engine knows about. - * this is sort of like fileBox... it returns a string for the - * account name or NULL on cancel. It's modal. -\****************************************************************/ +static void +build_acct_tree(QIFAccountPickerDialog * picker, QIFImportWindow * import) { + SCM get_accts = gh_eval_str("qif-import:get-all-accts"); + SCM acct_tree = gh_call1(get_accts, + gnc_ui_qif_import_druid_get_mappings(import)); + GtkCTreeNode * new_sel; + + gtk_clist_clear(GTK_CLIST(picker->treeview)); + acct_tree_add_accts(acct_tree, GTK_CTREE(picker->treeview), NULL, NULL); + + if(picker->selected_name) { + new_sel = + gtk_ctree_find_by_row_data_custom(GTK_CTREE(picker->treeview), + NULL, + picker->selected_name, + &test_str_cmp); + + gtk_ctree_select(GTK_CTREE(picker->treeview), new_sel); + } +} + +static void +new_child_string_cb(char * string, gpointer data) { + if(string) { + strncpy(data, string, 250); + } + else { + *(char *)data = 0; + } +} + +void +gnc_ui_qif_account_picker_new_cb(GtkButton * w, gpointer user_data) { + QIFAccountPickerDialog * wind = + gtk_object_get_data(GTK_OBJECT(user_data), + "account_picker_struct"); + SCM name_setter = gh_eval_str("qif-map-entry:set-gnc-name!"); + char name[251] = ""; + char sep[2] = " "; + int retval = -1; + char * fullname = NULL; + + GtkWidget * dlg = gnome_request_dialog(FALSE, + _("Enter a name for the account"), + "", 250, + &new_child_string_cb, &name[0], + NULL); + retval = gnome_dialog_run_and_close(GNOME_DIALOG(dlg)); + sep[0] = gnc_get_account_separator(); + + /* retval is 0 if the 'ok' button was clicked */ + if(retval == 0) { + if(wind->selected_name && (strlen(wind->selected_name) > 0)) { + fullname = g_strjoin(sep, wind->selected_name, name, NULL); + } + else { + fullname = g_strdup(name); + } + wind->selected_name = g_strdup(fullname); + gh_call2(name_setter, wind->map_entry, gh_str02scm(fullname)); + g_free(fullname); + } + + build_acct_tree(wind, wind->qif_wind); + +} + +static void +gnc_ui_qif_account_picker_select_cb(GtkCTree * tree, + GtkCTreeNode * node, + gint column, + gpointer user_data) { + QIFAccountPickerDialog * wind = + gtk_object_get_data(GTK_OBJECT(user_data), + "account_picker_struct"); + SCM name_setter = gh_eval_str("qif-map-entry:set-gnc-name!"); + + g_free(wind->selected_name); + wind->selected_name = + g_strdup(gtk_ctree_node_get_row_data(tree, node)); + + gh_call2(name_setter, wind->map_entry, gh_str02scm(wind->selected_name)); +} + + +static void +gnc_ui_qif_account_picker_unselect_cb(GtkCTree * tree, + GtkCTreeNode * node, + gint column, + gpointer user_data) { + QIFAccountPickerDialog * wind = + gtk_object_get_data(GTK_OBJECT(user_data), + "account_picker_struct"); + g_free(wind->selected_name); + wind->selected_name = NULL; +} + +/**************************************************************** + * accountPickerBox + * select an account from the ones that the engine knows about, plus + * the ones that will be created newly by the QIF import. this is + * sort of like fileBox... it returns a string for the account name or + * NULL on cancel. It's modal. + ****************************************************************/ SCM -accountPickerBox(char * initial_selection, int initial_type) { - +qif_account_picker_dialog(QIFImportWindow * qif_wind, SCM map_entry) { QIFAccountPickerDialog * wind; - - AccountGroup * topgroup; - Account * selected; - GtkWidget * treeitem = gtk_tree_item_new_with_label(_("All Accounts")); - GtkWidget * subtree = gtk_tree_new(); - SCM infolist; - + SCM save_entry = gh_eval_str("qif-map-entry:clone"); + SCM init_pick = gh_eval_str("qif-map-entry:gnc-name"); + SCM saved_entry = gh_call1(save_entry, map_entry); + int retval = -1; + char * scmname; wind = g_new0(QIFAccountPickerDialog, 1); wind->dialog = create_QIF_Import_Account_Picker(); wind->treeview = gtk_object_get_data(GTK_OBJECT(wind->dialog), "account_tree"); - wind->acct_entry = - gtk_object_get_data(GTK_OBJECT(wind->dialog), "acct_entry"); - wind->descript_entry = - gtk_object_get_data(GTK_OBJECT(wind->dialog), "acct_description_entry"); - wind->type_picker = - gtk_object_get_data(GTK_OBJECT(wind->dialog), "acct_type_picker"); + wind->qif_wind = qif_wind; - gtk_object_set_data(GTK_OBJECT(wind->dialog), "account-picker-dialog", + wind->map_entry = map_entry; + + scmname = gh_scm2newstr(gh_call1(init_pick, map_entry), NULL); + wind->selected_name = g_strdup(scmname); + free(scmname); + + scm_protect_object(wind->map_entry); + + gtk_object_set_data(GTK_OBJECT(wind->dialog), "account_picker_struct", wind); - gtk_signal_connect(GTK_OBJECT(subtree), "select_child", - GTK_SIGNAL_FUNC(gnc_ui_account_picker_select_cb), + gtk_signal_connect(GTK_OBJECT(wind->treeview), "tree_select_row", + GTK_SIGNAL_FUNC(gnc_ui_qif_account_picker_select_cb), wind->dialog); - gtk_signal_connect (GTK_OBJECT (wind->dialog), "close", - GTK_SIGNAL_FUNC (close_cb), NULL); + gtk_signal_connect(GTK_OBJECT(wind->treeview), "tree_unselect_row", + GTK_SIGNAL_FUNC(gnc_ui_qif_account_picker_unselect_cb), + wind->dialog); - /* do some setup */ - topgroup = gncGetCurrentGroup(); - gtk_tree_append(GTK_TREE(wind->treeview), treeitem); - gtk_widget_show(treeitem); - - build_acct_tree(topgroup, subtree, wind->dialog); - gtk_tree_item_set_subtree(GTK_TREE_ITEM(treeitem), subtree); - - gtk_tree_set_view_lines(GTK_TREE(wind->treeview), TRUE); - gtk_tree_item_expand(GTK_TREE_ITEM(treeitem)); - - gnc_option_menu_init(wind->type_picker); - - if(initial_selection) { - selected = xaccGetAccountFromFullName(topgroup, initial_selection, ':'); - gtk_entry_set_text(GTK_ENTRY(wind->acct_entry), initial_selection); - - if(selected) { - if(xaccAccountGetDescription(selected)) { - gtk_entry_set_text(GTK_ENTRY(wind->descript_entry), - xaccAccountGetDescription(selected)); - } - gtk_option_menu_set_history(GTK_OPTION_MENU(wind->type_picker), - xaccAccountGetType(selected)); - infolist = SCM_LIST3(gh_str02scm(initial_selection), - gh_int2scm(xaccAccountGetType(selected)), - gh_str02scm(xaccAccountGetDescription(selected))); - } - else { - gtk_entry_set_text(GTK_ENTRY(wind->descript_entry), ""); - gtk_option_menu_set_history(GTK_OPTION_MENU(wind->type_picker), - initial_type); - infolist = SCM_LIST3(gh_str02scm(initial_selection), - gh_int2scm(initial_type), - gh_str02scm("")); - } - - scm_protect_object(infolist); - wind->scm_acct_info = infolist; - } - - /* make sure the window is modal, then wait on it */ - gtk_window_set_modal(GTK_WINDOW(wind->dialog), TRUE); - gtk_widget_show(GTK_WIDGET(wind->treeview)); - gtk_widget_show(GTK_WIDGET(wind->dialog)); - gtk_main(); - - infolist = wind->scm_acct_info; - - /* destroy the window */ - scm_unprotect_object(wind->scm_acct_info); + /* update the tree display with all the existing accounts plus all + * the ones the QIF importer thinks it will be creating. this will + * also select the map_entry line. */ + build_acct_tree(wind, qif_wind); + + retval = gnome_dialog_run_and_close(GNOME_DIALOG(wind->dialog)); + + scm_unprotect_object(wind->map_entry); + g_free(wind->selected_name); g_free(wind); - return infolist; -} - -void -gnc_ui_account_picker_select_cb(GtkTree * tree, - GtkWidget * widget, - gpointer user_data) { - QIFAccountPickerDialog * wind; - Account * gnc_acct; - const char * description; - char * name; - int acct_type; - SCM infolist; - - wind = gtk_object_get_data(GTK_OBJECT(user_data), - "account-picker-dialog"); - - gnc_acct = gtk_object_get_user_data(GTK_OBJECT(widget)); - - name = xaccAccountGetFullName (gnc_acct, ':'); - if (name == NULL) - name = g_strdup (""); - - gtk_entry_set_text(GTK_ENTRY(wind->acct_entry), name); - - description = xaccAccountGetDescription(gnc_acct); - if (description == NULL) - description = ""; - - acct_type = xaccAccountGetType(gnc_acct); - - gtk_entry_set_text(GTK_ENTRY(wind->descript_entry), - description); - gtk_option_menu_set_history(GTK_OPTION_MENU(wind->type_picker), - acct_type); - infolist = SCM_LIST3(gh_str02scm(name), - gh_int2scm(acct_type), - gh_str02scm((char *) description)); - scm_protect_object(infolist); - - scm_unprotect_object(wind->scm_acct_info); - wind->scm_acct_info = infolist; - - g_free (name); -} - -void -gnc_ui_account_picker_ok_cb(GtkButton *button, - gpointer user_data) { - QIFAccountPickerDialog * wind; - - char * selected_acct; - char * description; - int acct_type; - SCM infolist; - - wind = gtk_object_get_data(GTK_OBJECT(user_data), - "account-picker-dialog"); - - selected_acct = gtk_entry_get_text(GTK_ENTRY(wind->acct_entry)); - description = gtk_entry_get_text(GTK_ENTRY(wind->descript_entry)); - - acct_type = gnc_option_menu_get_active(wind->type_picker); - gtk_entry_set_text(GTK_ENTRY(wind->descript_entry), - description); - infolist = SCM_LIST3(gh_str02scm(selected_acct), - gh_int2scm(acct_type), - gh_str02scm(description)); - scm_protect_object(infolist); - - scm_unprotect_object(wind->scm_acct_info); - wind->scm_acct_info = infolist; - - gnome_dialog_close (GNOME_DIALOG (wind->dialog)); -} - -void -gnc_ui_account_picker_cancel_cb(GtkButton * button, - gpointer user_data) { - QIFAccountPickerDialog * wind = - gtk_object_get_data(GTK_OBJECT(user_data), "account-picker-dialog"); - - scm_unprotect_object(wind->scm_acct_info); - - wind->scm_acct_info = SCM_BOOL_F; - scm_protect_object(wind->scm_acct_info); - - gnome_dialog_close (GNOME_DIALOG (wind->dialog)); + if(retval == 0) { + return map_entry; + } + else { + return saved_entry; + } } diff --git a/src/gnome/dialog-account-picker.h b/src/gnome/dialog-account-picker.h index bb3aa92bb1..1c3ecca9bf 100644 --- a/src/gnome/dialog-account-picker.h +++ b/src/gnome/dialog-account-picker.h @@ -24,24 +24,12 @@ #ifndef __DIALOG_ACCOUNT_PICKER_H_ #define __DIALOG_ACCOUNT_PICKER_H_ -#include "glade-gnc-dialogs.h" -#include "glade-cb-gnc-dialogs.h" - #include +#include "druid-qif-import.h" -SCM accountPickerBox(char *initial_pick, int initial_type); +SCM qif_account_picker_dialog(QIFImportWindow * wind, SCM initial_sel); -typedef struct _accountpickerdialog { - - GtkWidget * dialog; - GtkWidget * treeview; - GtkWidget * acct_entry; - GtkWidget * descript_entry; - GtkWidget * type_picker; - - SCM scm_acct_info; - -} QIFAccountPickerDialog; +typedef struct _accountpickerdialog QIFAccountPickerDialog; #endif diff --git a/src/gnome/druid-qif-import.c b/src/gnome/druid-qif-import.c index dcb142b1b1..d4f16e492a 100644 --- a/src/gnome/druid-qif-import.c +++ b/src/gnome/druid-qif-import.c @@ -59,26 +59,12 @@ struct _qifimportwindow { GtkWidget * selected_file_list; GtkWidget * acct_list; GtkWidget * cat_list; + GtkWidget * memo_list; GtkWidget * currency_picker; GtkWidget * currency_entry; GtkWidget * new_transaction_list; GtkWidget * old_transaction_list; - GtkWidget * start_page; - GtkWidget * loaded_files_page; - GtkWidget * load_file_page; - GtkWidget * date_format_page; - GtkWidget * account_name_page; - GtkWidget * account_doc_page; - GtkWidget * account_match_page; - GtkWidget * category_doc_page; - GtkWidget * category_match_page; - GtkWidget * currency_page; - GtkWidget * commodity_doc_page; - GtkWidget * match_doc_page; - GtkWidget * match_duplicates_page; - GtkWidget * end_page; - GList * pre_comm_pages; GList * commodity_pages; GList * post_comm_pages; @@ -95,6 +81,9 @@ struct _qifimportwindow { SCM cat_map_info; SCM cat_display_info; + SCM memo_map_info; + SCM memo_display_info; + SCM gnc_acct_info; SCM stock_hash; @@ -123,9 +112,9 @@ static GdkColor std_bg_color = { 0, 39835, 49087, 40092 }; static GdkColor std_logo_bg_color = { 0, 65535, 65535, 65535 }; static GdkColor std_title_color = { 0, 65535, 65535, 65535 }; -#define NUM_PRE_PAGES 11 +#define NUM_PRE_PAGES 13 #define NUM_POST_PAGES 3 -#define NUM_DOC_PAGES 5 +#define NUM_DOC_PAGES 6 static GnomeDruidPage * get_named_page(QIFImportWindow * w, const char * name) { @@ -150,8 +139,8 @@ gnc_ui_qif_import_druid_make(void) { char * pre_page_names[NUM_PRE_PAGES] = { "start_page", "load_file_page", "date_format_page", "account_name_page", "loaded_files_page", "account_doc_page", "account_match_page", - "category_doc_page", "category_match_page", "currency_page", - "commodity_doc_page" + "category_doc_page", "category_match_page", "memo_doc_page", + "memo_match_page", "currency_page", "commodity_doc_page" }; char * post_page_names[NUM_POST_PAGES] = { @@ -160,7 +149,7 @@ gnc_ui_qif_import_druid_make(void) { char * doc_page_names[NUM_DOC_PAGES] = { "start_page", "account_doc_page", "category_doc_page", - "commodity_doc_page", "match_doc_page" + "commodity_doc_page", "memo_doc_page", "match_doc_page" }; retval = g_new0(QIFImportWindow, 1); @@ -175,6 +164,8 @@ gnc_ui_qif_import_druid_make(void) { retval->cat_map_info = SCM_BOOL_F; retval->acct_display_info = SCM_BOOL_F; retval->acct_map_info = SCM_BOOL_F; + retval->memo_display_info = SCM_BOOL_F; + retval->memo_map_info = SCM_BOOL_F; retval->stock_hash = SCM_BOOL_F; retval->imported_account_group = SCM_BOOL_F; retval->match_transactions = SCM_BOOL_F; @@ -190,6 +181,7 @@ gnc_ui_qif_import_druid_make(void) { retval->currency_entry = gtk_object_get_data(wobj, "currency_entry"); retval->acct_list = gtk_object_get_data(wobj, "account_page_list"); retval->cat_list = gtk_object_get_data(wobj, "category_page_list"); + retval->memo_list = gtk_object_get_data(wobj, "memo_page_list"); retval->new_transaction_list = gtk_object_get_data(wobj, "new_transaction_list"); retval->old_transaction_list = @@ -227,15 +219,18 @@ gnc_ui_qif_import_druid_make(void) { load_map_prefs = gh_eval_str("qif-import:load-map-prefs"); mapping_info = gh_call0(load_map_prefs); - retval->gnc_acct_info = gh_car(mapping_info); - retval->acct_map_info = gh_cadr(mapping_info); - retval->cat_map_info = gh_caddr(mapping_info); - + retval->gnc_acct_info = gh_list_ref(mapping_info, gh_int2scm(0)); + retval->acct_map_info = gh_list_ref(mapping_info, gh_int2scm(1)); + retval->cat_map_info = gh_list_ref(mapping_info, gh_int2scm(2)); + retval->memo_map_info = gh_list_ref(mapping_info, gh_int2scm(3)); + scm_protect_object(retval->imported_files); scm_protect_object(retval->selected_file); scm_protect_object(retval->gnc_acct_info); scm_protect_object(retval->cat_display_info); scm_protect_object(retval->cat_map_info); + scm_protect_object(retval->memo_display_info); + scm_protect_object(retval->memo_map_info); scm_protect_object(retval->acct_display_info); scm_protect_object(retval->acct_map_info); scm_protect_object(retval->stock_hash); @@ -278,6 +273,8 @@ gnc_ui_qif_import_druid_destroy (QIFImportWindow * window) { scm_unprotect_object(window->gnc_acct_info); scm_unprotect_object(window->cat_display_info); scm_unprotect_object(window->cat_map_info); + scm_unprotect_object(window->memo_display_info); + scm_unprotect_object(window->memo_map_info); scm_unprotect_object(window->acct_display_info); scm_unprotect_object(window->acct_map_info); scm_unprotect_object(window->stock_hash); @@ -411,6 +408,7 @@ gnc_ui_qif_import_generic_next_cb(GnomeDruidPage * page, gpointer arg1, if(next_page) { gnome_druid_set_page(GNOME_DRUID(wind->druid), GNOME_DRUID_PAGE(next_page)); + return TRUE; } else { @@ -1040,6 +1038,76 @@ update_categories_page(QIFImportWindow * wind) { } +/**************************************************************** + * update_memo_page + * Ask the Scheme side to guess some account translations , then show + * the category name and suggested translation in the Accounts page + * clist. + ****************************************************************/ + +static void +update_memo_page(QIFImportWindow * wind) { + SCM make_memo_display = gh_eval_str("qif-dialog:make-memo-display"); + SCM get_qif_name = gh_eval_str("qif-map-entry:qif-name"); + SCM get_gnc_name = gh_eval_str("qif-map-entry:gnc-name"); + SCM get_new = gh_eval_str("qif-map-entry:new-acct?"); + SCM memos_left; + int sel_row=0; + char * row_text[3]; + + /* get the old selection row */ + sel_row = (GTK_CLIST(wind->cat_list))->focus_row; + + /* now get the list of strings to display in the clist widget */ + memos_left = gh_call3(make_memo_display, + wind->imported_files, + wind->memo_map_info, + wind->gnc_acct_info); + + scm_unprotect_object(wind->memo_display_info); + wind->memo_display_info = memos_left; + scm_protect_object(wind->memo_display_info); + + /* clear the list */ + gtk_clist_clear(GTK_CLIST(wind->memo_list)); + + /* update the text in the boxes */ + gtk_clist_freeze(GTK_CLIST(wind->memo_list)); + + gtk_clist_set_column_justification(GTK_CLIST(wind->memo_list), + 0, + GTK_JUSTIFY_RIGHT); + gtk_clist_set_column_justification(GTK_CLIST(wind->memo_list), + 1, + GTK_JUSTIFY_RIGHT); + while(!gh_null_p(memos_left)) { + row_text[0] = gh_scm2newstr(gh_call1(get_qif_name, gh_car(memos_left)), + NULL); + row_text[1] = gh_scm2newstr(gh_call1(get_gnc_name, gh_car(memos_left)), + NULL); + if(gh_call1(get_new, gh_car(memos_left)) == SCM_BOOL_T) { + row_text[2] = "Y"; + } + else { + row_text[2] = "N"; + } + + gtk_clist_append(GTK_CLIST(wind->memo_list), row_text); + memos_left = gh_cdr(memos_left); + + free (row_text[0]); + free (row_text[1]); + } + + gtk_clist_thaw(GTK_CLIST(wind->memo_list)); + + /* move to the old selected row */ + (GTK_CLIST(wind->memo_list))->focus_row = sel_row; + gtk_clist_moveto(GTK_CLIST(wind->memo_list), sel_row, 0, 0.0, 0.0); + +} + + /******************************************************************** * gnc_ui_qif_import_account_line_select_cb @@ -1053,37 +1121,22 @@ gnc_ui_qif_import_account_line_select_cb(GtkCList * clist, gint row, gpointer user_data) { QIFImportWindow * wind = gtk_object_get_data(GTK_OBJECT(user_data), "qif_window_struct"); - SCM get_gnc_name = gh_eval_str("qif-map-entry:gnc-name"); - SCM get_allowed_types = gh_eval_str("qif-map-entry:allowed-types"); - SCM set_gnc_name = gh_eval_str("qif-map-entry:set-gnc-name!"); - SCM set_allowed_types = gh_eval_str("qif-map-entry:set-allowed-types!"); - SCM set_description = gh_eval_str("qif-map-entry:set-description!"); + SCM get_name = gh_eval_str("qif-map-entry:qif-name"); SCM selected_acct; - SCM new_acct_info; - char * gnc_name; - int initial_type; - + + /* find the corresponding to the selected row */ - selected_acct = gh_list_ref(wind->acct_display_info, - gh_int2scm(row)); + selected_acct = gh_list_ref(wind->acct_display_info, gh_int2scm(row)); + + /* call the account picker to update it */ + selected_acct = qif_account_picker_dialog(wind, selected_acct); - /* call the account picker to get the new account */ - gnc_name = gh_scm2newstr(gh_call1(get_gnc_name, selected_acct), NULL); - initial_type = - gh_scm2int(gh_car(gh_call1(get_allowed_types, selected_acct))); - - new_acct_info = accountPickerBox(gnc_name, initial_type); - - if(gh_list_p(new_acct_info)) { - gh_call2(set_gnc_name, selected_acct, gh_car(new_acct_info)); - gh_call2(set_allowed_types, selected_acct, - SCM_LIST1(gh_cadr(new_acct_info))); - gh_call2(set_description, selected_acct, gh_caddr(new_acct_info)); - } + scm_hash_set_x(wind->acct_map_info, + gh_call1(get_name, selected_acct), + selected_acct); + /* update display */ update_accounts_page(wind); - - free (gnc_name); } @@ -1100,44 +1153,56 @@ gnc_ui_qif_import_category_line_select_cb(GtkCList * clist, gint row, gpointer user_data) { QIFImportWindow * wind = gtk_object_get_data(GTK_OBJECT(user_data), "qif_window_struct"); - SCM get_gnc_name = gh_eval_str("qif-map-entry:gnc-name"); - SCM get_allowed_types = gh_eval_str("qif-map-entry:allowed-types"); - SCM set_gnc_name = gh_eval_str("qif-map-entry:set-gnc-name!"); - SCM set_allowed_types = gh_eval_str("qif-map-entry:set-allowed-types!"); - SCM set_description = gh_eval_str("qif-map-entry:set-description!"); + SCM get_name = gh_eval_str("qif-map-entry:qif-name"); SCM selected_acct; - SCM new_acct_info; - char * gnc_name; - int initial_type; /* find the corresponding to the selected row */ - selected_acct = gh_list_ref(wind->cat_display_info, - gh_int2scm(row)); + selected_acct = gh_list_ref(wind->cat_display_info, gh_int2scm(row)); - /* call the account picker to get the new account */ - gnc_name = gh_scm2newstr(gh_call1(get_gnc_name, selected_acct), NULL); - initial_type = - gh_scm2int(gh_car(gh_call1(get_allowed_types, selected_acct))); - - new_acct_info = accountPickerBox(gnc_name, initial_type); - - if(gh_list_p(new_acct_info)) { - gh_call2(set_gnc_name, selected_acct, gh_car(new_acct_info)); - gh_call2(set_allowed_types, selected_acct, - SCM_LIST1(gh_cadr(new_acct_info))); - gh_call2(set_description, selected_acct, gh_caddr(new_acct_info)); - } + /* call the account picker to update it */ + selected_acct = qif_account_picker_dialog(wind, selected_acct); + scm_hash_set_x(wind->cat_map_info, + gh_call1(get_name, selected_acct), + selected_acct); + + /* update display */ update_categories_page(wind); +} - free(gnc_name); + +/******************************************************************** + * gnc_ui_qif_import_memo_line_select_cb + * when a memo is clicked for editing in the "map QIF memos to GNC" + * page. + ********************************************************************/ + +void +gnc_ui_qif_import_memo_line_select_cb(GtkCList * clist, gint row, + gint column, GdkEvent * event, + gpointer user_data) { + QIFImportWindow * wind = + gtk_object_get_data(GTK_OBJECT(user_data), "qif_window_struct"); + SCM get_name = gh_eval_str("qif-map-entry:qif-name"); + SCM selected_acct; + + /* find the corresponding to the selected row */ + selected_acct = gh_list_ref(wind->memo_display_info, gh_int2scm(row)); + + /* call the account picker to update it */ + selected_acct = qif_account_picker_dialog(wind, selected_acct); + + scm_hash_set_x(wind->memo_map_info, + gh_call1(get_name, selected_acct), + selected_acct); + + /* update display */ + update_memo_page(wind); } /******************************************************************** * gnc_ui_qif_import_accounts_prepare_cb - * - * Invoked when the "next" button is clicked on the loaded files page. ********************************************************************/ void @@ -1153,8 +1218,6 @@ gnc_ui_qif_import_accounts_prepare_cb(GnomeDruidPage * page, /******************************************************************** * gnc_ui_qif_import_categories_prepare_cb - * - * Invoked when the "next" button is clicked on the loaded files page. ********************************************************************/ void @@ -1167,6 +1230,20 @@ gnc_ui_qif_import_categories_prepare_cb(GnomeDruidPage * page, update_categories_page(wind); } +/******************************************************************** + * gnc_ui_qif_import_memo_prepare_cb + ********************************************************************/ + +void +gnc_ui_qif_import_memo_prepare_cb(GnomeDruidPage * page, + gpointer arg1, + gpointer user_data) { + QIFImportWindow * wind = + gtk_object_get_data(GTK_OBJECT(user_data), "qif_window_struct"); + + update_memo_page(wind); +} + /**************************************************************** * gnc_ui_qif_import_convert @@ -1221,9 +1298,10 @@ gnc_ui_qif_import_convert(QIFImportWindow * wind) { /* call a scheme function to do the work. The return value is an * account group containing all the new accounts and transactions */ retval = gh_apply(qif_to_gnc, - SCM_LIST5(wind->imported_files, + SCM_LIST6(wind->imported_files, wind->acct_map_info, wind->cat_map_info, + wind->memo_map_info, wind->stock_hash, gh_str02scm(currname))); @@ -1300,16 +1378,16 @@ gnc_ui_qif_import_convert(QIFImportWindow * wind) { /******************************************************************** - * gnc_ui_qif_import_categories_next_cb + * gnc_ui_qif_import_memo_next_cb ********************************************************************/ gboolean -gnc_ui_qif_import_categories_next_cb(GnomeDruidPage * page, - gpointer arg1, - gpointer user_data) { +gnc_ui_qif_import_memo_next_cb(GnomeDruidPage * page, + gpointer arg1, + gpointer user_data) { QIFImportWindow * wind = gtk_object_get_data(GTK_OBJECT(user_data), "qif_window_struct"); - + SCM any_new = gh_eval_str("qif-import:any-new-accts?"); SCM any_stock = gh_eval_str("qif-import:any-new-stock-accts?"); int show_matches; @@ -1414,12 +1492,15 @@ static gboolean gnc_ui_qif_import_comm_check_cb(GnomeDruidPage * page, gpointer arg1, gpointer user_data) { + QIFImportWindow * wind = + gtk_object_get_data(GTK_OBJECT(user_data), "qif_window_struct"); QIFDruidPage * qpage = gtk_object_get_data(GTK_OBJECT(page), "page_struct"); char * namespace = gtk_entry_get_text(GTK_ENTRY(qpage->new_type_entry)); char * name = gtk_entry_get_text(GTK_ENTRY(qpage->new_name_entry)); char * mnemonic = gtk_entry_get_text(GTK_ENTRY(qpage->new_mnemonic_entry)); + int show_matches; if(!namespace || (namespace[0] == 0)) { gnc_warning_dialog(_("You must enter a Type for the commodity.")); @@ -1434,7 +1515,29 @@ gnc_ui_qif_import_comm_check_cb(GnomeDruidPage * page, return TRUE; } - return FALSE; + if(page == (g_list_last(wind->commodity_pages))->data) { + /* it's time to import the accounts. */ + show_matches = gnc_ui_qif_import_convert(wind); + + if(show_matches) { + if(wind->show_doc_pages) { + /* check for matches .. the docpage does it automatically */ + gnome_druid_set_page(GNOME_DRUID(wind->druid), + get_named_page(wind, "match_doc_page")); + } + else { + gnome_druid_set_page(GNOME_DRUID(wind->druid), + get_named_page(wind, "match_duplicates_page")); + } + } + else { + gnome_druid_set_page(GNOME_DRUID(wind->druid), + get_named_page(wind, "end_page")); + } + } + else { + return FALSE; + } } @@ -1457,7 +1560,7 @@ gnc_ui_qif_import_commodity_prepare_cb(GnomeDruidPage * page, SCM comm_ptr_token; gnc_commodity * commodity; - GnomeDruidPage * back_page = GNOME_DRUID_PAGE(wind->commodity_doc_page); + GnomeDruidPage * back_page = get_named_page(wind, "commodity_doc_page"); QIFDruidPage * new_page; /* only set up once */ @@ -1695,7 +1798,9 @@ gnc_ui_qif_import_finish_cb(GnomeDruidPage * gpage, gnc_suspend_gui_refresh(); /* prune the old transactions marked as dupes */ - gh_call1(prune_xtns, wind->match_transactions); + if(wind->match_transactions != SCM_BOOL_F) { + gh_call1(prune_xtns, wind->match_transactions); + } /* actually add in the new transactions. */ gh_call2(cat_and_merge, @@ -1705,7 +1810,8 @@ gnc_ui_qif_import_finish_cb(GnomeDruidPage * gpage, gnc_resume_gui_refresh(); /* write out mapping info before destroying the window */ - gh_call2(save_map_prefs, wind->acct_map_info, wind->cat_map_info); + gh_call3(save_map_prefs, wind->acct_map_info, wind->cat_map_info, + wind->memo_map_info); gnc_ui_qif_import_druid_destroy(wind); } @@ -1721,6 +1827,14 @@ gnc_ui_qif_import_cancel_cb (GnomeDruid * druid, gnc_ui_qif_import_druid_destroy(wind); } +SCM +gnc_ui_qif_import_druid_get_mappings(QIFImportWindow * w) { + return SCM_LIST3(w->acct_map_info, + w->cat_map_info, + w->memo_map_info); +} + + /* ======================================================== */ void @@ -1730,3 +1844,4 @@ gncFileQIFImport (void) gnc_ui_qif_import_druid_make(); } + diff --git a/src/gnome/druid-qif-import.h b/src/gnome/druid-qif-import.h index 269288c38c..fceed15355 100644 --- a/src/gnome/druid-qif-import.h +++ b/src/gnome/druid-qif-import.h @@ -32,5 +32,5 @@ QIFImportWindow * gnc_ui_qif_import_druid_make(void); void gnc_ui_qif_import_druid_destroy (QIFImportWindow * window); - +SCM gnc_ui_qif_import_druid_get_mappings(QIFImportWindow * w); #endif diff --git a/src/gnome/glade-cb-gnc-dialogs.h b/src/gnome/glade-cb-gnc-dialogs.h index cc4e1b5e41..151ef7f2e4 100644 --- a/src/gnome/glade-cb-gnc-dialogs.h +++ b/src/gnome/glade-cb-gnc-dialogs.h @@ -234,3 +234,51 @@ gboolean gnc_ui_qif_import_generic_next_cb (GnomeDruidPage *gnomedruidpage, gpointer arg1, gpointer user_data); + +gboolean +gnc_ui_qif_import_generic_next_cb (GnomeDruidPage *gnomedruidpage, + gpointer arg1, + gpointer user_data); + +gboolean +gnc_ui_qif_import_generic_back_cb (GnomeDruidPage *gnomedruidpage, + gpointer arg1, + gpointer user_data); + +void +gnc_ui_qif_import_memo_line_select_cb (GtkCList *clist, + gint row, + gint column, + GdkEvent *event, + gpointer user_data); + +gboolean +gnc_ui_qif_import_generic_next_cb (GnomeDruidPage *gnomedruidpage, + gpointer arg1, + gpointer user_data); + +gboolean +gnc_ui_qif_import_memo_next_cb (GnomeDruidPage *gnomedruidpage, + gpointer arg1, + gpointer user_data); + +void +gnc_ui_qif_import_memo_prepare_cb (GnomeDruidPage *gnomedruidpage, + gpointer arg1, + gpointer user_data); + +void +gnc_ui_account_picker_new_cb (GtkButton *button, + gpointer user_data); + +void +gnc_ui_qif_account_picker_new_cb (GtkButton *button, + gpointer user_data); + +void +gnc_ui_qif_account_picker_ok_cb (GtkButton *button, + gpointer user_data); + +void +gnc_ui_qif_account_picker_cancel_cb (GtkButton *button, + gpointer user_data); diff --git a/src/gnome/glade-gnc-dialogs.c b/src/gnome/glade-gnc-dialogs.c index bb78a9931d..ef7c62b7ea 100644 --- a/src/gnome/glade-gnc-dialogs.c +++ b/src/gnome/glade-gnc-dialogs.c @@ -24,27 +24,19 @@ create_QIF_Import_Account_Picker (void) GtkWidget *vbox1; GtkWidget *vbox2; GtkWidget *frame1; - GtkWidget *scrolledwindow1; - GtkWidget *viewport1; + GtkWidget *scrolledwindow24; GtkWidget *account_tree; - GtkWidget *hbox5; - GtkWidget *vbox4; - GtkWidget *label1; - GtkWidget *label2; - GtkWidget *label3; - GtkWidget *vbox5; - GtkWidget *acct_entry; - GtkWidget *acct_description_entry; - GtkWidget *acct_type_picker; - GtkWidget *acct_type_picker_menu; - GtkWidget *glade_menuitem; + GtkWidget *label847711; + GtkWidget *label847712; + GtkWidget *button78; GtkWidget *hbuttonbox1; GtkWidget *button1; GtkWidget *button2; QIF_Import_Account_Picker = gnome_dialog_new (_("Select Account"), NULL); gtk_object_set_data (GTK_OBJECT (QIF_Import_Account_Picker), "QIF_Import_Account_Picker", QIF_Import_Account_Picker); - gtk_window_set_policy (GTK_WINDOW (QIF_Import_Account_Picker), TRUE, TRUE, FALSE); + gtk_window_set_default_size (GTK_WINDOW (QIF_Import_Account_Picker), 300, 400); + gtk_window_set_policy (GTK_WINDOW (QIF_Import_Account_Picker), TRUE, TRUE, TRUE); vbox1 = GNOME_DIALOG (QIF_Import_Account_Picker)->vbox; gtk_object_set_data (GTK_OBJECT (QIF_Import_Account_Picker), "vbox1", vbox1); @@ -57,139 +49,51 @@ create_QIF_Import_Account_Picker (void) gtk_widget_show (vbox2); gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0); - frame1 = gtk_frame_new (_("Accounts")); + frame1 = gtk_frame_new (_("Select or add a Gnucash account")); gtk_widget_ref (frame1); gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "frame1", frame1, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (frame1); gtk_box_pack_start (GTK_BOX (vbox2), frame1, TRUE, TRUE, 0); - scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_ref (scrolledwindow1); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "scrolledwindow1", scrolledwindow1, + scrolledwindow24 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_ref (scrolledwindow24); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "scrolledwindow24", scrolledwindow24, (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (scrolledwindow1); - gtk_container_add (GTK_CONTAINER (frame1), scrolledwindow1); - gtk_widget_set_usize (scrolledwindow1, 250, 200); + gtk_widget_show (scrolledwindow24); + gtk_container_add (GTK_CONTAINER (frame1), scrolledwindow24); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow24), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - viewport1 = gtk_viewport_new (NULL, NULL); - gtk_widget_ref (viewport1); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "viewport1", viewport1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (viewport1); - gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1); - - account_tree = gtk_tree_new (); + account_tree = gtk_ctree_new (2, 0); gtk_widget_ref (account_tree); gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "account_tree", account_tree, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (account_tree); - gtk_container_add (GTK_CONTAINER (viewport1), account_tree); + gtk_container_add (GTK_CONTAINER (scrolledwindow24), account_tree); + gtk_clist_set_column_width (GTK_CLIST (account_tree), 0, 214); + gtk_clist_set_column_width (GTK_CLIST (account_tree), 1, 48); + gtk_clist_column_titles_show (GTK_CLIST (account_tree)); - hbox5 = gtk_hbox_new (FALSE, 0); - gtk_widget_ref (hbox5); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "hbox5", hbox5, + label847711 = gtk_label_new (_("Account")); + gtk_widget_ref (label847711); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "label847711", label847711, (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox5); - gtk_box_pack_start (GTK_BOX (vbox1), hbox5, FALSE, FALSE, 0); + gtk_widget_show (label847711); + gtk_clist_set_column_widget (GTK_CLIST (account_tree), 0, label847711); - vbox4 = gtk_vbox_new (TRUE, 0); - gtk_widget_ref (vbox4); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "vbox4", vbox4, + label847712 = gtk_label_new (_("New?")); + gtk_widget_ref (label847712); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "label847712", label847712, (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox4); - gtk_box_pack_start (GTK_BOX (hbox5), vbox4, TRUE, TRUE, 5); + gtk_widget_show (label847712); + gtk_clist_set_column_widget (GTK_CLIST (account_tree), 1, label847712); - label1 = gtk_label_new (_("Selected account:")); - gtk_widget_ref (label1); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "label1", label1, + button78 = gtk_button_new_with_label (_("New Account (child of selected) ...")); + gtk_widget_ref (button78); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "button78", button78, (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label1); - gtk_box_pack_start (GTK_BOX (vbox4), label1, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_RIGHT); - gtk_misc_set_alignment (GTK_MISC (label1), 1, 0.5); - - label2 = gtk_label_new (_("Description:")); - gtk_widget_ref (label2); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "label2", label2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label2); - gtk_box_pack_start (GTK_BOX (vbox4), label2, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_RIGHT); - gtk_misc_set_alignment (GTK_MISC (label2), 1, 0.5); - - label3 = gtk_label_new (_("Account type:")); - gtk_widget_ref (label3); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "label3", label3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label3); - gtk_box_pack_start (GTK_BOX (vbox4), label3, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_RIGHT); - gtk_misc_set_alignment (GTK_MISC (label3), 1, 0.5); - - vbox5 = gtk_vbox_new (TRUE, 0); - gtk_widget_ref (vbox5); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "vbox5", vbox5, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox5); - gtk_box_pack_start (GTK_BOX (hbox5), vbox5, TRUE, TRUE, 0); - - acct_entry = gtk_entry_new (); - gtk_widget_ref (acct_entry); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "acct_entry", acct_entry, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (acct_entry); - gtk_box_pack_start (GTK_BOX (vbox5), acct_entry, FALSE, FALSE, 0); - - acct_description_entry = gtk_entry_new (); - gtk_widget_ref (acct_description_entry); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "acct_description_entry", acct_description_entry, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (acct_description_entry); - gtk_box_pack_start (GTK_BOX (vbox5), acct_description_entry, FALSE, FALSE, 0); - - acct_type_picker = gtk_option_menu_new (); - gtk_widget_ref (acct_type_picker); - gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Account_Picker), "acct_type_picker", acct_type_picker, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (acct_type_picker); - gtk_box_pack_start (GTK_BOX (vbox5), acct_type_picker, FALSE, FALSE, 0); - gtk_widget_set_usize (acct_type_picker, 150, 30); - acct_type_picker_menu = gtk_menu_new (); - glade_menuitem = gtk_menu_item_new_with_label (_("Bank")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - glade_menuitem = gtk_menu_item_new_with_label (_("Cash")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - glade_menuitem = gtk_menu_item_new_with_label (_("Asset")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - glade_menuitem = gtk_menu_item_new_with_label (_("Credit")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - glade_menuitem = gtk_menu_item_new_with_label (_("Liability")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - glade_menuitem = gtk_menu_item_new_with_label (_("Stock")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - glade_menuitem = gtk_menu_item_new_with_label (_("Mutual")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - glade_menuitem = gtk_menu_item_new_with_label (_("Currency")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - glade_menuitem = gtk_menu_item_new_with_label (_("Income")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - glade_menuitem = gtk_menu_item_new_with_label (_("Expense")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - glade_menuitem = gtk_menu_item_new_with_label (_("Equity")); - gtk_widget_show (glade_menuitem); - gtk_menu_append (GTK_MENU (acct_type_picker_menu), glade_menuitem); - gtk_option_menu_set_menu (GTK_OPTION_MENU (acct_type_picker), acct_type_picker_menu); + gtk_widget_show (button78); + gtk_box_pack_start (GTK_BOX (vbox1), button78, FALSE, FALSE, 0); hbuttonbox1 = GNOME_DIALOG (QIF_Import_Account_Picker)->action_area; gtk_object_set_data (GTK_OBJECT (QIF_Import_Account_Picker), "hbuttonbox1", hbuttonbox1); @@ -213,14 +117,8 @@ create_QIF_Import_Account_Picker (void) gtk_widget_show (button2); GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); - gtk_signal_connect (GTK_OBJECT (account_tree), "select_child", - GTK_SIGNAL_FUNC (gnc_ui_account_picker_select_cb), - QIF_Import_Account_Picker); - gtk_signal_connect (GTK_OBJECT (button1), "clicked", - GTK_SIGNAL_FUNC (gnc_ui_account_picker_ok_cb), - QIF_Import_Account_Picker); - gtk_signal_connect (GTK_OBJECT (button2), "clicked", - GTK_SIGNAL_FUNC (gnc_ui_account_picker_cancel_cb), + gtk_signal_connect (GTK_OBJECT (button78), "clicked", + GTK_SIGNAL_FUNC (gnc_ui_qif_account_picker_new_cb), QIF_Import_Account_Picker); return QIF_Import_Account_Picker; @@ -3939,6 +3837,23 @@ create_QIF_Import_Druid (void) GtkWidget *label838; GtkWidget *label839; GtkWidget *label829; + GtkWidget *memo_doc_page; + GdkColor memo_doc_page_bg_color = { 0, 39321, 49087, 39578 }; + GdkColor memo_doc_page_logo_bg_color = { 0, 65535, 65535, 65535 }; + GdkColor memo_doc_page_title_color = { 0, 65535, 65535, 65535 }; + GtkWidget *druid_vbox39; + GtkWidget *label847707; + GtkWidget *memo_match_page; + GdkColor memo_match_page_bg_color = { 0, 39321, 49087, 39578 }; + GdkColor memo_match_page_logo_bg_color = { 0, 65535, 65535, 65535 }; + GdkColor memo_match_page_title_color = { 0, 65535, 65535, 65535 }; + GtkWidget *druid_vbox40; + GtkWidget *label847713; + GtkWidget *scrolledwindow25; + GtkWidget *memo_page_list; + GtkWidget *label847708; + GtkWidget *label847709; + GtkWidget *label847710; GtkWidget *currency_page; GdkColor currency_page_bg_color = { 0, 39321, 49087, 39578 }; GdkColor currency_page_logo_bg_color = { 0, 65535, 65535, 65535 }; @@ -4239,7 +4154,7 @@ create_QIF_Import_Druid (void) gnome_druid_page_standard_set_bg_color (GNOME_DRUID_PAGE_STANDARD (account_doc_page), &account_doc_page_bg_color); gnome_druid_page_standard_set_logo_bg_color (GNOME_DRUID_PAGE_STANDARD (account_doc_page), &account_doc_page_logo_bg_color); gnome_druid_page_standard_set_title_color (GNOME_DRUID_PAGE_STANDARD (account_doc_page), &account_doc_page_title_color); - gnome_druid_page_standard_set_title (GNOME_DRUID_PAGE_STANDARD (account_doc_page), _("Your accounts and stock holdings")); + gnome_druid_page_standard_set_title (GNOME_DRUID_PAGE_STANDARD (account_doc_page), _("Accounts and stock holdings")); druid_vbox13 = GNOME_DRUID_PAGE_STANDARD (account_doc_page)->vbox; gtk_widget_ref (druid_vbox13); @@ -4408,6 +4323,95 @@ create_QIF_Import_Druid (void) gtk_widget_show (label829); gtk_box_pack_start (GTK_BOX (druid_vbox4), label829, FALSE, FALSE, 3); + memo_doc_page = gnome_druid_page_standard_new_with_vals ("", NULL); + gtk_widget_ref (memo_doc_page); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "memo_doc_page", memo_doc_page, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show_all (memo_doc_page); + gnome_druid_append_page (GNOME_DRUID (qif_import_druid), GNOME_DRUID_PAGE (memo_doc_page)); + gnome_druid_page_standard_set_bg_color (GNOME_DRUID_PAGE_STANDARD (memo_doc_page), &memo_doc_page_bg_color); + gnome_druid_page_standard_set_logo_bg_color (GNOME_DRUID_PAGE_STANDARD (memo_doc_page), &memo_doc_page_logo_bg_color); + gnome_druid_page_standard_set_title_color (GNOME_DRUID_PAGE_STANDARD (memo_doc_page), &memo_doc_page_title_color); + gnome_druid_page_standard_set_title (GNOME_DRUID_PAGE_STANDARD (memo_doc_page), _("Payees and memos")); + + druid_vbox39 = GNOME_DRUID_PAGE_STANDARD (memo_doc_page)->vbox; + gtk_widget_ref (druid_vbox39); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "druid_vbox39", druid_vbox39, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (druid_vbox39); + + label847707 = gtk_label_new (_("QIF files dowloaded from banks and other financial institutions may not have\ninformation about Accounts and Categories which would allow them to be\ncorrectly assigned to Gnucash accounts. \n\nIn the following page, you will see the text that appears in the Payee and \nMemo fields of transactions with no QIF Account or Category. By default\nthese transactions are assigned to the 'Unspecified' account in Gnucash. \nIf you select a different account, it will be remembered for future QIF \nfiles. ")); + gtk_widget_ref (label847707); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "label847707", label847707, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label847707); + gtk_box_pack_start (GTK_BOX (druid_vbox39), label847707, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label847707), GTK_JUSTIFY_LEFT); + + memo_match_page = gnome_druid_page_standard_new_with_vals ("", NULL); + gtk_widget_ref (memo_match_page); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "memo_match_page", memo_match_page, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show_all (memo_match_page); + gnome_druid_append_page (GNOME_DRUID (qif_import_druid), GNOME_DRUID_PAGE (memo_match_page)); + gnome_druid_page_standard_set_bg_color (GNOME_DRUID_PAGE_STANDARD (memo_match_page), &memo_match_page_bg_color); + gnome_druid_page_standard_set_logo_bg_color (GNOME_DRUID_PAGE_STANDARD (memo_match_page), &memo_match_page_logo_bg_color); + gnome_druid_page_standard_set_title_color (GNOME_DRUID_PAGE_STANDARD (memo_match_page), &memo_match_page_title_color); + gnome_druid_page_standard_set_title (GNOME_DRUID_PAGE_STANDARD (memo_match_page), _("Match payees/memos to Gnucash accounts")); + + druid_vbox40 = GNOME_DRUID_PAGE_STANDARD (memo_match_page)->vbox; + gtk_widget_ref (druid_vbox40); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "druid_vbox40", druid_vbox40, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (druid_vbox40); + + label847713 = gtk_label_new (_("This doesn't actually affect the QIF import yet. \nGive it a couple more days :)")); + gtk_widget_ref (label847713); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "label847713", label847713, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label847713); + gtk_box_pack_start (GTK_BOX (druid_vbox40), label847713, FALSE, FALSE, 0); + + scrolledwindow25 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_ref (scrolledwindow25); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "scrolledwindow25", scrolledwindow25, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (scrolledwindow25); + gtk_box_pack_start (GTK_BOX (druid_vbox40), scrolledwindow25, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow25), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + + memo_page_list = gtk_clist_new (3); + gtk_widget_ref (memo_page_list); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "memo_page_list", memo_page_list, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (memo_page_list); + gtk_container_add (GTK_CONTAINER (scrolledwindow25), memo_page_list); + gtk_clist_set_column_width (GTK_CLIST (memo_page_list), 0, 285); + gtk_clist_set_column_width (GTK_CLIST (memo_page_list), 1, 228); + gtk_clist_set_column_width (GTK_CLIST (memo_page_list), 2, 72); + gtk_clist_column_titles_show (GTK_CLIST (memo_page_list)); + + label847708 = gtk_label_new (_("QIF payee/memo")); + gtk_widget_ref (label847708); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "label847708", label847708, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label847708); + gtk_clist_set_column_widget (GTK_CLIST (memo_page_list), 0, label847708); + + label847709 = gtk_label_new (_("Gnucash account name")); + gtk_widget_ref (label847709); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "label847709", label847709, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label847709); + gtk_clist_set_column_widget (GTK_CLIST (memo_page_list), 1, label847709); + + label847710 = gtk_label_new (_("New?")); + gtk_widget_ref (label847710); + gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "label847710", label847710, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label847710); + gtk_clist_set_column_widget (GTK_CLIST (memo_page_list), 2, label847710); + currency_page = gnome_druid_page_standard_new_with_vals ("", NULL); gtk_widget_ref (currency_page); gtk_object_set_data_full (GTK_OBJECT (QIF_Import_Druid), "currency_page", currency_page, @@ -4717,7 +4721,7 @@ create_QIF_Import_Druid (void) GTK_SIGNAL_FUNC (gnc_ui_qif_import_categories_prepare_cb), QIF_Import_Druid); gtk_signal_connect (GTK_OBJECT (category_match_page), "next", - GTK_SIGNAL_FUNC (gnc_ui_qif_import_categories_next_cb), + GTK_SIGNAL_FUNC (gnc_ui_qif_import_generic_next_cb), QIF_Import_Druid); gtk_signal_connect (GTK_OBJECT (category_match_page), "back", GTK_SIGNAL_FUNC (gnc_ui_qif_import_generic_back_cb), @@ -4725,6 +4729,24 @@ create_QIF_Import_Druid (void) gtk_signal_connect (GTK_OBJECT (category_page_list), "select_row", GTK_SIGNAL_FUNC (gnc_ui_qif_import_category_line_select_cb), QIF_Import_Druid); + gtk_signal_connect (GTK_OBJECT (memo_doc_page), "next", + GTK_SIGNAL_FUNC (gnc_ui_qif_import_generic_next_cb), + QIF_Import_Druid); + gtk_signal_connect (GTK_OBJECT (memo_doc_page), "back", + GTK_SIGNAL_FUNC (gnc_ui_qif_import_generic_back_cb), + QIF_Import_Druid); + gtk_signal_connect (GTK_OBJECT (memo_match_page), "next", + GTK_SIGNAL_FUNC (gnc_ui_qif_import_memo_next_cb), + QIF_Import_Druid); + gtk_signal_connect (GTK_OBJECT (memo_match_page), "back", + GTK_SIGNAL_FUNC (gnc_ui_qif_import_generic_back_cb), + QIF_Import_Druid); + gtk_signal_connect (GTK_OBJECT (memo_match_page), "prepare", + GTK_SIGNAL_FUNC (gnc_ui_qif_import_memo_prepare_cb), + QIF_Import_Druid); + gtk_signal_connect (GTK_OBJECT (memo_page_list), "select_row", + GTK_SIGNAL_FUNC (gnc_ui_qif_import_memo_line_select_cb), + QIF_Import_Druid); gtk_signal_connect (GTK_OBJECT (currency_page), "next", GTK_SIGNAL_FUNC (gnc_ui_qif_import_currency_next_cb), QIF_Import_Druid); diff --git a/src/gnome/gnc-dialogs.glade b/src/gnome/gnc-dialogs.glade index d3fe45ba32..ffa6ed5a57 100644 --- a/src/gnome/gnc-dialogs.glade +++ b/src/gnome/gnc-dialogs.glade @@ -30,9 +30,11 @@ GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False + 300 + 400 True True - False + True False False @@ -70,12 +72,6 @@ button1 True True - - clicked - gnc_ui_account_picker_ok_cb - QIF_Import_Account_Picker - Thu, 02 Mar 2000 23:02:59 GMT - GNOME_STOCK_BUTTON_OK @@ -84,12 +80,6 @@ button2 True True - - clicked - gnc_ui_account_picker_cancel_cb - QIF_Import_Account_Picker - Thu, 02 Mar 2000 23:03:18 GMT - GNOME_STOCK_BUTTON_CANCEL @@ -108,7 +98,7 @@ GtkFrame frame1 - + 0 GTK_SHADOW_ETCHED_IN @@ -119,31 +109,46 @@ GtkScrolledWindow - scrolledwindow1 - 250 - 200 - GTK_POLICY_ALWAYS - GTK_POLICY_ALWAYS + scrolledwindow24 + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS - GtkViewport - viewport1 + GtkCTree + account_tree + True + 2 + 214,48 + GTK_SELECTION_SINGLE + True GTK_SHADOW_IN - GtkTree - account_tree - - select_child - gnc_ui_account_picker_select_cb - QIF_Import_Account_Picker - Thu, 02 Mar 2000 21:32:14 GMT - - GTK_SELECTION_SINGLE - GTK_TREE_VIEW_LINE - True + GtkLabel + CTree:title + label847711 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + CTree:title + label847712 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 @@ -151,146 +156,22 @@ - GtkHBox - hbox5 - False - 0 + GtkButton + button78 + True + + clicked + gnc_ui_qif_account_picker_new_cb + QIF_Import_Account_Picker + Sat, 10 Feb 2001 21:26:10 GMT + + + GTK_RELIEF_NORMAL 0 False False - - - GtkVBox - vbox4 - True - 0 - - 5 - True - True - - - - GtkLabel - label1 - - GTK_JUSTIFY_RIGHT - False - 1 - 0.5 - 0 - 0 - - 0 - False - False - - - - - GtkLabel - label2 - - GTK_JUSTIFY_RIGHT - False - 1 - 0.5 - 0 - 0 - - 0 - False - False - - - - - GtkLabel - label3 - - GTK_JUSTIFY_RIGHT - False - 1 - 0.5 - 0 - 0 - - 0 - False - False - - - - - - GtkVBox - vbox5 - True - 0 - - 0 - True - True - - - - GtkEntry - acct_entry - True - True - True - 0 - - - 0 - False - False - - - - - GtkEntry - acct_description_entry - True - True - True - 0 - - - 0 - False - False - - - - - GtkOptionMenu - acct_type_picker - 150 - 30 - True - Bank -Cash -Asset -Credit -Liability -Stock -Mutual -Currency -Income -Expense -Equity - - 0 - - 0 - False - False - - - @@ -5967,7 +5848,7 @@ in that program. next gnc_ui_qif_import_generic_next_cb QIF_Import_Druid - Tue, 06 Feb 2001 17:07:56 GMT + Fri, 09 Feb 2001 17:04:25 GMT back @@ -6132,7 +6013,7 @@ of the QIF import process. QIF_Import_Druid Tue, 06 Feb 2001 17:08:52 GMT - Your accounts and stock holdings + Accounts and stock holdings 255,255,255 153,191,153 255,255,255 @@ -6379,9 +6260,9 @@ within GnuCash. next - gnc_ui_qif_import_categories_next_cb + gnc_ui_qif_import_generic_next_cb QIF_Import_Druid - Tue, 05 Sep 2000 17:18:38 GMT + Fri, 09 Feb 2001 17:04:56 GMT back @@ -6495,6 +6376,193 @@ within GnuCash. + + GnomeDruidPageStandard + memo_doc_page + + next + gnc_ui_qif_import_generic_next_cb + QIF_Import_Druid + Fri, 09 Feb 2001 16:17:27 GMT + + + back + gnc_ui_qif_import_generic_back_cb + QIF_Import_Druid + Fri, 09 Feb 2001 16:17:45 GMT + + Payees and memos + 255,255,255 + 153,191,154 + 255,255,255 + + + GtkVBox + GnomeDruidPageStandard:vbox + druid-vbox39 + False + 0 + + 0 + True + True + + + + GtkLabel + label847707 + + GTK_JUSTIFY_LEFT + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + + + GnomeDruidPageStandard + memo_match_page + + next + gnc_ui_qif_import_memo_next_cb + QIF_Import_Druid + Fri, 09 Feb 2001 17:05:14 GMT + + + back + gnc_ui_qif_import_generic_back_cb + QIF_Import_Druid + Fri, 09 Feb 2001 16:18:32 GMT + + + prepare + gnc_ui_qif_import_memo_prepare_cb + QIF_Import_Druid + Fri, 09 Feb 2001 16:39:58 GMT + + Match payees/memos to Gnucash accounts + 255,255,255 + 153,191,154 + 255,255,255 + + + GtkVBox + GnomeDruidPageStandard:vbox + druid-vbox40 + False + 0 + + 0 + True + True + + + + GtkLabel + label847713 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkScrolledWindow + scrolledwindow25 + GTK_POLICY_NEVER + GTK_POLICY_ALWAYS + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + 0 + True + True + + + + GtkCList + memo_page_list + True + + select_row + gnc_ui_qif_import_memo_line_select_cb + QIF_Import_Druid + Fri, 09 Feb 2001 16:28:31 GMT + + 3 + 285,228,72 + GTK_SELECTION_SINGLE + True + GTK_SHADOW_IN + + + GtkLabel + CList:title + label847708 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + CList:title + label847709 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + CList:title + label847710 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + + GnomeDruidPageStandard currency_page diff --git a/src/scm/gnc-numeric.scm b/src/scm/gnc-numeric.scm index 274b063eea..694f51982e 100644 --- a/src/scm/gnc-numeric.scm +++ b/src/scm/gnc-numeric.scm @@ -23,7 +23,7 @@ (gnc:support "gnc-numeric.scm") -;; use 'logor' in guile to bit-combine RND and DENOM flags. +;; use 'logior' in guile to bit-combine RND and DENOM flags. (define GNC-RND-FLOOR 1) (define GNC-RND-CEIL 2) @@ -38,6 +38,10 @@ (define GNC-DENOM-REDUCE 32) (define GNC-DENOM-FIXED 64) (define GNC-DENOM-LCD 48) +(define GNC-DENOM-SIGFIG 80) + +(define (GNC-DENOM-SIGFIGS n) + (logior GNC-DENOM-SIGFIG (* n 256))) (define GNC-ERROR-OK 0) (define GNC-ERROR-ARG -1) diff --git a/src/scm/html-utilities.scm b/src/scm/html-utilities.scm index f8f3463a41..4c66e57b6b 100644 --- a/src/scm/html-utilities.scm +++ b/src/scm/html-utilities.scm @@ -317,8 +317,10 @@ " = " (gnc:commodity-value->string (list common-commodity + ;; convert to 6 significant figures (gnc:numeric-convert - ;; FIXME: remove the constant 100000 - (cadr pair) 100000 GNC-RND-ROUND)))))) + (cadr pair) + GNC-DENOM-AUTO + (logor (GNC-DENOM-SIGFIGS 6) GNC-RND-ROUND))))))) alist)) diff --git a/src/scm/qif-import/qif-dialog-utils.scm b/src/scm/qif-import/qif-dialog-utils.scm index daa7fed47d..eee1662813 100644 --- a/src/scm/qif-import/qif-dialog-utils.scm +++ b/src/scm/qif-import/qif-dialog-utils.scm @@ -15,47 +15,60 @@ (string-append brokerage (gnc:account-separator-char) security)) (define (default-dividend-acct brokerage security) - (string-append "Dividends" (gnc:account-separator-char) + (string-append (_ "Dividends") (gnc:account-separator-char) brokerage (gnc:account-separator-char) security)) (define (default-interest-acct brokerage security) - (string-append "Interest" (gnc:account-separator-char) + (string-append (_ "Interest") (gnc:account-separator-char) brokerage (gnc:account-separator-char) security)) (define (default-capital-return-acct brokerage security) - (string-append "Cap Return" (gnc:account-separator-char) + (string-append (_ "Cap Return") (gnc:account-separator-char) brokerage (gnc:account-separator-char) security)) (define (default-cglong-acct brokerage security) - (string-append "Cap. gain (long)" (gnc:account-separator-char) + (string-append (_ "Cap. gain (long)") (gnc:account-separator-char) brokerage (gnc:account-separator-char) security)) (define (default-cgmid-acct brokerage security) - (string-append "Cap. gain (mid)" (gnc:account-separator-char) + (string-append (_ "Cap. gain (mid)") (gnc:account-separator-char) brokerage (gnc:account-separator-char) security)) (define (default-cgshort-acct brokerage security) - (string-append "Cap. gain (short)" (gnc:account-separator-char) + (string-append (_ "Cap. gain (short)") (gnc:account-separator-char) brokerage (gnc:account-separator-char) security)) -(define (default-equity-holding security) "Retained Earnings") +(define (default-equity-holding security) (_ "Retained Earnings")) -(define (default-equity-account) "Retained Earnings") +(define (default-equity-account) (_ "Retained Earnings")) (define (default-commission-acct brokerage) - (string-append "Commissions" (gnc:account-separator-char) + (string-append (_ "Commissions") (gnc:account-separator-char) brokerage)) (define (default-margin-interest-acct brokerage) - (string-append "Margin Interest" (gnc:account-separator-char) + (string-append (_ "Margin Interest") (gnc:account-separator-char) brokerage)) +(define (default-unspec-acct) + (_ "Unspecified")) + +(define (qif-import:gnc-account-exists map-entry acct-list) + (let ((retval #f)) + (for-each + (lambda (acct) + (if (string=? (qif-map-entry:gnc-name map-entry) + (car acct)) + (set! retval #t))) + acct-list) + retval)) + ;; the account-display is a 3-columned list of accounts in the QIF ;; import dialog (the "Account" page of the notebook). Column 1 is ;; the account name in the QIF file, column 2 is the number of QIF @@ -63,16 +76,20 @@ ;; translation. Sorted on # transactions, then alpha. (define (qif-dialog:make-account-display qif-files acct-hash gnc-acct-info) - ;; first, clear the "display" flags in the acct-hash. If there's - ;; nothing to show any more, don't. + ;; first, clear the "display" flags in the acct-hash and set up the + ;; new-file? flags. If there's nothing to show any more, don't. (for-each (lambda (bin) (for-each (lambda (elt) - (qif-map-entry:set-display?! (cdr elt) #f)) + (qif-map-entry:set-display?! (cdr elt) #f) + (qif-map-entry:set-new-acct?! + (cdr elt) + (if (qif-import:gnc-account-exists (cdr elt) gnc-acct-info) + #f #t))) bin)) (vector->list acct-hash)) - + (let ((retval '())) ;; we want to make two passes here. The first pass picks the ;; explicit Account descriptions out of each file. These are the @@ -359,10 +376,14 @@ (lambda (bin) (for-each (lambda (elt) - (qif-map-entry:set-display?! (cdr elt) #f)) + (qif-map-entry:set-display?! (cdr elt) #f) + (qif-map-entry:set-new-acct?! + (cdr elt) + (if (qif-import:gnc-account-exists (cdr elt) gnc-acct-info) + #f #t))) bin)) (vector->list cat-hash)) - + (let ((retval '()) (entry #f)) ;; get the Cat entries from each file @@ -438,16 +459,19 @@ (define (qif-dialog:make-memo-display qif-files memo-hash gnc-acct-info) (let ((retval '())) - ;; clear the display flags for existing items (for-each (lambda (bin) (for-each (lambda (elt) + (qif-map-entry:set-new-acct?! + (cdr elt) + (if (qif-import:gnc-account-exists (cdr elt) gnc-acct-info) + #f #t)) (qif-map-entry:set-display?! (cdr elt) #f)) bin)) (vector->list memo-hash)) - + ;; iterate over every imported transaction. If there's no ;; category in the transaction, look at the payee to get a clue. ;; of there's no payee, look at the split memo. @@ -460,34 +484,42 @@ (for-each (lambda (split) (let ((cat (qif-split:category split)) - (memo (qif-split:memo split))) + (memo (qif-split:memo split)) + (key-string #f)) ;; for each split: if there's a category, do nothing. ;; if there's a payee, use that as the ;; key. otherwise, use the split memo. (cond ((and cat (or (not (string? cat)) - (string=? cat ""))) + (not (string=? cat "")))) (set! key-string #f)) (payee (set! key-string payee)) (memo - (set! ley-string memo))) + (set! key-string memo))) (if key-string (let ((entry (hash-ref memo-hash key-string))) (if (not entry) - (set! entry - (qif-import:guess-acct - payee - (if (> (qif-split:amount split) 0) - (list GNC-INCOME-TYPE) - (list GNC-EXPENSE-TYPE))))) + (begin + (set! entry (make-qif-map-entry)) + (qif-map-entry:set-qif-name! entry key-string) + (qif-map-entry:set-gnc-name! + entry (default-unspec-acct)) + (qif-map-entry:set-new-acct?! + entry (if (qif-import:gnc-account-exists + entry gnc-acct-info) + #f #t)) + (qif-map-entry:set-allowed-types! + entry (if (> (qif-split:amount split) 0) + (list GNC-INCOME-TYPE) + (list GNC-EXPENSE-TYPE))))) (qif-map-entry:set-display?! entry #t) (hash-set! memo-hash key-string entry))))) splits))) (qif-file:xtns file))) qif-files) - + ;; build display list (for-each (lambda (bin) @@ -613,6 +645,88 @@ (list newhash (sort names string item -1) (let ((i 0)) diff --git a/src/scm/qif-import/qif-guess-map.scm b/src/scm/qif-import/qif-guess-map.scm index 9c68146ab4..6eaa148717 100644 --- a/src/scm/qif-import/qif-guess-map.scm +++ b/src/scm/qif-import/qif-guess-map.scm @@ -62,7 +62,7 @@ ;; (shortname fullname account) format. ;; - a hash of QIF account name to gnucash account info ;; - a hash of QIF category to gnucash account info - ;; - a hash of QIF memo/payee to gnucash account info <-- not yet + ;; - a hash of QIF memo/payee to gnucash account info ;; (older saved prefs may not have this one) (let* ((pref-dir (build-path (getenv "HOME") ".gnucash")) (pref-filename (build-path pref-dir "qif-accounts-map")) @@ -92,18 +92,16 @@ (set! qif-cat-hash (make-hash-table 20)) (set! qif-cat-hash (qif-import:read-map qif-cat-list))) -;;; (set! qif-memo-list (safe-read)) -;;; (if (not (list? qif-cat-list)) -;;; (set! qif-memo-hash (make-hash-table 20)) -;;; (set! qif-memo-hash (qif-import:read-map qif-memo-list))) - -;;; (set! results -;;; (list qif-account-hash qif-cat-hash qif-memo-hash))))) + (set! qif-memo-list (safe-read)) + (if (not (list? qif-memo-list)) + (set! qif-memo-hash (make-hash-table 20)) + (set! qif-memo-hash (qif-import:read-map qif-memo-list))) + (set! results - (list qif-account-hash qif-cat-hash))))) + (list qif-account-hash qif-cat-hash qif-memo-hash))))) (begin (set! results (list (make-hash-table 20) -;;; (make-hash-table 20) + (make-hash-table 20) (make-hash-table 20))))) ;; now build the list of all known account names @@ -112,7 +110,6 @@ (set! results (cons all-account-info results))) results)) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; dump the mapping hash tables to a file. The hash tables are ;; updated when the user clicks the big "OK" button on the dialog, @@ -146,7 +143,7 @@ tablist) table)) -(define (qif-import:save-map-prefs acct-map cat-map) ;; memo-map) +(define (qif-import:save-map-prefs acct-map cat-map memo-map) (let* ((pref-dir (build-path (getenv "HOME") ".gnucash")) (pref-filename (build-path pref-dir "qif-accounts-map")) (save-ok #f)) @@ -175,8 +172,8 @@ (display ";;; map from QIF categories to GNC accounts") (newline) (qif-import:write-map cat-map) -;;; (display ";;; map from QIF payee/memo to GNC accounts") (newline) -;;; (qif-import:write-map memo-map) + (display ";;; map from QIF payee/memo to GNC accounts") (newline) + (qif-import:write-map memo-map) (newline)))))) @@ -314,5 +311,5 @@ (not (string=? qif-acct ""))) (list qif-acct (car allowed-types))) (#t - (list "Unspecified" (car allowed-types))))) + (list (default-unspec-acct) (car allowed-types))))) diff --git a/src/scm/qif-import/qif-objects.scm b/src/scm/qif-import/qif-objects.scm index 6aaf10c81e..246791216d 100644 --- a/src/scm/qif-import/qif-objects.scm +++ b/src/scm/qif-import/qif-objects.scm @@ -507,6 +507,16 @@ (define (make-qif-map-entry) (make-simple-obj )) +(define (qif-map-entry:clone orig) + (let ((me (make-qif-map-entry))) + (qif-map-entry:set-qif-name! me (qif-map-entry:qif-name orig)) + (qif-map-entry:set-allowed-types! me (qif-map-entry:allowed-types orig)) + (qif-map-entry:set-description! me (qif-map-entry:description orig)) + (qif-map-entry:set-gnc-name! me (qif-map-entry:gnc-name orig)) + (qif-map-entry:set-new-acct?! me (qif-map-entry:new-acct? orig)) + (qif-map-entry:set-display?! me (qif-map-entry:display? orig)) + me)) + (define qif-map-entry:qif-name (simple-obj-getter 'qif-name)) diff --git a/src/scm/qif-import/qif-to-gnc.scm b/src/scm/qif-import/qif-to-gnc.scm index d5d9e223ed..b8c381bd7f 100644 --- a/src/scm/qif-import/qif-to-gnc.scm +++ b/src/scm/qif-import/qif-to-gnc.scm @@ -9,8 +9,6 @@ (gnc:support "qif-import/qif-to-gnc.scm") -(define gnc:*default-denom* 100000) - (define (gnc:qif-fuzzy= num-1 num-2) (< (abs (- num-1 num-2)) .00000001)) @@ -50,8 +48,9 @@ (if same-gnc-account (if (and (gnc:commodity-equiv? currency (gnc:account-get-currency same-gnc-account)) - (gnc:commodity-equiv? - security (gnc:account-get-security same-gnc-account)) + (or (eq? (gnc:account-get-security same-gnc-account) #f) + (gnc:commodity-equiv? + security (gnc:account-get-security same-gnc-account))) (list? allowed-types) (memq (gnc:account-get-type same-gnc-account) allowed-types)) @@ -168,173 +167,196 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (qif-import:qif-to-gnc qif-files-list - qif-acct-map qif-cat-map stock-map + qif-acct-map qif-cat-map + qif-memo-map stock-map default-currency-name) - (false-if-exception - (let* ((old-group (gnc:get-current-group)) - (new-group (gnc:malloc-account-group)) - (gnc-acct-hash (make-hash-table 20)) - (separator (string-ref (gnc:account-separator-char) 0)) - (default-currency - (gnc:commodity-table-find-full - (gnc:engine-commodities) - GNC_COMMODITY_NS_ISO default-currency-name)) - (sorted-accounts-list '()) - (markable-xtns '()) - (sorted-qif-files-list - (sort qif-files-list - (lambda (a b) - (> (length (qif-file:xtns a)) - (length (qif-file:xtns b)))))) - (progress-dialog #f) - (work-to-do 0) - (work-done 0)) - - ;; first, build a local account tree that mirrors the gnucash - ;; accounts in the mapping data. we need to iterate over the - ;; cat-map and the acct-map to build the list - (for-each - (lambda (bin) - (for-each - (lambda (hashpair) - (let* ((acctinfo (cdr hashpair))) - (if (qif-map-entry:display? acctinfo) - (set! sorted-accounts-list - (cons acctinfo sorted-accounts-list))))) - bin)) - (vector->list qif-acct-map)) - - (for-each - (lambda (bin) - (for-each - (lambda (hashpair) - (let* ((acctinfo (cdr hashpair))) - (if (qif-map-entry:display? acctinfo) - (set! sorted-accounts-list - (cons acctinfo sorted-accounts-list))))) - bin)) - (vector->list qif-cat-map)) - - - ;; sort the account info on the depth of the account path. if a - ;; short part is explicitly mentioned, make sure it gets created - ;; before the deeper path, which will create the parent accounts - ;; without the information about their type. - (set! sorted-accounts-list - (sort sorted-accounts-list - (lambda (a b) - (let ((a-depth - (length - (string-split-on (qif-map-entry:gnc-name a) - separator))) - (b-depth - (length - (string-split-on (qif-map-entry:gnc-name b) - separator)))) - (< a-depth b-depth))))) - - ;; make all the accounts - (for-each - (lambda (acctinfo) - (let* ((security - (and stock-map - (hash-ref stock-map - (qif-import:get-account-name - (qif-map-entry:qif-name acctinfo))))) - (ok-types (qif-map-entry:allowed-types acctinfo)) - (equity? (memq GNC-EQUITY-TYPE ok-types))) - - (cond ((and equity? security) ;; a "retained holdings" acct - (qif-import:find-or-make-acct acctinfo - security security - gnc-acct-hash - old-group new-group)) - (security - (qif-import:find-or-make-acct - acctinfo default-currency security - gnc-acct-hash old-group new-group)) - (#t - (qif-import:find-or-make-acct - acctinfo default-currency default-currency - gnc-acct-hash old-group new-group))))) - sorted-accounts-list) - - ;; before trying to mark transactions, prune down the list of - ;; ones to match. - (for-each - (lambda (qif-file) - (for-each - (lambda (xtn) - (set! work-to-do (+ 1 work-to-do)) - (let splitloop ((splits (qif-xtn:splits xtn))) - (if (qif-split:category-is-account? (car splits)) - (begin - (set! markable-xtns (cons xtn markable-xtns)) - (set! work-to-do (+ 1 work-to-do))) - (if (not (null? (cdr splits))) - (splitloop (cdr splits)))))) - (qif-file:xtns qif-file))) - qif-files-list) - - (if (> work-to-do 100) - (begin - (set! progress-dialog (gnc:progress-dialog-new #f #f)) - (gnc:progress-dialog-set-title progress-dialog "Progress") - (gnc:progress-dialog-set-heading progress-dialog - "Importing transactions...") - (gnc:progress-dialog-set-limits progress-dialog 0.0 100.0))) - - - ;; now run through the markable transactions marking any - ;; duplicates. marked transactions/splits won't get imported. - (if (> (length markable-xtns) 1) - (let xloop ((xtn (car markable-xtns)) - (rest (cdr markable-xtns))) - (set! work-done (+ 1 work-done)) - (if progress-dialog - (begin - (gnc:progress-dialog-set-value - progress-dialog (* 100 (/ work-done work-to-do))) - (gnc:progress-dialog-update progress-dialog))) - (if (not (qif-xtn:mark xtn)) - (qif-import:mark-matching-xtns xtn rest)) - (if (not (null? (cdr rest))) - (xloop (car rest) (cdr rest))))) - - ;; iterate over files. Going in the sort order by number of - ;; transactions should give us a small speed advantage. - (for-each - (lambda (qif-file) - (for-each - (lambda (xtn) - (set! work-done (+ 1 work-done)) - (if progress-dialog - (begin - (gnc:progress-dialog-set-value - progress-dialog (* 100 (/ work-done work-to-do))) - (gnc:progress-dialog-update progress-dialog))) - (if (not (qif-xtn:mark xtn)) - (begin - ;; create and fill in the GNC transaction - (let ((gnc-xtn (gnc:transaction-create))) - (gnc:transaction-begin-edit gnc-xtn) - - ;; build the transaction - (qif-import:qif-xtn-to-gnc-xtn - xtn qif-file gnc-xtn gnc-acct-hash - qif-acct-map qif-cat-map) - - ;; rebalance and commit everything - (gnc:transaction-commit-edit gnc-xtn))))) - (qif-file:xtns qif-file))) - sorted-qif-files-list) - - ;; get rid of the progress dialog - (if progress-dialog - (gnc:progress-dialog-destroy progress-dialog)) - - new-group))) + (define (dumper key . args) + (let ((stack (make-stack #t dumper))) + (display-backtrace stack (current-error-port)) + (apply display-error stack (current-error-port) args) + (throw 'ignore))) + (catch + 'ignore + (lambda () + (lazy-catch #t + (lambda () (qif-import:qif-to-gnc-unsafe + qif-files-list + qif-acct-map qif-cat-map + qif-memo-map stock-map + default-currency-name)) + dumper)) + (lambda (key . args) + #f))) + +(define (qif-import:qif-to-gnc-unsafe qif-files-list + qif-acct-map qif-cat-map qif-memo-map + stock-map + default-currency-name) + (let* ((old-group (gnc:get-current-group)) + (new-group (gnc:malloc-account-group)) + (gnc-acct-hash (make-hash-table 20)) + (separator (string-ref (gnc:account-separator-char) 0)) + (default-currency + (gnc:commodity-table-find-full + (gnc:engine-commodities) + GNC_COMMODITY_NS_ISO default-currency-name)) + (sorted-accounts-list '()) + (markable-xtns '()) + (sorted-qif-files-list + (sort qif-files-list + (lambda (a b) + (> (length (qif-file:xtns a)) + (length (qif-file:xtns b)))))) + (progress-dialog #f) + (work-to-do 0) + (work-done 0)) + + ;; first, build a local account tree that mirrors the gnucash + ;; accounts in the mapping data. we need to iterate over the + ;; cat-map and the acct-map to build the list + (for-each + (lambda (bin) + (for-each + (lambda (hashpair) + (let* ((acctinfo (cdr hashpair))) + (if (qif-map-entry:display? acctinfo) + (set! sorted-accounts-list + (cons acctinfo sorted-accounts-list))))) + bin)) + (vector->list qif-acct-map)) + + (for-each + (lambda (bin) + (for-each + (lambda (hashpair) + (let* ((acctinfo (cdr hashpair))) + (if (qif-map-entry:display? acctinfo) + (set! sorted-accounts-list + (cons acctinfo sorted-accounts-list))))) + bin)) + (vector->list qif-cat-map)) + + + ;; sort the account info on the depth of the account path. if a + ;; short part is explicitly mentioned, make sure it gets created + ;; before the deeper path, which will create the parent accounts + ;; without the information about their type. + (set! sorted-accounts-list + (sort sorted-accounts-list + (lambda (a b) + (let ((a-depth + (length + (string-split-on (qif-map-entry:gnc-name a) + separator))) + (b-depth + (length + (string-split-on (qif-map-entry:gnc-name b) + separator)))) + (< a-depth b-depth))))) + + ;; make all the accounts + (for-each + (lambda (acctinfo) + (let* ((security + (and stock-map + (hash-ref stock-map + (qif-import:get-account-name + (qif-map-entry:qif-name acctinfo))))) + (ok-types (qif-map-entry:allowed-types acctinfo)) + (equity? (memq GNC-EQUITY-TYPE ok-types))) + + (cond ((and equity? security) ;; a "retained holdings" acct + (qif-import:find-or-make-acct acctinfo + security security + gnc-acct-hash + old-group new-group)) + (security + (qif-import:find-or-make-acct + acctinfo default-currency security + gnc-acct-hash old-group new-group)) + (#t + (qif-import:find-or-make-acct + acctinfo default-currency default-currency + gnc-acct-hash old-group new-group))))) + sorted-accounts-list) + + ;; before trying to mark transactions, prune down the list of + ;; ones to match. + (for-each + (lambda (qif-file) + (for-each + (lambda (xtn) + (set! work-to-do (+ 1 work-to-do)) + (let splitloop ((splits (qif-xtn:splits xtn))) + (if (qif-split:category-is-account? (car splits)) + (begin + (set! markable-xtns (cons xtn markable-xtns)) + (set! work-to-do (+ 1 work-to-do))) + (if (not (null? (cdr splits))) + (splitloop (cdr splits)))))) + (qif-file:xtns qif-file))) + qif-files-list) + + (if (> work-to-do 100) + (begin + (set! progress-dialog (gnc:progress-dialog-new #f #f)) + (gnc:progress-dialog-set-title progress-dialog "Progress") + (gnc:progress-dialog-set-heading progress-dialog + "Importing transactions...") + (gnc:progress-dialog-set-limits progress-dialog 0.0 100.0))) + + + ;; now run through the markable transactions marking any + ;; duplicates. marked transactions/splits won't get imported. + (if (> (length markable-xtns) 1) + (let xloop ((xtn (car markable-xtns)) + (rest (cdr markable-xtns))) + (set! work-done (+ 1 work-done)) + (if progress-dialog + (begin + (gnc:progress-dialog-set-value + progress-dialog (* 100 (/ work-done work-to-do))) + (gnc:progress-dialog-update progress-dialog))) + (if (not (qif-xtn:mark xtn)) + (qif-import:mark-matching-xtns xtn rest)) + (if (not (null? (cdr rest))) + (xloop (car rest) (cdr rest))))) + + ;; iterate over files. Going in the sort order by number of + ;; transactions should give us a small speed advantage. + (for-each + (lambda (qif-file) + (for-each + (lambda (xtn) + (set! work-done (+ 1 work-done)) + (if progress-dialog + (begin + (gnc:progress-dialog-set-value + progress-dialog (* 100 (/ work-done work-to-do))) + (gnc:progress-dialog-update progress-dialog))) + (if (not (qif-xtn:mark xtn)) + (begin + ;; create and fill in the GNC transaction + (let ((gnc-xtn (gnc:transaction-create))) + (gnc:transaction-begin-edit gnc-xtn) + + ;; build the transaction + (qif-import:qif-xtn-to-gnc-xtn + xtn qif-file gnc-xtn gnc-acct-hash + qif-acct-map qif-cat-map) + + ;; rebalance and commit everything + (gnc:transaction-commit-edit gnc-xtn))))) + (qif-file:xtns qif-file))) + sorted-qif-files-list) + + ;; get rid of the progress dialog + (if progress-dialog + (gnc:progress-dialog-destroy progress-dialog)) + + new-group)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; qif-import:qif-xtn-to-gnc-xtn ;; translate a single transaction to a set of gnucash splits and @@ -358,8 +380,9 @@ (qif-cleared (qif-xtn:cleared qif-xtn)) (amt-cvt (lambda (n) (if n - (gnc:double-to-gnc-numeric n gnc:*default-denom* - GNC-RND-ROUND) + (gnc:double-to-gnc-numeric + n GNC-DENOM-AUTO + (logior (GNC-DENOM-SIGFIGS 6) GNC-RND-ROUND)) (gnc:numeric-zero)))) (n- (lambda (n) (gnc:numeric-neg n))) (nsub (lambda (a b) (gnc:numeric-sub a b 0 GNC-DENOM-LCD)))