The Account Picker
+
+ This account picker is sort of broken. The idea is that you
+can select an existing account from the tree display, or enter
+information for a new account in the boxes below. However, right now
+it's possible to do Very Bad things like specify a subaccount of an
+existing account with a type that's not compatible with the parent.
+As soon as I figure out how I want this dialog to work I'll fix it. I
+have tested out the worst things that you can do and nothing terrible
+happens, except your account tree might be in a state that you could
+never have created through the GUI (a Credit Card account as a child
+of a Bank account, for example). Don't do that. I'll fix it Real
+Soon.
+
+
Table of Contents
+
+The "OK" Button
+
+
Everything really happens when you hit the "OK" button, so it
+gets a section to itself.
+
+ First we do a "mark and sweep" to eliminate the duplicated
+halves of transfers in the loaded Quicken transactions.
+ A GnuCash account tree is created which mirrors
+your existing tree and includes any new accounts added by your
+Accounts and Categories mappings.
+ All the QIF transactions are converted into GnuCash splits and
+stuffed into the new account tree.
+ Finally, the GnuCash engine is asked to merge the old account
+tree with the new account tree.
+
+
+Table of Contents
+
+A few hints
+
+ Opening Balance
+
If your Quicken files have "Opening Balance" records, you will
+see an account called "Opening Balance" in the Accounts tab.
+Accounting for the source of opening balances is sort of a hassle,
+when you think about it, because they come from accounts that are
+outside the scope of the GnuCash universe. The suggestion I've seen
+on the gnucash-devel list is to make Opening Balances point to a
+GnuCash account called "Retained Earnings", of type Equity. I don't
+exactly understand this but it seems reasonable, and it's the default
+for accounts called "Opening Balance".
+
+ Empty category
+
+
In the Categories display, you may notice a blank QIF Category
+entry. Quicken transactions are not required to have a Category, but
+GnuCash transactions are required to have a source and a destination.
+The blank category lets you select which GnuCash account all
+uncategorized transactions go to. This will generally be
+miscellaneous checks you have written, cash withdrawals, and so on, so
+you probably want to put these in a "Misc Expenses" account or
+something similar. It may make sense to put this in an equity
+account; let me know if there's a good explanation for how it should
+be.
+
+ Dividend category
+
+
Quicken stock transactions have a recognizable pattern for
+dividend payments. If the importer can definitely tell that a
+transaction is a transfer from dividends then it will default to
+creating a "Dividend" income account. This category is usually not
+present in the Quicken file, so it's being manufactured out of
+nowhere.
+
+ Fund families
+
+
Quicken has the abstraction of a single account representing a
+"fund family" for the purpose of allowing smooth transfers between the
+various accounts administered within the family. The GnuCash Importer
+will ALWAYS get this wrong the first time, because Quicken explicitly
+puts the wrong information in the file. The "blanket" account
+representing the fund family as a whole should probably be a Bank
+account, since the transfers to and from it in the Quicken file are
+denominated in currency, not shares. The balance of such an account
+is supposed to always be 0 since you just use it as an intermediary
+between two accounts in the family. Hopefully I'll fix this at some
+point if someone tells me how it's supposed to work.
+
+ Brokerage accounts
+
+
Brokerage accounts are really confusing to me. Basically, my
+thinking is that the brokerage account itself should probably be a
+Bank account. The only wierdness is in stuff like dividends paid from
+securities to the brokerage account. If you're using a Dividend
+account, you can lose the information about where the dividend came
+from. The importer tries to save this information by putting the
+security name in the Payee slot (which shows up in the GnuCash
+Description field for the transaction). If you have a better idea,
+let me know.
+
+
+
+
diff --git a/README b/README
index 2448c4ab31..b14a776244 100644
--- a/README
+++ b/README
@@ -549,6 +549,7 @@ Bob Drzyzgula for budgeting design notes
Jan-Uwe Finck for German message translation
Ron Forrester for gnome patches
Dave Freese for leap-year fix
+Bill Gribble qif importation code
Otto Hammersmith for RedHat RPM version
Alexandru Harsanyi for core dumps, lockups, gtk work.
Jon K}re Hellan misc core dump fixes
diff --git a/po/fr.po b/po/fr.po
index f4872ed44e..a44bc811d3 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -4,9 +4,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: gnucash 1.2.0\n"
+"Project-Id-Version: gnucash 1.3.0\n"
"POT-Creation-Date: 2000-03-15 03:12-0800\n"
-"PO-Revision-Date: 2000-03-06 23:47+0200\n"
+"PO-Revision-Date: 2000-03-15 23:47+0200\n"
"Last-Translator: Yannick LE NY \n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
@@ -27,7 +27,7 @@ msgstr "Fonds communs(SICAV / FCP)"
#: ../po/guile_strings.txt:4
msgid "Status"
-msgstr ""
+msgstr "Etats"
#: ../po/guile_strings.txt:5 messages-i18n.c:259
msgid "Date"
@@ -35,7 +35,7 @@ msgstr "Date"
#: ../po/guile_strings.txt:6 messages-i18n.c:274
msgid "Equity"
-msgstr "Capitaux propres(Actif)"
+msgstr "Capitaux propres"
#: ../po/guile_strings.txt:7
msgid "Account Separator"
@@ -46,7 +46,7 @@ msgid ""
"The default background color for splits in multi-line mode and the auto modes"
msgstr ""
"La couleur de l'arrière-plan par défaut pour les répartitions en mode lignes "
-"multiet les modes auto"
+"multi et les modes auto"
#: ../po/guile_strings.txt:9
msgid "Auto-Raise Lists"
@@ -71,7 +71,7 @@ msgstr "Le bon"
#: ../po/guile_strings.txt:14
#, c-format
msgid "The current time is %s."
-msgstr ""
+msgstr "L'heure actuelle est %s."
#: ../po/guile_strings.txt:15 messages-i18n.c:170
msgid "Double Line"
@@ -88,14 +88,13 @@ msgstr "Revenus:Salaire:Imposable"
#: ../po/guile_strings.txt:18
msgid "Type of budget report"
-msgstr ""
+msgstr "Type de rapport de budget"
#: ../po/guile_strings.txt:19
msgid "reg_win_width"
msgstr ""
#: ../po/guile_strings.txt:20
-#, fuzzy
msgid "Balancing"
msgstr "Solde"
@@ -136,12 +135,11 @@ msgid "_Account Transactions"
msgstr "Transactions du compte"
#: ../po/guile_strings.txt:29
-#, fuzzy, c-format
+#, c-format
msgid "The date option is %s."
-msgstr "C'est une option de date"
+msgstr "L'option de date est %s."
#: ../po/guile_strings.txt:30
-#, fuzzy
msgid "Account Transactions"
msgstr "Transactions du compte"
@@ -199,7 +197,7 @@ msgstr "Ligne multiple"
#: ../po/guile_strings.txt:44
msgid "View"
-msgstr ""
+msgstr "Vue"
#: ../po/guile_strings.txt:45
msgid "The default background color for odd rows in double mode"
@@ -208,14 +206,12 @@ msgstr ""
"double"
#: ../po/guile_strings.txt:46
-#, fuzzy
msgid "UK-style dd/mm/yyyy"
msgstr "Style-UK: jj/mm/aaaa"
#: ../po/guile_strings.txt:47
-#, fuzzy
msgid "Show all columns"
-msgstr "Montre toutes les transactions"
+msgstr "Montre toutes les colonnes"
#: ../po/guile_strings.txt:48 messages-i18n.c:229
msgid "Account"
@@ -272,14 +268,12 @@ msgid "Income/Salary/Taxable"
msgstr "Revenus/Salaire/Imposable"
#: ../po/guile_strings.txt:61
-#, fuzzy
msgid "There are no selected accounts in the account list option."
-msgstr "Ouvrir le compte sélectionné et tous ses sous-comptes."
+msgstr "Il n'y a aucun comptes selectionnés dans la liste d'options du compte."
#: ../po/guile_strings.txt:62
-#, fuzzy
msgid "_Budget"
-msgstr "Acheté"
+msgstr "Budget"
#: ../po/guile_strings.txt:63
msgid "Continental Europe: dd.mm.yyyy"
@@ -310,9 +304,9 @@ msgid "Register Colors"
msgstr "Couleurs du registre"
#: ../po/guile_strings.txt:70
-#, fuzzy, c-format
+#, c-format
msgid "The boolean option is %s."
-msgstr "C'est une option booléenne"
+msgstr "L'option boléenne est %s."
#: ../po/guile_strings.txt:71
msgid "Multi mode default transaction background"
@@ -323,8 +317,8 @@ msgid ""
"Double clicking on an account with children expands the account instead of "
"opening a register."
msgstr ""
-"Double cliquez sur un compte avec des enfants développe le compte à la "
-"placede l'ouverture d'un registre."
+"Double cliquer sur un compte avec des enfants développe le compte à la "
+"place de l'ouverture d'un registre."
#: ../po/guile_strings.txt:73
msgid "The background color for the active transaction in single mode"
@@ -383,9 +377,8 @@ msgid "Average"
msgstr "Moyenne"
#: ../po/guile_strings.txt:86
-#, fuzzy
msgid "The items selected in the list option are:"
-msgstr "C'est une option de liste de compte"
+msgstr "Les éléments sélectionnés dans la liste d'options sont:"
#: ../po/guile_strings.txt:87
msgid "A_ccount Balance Tracker"
@@ -405,7 +398,7 @@ msgstr ""
#: ../po/guile_strings.txt:91
msgid "Full"
-msgstr ""
+msgstr "Plein"
#: ../po/guile_strings.txt:92
msgid "Multi mode default split background"
@@ -445,7 +438,7 @@ msgstr ""
#: ../po/guile_strings.txt:101
msgid "A report useful for balancing the budget"
-msgstr ""
+msgstr "Un rapport utile pour équilibrer le budget"
#: ../po/guile_strings.txt:102
msgid "Date Format Display"
@@ -464,7 +457,6 @@ msgid "Account fields to display"
msgstr "Champs du compte à afficher"
#: ../po/guile_strings.txt:106
-#, fuzzy
msgid "Account Balance Tracker"
msgstr "Suivi du solde du compte"
@@ -511,7 +503,7 @@ msgid ""
"The default background color for transactions in multi-line mode and the "
"auto modes"
msgstr ""
-"La couleur de l'arrière-plan par défaut pour les transactionsen mode ligne "
+"La couleur de l'arrière-plan par défaut pour les transactions en mode ligne "
"multi et les modes auto"
#: ../po/guile_strings.txt:117
@@ -528,7 +520,7 @@ msgstr "Option laide"
#: ../po/guile_strings.txt:120
msgid "How are you doing on your budget?"
-msgstr ""
+msgstr "Comment aller vous faire votre budget?"
#: ../po/guile_strings.txt:121
msgid "Save Translatable Strings"
@@ -560,7 +552,7 @@ msgstr "Format de date"
#: ../po/guile_strings.txt:128
msgid "A list option"
-msgstr "Une option de liste"
+msgstr "Une liste d'option"
#: ../po/guile_strings.txt:129
msgid "ISO Standard: yyyy-mm-dd"
@@ -583,9 +575,9 @@ msgid "Double mode default even row background"
msgstr "Arrière-plan des lignes paires en mode double par défaut"
#: ../po/guile_strings.txt:134
-#, fuzzy, c-format
+#, c-format
msgid "The multi-choice option is %s."
-msgstr "C'est une option à choix multiple"
+msgstr "L'option à choix multiple est %s."
#: ../po/guile_strings.txt:135
msgid "Double mode colors alternate with transactions"
@@ -610,7 +602,7 @@ msgstr "Sous-comptes"
#: ../po/guile_strings.txt:140
#, c-format
msgid "The date and time option is %s."
-msgstr ""
+msgstr "L'option de date et d'heure est %s."
#: ../po/guile_strings.txt:141 messages-i18n.c:290
msgid "Liability"
@@ -658,9 +650,9 @@ msgid "Notes"
msgstr "Notes"
#: ../po/guile_strings.txt:152
-#, fuzzy, c-format
+#, c-format
msgid "The string option is %s."
-msgstr "C'est une option de chaine"
+msgstr "L'option de chaine est %s."
#: ../po/guile_strings.txt:153
msgid "_Reports"
@@ -712,7 +704,7 @@ msgstr "Deux semaines"
#: ../po/guile_strings.txt:165
msgid "Save Window Geometry"
-msgstr "Sauvegarger la géométrie de la fenêtre"
+msgstr "Sauvegarder la géométrie de la fenêtre"
#: ../po/guile_strings.txt:166
msgid "Income\\Salary\\Taxable"
@@ -723,7 +715,6 @@ msgid "Code"
msgstr "Code"
#: ../po/guile_strings.txt:168
-#, fuzzy
msgid "Balance sheet"
msgstr "Feuille du solde/bilan"
@@ -749,7 +740,7 @@ msgstr "Trier par ce second crit
#: ../po/guile_strings.txt:174
msgid "true"
-msgstr ""
+msgstr "vrai"
#: ../po/guile_strings.txt:175
msgid "Income.Salary.Taxable"
@@ -792,9 +783,8 @@ msgid "Just a Date Option"
msgstr "Uniquement une option de date"
#: ../po/guile_strings.txt:185
-#, fuzzy
msgid "The accounts selected in the account list option are:"
-msgstr "C'est une option de liste de compte"
+msgstr "Les comptes sélectionnés dans la liste d'options du compte sont:"
#: ../po/guile_strings.txt:186
#, c-format
@@ -802,6 +792,8 @@ msgid ""
"This is a sample GnuCash report. See the guile (scheme) source code in %s "
"for details on writing your own reports, or extending existing reports."
msgstr ""
+"C'est un exemple de rapport de Gnucash. Regardez le code source de Guile (scheme) dans %s"
+"pour les détails sur l'écriture de vos propres rapports, ou étendez les rapports existants."
#: ../po/guile_strings.txt:187
msgid "The default background color for even rows in single mode"
@@ -814,7 +806,6 @@ msgstr ""
"La couleur de l'arrière-plan par défaut pour les lignes paires en mode double"
#: ../po/guile_strings.txt:189
-#, fuzzy
msgid "Display the Budget report."
msgstr "Affiche le rapport de la feuille du solde/bilan"
@@ -851,9 +842,8 @@ msgid "Plot Type"
msgstr "Type de graphique"
#: ../po/guile_strings.txt:197
-#, fuzzy
msgid "Budget"
-msgstr "Acheté"
+msgstr "Budget"
#: ../po/guile_strings.txt:198
msgid "Choose whether to display icons, text, or both for toolbar buttons"
@@ -911,9 +901,8 @@ msgid "Default number of register rows to display."
msgstr "Nombre de lignes du registre par défaut à afficher"
#: ../po/guile_strings.txt:211
-#, fuzzy
msgid "Report end date"
-msgstr "Trier par date"
+msgstr "Date de fin du rapport"
#: ../po/guile_strings.txt:212
msgid "None"
@@ -948,9 +937,8 @@ msgid "__gui"
msgstr ""
#: ../po/guile_strings.txt:220
-#, fuzzy
msgid "Report start date"
-msgstr "Eléments de rapports depuis cette date"
+msgstr "Date de départ du rapport"
#: ../po/guile_strings.txt:221 messages-i18n.c:334
msgid "To"
@@ -1022,12 +1010,11 @@ msgstr "Rien"
#: ../po/guile_strings.txt:238
msgid "You have selected no values in the list option."
-msgstr ""
+msgstr "Vous n'avez sélectionné aucune valeurs dans la liste d'option."
#: ../po/guile_strings.txt:239
-#, fuzzy
msgid "false"
-msgstr "Fermer"
+msgstr "faux"
#: ../po/guile_strings.txt:240 messages-i18n.c:276
msgid "Expense"
@@ -1067,7 +1054,7 @@ msgstr "Affiche le rapport des transactions du compte."
#: ../po/guile_strings.txt:249
msgid "Have a nice day!"
-msgstr ""
+msgstr "Ayez une bonne journée!"
#: ../po/guile_strings.txt:250
msgid "This is a list option"
@@ -1096,14 +1083,17 @@ msgid ""
"report, consult the mailing list %s. For details on subscribing to that "
"list, see %s."
msgstr ""
+"Pour l'aide sur l'écriture de rapports,ou pour contribuer à notre flambant neuf,"
+"totallement cool rapport, consultez la liste de courriers %s. Pour les détails "
+"sur l'inscription à cette liste, regardez %s."
#: ../po/guile_strings.txt:256
msgid ""
"The background color for an active transaction in multi-line mode and the "
"auto modes"
msgstr ""
-"L'arrière-plan en couleur pour une répartition active en mode multiet modes "
-"auto"
+"L'arrière-plan en couleur pour une répartition active en mode multi lignes"
+"et en modes auto"
#: ../po/guile_strings.txt:257
msgid "This is a multi choice option."
@@ -1114,7 +1104,6 @@ msgid "Income & Expense"
msgstr "Revenus et dépenses"
#: ../po/guile_strings.txt:259
-#, fuzzy
msgid "Hello, World"
msgstr "Bonjour, tout le monde!"
@@ -1560,9 +1549,8 @@ msgid "Delete the current transaction"
msgstr "Supprimer la transaction en cours"
#: messages-i18n.c:74
-#, fuzzy
msgid "Make a copy of the current transaction"
-msgstr "Enregistrer la transaction en cours"
+msgstr "Faire une copie de la transaction actuelle"
#: messages-i18n.c:75
msgid "Edit the selected account"
@@ -1795,9 +1783,8 @@ msgid "_Delete"
msgstr "Supprimer"
#: messages-i18n.c:132
-#, fuzzy
msgid "D_uplicate"
-msgstr "Date"
+msgstr "Dupliquer"
#: messages-i18n.c:133
msgid "_Edit"
@@ -2281,7 +2268,7 @@ msgstr "Diff
#: messages-i18n.c:269
msgid "Direct Debit"
-msgstr ""
+msgstr "Débit direct"
#: messages-i18n.c:270
msgid "Dist"
@@ -2292,9 +2279,8 @@ msgid "Div"
msgstr "Div"
#: messages-i18n.c:272
-#, fuzzy
msgid "Duplicate"
-msgstr "Date"
+msgstr "Dupliquer"
#: messages-i18n.c:273
msgid "Edit"
diff --git a/src/FileDialog.c b/src/FileDialog.c
index 8c321ee2d8..3ab3cef1ed 100644
--- a/src/FileDialog.c
+++ b/src/FileDialog.c
@@ -299,41 +299,8 @@ gncFileOpenFile (const char * newfile)
void
gncFileQIFImport (void)
{
- char * newfile;
- char buf[BUFSIZE];
- int io_error, uh_oh = 0;
- AccountGroup *newgrp;
-
- newfile = fileBox(IMPORT_QIF_STR, "*.qif");
- if (!newfile) return;
-
- gnc_set_busy_cursor(NULL);
-
- /* load the accounts from the file the user specified */
- newgrp = xaccReadQIFAccountGroup (newfile);
-
- gnc_unset_busy_cursor(NULL);
-
- /* check for i/o error, put up appropriate error message */
- io_error = xaccGetQIFIOError();
- SHOW_IO_ERR_MSG(io_error);
-
- if (uh_oh) return;
-
- if( NULL == topgroup ) {
- /* no topgroup exists */
- topgroup = xaccMallocAccountGroup();
- }
-
- gnc_set_busy_cursor(NULL);
-
- /* since quicken will not export all accounts
- * into one file, we must merge them in one by one */
- xaccConcatGroups (topgroup, newgrp);
- xaccMergeAccounts (topgroup);
- xaccConsolidateGrpTransactions (topgroup);
-
- gnc_unset_busy_cursor(NULL);
+ /* pop up the QIF File Import dialog box */
+ gnc_ui_qif_import_dialog_make(NULL);
}
/* ======================================================== */
diff --git a/src/gnome/.cvsignore b/src/gnome/.cvsignore
index 88ec348c94..10349d9b33 100644
--- a/src/gnome/.cvsignore
+++ b/src/gnome/.cvsignore
@@ -2,3 +2,4 @@ Makefile
tmp
obj
*.diff
+backup.glade
diff --git a/src/gnome/Makefile.in b/src/gnome/Makefile.in
index 8dcda458c1..9ba3e9ba62 100644
--- a/src/gnome/Makefile.in
+++ b/src/gnome/Makefile.in
@@ -34,7 +34,7 @@ INCLPATH := -I.. \
-I@top_srcdir@/lib/g-wrap-install/include \
-I@top_srcdir@/src/g-wrap \
-I${includedir} \
- -I@top_srcdir@/src/register/gnome
+ -I@top_srcdir@/src/register/gnome
# All the other GNOME CFLAGS are handled in Makefile.common now
CFLAGS = @CFLAGS@ ${INCLPATH}
@@ -69,7 +69,9 @@ GNOME_SRCS := top-level.c window-main.c window-register.c window-adjust.c \
dialog-options.c dialog-filebox.c dialog-transfer.c \
dialog-add.c dialog-edit.c dialog-utils.c \
extensions.c query-user.c reconcile-list.c \
- window-report.c global-options.c
+ window-report.c global-options.c \
+ dialog-qif-import.c glade-qif-import.c \
+ dialog-account-picker.c glade-account-picker.c
######################################################################
all: gnome
@@ -85,3 +87,6 @@ gnome: @top_srcdir@/gnucash.gnome
gnome.static: @top_srcdir@/gnucash.gnome.static
@top_srcdir@/gnucash.gnome.static: ${GNOME_OBJS} ${OTHER_OBJS}
$(CC) -static $(LDFLAGS) -o $@ $^ $(LIBS)
+
+
+
diff --git a/src/gnome/account-tree.c b/src/gnome/account-tree.c
index dbf7a4c6fc..9dfa40f4f8 100644
--- a/src/gnome/account-tree.c
+++ b/src/gnome/account-tree.c
@@ -4,6 +4,7 @@
* GnuCash. *
* Copyright (C) 1998,1999 Jeremy Collins *
* Copyright (C) 1998,1999 Linas Vepstas *
+ * Copyright (C) 2000 Dave Peticolas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
diff --git a/src/gnome/account-tree.h b/src/gnome/account-tree.h
index 7017a1c614..0bc10d4890 100644
--- a/src/gnome/account-tree.h
+++ b/src/gnome/account-tree.h
@@ -1,6 +1,7 @@
/*******************************************************************\
* account-tree.h -- GNOME account tree functions *
* Copyright (C) 1998,1999 Linas Vepstas *
+ * Copyright (C) 2000 Dave Peticolas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
diff --git a/src/gnome/account-treeP.h b/src/gnome/account-treeP.h
index 9dce9376c7..3b647dadae 100644
--- a/src/gnome/account-treeP.h
+++ b/src/gnome/account-treeP.h
@@ -1,6 +1,7 @@
/********************************************************************\
* account-treeP.h -- private GNOME account tree functions *
* Copyright (C) 1998,1999 Linas Vepstas *
+ * Copyright (C) 2000 Dave Peticolas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
diff --git a/src/gnome/dialog-account-picker.c b/src/gnome/dialog-account-picker.c
new file mode 100644
index 0000000000..20d817963c
--- /dev/null
+++ b/src/gnome/dialog-account-picker.c
@@ -0,0 +1,271 @@
+/********************************************************************\
+ * dialog-account-picker.c -- window for picking a Gnucash account *
+ * (GnuCash) *
+ * Copyright (C) 2000 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 *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+\********************************************************************/
+
+#include "top-level.h"
+
+#include
+#include
+
+#include "glade-account-picker.h"
+#include "glade-cb-account-picker.h"
+
+#include
+
+#include "FileDialog.h"
+#include "Group.h"
+#include "Account.h"
+
+#include "dialog-utils.h"
+#include "query-user.h"
+#include "util.h"
+
+
+static void
+build_acct_tree(AccountGroup * group, GtkWidget * tree, GtkWidget * picker) {
+ Account ** accts;
+ AccountGroup * children;
+ GtkWidget * tree_item;
+ GtkWidget * sub_tree;
+ int num_accts;
+ int i;
+
+ accts = xaccGetAccounts(group);
+ num_accts = xaccGetNumAccounts(group);
+
+ for(i = 0; i < num_accts; i++) {
+ if(group == xaccAccountGetParent(accts[i])) {
+ tree_item =
+ gtk_tree_item_new_with_label(xaccAccountGetName(accts[i]));
+
+ gtk_object_set_data(GTK_OBJECT(tree_item),
+ "acct_name",
+ xaccAccountGetFullName(accts[i], ':'));
+
+ gtk_tree_append(GTK_TREE(tree), tree_item);
+ children = xaccAccountGetChildren(accts[i]);
+
+ if(children && (xaccGetNumAccounts(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);
+ }
+ }
+}
+
+
+/****************************************************************\
+ * 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.
+\****************************************************************/
+
+SCM
+accountPickerBox(char * initial_selection, int initial_type) {
+ AccountGroup * topgroup;
+ Account * selected;
+ int i;
+
+ GtkWidget * picker = create_GNUcash_Account_Picker();
+ GtkWidget * treeview = gtk_object_get_data(GTK_OBJECT(picker),
+ "account_tree");
+ GtkWidget * entry = gtk_object_get_data(GTK_OBJECT(picker),
+ "acct_entry");
+ GtkWidget * descript = gtk_object_get_data(GTK_OBJECT(picker),
+ "acct_description_entry");
+ GtkWidget * type_pick = gtk_object_get_data(GTK_OBJECT(picker),
+ "acct_type_picker");
+ GtkWidget * treeitem = gtk_tree_item_new_with_label("All Accounts");
+ GtkWidget * subtree = gtk_tree_new();
+
+ char * selected_account = NULL;
+ SCM infolist;
+
+ GtkWidget * active, * menu;
+
+ gtk_object_set_data(GTK_OBJECT(picker), "string_return",
+ &selected_account);
+
+ gtk_signal_connect(GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(gnc_ui_account_picker_select_cb),
+ picker);
+
+ /* do some setup */
+ topgroup = gncGetCurrentGroup();
+ gtk_tree_append(GTK_TREE(treeview), treeitem);
+ gtk_widget_show(treeitem);
+
+ build_acct_tree(topgroup, subtree, picker);
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(treeitem), subtree);
+
+ gtk_tree_set_view_lines(GTK_TREE(treeview), TRUE);
+ gtk_tree_item_expand(GTK_TREE_ITEM(treeitem));
+
+ /* this is a pain in the butt but there's no other way to easily
+ * find out the index of the optionmeny selection */
+ menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(type_pick));
+ for(i = 0; i < 11; i++) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(type_pick), i);
+ active = gtk_menu_get_active(GTK_MENU(menu));
+ gtk_object_set_data(GTK_OBJECT(active),
+ "option_index",
+ (gpointer)(i));
+ }
+
+ gtk_option_menu_set_history(GTK_OPTION_MENU(type_pick), 0);
+
+ if(initial_selection) {
+ printf("setting up initial selection..\n");
+ selected = xaccGetAccountFromFullName(topgroup, initial_selection, ':');
+ gtk_entry_set_text(GTK_ENTRY(entry), initial_selection);
+
+ if(selected) {
+ if(xaccAccountGetDescription(selected)) {
+ gtk_entry_set_text(GTK_ENTRY(descript),
+ xaccAccountGetDescription(selected));
+ }
+ gtk_option_menu_set_history(GTK_OPTION_MENU(type_pick),
+ xaccAccountGetType(selected));
+ infolist = SCM_LIST3(gh_str02scm(selected_account),
+ gh_int2scm(xaccAccountGetType(selected)),
+ gh_str02scm(xaccAccountGetDescription(selected)));
+ }
+ else {
+ gtk_entry_set_text(GTK_ENTRY(descript), "");
+ gtk_option_menu_set_history(GTK_OPTION_MENU(type_pick),
+ initial_type);
+ infolist = SCM_LIST3(gh_str02scm(selected_account),
+ gh_int2scm(initial_type),
+ gh_str02scm(""));
+ }
+
+ scm_protect_object(infolist);
+ gtk_object_set_data(GTK_OBJECT(picker),
+ "scm_acct_info", (gpointer)infolist);
+ }
+
+ /* make sure the window is modal, then wait on it */
+ gtk_window_set_modal(GTK_WINDOW(picker), TRUE);
+ gtk_widget_show(GTK_WIDGET(treeview));
+ gtk_widget_show(GTK_WIDGET(picker));
+ gtk_main();
+
+ infolist = (SCM)gtk_object_get_data(GTK_OBJECT(picker),
+ "scm_acct_info");
+
+ /* murder it */
+ gtk_widget_destroy(picker);
+
+ return infolist;
+}
+
+void
+gnc_ui_account_picker_select_cb(GtkTree * tree,
+ GtkWidget * widget,
+ gpointer user_data) {
+ AccountGroup * topgroup = gncGetCurrentGroup();
+ Account * gnc_acct;
+ GtkWidget * acct_entry = gtk_object_get_data(GTK_OBJECT(user_data),
+ "acct_entry");
+ GtkWidget * descript = gtk_object_get_data(GTK_OBJECT(user_data),
+ "acct_description_entry");
+ GtkWidget * type_pick = gtk_object_get_data(GTK_OBJECT(user_data),
+ "acct_type_picker");
+ char * selected_acct;
+ char * description;
+ int acct_type;
+ SCM infolist;
+
+ printf("in select cb\n");
+ selected_acct = gtk_object_get_data(GTK_OBJECT(widget), "acct_name");
+ gnc_acct = xaccGetAccountFromFullName(topgroup, selected_acct,
+ ':');
+
+ gtk_entry_set_text(GTK_ENTRY(acct_entry), selected_acct);
+ description = xaccAccountGetDescription(gnc_acct);
+ acct_type = xaccAccountGetType(gnc_acct);
+
+ gtk_entry_set_text(GTK_ENTRY(descript),
+ description);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(type_pick),
+ acct_type);
+ infolist = SCM_LIST3(gh_str02scm(selected_acct),
+ gh_int2scm(acct_type),
+ gh_str02scm(description));
+ scm_protect_object(infolist);
+ gtk_object_set_data(GTK_OBJECT(user_data),
+ "scm_acct_info", (gpointer)infolist);
+ printf("leaving select cb\n");
+}
+
+
+void
+gnc_ui_account_picker_ok_cb(GtkButton *button,
+ gpointer user_data) {
+ GtkWidget * acct_entry = gtk_object_get_data(GTK_OBJECT(user_data),
+ "acct_entry");
+ GtkWidget * descript = gtk_object_get_data(GTK_OBJECT(user_data),
+ "acct_description_entry");
+ GtkWidget * type_pick = gtk_object_get_data(GTK_OBJECT(user_data),
+ "acct_type_picker");
+ GtkWidget * type_menu;
+ GtkWidget * menuitem;
+
+ char * selected_acct;
+ char * description;
+ int acct_type;
+ SCM infolist;
+
+ selected_acct = gtk_entry_get_text(GTK_ENTRY(acct_entry));
+ description = gtk_entry_get_text(GTK_ENTRY(descript));
+
+ type_menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(type_pick));
+ menuitem = gtk_menu_get_active(GTK_MENU(type_menu));
+ acct_type = (int)(gtk_object_get_data(GTK_OBJECT(menuitem),
+ "option_index"));
+
+ gtk_entry_set_text(GTK_ENTRY(descript),
+ description);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(type_pick),
+ acct_type);
+ infolist = SCM_LIST3(gh_str02scm(selected_acct),
+ gh_int2scm(acct_type),
+ gh_str02scm(description));
+ scm_protect_object(infolist);
+ gtk_object_set_data(GTK_OBJECT(user_data),
+ "scm_acct_info", (gpointer)infolist);
+
+ gtk_main_quit();
+}
+
+void
+gnc_ui_account_picker_cancel_cb(GtkButton * button,
+ gpointer user_data) {
+ gtk_object_set_data(GTK_OBJECT(user_data),
+ "scm_acct_info",
+ (gpointer)SCM_BOOL_F);
+ gtk_main_quit();
+}
diff --git a/src/gnome/dialog-account-picker.glade b/src/gnome/dialog-account-picker.glade
new file mode 100644
index 0000000000..9694caf1d7
--- /dev/null
+++ b/src/gnome/dialog-account-picker.glade
@@ -0,0 +1,313 @@
+
+
+
+
+ GNUCash Account Picker
+ gnucash
+
+
+ pixmaps
+ C
+ True
+ True
+ False
+ False
+ True
+ False
+ False
+ glade-account-picker.c
+ glade-account-picker.h
+ glade-cb-account-picker.c
+ glade-cb-account-picker.h
+ glade-support-account-picker.c
+ glade-support-account-picker.h
+
+
+
+
+ GnomeDialog
+ GNUcash Account Picker
+ GTK_WINDOW_TOPLEVEL
+ GTK_WIN_POS_NONE
+ False
+ True
+ True
+ False
+ False
+ False
+
+
+ GtkVBox
+ GnomeDialog:vbox
+ vbox1
+ False
+ 8
+
+ 1
+ True
+ True
+
+
+
+ GtkVBox
+ vbox2
+ False
+ 0
+
+ 0
+ True
+ True
+
+
+
+ GtkHBox
+ hbox1
+ False
+ 0
+
+ 0
+ True
+ True
+
+
+
+ GtkFrame
+ frame1
+ Accounts
+ 0
+ GTK_SHADOW_ETCHED_IN
+
+ 0
+ True
+ True
+
+
+
+ GtkScrolledWindow
+ scrolledwindow1
+ 250
+ 200
+ GTK_POLICY_ALWAYS
+ GTK_POLICY_ALWAYS
+ GTK_UPDATE_CONTINUOUS
+ GTK_UPDATE_CONTINUOUS
+
+
+ GtkViewport
+ viewport1
+ GTK_SHADOW_IN
+
+
+ GtkTree
+ account_tree
+
+ select_child
+ gnc_ui_account_picker_select_cb
+ GNUcash_Account_Picker
+ Thu, 02 Mar 2000 21:32:14 GMT
+
+ GTK_SELECTION_SINGLE
+ GTK_TREE_VIEW_LINE
+ True
+
+
+
+
+
+
+
+ GtkHBox
+ hbox2
+ False
+ 0
+
+ 6
+ False
+ False
+
+
+
+ GtkLabel
+ label1
+ 90
+ Selected account
+ GTK_JUSTIFY_CENTER
+ False
+ 1
+ 0.5
+ 0
+ 0
+
+ 8
+ False
+ False
+
+
+
+
+ GtkEntry
+ acct_entry
+ True
+ True
+ True
+ 0
+
+
+ 0
+ True
+ True
+
+
+
+
+
+
+ GtkHBox
+ hbox3
+ False
+ 0
+
+ 0
+ False
+ False
+
+
+
+ GtkLabel
+ label2
+ 90
+ Description
+ GTK_JUSTIFY_CENTER
+ False
+ 1
+ 0.5
+ 0
+ 0
+
+ 8
+ False
+ False
+
+
+
+
+ GtkEntry
+ acct_description_entry
+ True
+ True
+ True
+ 0
+
+
+ 0
+ True
+ True
+
+
+
+
+
+ GtkHBox
+ hbox4
+ False
+ 0
+
+ 0
+ False
+ False
+
+
+
+ GtkLabel
+ label3
+ 90
+ Account type
+ GTK_JUSTIFY_CENTER
+ False
+ 1
+ 0.5
+ 0
+ 0
+
+ 8
+ False
+ False
+
+
+
+
+ GtkOptionMenu
+ acct_type_picker
+ 150
+ 30
+ True
+ Bank
+Cash
+Asset
+Credit
+Liability
+Stock
+Mutual
+Currency
+Income
+Expense
+Equity
+
+ 0
+
+ 0
+ False
+ False
+
+
+
+
+
+ GtkHButtonBox
+ GnomeDialog:action_area
+ hbuttonbox1
+ GTK_BUTTONBOX_SPREAD
+ 8
+ 85
+ 27
+ 7
+ 0
+
+ 0
+ False
+ False
+ GTK_PACK_END
+
+
+
+ GtkButton
+ button1
+ True
+ True
+
+ clicked
+ gnc_ui_account_picker_ok_cb
+ GNUcash_Account_Picker
+ Thu, 02 Mar 2000 23:02:59 GMT
+
+ GNOME_STOCK_BUTTON_OK
+
+
+
+ GtkButton
+ button2
+ True
+ True
+
+ clicked
+ gnc_ui_account_picker_cancel_cb
+ GNUcash_Account_Picker
+ Thu, 02 Mar 2000 23:03:18 GMT
+
+ GNOME_STOCK_BUTTON_CANCEL
+
+
+
+
+
+
diff --git a/src/gnome/dialog-account-picker.h b/src/gnome/dialog-account-picker.h
new file mode 100644
index 0000000000..b6b55b4957
--- /dev/null
+++ b/src/gnome/dialog-account-picker.h
@@ -0,0 +1,29 @@
+/********************************************************************\
+ * dialog-account-picker.h -- window for picking a GNUcash account *
+ * (GnuCash) *
+ * Copyright (C) 2000 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 *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+\********************************************************************/
+
+#ifndef __DIALOG_ACCOUNT_PICKER_H_
+#define __DIALOG_ACCOUNT_PICKER_H_
+
+#include "glade-account-picker.h"
+#include "glade-cb-account-picker.h"
+
+SCM accountPickerBox(char *initial_pick, int initial_type);
+
+#endif
diff --git a/src/gnome/dialog-qif-import.c b/src/gnome/dialog-qif-import.c
new file mode 100644
index 0000000000..96e3af1dc9
--- /dev/null
+++ b/src/gnome/dialog-qif-import.c
@@ -0,0 +1,919 @@
+/********************************************************************\
+ * dialog-qif-import.c -- window for importing QIF files *
+ * (GnuCash) *
+ * Copyright (C) 2000 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 *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+\********************************************************************/
+
+#define _GNU_SOURCE
+
+#include "top-level.h"
+
+#include
+#include
+
+#include
+
+#include "dialog-qif-import.h"
+#include "dialog-account-picker.h"
+#include "window-help.h"
+#include "messages.h"
+#include "gnome-top-level.h"
+
+#include "Account.h"
+#include "AccInfo.h"
+#include "FileDialog.h"
+#include "FileBox.h"
+#include "dialog-utils.h"
+#include "query-user.h"
+#include "util.h"
+
+static void update_file_info(QIFImportWindow * win, SCM qiffile);
+static void update_file_page(QIFImportWindow * win);
+static void update_accounts_page(QIFImportWindow * win);
+static void update_categories_page(QIFImportWindow * win);
+
+
+/********************************************************************\
+ * gnc_ui_qif_import_dialog_make(GtkWidget * parent) * build the
+ * dialog. For now, there can be only one (obhighlanderref)
+\********************************************************************/
+
+QIFImportWindow *
+gnc_ui_qif_import_dialog_make(GtkWidget * parent)
+{
+ QIFImportWindow * retval;
+
+ GtkWidget * optionmenu;
+ GtkWidget * menu;
+ GtkWidget * active;
+ GtkWidget * currency_entry;
+
+ int i;
+
+ SCM load_map_prefs;
+ SCM mapping_info;
+ SCM lookup_option;
+ SCM lookup_value;
+ SCM default_currency;
+ int scm_strlen;
+
+ retval = (QIFImportWindow *) malloc(sizeof(QIFImportWindow));
+
+ retval->parent = parent;
+ retval->dialog = create_QIF_File_Import_Dialog();
+ retval->imported_files =
+ SCM_EOL;
+ retval->selected_file = SCM_BOOL_F;
+
+ gtk_object_set_data(GTK_OBJECT(retval->dialog),
+ "qif_window_struct", retval);
+
+ /* load the saved-state of the mappings from Quicken accounts and
+ * categories to gnucash accounts */
+ load_map_prefs = gh_eval_str("qif-import:load-map-prefs");
+ lookup_option = gh_eval_str("gnc:lookup-global-option");
+ lookup_value = gh_eval_str("gnc:option-value");
+
+ mapping_info = gh_call0(load_map_prefs);
+ retval->mapping_info = mapping_info;
+
+ default_currency = gh_call1(lookup_value,
+ gh_call2(lookup_option,
+ gh_str02scm("International"),
+ gh_str02scm("Default Currency")));
+
+ scm_protect_object(retval->imported_files);
+ scm_protect_object(retval->mapping_info);
+
+ /* set the currency entry to the GNC default currency */
+ currency_entry = gtk_object_get_data(GTK_OBJECT(retval->dialog),
+ "qif_currency_entry");
+ gtk_entry_set_text(GTK_ENTRY(currency_entry),
+ gh_scm2newstr(default_currency, &scm_strlen));
+
+ /* repair the option menus to associate "option_index" with the
+ * index number for each menu item */
+ optionmenu = gtk_object_get_data(GTK_OBJECT(retval->dialog),
+ "qif_radix_picker");
+ menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optionmenu));
+
+ for(i = 0; i < 3; i++) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(optionmenu), i);
+ active = gtk_menu_get_active(GTK_MENU(menu));
+ gtk_object_set_data(GTK_OBJECT(active),
+ "option_index",
+ (gpointer)(i));
+ }
+ gtk_option_menu_set_history(GTK_OPTION_MENU(optionmenu), 0);
+
+ optionmenu = gtk_object_get_data(GTK_OBJECT(retval->dialog),
+ "qif_date_picker");
+ menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optionmenu));
+
+ for(i = 0; i < 5; i++) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(optionmenu), i);
+ active = gtk_menu_get_active(GTK_MENU(menu));
+ gtk_object_set_data(GTK_OBJECT(active),
+ "option_index",
+ (gpointer)(i));
+ }
+ gtk_option_menu_set_history(GTK_OPTION_MENU(optionmenu), 0);
+
+ gtk_widget_show(retval->dialog);
+
+ if (retval->dialog->window == NULL) {
+ free(retval);
+ return NULL;
+ }
+
+ gdk_window_raise(retval->dialog->window);
+
+ return retval;
+}
+
+
+/********************************************************************\
+ * gnc_ui_qif_import_dialog_destroy
+ * close the QIF Import dialog window
+\********************************************************************/
+
+void
+gnc_ui_qif_import_dialog_destroy (QIFImportWindow * window)
+{
+ if(window) {
+ gnome_dialog_close(GNOME_DIALOG(window->dialog));
+ }
+}
+
+
+/********************************************************************\
+ * gnc_ui_qif_import_select_file_cb
+ * invoked when the "select file" button is clicked
+ * this is just to pick a file name and reset-to-defaults all the
+ * fields describing how to parse the file.
+\********************************************************************/
+
+void
+gnc_ui_qif_import_select_file_cb(GtkButton * button,
+ gpointer user_data) {
+ GtkWidget * dialog = GTK_WIDGET(user_data);
+ QIFImportWindow * wind =
+ gtk_object_get_data(GTK_OBJECT(dialog), "qif_window_struct");
+
+ GtkWidget * qif_filename_entry =
+ gtk_object_get_data(GTK_OBJECT(wind->dialog), "qif_filename_entry");
+ GtkWidget * acct_auto_button =
+ gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "qif_account_auto_check");
+ GtkWidget * qif_acct_entry =
+ gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "qif_account_entry");
+ GtkWidget * qif_radix_picker =
+ gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "qif_radix_picker");
+ GtkWidget * qif_date_picker =
+ gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "qif_date_picker");
+
+ char * new_file_name;
+
+ new_file_name = (char *)fileBox("Select QIF File", "*.qif");
+
+ if(new_file_name) {
+
+ /* set the filename entry for what was selected */
+ if(qif_filename_entry) {
+ gtk_entry_set_text(GTK_ENTRY(qif_filename_entry),
+ new_file_name);
+ }
+
+ /* the account should be auto-determined by default
+ * if the "opening balance" trick doesn't work "auto" will
+ * use the file name as a guess */
+ if(acct_auto_button) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(acct_auto_button),
+ TRUE);
+ }
+ if(qif_acct_entry) {
+ gtk_entry_set_text(GTK_ENTRY(qif_acct_entry),
+ "");
+ }
+
+ /* radix and date formats are auto-determined by default */
+ if(qif_date_picker) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(qif_date_picker),
+ 0);
+ }
+ if(qif_radix_picker) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(qif_radix_picker),
+ 0);
+ }
+ }
+}
+
+
+/********************************************************************\
+ * gnc_ui_qif_import_load_file_cb
+ *
+ * Invoked when the "load file" button is clicked on the first page of
+ * the QIF Import notebook. Filename, currency, radix format, and
+ * date format are read from the UI and passed to the Scheme side.
+\********************************************************************/
+
+void
+gnc_ui_qif_import_load_file_cb (GtkButton *button,
+ gpointer user_data) {
+ GtkWidget * dialog = GTK_WIDGET(user_data);
+ QIFImportWindow * wind =
+ gtk_object_get_data(GTK_OBJECT(dialog), "qif_window_struct");
+
+ char * path_to_load;
+ char * qif_account;
+ char * currency;
+ int radix_format;
+ int date_format;
+
+ GtkWidget * filename_box = gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "qif_filename_entry");
+ GtkWidget * currency_box = gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "qif_currency_entry");
+ GtkWidget * radix_picker = gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "qif_radix_picker");
+ GtkWidget * date_picker = gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "qif_date_picker");
+ GtkWidget * account_entry = gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "qif_account_entry");
+ GtkWidget * account_auto = gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "qif_account_auto_check");
+
+ GtkWidget * menuitem;
+
+ SCM make_qif_file, qif_file_load, qif_file_loaded, unload_qif_file;
+ SCM scm_filename, scm_currency, scm_radix, scm_date, scm_qif_account;
+ SCM scm_qiffile;
+ SCM imported_files = SCM_EOL;
+
+ char * radix_symbols [] = { "unknown", "decimal", "comma" };
+ char * date_symbols [] = { "unknown", "m-d-y", "d-m-y",
+ "y-m-d", "y-d-m" };
+
+ /* get the UI elements */
+ path_to_load = gtk_entry_get_text(GTK_ENTRY(filename_box));
+ currency = gtk_entry_get_text(GTK_ENTRY(currency_box));
+ qif_account = gtk_entry_get_text(GTK_ENTRY(account_entry));
+
+ radix_picker = gtk_option_menu_get_menu(GTK_OPTION_MENU(radix_picker));
+ menuitem = gtk_menu_get_active(GTK_MENU(radix_picker));
+ radix_format = (int)(gtk_object_get_data(GTK_OBJECT(menuitem),
+ "option_index"));
+
+ date_picker = gtk_option_menu_get_menu(GTK_OPTION_MENU(date_picker));
+ menuitem = gtk_menu_get_active(GTK_MENU(date_picker));
+ date_format = (int)(gtk_object_get_data(GTK_OBJECT(menuitem),
+ "option_index"));
+
+ if(strlen(path_to_load) == 0) {
+ gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
+ "You must specify a file to load.");
+ }
+ else if(strlen(currency) == 0) {
+ gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
+ "You must specify a currency.");
+ }
+ else {
+ /* find the make and load functions. */
+ make_qif_file = gh_eval_str("make-qif-file");
+ qif_file_load = gh_eval_str("qif-file:read-file");
+ qif_file_loaded = gh_eval_str("qif-dialog:qif-file-loaded?");
+ unload_qif_file = gh_eval_str("qif-dialog:unload-qif-file");
+
+ if((!gh_procedure_p(make_qif_file)) ||
+ (!gh_procedure_p(qif_file_load)) ||
+ (!gh_procedure_p(qif_file_loaded))) {
+ gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
+ "QIF File scheme code not loaded properly.");
+ }
+ else {
+ /* convert args */
+ scm_filename = gh_str02scm(path_to_load);
+ scm_currency = gh_str02scm(currency);
+ scm_radix = gh_symbol2scm(radix_symbols[radix_format]);
+ scm_date = gh_symbol2scm(date_symbols[date_format]);
+
+ if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(account_auto))) {
+ scm_qif_account = gh_symbol2scm("unknown");
+ }
+ else {
+ scm_qif_account = gh_str02scm(qif_account);
+ }
+
+ imported_files = wind->imported_files;
+
+ if(gh_call2(qif_file_loaded, scm_filename, wind->imported_files)
+ == SCM_BOOL_T) {
+ if(gnc_verify_dialog_parented(GTK_WINDOW(wind->dialog),
+ "QIF File already loaded. Reload "
+ "with current settings?", TRUE)) {
+ imported_files =
+ gh_call2(unload_qif_file, scm_filename, wind->imported_files);
+ }
+ else {
+ return;
+ }
+ }
+
+ /* create the object */
+ scm_qiffile = gh_apply(make_qif_file,
+ SCM_LIST4(scm_qif_account, scm_radix,
+ scm_date, scm_currency));
+
+ imported_files =
+ gh_cons(scm_qiffile, imported_files);
+
+ wind->selected_file = scm_qiffile;
+
+ /* I think I have to do this since it's a global but not in
+ * guile-space */
+ scm_protect_object(wind->selected_file);
+
+ /* import the file into it */
+ if(gh_call2(qif_file_load,
+ gh_car(imported_files),
+ scm_filename) != SCM_BOOL_T) {
+ gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
+ "Failed to load QIF file. Are you "
+ "sure it's a QIF file?");
+ imported_files =
+ gh_call2(unload_qif_file, scm_filename, imported_files);
+ }
+ wind->imported_files = imported_files;
+ scm_protect_object(wind->imported_files);
+
+ /* now update the Accounts and Categories pages in the notebook */
+ update_file_page(wind);
+ update_accounts_page(wind);
+ update_categories_page(wind);
+
+ }
+ }
+}
+
+
+void
+gnc_ui_qif_import_select_loaded_file_cb(GtkList * list,
+ GtkWidget * widget,
+ gpointer user_data) {
+ GtkWidget * dialog = GTK_WIDGET(user_data);
+ QIFImportWindow * wind =
+ gtk_object_get_data(GTK_OBJECT(dialog), "qif_window_struct");
+
+ SCM scm_qiffile;
+
+ scm_qiffile = (SCM)gtk_object_get_data(GTK_OBJECT(widget), "scm-object");
+
+ wind->selected_file = scm_qiffile;
+ scm_protect_object(wind->selected_file);
+ update_file_info(wind, scm_qiffile);
+
+}
+
+
+/****************************************************************\
+ * qif_import_ok_cb
+ * do the work of actually translating QIF xtns to GNC xtns.
+\****************************************************************/
+
+void
+gnc_ui_qif_import_ok_cb(GtkButton * button, gpointer user_data) {
+
+ SCM save_map_prefs;
+ SCM qif_to_gnc;
+ SCM hash_set;
+ SCM hash_data;
+ char * qif_acct_name;
+ char * qif_cat_name;
+ int row;
+
+ GtkWidget * dialog = GTK_WIDGET(user_data);
+ QIFImportWindow * wind =
+ gtk_object_get_data(GTK_OBJECT(dialog), "qif_window_struct");
+
+ GtkWidget * acc_list = gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "account_page_list");
+ GtkWidget * cat_list = gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "category_page_list");
+
+ save_map_prefs = gh_eval_str("qif-import:save-map-prefs");
+ qif_to_gnc = gh_eval_str("qif-import:qif-to-gnc");
+ hash_set = gh_eval_str("hash-set!");
+
+ /* transfer the info from the account / category pickers to
+ * the mapping info hash tables */
+ for(row=0; row < GTK_CLIST(acc_list)->rows; row++) {
+ gtk_clist_get_text(GTK_CLIST(acc_list), row, 0, &qif_acct_name);
+
+ hash_data = (SCM)gtk_clist_get_row_data(GTK_CLIST(acc_list), row);
+ gh_call3(hash_set, gh_cadr(wind->mapping_info),
+ gh_str02scm(qif_acct_name),
+ hash_data);
+ }
+
+ for(row=0; row < GTK_CLIST(cat_list)->rows; row++) {
+ gtk_clist_get_text(GTK_CLIST(cat_list), row, 0, &qif_cat_name);
+
+ hash_data = (SCM)gtk_clist_get_row_data(GTK_CLIST(cat_list), row);
+ gh_call3(hash_set, gh_caddr(wind->mapping_info),
+ gh_str02scm(qif_cat_name),
+ hash_data);
+ }
+
+ /* call a scheme function to do the work */
+ gh_call2(qif_to_gnc, wind->imported_files,
+ wind->mapping_info);
+
+ /* write out mapping info before destroying the window */
+ gh_call1(save_map_prefs, wind->mapping_info);
+
+ gnc_ui_qif_import_dialog_destroy(wind);
+ wind = NULL;
+}
+
+
+void
+gnc_ui_qif_import_cancel_cb (GtkButton * button, gpointer user_data) {
+
+ GtkWidget * dialog = GTK_WIDGET(user_data);
+ QIFImportWindow * wind =
+ gtk_object_get_data(GTK_OBJECT(dialog), "qif_window_struct");
+
+ gnc_ui_qif_import_dialog_destroy(wind);
+}
+
+
+void
+gnc_ui_qif_import_help_cb (GtkButton * button, gpointer user_data) {
+
+ helpWindow(NULL, HELP_STR, HH_QIFIMPORT);
+}
+
+void
+gnc_ui_qif_import_account_line_select_cb(GtkCList * clist, gint row,
+ gint column, GdkEvent * event,
+ gpointer user_data) {
+ char * initial_string;
+ int initial_type;
+
+ SCM scm_acct;
+ SCM old_info;
+ SCM munge_func = gh_eval_str("qif-dialog:munge-account-mapping");
+
+ old_info = (SCM)gtk_clist_get_row_data(GTK_CLIST(clist), row);
+
+ gtk_clist_get_text(GTK_CLIST(clist), row, 2, &initial_string);
+
+ initial_type = gh_scm2int(gh_list_ref(old_info, gh_int2scm(2)));
+
+ scm_acct = accountPickerBox(initial_string, initial_type);
+
+ if(gh_list_p(scm_acct)) {
+ gh_call2(munge_func, old_info, scm_acct);
+
+ gtk_clist_set_text(GTK_CLIST(clist), row, 2,
+ gh_scm2newstr(gh_car(scm_acct), NULL));
+ gtk_clist_set_text(GTK_CLIST(clist), row, 3,
+ xaccAccountTypeEnumAsString
+ (gh_scm2int(gh_cadr(scm_acct))));
+ }
+}
+
+void
+gnc_ui_qif_import_category_line_select_cb(GtkCList * clist, gint row,
+ gint column, GdkEvent * event,
+ gpointer user_data) {
+ char * initial_string;
+ int initial_type;
+
+ SCM scm_acct;
+ SCM old_info;
+ SCM munge_func = gh_eval_str("qif-dialog:munge-account-mapping");
+
+ old_info = (SCM)gtk_clist_get_row_data(GTK_CLIST(clist), row);
+
+ gtk_clist_get_text(GTK_CLIST(clist), row, 2, &initial_string);
+ initial_type = gh_scm2int(gh_list_ref(old_info, gh_int2scm(2)));
+
+ scm_acct = accountPickerBox(initial_string, initial_type);
+
+ if(gh_list_p(scm_acct)) {
+ gh_call2(munge_func, old_info, scm_acct);
+
+ gtk_clist_set_text(GTK_CLIST(clist), row, 2,
+ gh_scm2newstr(gh_car(scm_acct), NULL));
+ gtk_clist_set_text(GTK_CLIST(clist), row, 3,
+ xaccAccountTypeEnumAsString
+ (gh_scm2int(gh_cadr(scm_acct))));
+ }
+}
+
+
+
+/********************************************************************\
+ * update_file_page
+ * update the left-side list and the right-side info.
+\********************************************************************/
+
+static void
+update_file_page(QIFImportWindow * wind) {
+
+ GtkWidget * new_list_item;
+ GList * new_loaded_file;
+ SCM loaded_file_list = wind->imported_files;
+ SCM scm_qiffile;
+ SCM qif_file_path;
+ int path_strlen;
+
+ /* find the list of loaded files */
+ GtkWidget * loaded_files = gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "selected_file_list");
+ /* clear the list */
+ gtk_list_remove_items(GTK_LIST(loaded_files),
+ gtk_container_children(GTK_CONTAINER(loaded_files)));
+ qif_file_path = gh_eval_str("qif-file:path");
+
+ /* iterate over all the imported files */
+ while(!gh_null_p(loaded_file_list)) {
+ scm_qiffile = gh_car(loaded_file_list);
+
+ /* make a list item with the SCM object attached as data */
+ new_list_item =
+ gtk_list_item_new_with_label(gh_scm2newstr(gh_call1(qif_file_path,
+ scm_qiffile),
+ &path_strlen));
+ gtk_object_set_data(GTK_OBJECT(new_list_item),
+ "scm-object", (gpointer)scm_qiffile);
+ scm_protect_object(scm_qiffile);
+
+ /* tack it on to the displayed list */
+ new_loaded_file = g_list_alloc();
+ new_loaded_file->next = NULL;
+ new_loaded_file->prev = NULL;
+ gtk_widget_show(new_list_item);
+ new_loaded_file->data = new_list_item;
+
+ /* now add the file to the loaded-files list */
+ gtk_list_append_items(GTK_LIST(loaded_files), new_loaded_file);
+
+ /* select_child will update the file info */
+ if(scm_qiffile == wind->selected_file) {
+ gtk_list_select_child(GTK_LIST(loaded_files), new_list_item);
+ }
+
+ loaded_file_list = gh_cdr(loaded_file_list);
+ }
+}
+
+
+/********************************************************************\
+ * update_file_info
+ *
+ * Invoked when a file is loaded or the name of a loaded file is
+ * clicked in the loaded files list. This causes the pickers and text
+ * boxes on the right side to be updated to reflect the actual values
+ * used or detected in loading the files.
+\********************************************************************/
+
+static void
+update_file_info(QIFImportWindow * win, SCM qif_file) {
+
+ SCM qif_file_radix_format;
+ SCM qif_file_date_format;
+ SCM qif_file_currency;
+ SCM qif_file_path;
+ SCM qif_file_account;
+ SCM scm_radix_format;
+ SCM scm_date_format;
+ SCM scm_currency;
+ SCM scm_qif_account;
+ SCM scm_qif_path;
+
+ GtkWidget * path_entry;
+ GtkWidget * currency_entry;
+ GtkWidget * radix_optionmenu;
+ GtkWidget * date_optionmenu;
+ GtkWidget * account_entry;
+ GtkWidget * account_auto;
+
+ int scm_strlen;
+
+ /* look up the methods */
+ qif_file_radix_format = gh_eval_str("qif-file:radix-format");
+ qif_file_date_format = gh_eval_str("qif-file:date-format");
+ qif_file_currency = gh_eval_str("qif-file:currency");
+ qif_file_path = gh_eval_str("qif-file:path");
+ qif_file_account = gh_eval_str("qif-file:account");
+
+ /* make sure the methods are loaded */
+ if((!gh_procedure_p(qif_file_radix_format)) ||
+ (!gh_procedure_p(qif_file_date_format)) ||
+ (!gh_procedure_p(qif_file_currency)) ||
+ (!gh_procedure_p(qif_file_account)) ||
+ (!gh_procedure_p(qif_file_path))) {
+ gnc_error_dialog_parented(GTK_WINDOW(win->dialog),
+ "QIF File scheme code not loaded properly.");
+ return;
+ }
+ else {
+ /* find the relevant widgets */
+ path_entry = gtk_object_get_data(GTK_OBJECT(win->dialog),
+ "qif_filename_entry");
+ currency_entry = gtk_object_get_data(GTK_OBJECT(win->dialog),
+ "qif_currency_entry");
+ radix_optionmenu = gtk_object_get_data(GTK_OBJECT(win->dialog),
+ "qif_radix_picker");
+ date_optionmenu = gtk_object_get_data(GTK_OBJECT(win->dialog),
+ "qif_date_picker");
+ account_entry = gtk_object_get_data(GTK_OBJECT(win->dialog),
+ "qif_account_entry");
+ account_auto = gtk_object_get_data(GTK_OBJECT(win->dialog),
+ "qif_account_auto_check");
+
+ /* stick the currently-selected qiffile scm in the window data */
+ gtk_object_set_data(GTK_OBJECT(win->dialog),
+ "current_qif_file", (gpointer)qif_file);
+
+ scm_protect_object(qif_file);
+
+ /* get the radix/date formats, currency etc from the Scheme side */
+ scm_radix_format = gh_call1(qif_file_radix_format,
+ qif_file);
+ scm_date_format = gh_call1(qif_file_date_format,
+ qif_file);
+ scm_currency = gh_call1(qif_file_currency,
+ qif_file);
+ scm_qif_path = gh_call1(qif_file_path,
+ qif_file);
+ scm_qif_account = gh_call1(qif_file_account,
+ qif_file);
+
+ /* put the data in the info fields */
+ gtk_entry_set_text(GTK_ENTRY(path_entry),
+ gh_scm2newstr(scm_qif_path, &scm_strlen));
+ gtk_entry_set_text(GTK_ENTRY(currency_entry),
+ gh_scm2newstr(scm_currency, &scm_strlen));
+
+ /* account is weird. after loading, either we know it or we don't
+ * but in either case the auto should be off. */
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(account_auto), FALSE);
+ gtk_entry_set_text(GTK_ENTRY(account_entry),
+ gh_scm2newstr(scm_qif_account, &scm_strlen));
+
+ /* set the option menu selections */
+ if(!strcmp(gh_symbol2newstr(scm_radix_format, &scm_strlen),
+ "unknown")) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(radix_optionmenu), 0);
+ }
+ else if(!strcmp(gh_symbol2newstr(scm_radix_format, &scm_strlen),
+ "decimal")) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(radix_optionmenu), 1);
+ }
+ else if(!strcmp(gh_symbol2newstr(scm_radix_format, &scm_strlen),
+ "comma")) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(radix_optionmenu), 2);
+ }
+
+ if(!strcmp(gh_symbol2newstr(scm_date_format, &scm_strlen),
+ "unknown")) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(date_optionmenu), 0);
+ }
+ else if(!strcmp(gh_symbol2newstr(scm_date_format, &scm_strlen),
+ "m-d-y")) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(date_optionmenu), 1);
+ }
+ else if(!strcmp(gh_symbol2newstr(scm_date_format, &scm_strlen),
+ "d-m-y")) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(date_optionmenu), 2);
+ }
+ else if(!strcmp(gh_symbol2newstr(scm_date_format, &scm_strlen),
+ "y-m-d")) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(date_optionmenu), 3);
+ }
+ else if(!strcmp(gh_symbol2newstr(scm_date_format, &scm_strlen),
+ "y-d-m")) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(date_optionmenu), 4);
+ }
+ }
+}
+
+
+
+/****************************************************************\
+ * update_accounts_page
+ * Ask the Scheme side to guess some account translations , then
+ * show the filename, account name, and suggested translation in
+ * the Accounts page clist.
+\****************************************************************/
+
+static void
+update_accounts_page(QIFImportWindow * wind) {
+
+ SCM make_account_display;
+ SCM strings_left;
+ SCM display_info;
+ SCM hash_data;
+ SCM hash_set;
+ int xtn_count;
+ char * xtn_count_string;
+ char * qif_acct_name;
+ GtkWidget * account_list;
+ int row;
+ int scheme_strlen;
+ char * row_text[4];
+
+ make_account_display = gh_eval_str("qif-dialog:make-account-display");
+ hash_set = gh_eval_str("hash-set!");
+
+ /* make sure we found the procedure */
+ if(!gh_procedure_p(make_account_display)) {
+ gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
+ "QIF File scheme code not loaded properly.");
+ return;
+ }
+
+ account_list = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "account_page_list");
+
+ /* transfer the existing info from the account picker to
+ * the mapping info hash table */
+ for(row=0; row < GTK_CLIST(account_list)->rows; row++) {
+ gtk_clist_get_text(GTK_CLIST(account_list), row, 0, &qif_acct_name);
+
+ hash_data = (SCM)gtk_clist_get_row_data(GTK_CLIST(account_list), row);
+ gh_call3(hash_set, gh_cadr(wind->mapping_info),
+ gh_str02scm(qif_acct_name),
+ hash_data);
+ }
+
+ /* now get the list of strings to display in the clist widget */
+ /* gnc_unprotect_object(wind->acct_display_info); */
+ display_info = gh_call2(make_account_display,
+ wind->imported_files,
+ wind->mapping_info);
+ wind->acct_display_info = display_info;
+
+ scm_protect_object(wind->acct_display_info);
+
+ strings_left = wind->acct_display_info;
+ if(!gh_list_p(strings_left)) {
+ gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
+ "Something is very wrong with QIF Importing.");
+ return;
+ }
+
+ /* clear the list */
+ gtk_clist_clear(GTK_CLIST(account_list));
+
+ /* update the text in the boxes */
+ gtk_clist_freeze(GTK_CLIST(account_list));
+
+ gtk_clist_set_column_justification(GTK_CLIST(account_list),
+ 0,
+ GTK_JUSTIFY_RIGHT);
+ row = 0;
+ while(!gh_null_p(strings_left)) {
+ row_text[0] = gh_scm2newstr(gh_caar(strings_left), &scheme_strlen);
+ xtn_count = gh_scm2int(gh_list_ref(gh_car(strings_left),
+ gh_int2scm(4)));
+ asprintf(&xtn_count_string, "%d", xtn_count);
+ row_text[1] = xtn_count_string;
+ row_text[2] = gh_scm2newstr(gh_cadr(gh_car(strings_left)),
+ &scheme_strlen);
+ row_text[3] =
+ xaccAccountTypeEnumAsString(gh_scm2int
+ (gh_caddr(gh_car(strings_left))));
+
+ gtk_clist_append(GTK_CLIST(account_list), row_text);
+
+ gtk_clist_set_row_data(GTK_CLIST(account_list), row,
+ (gpointer)(gh_car(strings_left)));
+
+ scm_protect_object(gh_car(strings_left));
+
+ strings_left = gh_cdr(strings_left);
+ row++;
+ }
+
+
+ gtk_clist_thaw(GTK_CLIST(account_list));
+}
+
+
+/****************************************************************\
+ * update_categories_page
+ * Ask the Scheme side to guess some account translations , then
+ * show the filename, account name, and suggested translation in
+ * the Accounts page clist.
+\****************************************************************/
+
+static void
+update_categories_page(QIFImportWindow * wind) {
+
+ SCM make_category_display;
+ SCM strings_left;
+ SCM display_info;
+ SCM hash_data;
+ SCM hash_set;
+ int xtn_count;
+ char * xtn_count_string;
+ char * qif_cat_name;
+ GtkWidget * category_list;
+ int row;
+ int scheme_strlen;
+ char * row_text[4];
+
+ make_category_display = gh_eval_str("qif-dialog:make-category-display");
+ hash_set = gh_eval_str("hash-set!");
+
+ /* make sure we found the procedure */
+ if(!gh_procedure_p(make_category_display)) {
+ gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
+ "QIF File scheme code not loaded properly.");
+ return;
+ }
+
+ category_list = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(wind->dialog),
+ "category_page_list");
+
+ /* get the existing mappings from the display */
+ for(row=0; row < GTK_CLIST(category_list)->rows; row++) {
+ gtk_clist_get_text(GTK_CLIST(category_list), row, 0, &qif_cat_name);
+
+ hash_data = (SCM)gtk_clist_get_row_data(GTK_CLIST(category_list), row);
+ gh_call3(hash_set, gh_caddr(wind->mapping_info),
+ gh_str02scm(qif_cat_name),
+ hash_data);
+ }
+
+
+ /* now get the list of strings to display in the clist widget */
+ /* gnc_unprotect_object(wind->cat_display_info); */
+ display_info = gh_call2(make_category_display,
+ wind->imported_files,
+ wind->mapping_info);
+ wind->cat_display_info = display_info;
+
+ scm_protect_object(wind->cat_display_info);
+
+ strings_left = wind->cat_display_info;
+ if(!gh_list_p(strings_left)) {
+ gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
+ "Something is very wrong with QIF Importing.");
+ return;
+ }
+
+ /* clear the list */
+ gtk_clist_clear(GTK_CLIST(category_list));
+
+ /* update the text in the boxes */
+ gtk_clist_freeze(GTK_CLIST(category_list));
+
+ gtk_clist_set_column_justification(GTK_CLIST(category_list),
+ 0,
+ GTK_JUSTIFY_RIGHT);
+ row = 0;
+ while(!gh_null_p(strings_left)) {
+ row_text[0] = gh_scm2newstr(gh_caar(strings_left), &scheme_strlen);
+ xtn_count = gh_scm2int(gh_list_ref(gh_car(strings_left),
+ gh_int2scm(4)));
+ asprintf(&xtn_count_string, "%d", xtn_count);
+ row_text[1] = xtn_count_string;
+ row_text[2] = gh_scm2newstr(gh_cadr(gh_car(strings_left)),
+ &scheme_strlen);
+ row_text[3] = xaccAccountTypeEnumAsString(gh_scm2int
+ (gh_caddr(gh_car(strings_left))));
+
+ gtk_clist_append(GTK_CLIST(category_list), row_text);
+ gtk_clist_set_row_data(GTK_CLIST(category_list), row,
+ (gpointer)gh_car(strings_left));
+ scm_protect_object(gh_car(strings_left));
+ strings_left = gh_cdr(strings_left);
+ row++;
+ }
+
+ gtk_clist_thaw(GTK_CLIST(category_list));
+}
+
+
diff --git a/src/gnome/dialog-qif-import.glade b/src/gnome/dialog-qif-import.glade
new file mode 100644
index 0000000000..90fb84ff37
--- /dev/null
+++ b/src/gnome/dialog-qif-import.glade
@@ -0,0 +1,694 @@
+
+
+
+
+ dialog-qif-import
+ dialog-qif-import
+
+
+ pixmaps
+ C
+ True
+ True
+ False
+ False
+ True
+ False
+ False
+ glade-qif-import.c
+ glade-qif-import.h
+ glade-cb-qif-import.c
+ glade-cb-qif-import.h
+ glade-support-qif-import.c
+ glade-support-qif-import.h
+
+
+
+
+ GnomeDialog
+ QIF File Import Dialog
+ GTK_WINDOW_TOPLEVEL
+ GTK_WIN_POS_NONE
+ False
+ True
+ True
+ False
+ False
+ False
+
+
+ GtkVBox
+ GnomeDialog:vbox
+ dialog-vbox2
+ False
+ 8
+
+ 4
+ True
+ True
+
+
+
+ GtkNotebook
+ notebook1
+ True
+ True
+ True
+ GTK_POS_TOP
+ False
+ 2
+ 2
+ False
+
+ 0
+ True
+ True
+
+
+
+ GtkHBox
+ hbox1
+ False
+ 0
+
+
+ GtkFrame
+ frame2
+ 200
+ Loaded Files
+ 0.05
+ GTK_SHADOW_ETCHED_IN
+
+ 0
+ True
+ True
+
+
+
+ GtkScrolledWindow
+ scrolledwindow1
+ 150
+ GTK_POLICY_AUTOMATIC
+ GTK_POLICY_ALWAYS
+ GTK_UPDATE_CONTINUOUS
+ GTK_UPDATE_CONTINUOUS
+
+
+ GtkViewport
+ viewport1
+ GTK_SHADOW_IN
+
+
+ GtkList
+ selected_file_list
+
+ select_child
+ gnc_ui_qif_import_select_loaded_file_cb
+ QIF_File_Import_Dialog
+ Tue, 14 Mar 2000 15:17:01 GMT
+
+ GTK_SELECTION_SINGLE
+
+
+
+
+
+
+ GtkFrame
+ frame1
+ 325
+ File Info
+ 0.01
+ GTK_SHADOW_ETCHED_IN
+
+ 0
+ False
+ False
+
+
+
+ GtkVBox
+ vbox1
+ True
+ 0
+
+
+ GtkHBox
+ hbox5
+ False
+ 0
+
+ 0
+ False
+ False
+
+
+
+ GtkLabel
+ label1
+ 70
+ QIF Filename
+ GTK_JUSTIFY_CENTER
+ False
+ 1
+ 0.5
+ 0
+ 0
+
+ 10
+ False
+ False
+
+
+
+
+ GtkEntry
+ qif_filename_entry
+ True
+ True
+ True
+ True
+ True
+ 0
+
+
+ 5
+ True
+ True
+
+
+
+
+
+ GtkHBox
+ hbox8
+ False
+ 0
+
+ 0
+ True
+ True
+
+
+
+ GtkLabel
+ label679
+ 70
+ QIF Account
+ GTK_JUSTIFY_CENTER
+ False
+ 1
+ 0.5
+ 0
+ 0
+
+ 10
+ False
+ False
+
+
+
+
+ GtkCheckButton
+ qif_account_auto_check
+ 45
+ 16
+ True
+ Auto
+ True
+ True
+
+ 2
+ False
+ False
+
+
+
+
+ GtkEntry
+ qif_account_entry
+ True
+ True
+ True
+ 0
+
+
+ 5
+ True
+ True
+
+
+
+
+
+ GtkHBox
+ hbox2
+ False
+ 0
+
+ 0
+ False
+ False
+
+
+
+ GtkLabel
+ currency_label
+ 70
+ Currency
+ GTK_JUSTIFY_LEFT
+ False
+ 1
+ 0.5
+ 0
+ 0
+
+ 10
+ False
+ False
+
+
+
+
+ GtkEntry
+ qif_currency_entry
+ 75
+ True
+ True
+ True
+ 0
+
+
+ 5
+ False
+ False
+
+
+
+
+
+ GtkHBox
+ hbox3
+ False
+ 0
+
+ 0
+ False
+ False
+
+
+
+ GtkLabel
+ radix_format_label
+ 70
+ Radix format
+ GTK_JUSTIFY_RIGHT
+ False
+ 1
+ 0.5
+ 0
+ 0
+
+ 10
+ False
+ False
+
+
+
+
+ GtkOptionMenu
+ qif_radix_picker
+ 140
+ True
+ Autodetect
+Decimal (1,000.00)
+Comma (1.000,00)
+
+ 0
+
+ 5
+ False
+ False
+
+
+
+
+
+ GtkHBox
+ hbox4
+ False
+ 0
+
+ 0
+ False
+ False
+
+
+
+ GtkLabel
+ date_format_label
+ 70
+ Date format
+ GTK_JUSTIFY_CENTER
+ False
+ 1
+ 0.5
+ 0
+ 0
+
+ 10
+ False
+ False
+
+
+
+
+ GtkOptionMenu
+ qif_date_picker
+ 140
+ True
+ Autodetect
+MM/DD/YYYY
+DD/MM/YYYY
+YYYY/MM/DD
+YYYY/DD/MM
+
+ 0
+
+ 5
+ False
+ False
+
+
+
+
+
+ GtkHBox
+ hbox6
+ False
+ 0
+
+ 5
+ True
+ True
+
+
+
+ GtkButton
+ file_select_btn
+ 125
+ True
+
+ clicked
+ gnc_ui_qif_import_select_file_cb
+ QIF_File_Import_Dialog
+ Tue, 14 Mar 2000 15:42:40 GMT
+
+ Select file
+
+ 3
+ True
+ False
+
+
+
+
+ GtkButton
+ add_file_button
+ 125
+ True
+
+ clicked
+ gnc_ui_qif_import_load_file_cb
+ QIF_File_Import_Dialog
+ Tue, 14 Mar 2000 15:14:48 GMT
+
+ Load file
+
+ 0
+ True
+ False
+
+
+
+
+
+
+
+
+ GtkLabel
+ Notebook:tab
+ label69
+ Files
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+ GtkScrolledWindow
+ scrolledwindow2
+ GTK_POLICY_ALWAYS
+ GTK_POLICY_ALWAYS
+ GTK_UPDATE_CONTINUOUS
+ GTK_UPDATE_CONTINUOUS
+
+
+ GtkCList
+ account_page_list
+ True
+
+ select_row
+ gnc_ui_qif_import_account_line_select_cb
+ Tue, 14 Mar 2000 14:58:13 GMT
+
+ 4
+ 116,80,204,80
+ GTK_SELECTION_SINGLE
+ True
+ GTK_SHADOW_IN
+
+
+ GtkLabel
+ CList:title
+ label682
+ QIF Account
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+ GtkLabel
+ CList:title
+ label683
+ Transactions
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+ GtkLabel
+ CList:title
+ label684
+ GNUCash Account Name
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+ GtkLabel
+ CList:title
+ label685
+ Type
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+
+
+ GtkLabel
+ Notebook:tab
+ label2
+ Accounts
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+ GtkScrolledWindow
+ scrolledwindow3
+ GTK_POLICY_ALWAYS
+ GTK_POLICY_ALWAYS
+ GTK_UPDATE_CONTINUOUS
+ GTK_UPDATE_CONTINUOUS
+
+
+ GtkCList
+ category_page_list
+ True
+
+ select_row
+ gnc_ui_qif_import_category_line_select_cb
+ Tue, 14 Mar 2000 14:59:18 GMT
+
+ 4
+ 117,80,204,80
+ GTK_SELECTION_SINGLE
+ True
+ GTK_SHADOW_IN
+
+
+ GtkLabel
+ CList:title
+ label686
+ QIF Category
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+ GtkLabel
+ CList:title
+ label687
+ Transactions
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+ GtkLabel
+ CList:title
+ label688
+ GNUCash Account Name
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+ GtkLabel
+ CList:title
+ label689
+ Type
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+
+
+ GtkLabel
+ Notebook:tab
+ foo6868
+ Categories
+ GTK_JUSTIFY_CENTER
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+
+
+ GtkHButtonBox
+ GnomeDialog:action_area
+ dialog-action_area2
+ GTK_BUTTONBOX_SPREAD
+ 8
+ 85
+ 27
+ 7
+ 0
+
+ 0
+ False
+ True
+ GTK_PACK_END
+
+
+
+ GtkButton
+ button2
+ True
+ True
+
+ clicked
+ gnc_ui_qif_import_ok_cb
+ QIF_File_Import_Dialog
+ Tue, 14 Mar 2000 15:08:23 GMT
+
+ GNOME_STOCK_BUTTON_OK
+
+
+
+ GtkButton
+ button3
+ True
+ True
+
+ clicked
+ gnc_ui_qif_import_cancel_cb
+ QIF_File_Import_Dialog
+ Tue, 14 Mar 2000 15:08:04 GMT
+
+ GNOME_STOCK_BUTTON_CANCEL
+
+
+
+ GtkButton
+ button4
+ True
+ True
+
+ clicked
+ gnc_ui_qif_import_help_cb
+ QIF_File_Import_Dialog
+ Tue, 14 Mar 2000 15:08:59 GMT
+
+ GNOME_STOCK_BUTTON_HELP
+
+
+
+
+
+
diff --git a/src/gnome/dialog-qif-import.h b/src/gnome/dialog-qif-import.h
new file mode 100644
index 0000000000..75af7e6a2d
--- /dev/null
+++ b/src/gnome/dialog-qif-import.h
@@ -0,0 +1,46 @@
+/********************************************************************\
+ * dialog-qif-import.h -- window for controlling import of QIF data *
+ * (GnuCash) *
+ * Copyright (C) 2000 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 *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+\********************************************************************/
+
+#ifndef __DIALOG_QIF_IMPORT_H_
+#define __DIALOG_QIF_IMPORT_H_
+
+#include
+
+#include "glade-qif-import.h"
+#include "glade-cb-qif-import.h"
+
+typedef struct _qifimportwindow
+{
+
+ GtkWidget * parent;
+ GtkWidget * dialog;
+
+ SCM imported_files;
+ SCM selected_file;
+ SCM mapping_info;
+ SCM cat_display_info;
+ SCM acct_display_info;
+
+} QIFImportWindow;
+
+QIFImportWindow * gnc_ui_qif_import_dialog_make(GtkWidget * parent);
+void gnc_ui_qif_import_dialog_destroy(QIFImportWindow * window);
+
+#endif
diff --git a/src/gnome/glade-account-picker.c b/src/gnome/glade-account-picker.c
new file mode 100644
index 0000000000..8092a879be
--- /dev/null
+++ b/src/gnome/glade-account-picker.c
@@ -0,0 +1,236 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "glade-cb-account-picker.h"
+#include "glade-account-picker.h"
+#include "glade-support-account-picker.h"
+
+GtkWidget*
+create_GNUcash_Account_Picker (void)
+{
+ GtkWidget *GNUcash_Account_Picker;
+ GtkWidget *vbox1;
+ GtkWidget *vbox2;
+ GtkWidget *hbox1;
+ GtkWidget *frame1;
+ GtkWidget *scrolledwindow1;
+ GtkWidget *viewport1;
+ GtkWidget *account_tree;
+ GtkWidget *hbox2;
+ GtkWidget *label1;
+ GtkWidget *acct_entry;
+ GtkWidget *hbox3;
+ GtkWidget *label2;
+ GtkWidget *acct_description_entry;
+ GtkWidget *hbox4;
+ GtkWidget *label3;
+ GtkWidget *acct_type_picker;
+ GtkWidget *acct_type_picker_menu;
+ GtkWidget *glade_menuitem;
+ GtkWidget *hbuttonbox1;
+ GtkWidget *button1;
+ GtkWidget *button2;
+
+ GNUcash_Account_Picker = gnome_dialog_new (NULL, NULL);
+ gtk_object_set_data (GTK_OBJECT (GNUcash_Account_Picker), "GNUcash_Account_Picker", GNUcash_Account_Picker);
+ gtk_window_set_policy (GTK_WINDOW (GNUcash_Account_Picker), TRUE, TRUE, FALSE);
+
+ vbox1 = GNOME_DIALOG (GNUcash_Account_Picker)->vbox;
+ gtk_object_set_data (GTK_OBJECT (GNUcash_Account_Picker), "vbox1", vbox1);
+ gtk_widget_show (vbox1);
+
+ vbox2 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_ref (vbox2);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "vbox2", vbox2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (vbox2);
+ gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0);
+
+ hbox1 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox1);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "hbox1", hbox1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox1);
+ gtk_box_pack_start (GTK_BOX (vbox2), hbox1, TRUE, TRUE, 0);
+
+ frame1 = gtk_frame_new (_("Accounts"));
+ gtk_widget_ref (frame1);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "frame1", frame1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (frame1);
+ gtk_box_pack_start (GTK_BOX (hbox1), frame1, TRUE, TRUE, 0);
+
+ scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_ref (scrolledwindow1);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "scrolledwindow1", scrolledwindow1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (scrolledwindow1);
+ gtk_container_add (GTK_CONTAINER (frame1), scrolledwindow1);
+ gtk_widget_set_usize (scrolledwindow1, 250, 200);
+
+ viewport1 = gtk_viewport_new (NULL, NULL);
+ gtk_widget_ref (viewport1);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "viewport1", viewport1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (viewport1);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1);
+
+ account_tree = gtk_tree_new ();
+ gtk_widget_ref (account_tree);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "account_tree", account_tree,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (account_tree);
+ gtk_container_add (GTK_CONTAINER (viewport1), account_tree);
+
+ hbox2 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox2);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "hbox2", hbox2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox2);
+ gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 6);
+
+ label1 = gtk_label_new (_("Selected account"));
+ gtk_widget_ref (label1);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "label1", label1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label1);
+ gtk_box_pack_start (GTK_BOX (hbox2), label1, FALSE, FALSE, 8);
+ gtk_widget_set_usize (label1, 90, -2);
+ gtk_misc_set_alignment (GTK_MISC (label1), 1, 0.5);
+
+ acct_entry = gtk_entry_new ();
+ gtk_widget_ref (acct_entry);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "acct_entry", acct_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (acct_entry);
+ gtk_box_pack_start (GTK_BOX (hbox2), acct_entry, TRUE, TRUE, 0);
+
+ hbox3 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox3);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "hbox3", hbox3,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox3);
+ gtk_box_pack_start (GTK_BOX (vbox1), hbox3, FALSE, FALSE, 0);
+
+ label2 = gtk_label_new (_("Description"));
+ gtk_widget_ref (label2);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "label2", label2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label2);
+ gtk_box_pack_start (GTK_BOX (hbox3), label2, FALSE, FALSE, 8);
+ gtk_widget_set_usize (label2, 90, -2);
+ gtk_misc_set_alignment (GTK_MISC (label2), 1, 0.5);
+
+ acct_description_entry = gtk_entry_new ();
+ gtk_widget_ref (acct_description_entry);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "acct_description_entry", acct_description_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (acct_description_entry);
+ gtk_box_pack_start (GTK_BOX (hbox3), acct_description_entry, TRUE, TRUE, 0);
+
+ hbox4 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox4);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "hbox4", hbox4,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox4);
+ gtk_box_pack_start (GTK_BOX (vbox1), hbox4, FALSE, FALSE, 0);
+
+ label3 = gtk_label_new (_("Account type"));
+ gtk_widget_ref (label3);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "label3", label3,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label3);
+ gtk_box_pack_start (GTK_BOX (hbox4), label3, FALSE, FALSE, 8);
+ gtk_widget_set_usize (label3, 90, -2);
+ gtk_misc_set_alignment (GTK_MISC (label3), 1, 0.5);
+
+ acct_type_picker = gtk_option_menu_new ();
+ gtk_widget_ref (acct_type_picker);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "acct_type_picker", acct_type_picker,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (acct_type_picker);
+ gtk_box_pack_start (GTK_BOX (hbox4), 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);
+
+ hbuttonbox1 = GNOME_DIALOG (GNUcash_Account_Picker)->action_area;
+ gtk_object_set_data (GTK_OBJECT (GNUcash_Account_Picker), "hbuttonbox1", hbuttonbox1);
+ gtk_widget_show (hbuttonbox1);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD);
+ gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox1), 8);
+
+ gnome_dialog_append_button (GNOME_DIALOG (GNUcash_Account_Picker), GNOME_STOCK_BUTTON_OK);
+ button1 = g_list_last (GNOME_DIALOG (GNUcash_Account_Picker)->buttons)->data;
+ gtk_widget_ref (button1);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "button1", button1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (button1);
+ GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT);
+
+ gnome_dialog_append_button (GNOME_DIALOG (GNUcash_Account_Picker), GNOME_STOCK_BUTTON_CANCEL);
+ button2 = g_list_last (GNOME_DIALOG (GNUcash_Account_Picker)->buttons)->data;
+ gtk_widget_ref (button2);
+ gtk_object_set_data_full (GTK_OBJECT (GNUcash_Account_Picker), "button2", button2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ 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),
+ GNUcash_Account_Picker);
+ gtk_signal_connect (GTK_OBJECT (button1), "clicked",
+ GTK_SIGNAL_FUNC (gnc_ui_account_picker_ok_cb),
+ GNUcash_Account_Picker);
+ gtk_signal_connect (GTK_OBJECT (button2), "clicked",
+ GTK_SIGNAL_FUNC (gnc_ui_account_picker_cancel_cb),
+ GNUcash_Account_Picker);
+
+ return GNUcash_Account_Picker;
+}
+
diff --git a/src/gnome/glade-account-picker.h b/src/gnome/glade-account-picker.h
new file mode 100644
index 0000000000..711efef5d0
--- /dev/null
+++ b/src/gnome/glade-account-picker.h
@@ -0,0 +1,5 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+GtkWidget* create_GNUcash_Account_Picker (void);
diff --git a/src/gnome/glade-cb-account-picker.c b/src/gnome/glade-cb-account-picker.c
new file mode 100644
index 0000000000..4077bed6eb
--- /dev/null
+++ b/src/gnome/glade-cb-account-picker.c
@@ -0,0 +1,35 @@
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include
+
+#include "glade-cb-account-picker.h"
+#include "glade-account-picker.h"
+#include "glade-support-account-picker.h"
+
+
+void
+gnc_ui_account_picker_select_cb (GtkTree *tree,
+ GtkWidget *widget,
+ gpointer user_data)
+{
+
+}
+
+
+void
+gnc_ui_account_picker_ok_cb (GtkButton *button,
+ gpointer user_data)
+{
+
+}
+
+
+void
+gnc_ui_account_picker_cancel_cb (GtkButton *button,
+ gpointer user_data)
+{
+
+}
+
diff --git a/src/gnome/glade-cb-account-picker.h b/src/gnome/glade-cb-account-picker.h
new file mode 100644
index 0000000000..71bade142c
--- /dev/null
+++ b/src/gnome/glade-cb-account-picker.h
@@ -0,0 +1,15 @@
+#include
+
+
+void
+gnc_ui_account_picker_select_cb (GtkTree *tree,
+ GtkWidget *widget,
+ gpointer user_data);
+
+void
+gnc_ui_account_picker_ok_cb (GtkButton *button,
+ gpointer user_data);
+
+void
+gnc_ui_account_picker_cancel_cb (GtkButton *button,
+ gpointer user_data);
diff --git a/src/gnome/glade-cb-qif-import.c b/src/gnome/glade-cb-qif-import.c
new file mode 100644
index 0000000000..72db674ccb
--- /dev/null
+++ b/src/gnome/glade-cb-qif-import.c
@@ -0,0 +1,84 @@
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include
+
+#include "glade-cb-qif-import.h"
+#include "glade-qif-import.h"
+#include "glade-support-qif-import.h"
+
+
+void
+gnc_ui_qif_import_select_loaded_file_cb
+ (GtkList *list,
+ GtkWidget *widget,
+ gpointer user_data)
+{
+
+}
+
+
+void
+gnc_ui_qif_import_select_file_cb (GtkButton *button,
+ gpointer user_data)
+{
+
+}
+
+
+void
+gnc_ui_qif_import_load_file_cb (GtkButton *button,
+ gpointer user_data)
+{
+
+}
+
+
+void
+gnc_ui_qif_import_account_line_select_cb
+ (GtkCList *clist,
+ gint row,
+ gint column,
+ GdkEvent *event,
+ gpointer user_data)
+{
+
+}
+
+
+void
+gnc_ui_qif_import_category_line_select_cb
+ (GtkCList *clist,
+ gint row,
+ gint column,
+ GdkEvent *event,
+ gpointer user_data)
+{
+
+}
+
+
+void
+gnc_ui_qif_import_ok_cb (GtkButton *button,
+ gpointer user_data)
+{
+
+}
+
+
+void
+gnc_ui_qif_import_cancel_cb (GtkButton *button,
+ gpointer user_data)
+{
+
+}
+
+
+void
+gnc_ui_qif_import_help_cb (GtkButton *button,
+ gpointer user_data)
+{
+
+}
+
diff --git a/src/gnome/glade-cb-qif-import.h b/src/gnome/glade-cb-qif-import.h
new file mode 100644
index 0000000000..39be014029
--- /dev/null
+++ b/src/gnome/glade-cb-qif-import.h
@@ -0,0 +1,44 @@
+#include
+
+
+void
+gnc_ui_qif_import_select_loaded_file_cb
+ (GtkList *list,
+ GtkWidget *widget,
+ gpointer user_data);
+
+void
+gnc_ui_qif_import_select_file_cb (GtkButton *button,
+ gpointer user_data);
+
+void
+gnc_ui_qif_import_load_file_cb (GtkButton *button,
+ gpointer user_data);
+
+void
+gnc_ui_qif_import_account_line_select_cb
+ (GtkCList *clist,
+ gint row,
+ gint column,
+ GdkEvent *event,
+ gpointer user_data);
+
+void
+gnc_ui_qif_import_category_line_select_cb
+ (GtkCList *clist,
+ gint row,
+ gint column,
+ GdkEvent *event,
+ gpointer user_data);
+
+void
+gnc_ui_qif_import_ok_cb (GtkButton *button,
+ gpointer user_data);
+
+void
+gnc_ui_qif_import_cancel_cb (GtkButton *button,
+ gpointer user_data);
+
+void
+gnc_ui_qif_import_help_cb (GtkButton *button,
+ gpointer user_data);
diff --git a/src/gnome/glade-qif-import.c b/src/gnome/glade-qif-import.c
new file mode 100644
index 0000000000..624f636742
--- /dev/null
+++ b/src/gnome/glade-qif-import.c
@@ -0,0 +1,499 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "glade-cb-qif-import.h"
+#include "glade-qif-import.h"
+#include "glade-support-qif-import.h"
+
+GtkWidget*
+create_QIF_File_Import_Dialog (void)
+{
+ GtkWidget *QIF_File_Import_Dialog;
+ GtkWidget *dialog_vbox2;
+ GtkWidget *notebook1;
+ GtkWidget *hbox1;
+ GtkWidget *frame2;
+ GtkWidget *scrolledwindow1;
+ GtkWidget *viewport1;
+ GtkWidget *selected_file_list;
+ GtkWidget *frame1;
+ GtkWidget *vbox1;
+ GtkWidget *hbox5;
+ GtkWidget *label1;
+ GtkWidget *qif_filename_entry;
+ GtkWidget *hbox8;
+ GtkWidget *label679;
+ GtkWidget *qif_account_auto_check;
+ GtkWidget *qif_account_entry;
+ GtkWidget *hbox2;
+ GtkWidget *currency_label;
+ GtkWidget *qif_currency_entry;
+ GtkWidget *hbox3;
+ GtkWidget *radix_format_label;
+ GtkWidget *qif_radix_picker;
+ GtkWidget *qif_radix_picker_menu;
+ GtkWidget *glade_menuitem;
+ GtkWidget *hbox4;
+ GtkWidget *date_format_label;
+ GtkWidget *qif_date_picker;
+ GtkWidget *qif_date_picker_menu;
+ GtkWidget *hbox6;
+ GtkWidget *file_select_btn;
+ GtkWidget *add_file_button;
+ GtkWidget *label69;
+ GtkWidget *scrolledwindow2;
+ GtkWidget *account_page_list;
+ GtkWidget *label682;
+ GtkWidget *label683;
+ GtkWidget *label684;
+ GtkWidget *label685;
+ GtkWidget *label2;
+ GtkWidget *scrolledwindow3;
+ GtkWidget *category_page_list;
+ GtkWidget *label686;
+ GtkWidget *label687;
+ GtkWidget *label688;
+ GtkWidget *label689;
+ GtkWidget *foo6868;
+ GtkWidget *dialog_action_area2;
+ GtkWidget *button2;
+ GtkWidget *button3;
+ GtkWidget *button4;
+
+ QIF_File_Import_Dialog = gnome_dialog_new (NULL, NULL);
+ gtk_object_set_data (GTK_OBJECT (QIF_File_Import_Dialog), "QIF_File_Import_Dialog", QIF_File_Import_Dialog);
+ gtk_window_set_policy (GTK_WINDOW (QIF_File_Import_Dialog), TRUE, TRUE, FALSE);
+
+ dialog_vbox2 = GNOME_DIALOG (QIF_File_Import_Dialog)->vbox;
+ gtk_object_set_data (GTK_OBJECT (QIF_File_Import_Dialog), "dialog_vbox2", dialog_vbox2);
+ gtk_widget_show (dialog_vbox2);
+
+ notebook1 = gtk_notebook_new ();
+ gtk_widget_ref (notebook1);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "notebook1", notebook1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (notebook1);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox2), notebook1, TRUE, TRUE, 0);
+
+ hbox1 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox1);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "hbox1", hbox1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox1);
+ gtk_container_add (GTK_CONTAINER (notebook1), hbox1);
+
+ frame2 = gtk_frame_new (_("Loaded Files"));
+ gtk_widget_ref (frame2);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "frame2", frame2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (frame2);
+ gtk_box_pack_start (GTK_BOX (hbox1), frame2, TRUE, TRUE, 0);
+ gtk_widget_set_usize (frame2, 200, -2);
+ gtk_frame_set_label_align (GTK_FRAME (frame2), 0.05, 0.5);
+
+ scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_ref (scrolledwindow1);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "scrolledwindow1", scrolledwindow1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (scrolledwindow1);
+ gtk_container_add (GTK_CONTAINER (frame2), scrolledwindow1);
+ gtk_widget_set_usize (scrolledwindow1, -2, 150);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+ viewport1 = gtk_viewport_new (NULL, NULL);
+ gtk_widget_ref (viewport1);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "viewport1", viewport1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (viewport1);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1);
+
+ selected_file_list = gtk_list_new ();
+ gtk_widget_ref (selected_file_list);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "selected_file_list", selected_file_list,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (selected_file_list);
+ gtk_container_add (GTK_CONTAINER (viewport1), selected_file_list);
+
+ frame1 = gtk_frame_new (_("File Info"));
+ gtk_widget_ref (frame1);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "frame1", frame1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (frame1);
+ gtk_box_pack_start (GTK_BOX (hbox1), frame1, FALSE, FALSE, 0);
+ gtk_widget_set_usize (frame1, 325, -2);
+ gtk_frame_set_label_align (GTK_FRAME (frame1), 0.01, 0.5);
+
+ vbox1 = gtk_vbox_new (TRUE, 0);
+ gtk_widget_ref (vbox1);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "vbox1", vbox1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (vbox1);
+ gtk_container_add (GTK_CONTAINER (frame1), vbox1);
+
+ hbox5 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox5);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "hbox5", hbox5,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox5);
+ gtk_box_pack_start (GTK_BOX (vbox1), hbox5, FALSE, FALSE, 0);
+
+ label1 = gtk_label_new (_("QIF Filename"));
+ gtk_widget_ref (label1);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label1", label1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label1);
+ gtk_box_pack_start (GTK_BOX (hbox5), label1, FALSE, FALSE, 10);
+ gtk_widget_set_usize (label1, 70, -2);
+ gtk_misc_set_alignment (GTK_MISC (label1), 1, 0.5);
+
+ qif_filename_entry = gtk_entry_new ();
+ gtk_widget_ref (qif_filename_entry);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "qif_filename_entry", qif_filename_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (qif_filename_entry);
+ gtk_box_pack_start (GTK_BOX (hbox5), qif_filename_entry, TRUE, TRUE, 5);
+ GTK_WIDGET_SET_FLAGS (qif_filename_entry, GTK_CAN_DEFAULT);
+
+ hbox8 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox8);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "hbox8", hbox8,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox8);
+ gtk_box_pack_start (GTK_BOX (vbox1), hbox8, TRUE, TRUE, 0);
+
+ label679 = gtk_label_new (_("QIF Account"));
+ gtk_widget_ref (label679);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label679", label679,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label679);
+ gtk_box_pack_start (GTK_BOX (hbox8), label679, FALSE, FALSE, 10);
+ gtk_widget_set_usize (label679, 70, -2);
+ gtk_misc_set_alignment (GTK_MISC (label679), 1, 0.5);
+
+ qif_account_auto_check = gtk_check_button_new_with_label (_("Auto"));
+ gtk_widget_ref (qif_account_auto_check);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "qif_account_auto_check", qif_account_auto_check,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (qif_account_auto_check);
+ gtk_box_pack_start (GTK_BOX (hbox8), qif_account_auto_check, FALSE, FALSE, 2);
+ gtk_widget_set_usize (qif_account_auto_check, 45, 16);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (qif_account_auto_check), TRUE);
+
+ qif_account_entry = gtk_entry_new ();
+ gtk_widget_ref (qif_account_entry);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "qif_account_entry", qif_account_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (qif_account_entry);
+ gtk_box_pack_start (GTK_BOX (hbox8), qif_account_entry, TRUE, TRUE, 5);
+
+ hbox2 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox2);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "hbox2", hbox2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox2);
+ gtk_box_pack_start (GTK_BOX (vbox1), hbox2, FALSE, FALSE, 0);
+
+ currency_label = gtk_label_new (_("Currency"));
+ gtk_widget_ref (currency_label);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "currency_label", currency_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (currency_label);
+ gtk_box_pack_start (GTK_BOX (hbox2), currency_label, FALSE, FALSE, 10);
+ gtk_widget_set_usize (currency_label, 70, -2);
+ gtk_label_set_justify (GTK_LABEL (currency_label), GTK_JUSTIFY_LEFT);
+ gtk_misc_set_alignment (GTK_MISC (currency_label), 1, 0.5);
+
+ qif_currency_entry = gtk_entry_new ();
+ gtk_widget_ref (qif_currency_entry);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "qif_currency_entry", qif_currency_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (qif_currency_entry);
+ gtk_box_pack_start (GTK_BOX (hbox2), qif_currency_entry, FALSE, FALSE, 5);
+ gtk_widget_set_usize (qif_currency_entry, 75, -2);
+
+ hbox3 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox3);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "hbox3", hbox3,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox3);
+ gtk_box_pack_start (GTK_BOX (vbox1), hbox3, FALSE, FALSE, 0);
+
+ radix_format_label = gtk_label_new (_("Radix format"));
+ gtk_widget_ref (radix_format_label);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "radix_format_label", radix_format_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (radix_format_label);
+ gtk_box_pack_start (GTK_BOX (hbox3), radix_format_label, FALSE, FALSE, 10);
+ gtk_widget_set_usize (radix_format_label, 70, -2);
+ gtk_label_set_justify (GTK_LABEL (radix_format_label), GTK_JUSTIFY_RIGHT);
+ gtk_misc_set_alignment (GTK_MISC (radix_format_label), 1, 0.5);
+
+ qif_radix_picker = gtk_option_menu_new ();
+ gtk_widget_ref (qif_radix_picker);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "qif_radix_picker", qif_radix_picker,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (qif_radix_picker);
+ gtk_box_pack_start (GTK_BOX (hbox3), qif_radix_picker, FALSE, FALSE, 5);
+ gtk_widget_set_usize (qif_radix_picker, 140, -2);
+ qif_radix_picker_menu = gtk_menu_new ();
+ glade_menuitem = gtk_menu_item_new_with_label (_("Autodetect"));
+ gtk_widget_show (glade_menuitem);
+ gtk_menu_append (GTK_MENU (qif_radix_picker_menu), glade_menuitem);
+ glade_menuitem = gtk_menu_item_new_with_label (_("Decimal (1,000.00)"));
+ gtk_widget_show (glade_menuitem);
+ gtk_menu_append (GTK_MENU (qif_radix_picker_menu), glade_menuitem);
+ glade_menuitem = gtk_menu_item_new_with_label (_("Comma (1.000,00)"));
+ gtk_widget_show (glade_menuitem);
+ gtk_menu_append (GTK_MENU (qif_radix_picker_menu), glade_menuitem);
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (qif_radix_picker), qif_radix_picker_menu);
+
+ hbox4 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox4);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "hbox4", hbox4,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox4);
+ gtk_box_pack_start (GTK_BOX (vbox1), hbox4, FALSE, FALSE, 0);
+
+ date_format_label = gtk_label_new (_("Date format"));
+ gtk_widget_ref (date_format_label);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "date_format_label", date_format_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (date_format_label);
+ gtk_box_pack_start (GTK_BOX (hbox4), date_format_label, FALSE, FALSE, 10);
+ gtk_widget_set_usize (date_format_label, 70, -2);
+ gtk_misc_set_alignment (GTK_MISC (date_format_label), 1, 0.5);
+
+ qif_date_picker = gtk_option_menu_new ();
+ gtk_widget_ref (qif_date_picker);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "qif_date_picker", qif_date_picker,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (qif_date_picker);
+ gtk_box_pack_start (GTK_BOX (hbox4), qif_date_picker, FALSE, FALSE, 5);
+ gtk_widget_set_usize (qif_date_picker, 140, -2);
+ qif_date_picker_menu = gtk_menu_new ();
+ glade_menuitem = gtk_menu_item_new_with_label (_("Autodetect "));
+ gtk_widget_show (glade_menuitem);
+ gtk_menu_append (GTK_MENU (qif_date_picker_menu), glade_menuitem);
+ glade_menuitem = gtk_menu_item_new_with_label (_("MM/DD/YYYY"));
+ gtk_widget_show (glade_menuitem);
+ gtk_menu_append (GTK_MENU (qif_date_picker_menu), glade_menuitem);
+ glade_menuitem = gtk_menu_item_new_with_label (_("DD/MM/YYYY"));
+ gtk_widget_show (glade_menuitem);
+ gtk_menu_append (GTK_MENU (qif_date_picker_menu), glade_menuitem);
+ glade_menuitem = gtk_menu_item_new_with_label (_("YYYY/MM/DD"));
+ gtk_widget_show (glade_menuitem);
+ gtk_menu_append (GTK_MENU (qif_date_picker_menu), glade_menuitem);
+ glade_menuitem = gtk_menu_item_new_with_label (_("YYYY/DD/MM"));
+ gtk_widget_show (glade_menuitem);
+ gtk_menu_append (GTK_MENU (qif_date_picker_menu), glade_menuitem);
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (qif_date_picker), qif_date_picker_menu);
+
+ hbox6 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox6);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "hbox6", hbox6,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbox6);
+ gtk_box_pack_start (GTK_BOX (vbox1), hbox6, TRUE, TRUE, 5);
+
+ file_select_btn = gtk_button_new_with_label (_("Select file"));
+ gtk_widget_ref (file_select_btn);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "file_select_btn", file_select_btn,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (file_select_btn);
+ gtk_box_pack_start (GTK_BOX (hbox6), file_select_btn, TRUE, FALSE, 3);
+ gtk_widget_set_usize (file_select_btn, 125, -2);
+
+ add_file_button = gtk_button_new_with_label (_("Load file"));
+ gtk_widget_ref (add_file_button);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "add_file_button", add_file_button,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (add_file_button);
+ gtk_box_pack_start (GTK_BOX (hbox6), add_file_button, TRUE, FALSE, 0);
+ gtk_widget_set_usize (add_file_button, 125, -2);
+
+ label69 = gtk_label_new (_("Files"));
+ gtk_widget_ref (label69);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label69", label69,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label69);
+ gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), label69);
+
+ scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_ref (scrolledwindow2);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "scrolledwindow2", scrolledwindow2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (scrolledwindow2);
+ gtk_container_add (GTK_CONTAINER (notebook1), scrolledwindow2);
+
+ account_page_list = gtk_clist_new (4);
+ gtk_widget_ref (account_page_list);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "account_page_list", account_page_list,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (account_page_list);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow2), account_page_list);
+ gtk_clist_set_column_width (GTK_CLIST (account_page_list), 0, 116);
+ gtk_clist_set_column_width (GTK_CLIST (account_page_list), 1, 80);
+ gtk_clist_set_column_width (GTK_CLIST (account_page_list), 2, 204);
+ gtk_clist_set_column_width (GTK_CLIST (account_page_list), 3, 80);
+ gtk_clist_column_titles_show (GTK_CLIST (account_page_list));
+
+ label682 = gtk_label_new (_("QIF Account"));
+ gtk_widget_ref (label682);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label682", label682,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label682);
+ gtk_clist_set_column_widget (GTK_CLIST (account_page_list), 0, label682);
+
+ label683 = gtk_label_new (_("Transactions"));
+ gtk_widget_ref (label683);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label683", label683,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label683);
+ gtk_clist_set_column_widget (GTK_CLIST (account_page_list), 1, label683);
+
+ label684 = gtk_label_new (_("GNUCash Account Name"));
+ gtk_widget_ref (label684);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label684", label684,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label684);
+ gtk_clist_set_column_widget (GTK_CLIST (account_page_list), 2, label684);
+
+ label685 = gtk_label_new (_("Type"));
+ gtk_widget_ref (label685);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label685", label685,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label685);
+ gtk_clist_set_column_widget (GTK_CLIST (account_page_list), 3, label685);
+
+ label2 = gtk_label_new (_("Accounts"));
+ gtk_widget_ref (label2);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label2", label2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label2);
+ gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 1), label2);
+
+ scrolledwindow3 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_ref (scrolledwindow3);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "scrolledwindow3", scrolledwindow3,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (scrolledwindow3);
+ gtk_container_add (GTK_CONTAINER (notebook1), scrolledwindow3);
+
+ category_page_list = gtk_clist_new (4);
+ gtk_widget_ref (category_page_list);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "category_page_list", category_page_list,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (category_page_list);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow3), category_page_list);
+ gtk_clist_set_column_width (GTK_CLIST (category_page_list), 0, 117);
+ gtk_clist_set_column_width (GTK_CLIST (category_page_list), 1, 80);
+ gtk_clist_set_column_width (GTK_CLIST (category_page_list), 2, 204);
+ gtk_clist_set_column_width (GTK_CLIST (category_page_list), 3, 80);
+ gtk_clist_column_titles_show (GTK_CLIST (category_page_list));
+
+ label686 = gtk_label_new (_("QIF Category"));
+ gtk_widget_ref (label686);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label686", label686,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label686);
+ gtk_clist_set_column_widget (GTK_CLIST (category_page_list), 0, label686);
+
+ label687 = gtk_label_new (_("Transactions"));
+ gtk_widget_ref (label687);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label687", label687,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label687);
+ gtk_clist_set_column_widget (GTK_CLIST (category_page_list), 1, label687);
+
+ label688 = gtk_label_new (_("GNUCash Account Name"));
+ gtk_widget_ref (label688);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label688", label688,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label688);
+ gtk_clist_set_column_widget (GTK_CLIST (category_page_list), 2, label688);
+
+ label689 = gtk_label_new (_("Type"));
+ gtk_widget_ref (label689);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "label689", label689,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label689);
+ gtk_clist_set_column_widget (GTK_CLIST (category_page_list), 3, label689);
+
+ foo6868 = gtk_label_new (_("Categories"));
+ gtk_widget_ref (foo6868);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "foo6868", foo6868,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (foo6868);
+ gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 2), foo6868);
+
+ dialog_action_area2 = GNOME_DIALOG (QIF_File_Import_Dialog)->action_area;
+ gtk_object_set_data (GTK_OBJECT (QIF_File_Import_Dialog), "dialog_action_area2", dialog_action_area2);
+ gtk_widget_show (dialog_action_area2);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area2), GTK_BUTTONBOX_SPREAD);
+ gtk_button_box_set_spacing (GTK_BUTTON_BOX (dialog_action_area2), 8);
+
+ gnome_dialog_append_button (GNOME_DIALOG (QIF_File_Import_Dialog), GNOME_STOCK_BUTTON_OK);
+ button2 = g_list_last (GNOME_DIALOG (QIF_File_Import_Dialog)->buttons)->data;
+ gtk_widget_ref (button2);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "button2", button2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (button2);
+ GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT);
+
+ gnome_dialog_append_button (GNOME_DIALOG (QIF_File_Import_Dialog), GNOME_STOCK_BUTTON_CANCEL);
+ button3 = g_list_last (GNOME_DIALOG (QIF_File_Import_Dialog)->buttons)->data;
+ gtk_widget_ref (button3);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "button3", button3,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (button3);
+ GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT);
+
+ gnome_dialog_append_button (GNOME_DIALOG (QIF_File_Import_Dialog), GNOME_STOCK_BUTTON_HELP);
+ button4 = g_list_last (GNOME_DIALOG (QIF_File_Import_Dialog)->buttons)->data;
+ gtk_widget_ref (button4);
+ gtk_object_set_data_full (GTK_OBJECT (QIF_File_Import_Dialog), "button4", button4,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (button4);
+ GTK_WIDGET_SET_FLAGS (button4, GTK_CAN_DEFAULT);
+
+ gtk_signal_connect (GTK_OBJECT (selected_file_list), "select_child",
+ GTK_SIGNAL_FUNC (gnc_ui_qif_import_select_loaded_file_cb),
+ QIF_File_Import_Dialog);
+ gtk_signal_connect (GTK_OBJECT (file_select_btn), "clicked",
+ GTK_SIGNAL_FUNC (gnc_ui_qif_import_select_file_cb),
+ QIF_File_Import_Dialog);
+ gtk_signal_connect (GTK_OBJECT (add_file_button), "clicked",
+ GTK_SIGNAL_FUNC (gnc_ui_qif_import_load_file_cb),
+ QIF_File_Import_Dialog);
+ gtk_signal_connect (GTK_OBJECT (account_page_list), "select_row",
+ GTK_SIGNAL_FUNC (gnc_ui_qif_import_account_line_select_cb),
+ NULL);
+ gtk_signal_connect (GTK_OBJECT (category_page_list), "select_row",
+ GTK_SIGNAL_FUNC (gnc_ui_qif_import_category_line_select_cb),
+ NULL);
+ gtk_signal_connect (GTK_OBJECT (button2), "clicked",
+ GTK_SIGNAL_FUNC (gnc_ui_qif_import_ok_cb),
+ QIF_File_Import_Dialog);
+ gtk_signal_connect (GTK_OBJECT (button3), "clicked",
+ GTK_SIGNAL_FUNC (gnc_ui_qif_import_cancel_cb),
+ QIF_File_Import_Dialog);
+ gtk_signal_connect (GTK_OBJECT (button4), "clicked",
+ GTK_SIGNAL_FUNC (gnc_ui_qif_import_help_cb),
+ QIF_File_Import_Dialog);
+
+ gtk_widget_grab_default (qif_filename_entry);
+ return QIF_File_Import_Dialog;
+}
+
diff --git a/src/gnome/glade-qif-import.h b/src/gnome/glade-qif-import.h
new file mode 100644
index 0000000000..2812a8fc79
--- /dev/null
+++ b/src/gnome/glade-qif-import.h
@@ -0,0 +1,5 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+GtkWidget* create_QIF_File_Import_Dialog (void);
diff --git a/src/gnome/glade-support-account-picker.c b/src/gnome/glade-support-account-picker.c
new file mode 100644
index 0000000000..212e81a271
--- /dev/null
+++ b/src/gnome/glade-support-account-picker.c
@@ -0,0 +1,143 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "glade-support-account-picker.h"
+
+/* This is an internally used function to create pixmaps. */
+static GtkWidget* create_dummy_pixmap (GtkWidget *widget,
+ gboolean gnome_pixmap);
+
+GtkWidget*
+lookup_widget (GtkWidget *widget,
+ const gchar *widget_name)
+{
+ GtkWidget *parent, *found_widget;
+
+ for (;;)
+ {
+ if (GTK_IS_MENU (widget))
+ parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
+ else
+ parent = widget->parent;
+ if (parent == NULL)
+ break;
+ widget = parent;
+ }
+
+ found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget),
+ widget_name);
+ if (!found_widget)
+ g_warning ("Widget not found: %s", widget_name);
+ return found_widget;
+}
+
+/* This is a dummy pixmap we use when a pixmap can't be found. */
+static char *dummy_pixmap_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"1 1 1 1",
+" c None",
+/* pixels */
+" ",
+" "
+};
+
+/* This is an internally used function to create pixmaps. */
+static GtkWidget*
+create_dummy_pixmap (GtkWidget *widget,
+ gboolean gnome_pixmap)
+{
+ GdkColormap *colormap;
+ GdkPixmap *gdkpixmap;
+ GdkBitmap *mask;
+ GtkWidget *pixmap;
+
+ if (gnome_pixmap)
+ {
+ return gnome_pixmap_new_from_xpm_d (dummy_pixmap_xpm);
+ }
+
+ colormap = gtk_widget_get_colormap (widget);
+ gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask,
+ NULL, dummy_pixmap_xpm);
+ if (gdkpixmap == NULL)
+ g_error ("Couldn't create replacement pixmap.");
+ pixmap = gtk_pixmap_new (gdkpixmap, mask);
+ gdk_pixmap_unref (gdkpixmap);
+ gdk_bitmap_unref (mask);
+ return pixmap;
+}
+
+/* This is an internally used function to create pixmaps. */
+GtkWidget*
+create_pixmap (GtkWidget *widget,
+ const gchar *filename,
+ gboolean gnome_pixmap)
+{
+ GtkWidget *pixmap;
+ GdkColormap *colormap;
+ GdkPixmap *gdkpixmap;
+ GdkBitmap *mask;
+ gchar *pathname;
+
+ pathname = gnome_pixmap_file (filename);
+ if (!pathname)
+ {
+ g_warning (_("Couldn't find pixmap file: %s"), filename);
+ return create_dummy_pixmap (widget, gnome_pixmap);
+ }
+
+ if (gnome_pixmap)
+ {
+ pixmap = gnome_pixmap_new_from_file (pathname);
+ g_free (pathname);
+ return pixmap;
+ }
+
+ colormap = gtk_widget_get_colormap (widget);
+ gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask,
+ NULL, pathname);
+ if (gdkpixmap == NULL)
+ {
+ g_warning (_("Couldn't create pixmap from file: %s"), pathname);
+ g_free (pathname);
+ return create_dummy_pixmap (widget, gnome_pixmap);
+ }
+ g_free (pathname);
+
+ pixmap = gtk_pixmap_new (gdkpixmap, mask);
+ gdk_pixmap_unref (gdkpixmap);
+ gdk_bitmap_unref (mask);
+ return pixmap;
+}
+
+/* This is an internally used function to create imlib images. */
+GdkImlibImage*
+create_image (const gchar *filename)
+{
+ GdkImlibImage *image;
+ gchar *pathname;
+
+ pathname = gnome_pixmap_file (filename);
+ if (!pathname)
+ {
+ g_warning (_("Couldn't find pixmap file: %s"), filename);
+ return NULL;
+ }
+
+ image = gdk_imlib_load_image (pathname);
+ g_free (pathname);
+ return image;
+}
+
diff --git a/src/gnome/glade-support-account-picker.h b/src/gnome/glade-support-account-picker.h
new file mode 100644
index 0000000000..d9bb0728a7
--- /dev/null
+++ b/src/gnome/glade-support-account-picker.h
@@ -0,0 +1,34 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#include
+
+/*
+ * Public Functions.
+ */
+
+/*
+ * This function returns a widget in a component created by Glade.
+ * Call it with the toplevel widget in the component (i.e. a window/dialog),
+ * or alternatively any widget in the component, and the name of the widget
+ * you want returned.
+ */
+GtkWidget* lookup_widget (GtkWidget *widget,
+ const gchar *widget_name);
+
+/* get_widget() is deprecated. Use lookup_widget instead. */
+#define get_widget lookup_widget
+
+
+/*
+ * Private Functions.
+ */
+
+/* This is used to create the pixmaps in the interface. */
+GtkWidget* create_pixmap (GtkWidget *widget,
+ const gchar *filename,
+ gboolean gnome_pixmap);
+
+GdkImlibImage* create_image (const gchar *filename);
+
diff --git a/src/gnome/glade-support-qif-import.c b/src/gnome/glade-support-qif-import.c
new file mode 100644
index 0000000000..5b21b4598b
--- /dev/null
+++ b/src/gnome/glade-support-qif-import.c
@@ -0,0 +1,143 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "glade-support-qif-import.h"
+
+/* This is an internally used function to create pixmaps. */
+static GtkWidget* create_dummy_pixmap (GtkWidget *widget,
+ gboolean gnome_pixmap);
+
+GtkWidget*
+lookup_widget (GtkWidget *widget,
+ const gchar *widget_name)
+{
+ GtkWidget *parent, *found_widget;
+
+ for (;;)
+ {
+ if (GTK_IS_MENU (widget))
+ parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
+ else
+ parent = widget->parent;
+ if (parent == NULL)
+ break;
+ widget = parent;
+ }
+
+ found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget),
+ widget_name);
+ if (!found_widget)
+ g_warning ("Widget not found: %s", widget_name);
+ return found_widget;
+}
+
+/* This is a dummy pixmap we use when a pixmap can't be found. */
+static char *dummy_pixmap_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"1 1 1 1",
+" c None",
+/* pixels */
+" ",
+" "
+};
+
+/* This is an internally used function to create pixmaps. */
+static GtkWidget*
+create_dummy_pixmap (GtkWidget *widget,
+ gboolean gnome_pixmap)
+{
+ GdkColormap *colormap;
+ GdkPixmap *gdkpixmap;
+ GdkBitmap *mask;
+ GtkWidget *pixmap;
+
+ if (gnome_pixmap)
+ {
+ return gnome_pixmap_new_from_xpm_d (dummy_pixmap_xpm);
+ }
+
+ colormap = gtk_widget_get_colormap (widget);
+ gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask,
+ NULL, dummy_pixmap_xpm);
+ if (gdkpixmap == NULL)
+ g_error ("Couldn't create replacement pixmap.");
+ pixmap = gtk_pixmap_new (gdkpixmap, mask);
+ gdk_pixmap_unref (gdkpixmap);
+ gdk_bitmap_unref (mask);
+ return pixmap;
+}
+
+/* This is an internally used function to create pixmaps. */
+GtkWidget*
+create_pixmap (GtkWidget *widget,
+ const gchar *filename,
+ gboolean gnome_pixmap)
+{
+ GtkWidget *pixmap;
+ GdkColormap *colormap;
+ GdkPixmap *gdkpixmap;
+ GdkBitmap *mask;
+ gchar *pathname;
+
+ pathname = gnome_pixmap_file (filename);
+ if (!pathname)
+ {
+ g_warning (_("Couldn't find pixmap file: %s"), filename);
+ return create_dummy_pixmap (widget, gnome_pixmap);
+ }
+
+ if (gnome_pixmap)
+ {
+ pixmap = gnome_pixmap_new_from_file (pathname);
+ g_free (pathname);
+ return pixmap;
+ }
+
+ colormap = gtk_widget_get_colormap (widget);
+ gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask,
+ NULL, pathname);
+ if (gdkpixmap == NULL)
+ {
+ g_warning (_("Couldn't create pixmap from file: %s"), pathname);
+ g_free (pathname);
+ return create_dummy_pixmap (widget, gnome_pixmap);
+ }
+ g_free (pathname);
+
+ pixmap = gtk_pixmap_new (gdkpixmap, mask);
+ gdk_pixmap_unref (gdkpixmap);
+ gdk_bitmap_unref (mask);
+ return pixmap;
+}
+
+/* This is an internally used function to create imlib images. */
+GdkImlibImage*
+create_image (const gchar *filename)
+{
+ GdkImlibImage *image;
+ gchar *pathname;
+
+ pathname = gnome_pixmap_file (filename);
+ if (!pathname)
+ {
+ g_warning (_("Couldn't find pixmap file: %s"), filename);
+ return NULL;
+ }
+
+ image = gdk_imlib_load_image (pathname);
+ g_free (pathname);
+ return image;
+}
+
diff --git a/src/gnome/glade-support-qif-import.h b/src/gnome/glade-support-qif-import.h
new file mode 100644
index 0000000000..d9bb0728a7
--- /dev/null
+++ b/src/gnome/glade-support-qif-import.h
@@ -0,0 +1,34 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#include
+
+/*
+ * Public Functions.
+ */
+
+/*
+ * This function returns a widget in a component created by Glade.
+ * Call it with the toplevel widget in the component (i.e. a window/dialog),
+ * or alternatively any widget in the component, and the name of the widget
+ * you want returned.
+ */
+GtkWidget* lookup_widget (GtkWidget *widget,
+ const gchar *widget_name);
+
+/* get_widget() is deprecated. Use lookup_widget instead. */
+#define get_widget lookup_widget
+
+
+/*
+ * Private Functions.
+ */
+
+/* This is used to create the pixmaps in the interface. */
+GtkWidget* create_pixmap (GtkWidget *widget,
+ const gchar *filename,
+ gboolean gnome_pixmap);
+
+GdkImlibImage* create_image (const gchar *filename);
+
diff --git a/src/gnome/window-html.h b/src/gnome/window-html.h
index 292213217b..401522aeb7 100644
--- a/src/gnome/window-html.h
+++ b/src/gnome/window-html.h
@@ -1,6 +1,9 @@
/********************************************************************\
* window-html -- an html window for gnucash. *
* Copyright (C) 1997 Robin D. Clark *
+ * Copyright (C) 1998 Linas Vepstas *
+ * Copyright (C) 1999 Jeremy Collins ( gtk-xmhtml port ) *
+ * Copyright (C) 2000 Linas Vepstas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
diff --git a/src/gnome/window-main.c b/src/gnome/window-main.c
index a6e484f011..50244d307a 100644
--- a/src/gnome/window-main.c
+++ b/src/gnome/window-main.c
@@ -45,6 +45,7 @@
#include "account-tree.h"
#include "dialog-transfer.h"
#include "dialog-edit.h"
+#include "dialog-qif-import.h"
#include "Scrub.h"
#include "util.h"
#include "gnc.h"
diff --git a/src/scm/extensions.scm b/src/scm/extensions.scm
index 309e5cef07..a6e272cdc9 100644
--- a/src/scm/extensions.scm
+++ b/src/scm/extensions.scm
@@ -45,15 +45,14 @@
(define (gnc:extensions-menu-setup win)
-
(define menu (gnc:make-menu "Extensions" (list "_Settings")))
-
+
(define export-item
(gnc:make-menu-item "Export data as text (Danger: Unfinished)"
"Export data as text."
(list "Extensions" "")
(lambda () (gnc:main-win-export-data-as-text win))))
-
+
(define qif-item
(gnc:make-menu-item "QIF File Import (Danger: Unfinished)"
"Import QIF File - Scripted in Guile."
@@ -83,6 +82,7 @@
(gnc:hook-add-dangler gnc:*main-window-opened-hook*
gnc:extensions-menu-setup))
+
;; Automatically pick accelerators for menu names
(define (gnc:new-menu-namer)
diff --git a/src/scm/main.scm b/src/scm/main.scm
index 2aa826bfdb..5a82560fc9 100644
--- a/src/scm/main.scm
+++ b/src/scm/main.scm
@@ -17,10 +17,17 @@
(gnc:depend "doc.scm")
(gnc:depend "extensions.scm")
(gnc:depend "text-export.scm")
- (gnc:depend "importqif.scm")
+; (gnc:depend "importqif.scm")
(gnc:depend "report.scm")
(gnc:depend "report/report-list.scm")
+ (gnc:config-var-value-set! gnc:*load-path* #f
+ (cons (string-append gnc:_share-dir-default_
+ "/scm/qif-import")
+ (gnc:config-var-value-get gnc:*load-path*)))
+
+ (gnc:depend "qif-import.scm")
+
;; Load the system configs
(if (not (gnc:load-system-config-if-needed))
(gnc:shutdown 1))
diff --git a/src/scm/qif-import/qif-dialog-utils.scm b/src/scm/qif-import/qif-dialog-utils.scm
new file mode 100644
index 0000000000..98479f194c
--- /dev/null
+++ b/src/scm/qif-import/qif-dialog-utils.scm
@@ -0,0 +1,264 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; qif-dialog-utils.scm
+;;; build qif->gnc account maps and put them in a displayable
+;;; form.
+;;;
+;;; Bill Gribble 20 Feb 2000
+;;; $Id$
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(gnc:support "qif-dialog-utils.scm")
+
+(define (qif-dialog:munge-account-mapping old-map new-info)
+ (let ((new-name (car new-info))
+ (new-type (cadr new-info))
+ (new-descript (caddr new-info)))
+ (list-set! old-map 1 new-name)
+ (list-set! old-map 2 new-type)
+ (cond ((qif-cat? (list-ref old-map 5))
+ (qif-cat:set-description! (list-ref old-map 5) new-descript))
+ ((qif-acct? (list-ref old-map 5))
+ (qif-acct:set-description! (list-ref old-map 5) new-descript))
+ (#t
+ (list-set! old-map 5 new-descript)))))
+
+
+;; 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
+;; xtns with that account name, and column 3 is the guess for the
+;; translation. Sorted on # transactions, then alpha.
+
+(define (qif-dialog:make-account-display qif-files gnc-acct-info)
+ (let ((acct-hash (make-hash-table 20))
+ (retval '()))
+
+ ;; we want to make two passes here. The first pass picks the
+ ;; explicit Account descriptions and implicit "this" description
+ ;; out of each file. These are the best sources of info because
+ ;; we will have types and so on for them. The second pass picks
+ ;; out account-style L fields and investment security names from
+ ;; the transactions. Hopefully we'll have most of the accounts
+ ;; already located by that point. Otherwise, we have to guess
+ ;; them.
+
+ ;; guess-acct returns a list that's
+ ;; (qif-name gnc-name gnc-type new-acct?)
+ ;; acct-hash hashes QIF account name to a list that's composed of
+ ;; (qif-acct-name gnc-acct-name gnc-acct-type gnc-acct-new?
+ ;; num-qif-xtns qif-object) so we can find the properties later.
+ (for-each
+ (lambda (file)
+ ;; first, get the explicit account references.
+ (for-each
+ (lambda (acct)
+ (if (not (hash-ref acct-hash (qif-acct:name acct)))
+ (hash-set!
+ acct-hash (qif-acct:name acct)
+ (append
+ (qif-import:guess-acct (qif-acct:name acct)
+ (list (qif-acct:type acct))
+ gnc-acct-info)
+ (list 0 acct)))))
+ (qif-file:accounts file))
+
+ ;; then make an implicit account entry for the file
+ (if (and (qif-file:account file)
+ (qif-file:account-type file))
+; (not (eq? (qif-file:account-type file) GNC-STOCK-TYPE)))
+ (let ((entry (hash-ref acct-hash (qif-file:account file))))
+ (if entry
+ ;; increment the xtn count in place
+ (list-set! entry 4
+ (+ (list-ref entry 4)
+ (length (qif-file:xtns file))))
+ ;; make a new hash table entry for the account
+ ;; make it a Bank account by default.
+ (hash-set!
+ acct-hash (qif-file:account file)
+ (append (qif-import:guess-acct
+ (qif-file:account file)
+ (list GNC-BANK-TYPE
+ GNC-CCARD-TYPE)
+ gnc-acct-info)
+ (list
+ (length (qif-file:xtns file))
+ #f)))))))
+ qif-files)
+
+ ;; now make the second pass through the files, looking at the
+ ;; transactions. Hopefully the accounts are all there already.
+ ;; stock accounts can have both a category/account and another
+ ;; account ref from the security name.
+ (for-each
+ (lambda (file)
+ (for-each
+ (lambda (xtn)
+ (let ((bank-xtn? (qif-xtn:bank-xtn? xtn))
+ (stock-acct (qif-xtn:security-name xtn))
+ (entry #f))
+ (if (not bank-xtn?)
+ (begin
+ (set! entry (hash-ref acct-hash stock-acct))
+ (if entry
+ (list-set! entry 4
+ (+ 1 (list-ref entry 4)))
+ (hash-set! acct-hash stock-acct
+ (append (qif-import:guess-acct
+ stock-acct
+ (list GNC-STOCK-TYPE
+ GNC-MUTUAL-TYPE)
+ gnc-acct-info)
+ (list 1 xtn)))))))
+
+ ;; iterate over the splits doing the same thing.
+ (for-each
+ (lambda (split)
+ (let ((xtn-is-acct (qif-split:category-is-account? split))
+ (xtn-acct #f)
+ (entry #f))
+ (if xtn-is-acct
+ (begin
+ (set! xtn-acct (qif-split:category split))
+ (set! entry (hash-ref acct-hash xtn-acct))
+ (if entry
+ (list-set! entry 4
+ (+ 1 (list-ref entry 4)))
+ (hash-set! acct-hash xtn-acct
+ (append (qif-import:guess-acct
+ xtn-acct
+ (list
+ GNC-BANK-TYPE
+ GNC-CCARD-TYPE
+ GNC-STOCK-TYPE)
+ gnc-acct-info)
+ (list 1 #f))))))))
+ (qif-xtn:splits xtn)))
+ (qif-file:xtns file)))
+ qif-files)
+
+ ;; now that the hash table is filled, make the display list
+ (for-each
+ (lambda (bin)
+ (for-each
+ (lambda (elt)
+ (if (> (list-ref (cdr elt) 4) 0)
+ (set! retval
+ (cons (cdr elt) retval))))
+ bin))
+ (vector->list acct-hash))
+
+ (list-set! gnc-acct-info 1 acct-hash)
+
+ ;; sort by number of transactions with that account so the
+ ;; most important are at the top
+; (set! retval (sort-list retval
+; (lambda (a b)
+; (or
+; (> (list-ref a 4) (list-ref b 4))
+; (and
+; (eq? (list-ref a 4) (list-ref b 4))
+; (string (car a) (car b)))))))
+ retval))
+
+
+;; the category display is similar to the Account display.
+;; QIF category name, xtn count, then GNUcash account.
+
+(define (qif-dialog:make-category-display qif-files gnc-acct-info)
+ (let ((cat-hash (make-hash-table 20))
+ (retval '()))
+
+ ;; get the Cat entries from each file
+ (for-each
+ (lambda (file)
+ (for-each
+ (lambda (cat)
+ (if (not (hash-ref cat-hash (qif-cat:name cat)))
+ (begin
+ (hash-set! cat-hash
+ (qif-cat:name cat)
+ (append
+ (qif-import:guess-acct
+ (qif-cat:name cat)
+ (if (qif-cat:expense-cat cat)
+ (list GNC-EXPENSE-TYPE)
+ (list GNC-INCOME-TYPE))
+ gnc-acct-info)
+ (list 0 cat))))))
+ (qif-file:cats file)))
+ qif-files)
+
+ ;; now look at every transaction and increment the count
+ ;; in the account slot if the string matches, or make a
+ ;; new hash reference if not.
+ (for-each
+ (lambda (qif-file)
+ (for-each
+ (lambda (xtn)
+ ;; iterate over the splits
+ (for-each
+ (lambda (split)
+ (let ((xtn-is-acct (qif-split:category-is-account? split))
+ (xtn-cat #f)
+ (entry #f))
+ (if (not xtn-is-acct)
+ (begin
+ (set! xtn-cat (qif-split:category split))
+ (set! entry (hash-ref cat-hash xtn-cat))
+ (if entry
+ (list-set! entry 4
+ (+ 1 (list-ref entry 4)))
+ (hash-set! cat-hash xtn-cat
+ (append (qif-import:guess-acct
+ xtn-cat
+ (if (> (qif-split:amount split) 0)
+ (list GNC-INCOME-TYPE)
+ (list GNC-EXPENSE-TYPE))
+ gnc-acct-info)
+ (list 1 #f))))))))
+ (qif-xtn:splits xtn)))
+ (qif-file:xtns qif-file)))
+ qif-files)
+
+ ;; now that the hash table is filled, make the display list
+ (for-each
+ (lambda (bin)
+ (for-each
+ (lambda (elt)
+ (if (> (list-ref (cdr elt) 4) 0)
+ (set! retval (cons (cdr elt) retval))))
+ bin))
+ (vector->list cat-hash))
+
+ (list-set! gnc-acct-info 2 cat-hash)
+
+ ;; sort by number of transactions with that account so the
+ ;; most important are at the top
+; (set! retval (sort-list retval
+; (lambda (a b)
+; (or
+; (> (list-ref a 4) (list-ref b 4))
+; (and
+; (eq? (list-ref a 4) (list-ref b 4))
+; (string (car a) (car b)))))))
+ retval))
+
+
+(define (qif-dialog:qif-file-loaded? filename list-of-files)
+ (let ((status (map
+ (lambda (file)
+ (string=? filename (qif-file:path file)))
+ list-of-files)))
+ (if (memq #t status)
+ #t
+ #f)))
+
+(define (qif-dialog:unload-qif-file filename list-of-files)
+ (delq #f
+ (map
+ (lambda (file)
+ (if (string=? filename (qif-file:path file))
+ #f
+ file))
+ list-of-files)))
diff --git a/src/scm/qif-import/qif-file.scm b/src/scm/qif-import/qif-file.scm
new file mode 100644
index 0000000000..2481e41d73
--- /dev/null
+++ b/src/scm/qif-import/qif-file.scm
@@ -0,0 +1,434 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; qif-file.scm
+;;; read a QIF file into a object
+;;;
+;;; Bill Gribble 20 Feb 2000
+;;; $Id$
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(gnc:depend "qif-objects.scm")
+(gnc:depend "qif-parse.scm")
+(gnc:depend "qif-utils.scm")
+
+(gnc:support "qif-file.scm")
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-file:read-file self path
+;; suck in all the transactions; if necessary, determine [guess]
+;; radix format first.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-file:read-file self path)
+ (qif-file:set-path! self path)
+ (let ((qstate-type #f)
+ (current-xtn #f)
+ (current-split #f)
+ (default-split #f)
+ (first-xtn #f)
+ (line #f)
+ (tag #f)
+ (value #f)
+ (heinous-error #f))
+ (with-input-from-file path
+ (lambda ()
+ ;; loop over lines
+ (let line-loop ()
+ (set! line (read-line))
+ (if (and
+ (not (eof-object? line))
+ (>= (string-length line) 1))
+ (begin
+ ;; pick the 1-char tag off from the remainder of the line
+ (set! tag (string-ref line 0))
+ (set! value (substring line 1 (string-length line)))
+
+ ;; now do something with the line
+ (cond
+ ;; the type switcher.
+ ((eq? tag #\!)
+ (set! qstate-type (qif-file:parse-bang-field self value))
+ (cond ((or (eq? qstate-type 'type:bank)
+ (eq? qstate-type 'type:cash)
+ (eq? qstate-type 'type:ccard)
+ (eq? qstate-type 'type:invst)
+ (eq? qstate-type '#{type:oth\ a}#)
+ (eq? qstate-type '#{type:oth\ l}#))
+
+ (set! current-xtn (make-qif-xtn))
+ (set! default-split (make-qif-split))
+ (qif-split:set-category! default-split "")
+ (qif-file:set-account-type!
+ self (qif-file:state-to-account-type
+ self qstate-type))
+ (set! first-xtn #t))
+ ((eq? qstate-type 'type:class)
+ (set! current-xtn (make-qif-class)))
+ ((eq? qstate-type 'type:cat)
+ (set! current-xtn (make-qif-cat)))
+ ((eq? qstate-type 'account)
+ (set! current-xtn (make-qif-acct)))
+ (#t
+ (display "qif-file:read-file can't handle ")
+ (write qstate-type)
+ (display " transactions yet.")
+ (newline))))
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;; account transactions
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ ((or (eq? qstate-type 'type:bank)
+ (eq? qstate-type 'type:cash)
+ (eq? qstate-type 'type:ccard)
+ (eq? qstate-type 'type:invst)
+ (eq? qstate-type '#{type:oth\ a}#)
+ (eq? qstate-type '#{type:oth\ l}#))
+ (cond
+ ;; D : transaction date
+ ((eq? tag #\D)
+ (qif-xtn:set-date! current-xtn
+ (qif-file:parse-date self value)))
+
+ ;; T : total amount
+ ((eq? tag #\T)
+ (qif-split:set-amount! default-split
+ (qif-file:parse-value self value)))
+
+ ;; P : payee
+ ((eq? tag #\P)
+ (qif-xtn:set-payee! current-xtn
+ (qif-file:parse-string self value)))
+
+ ;; A : address
+ ;; multiple "A" lines are appended together with
+ ;; newlines; some Quicken files have a lot of
+ ;; A lines.
+ ((eq? tag #\A)
+ (qif-xtn:set-address!
+ current-xtn
+ (let ((current (qif-xtn:address current-xtn)))
+ (if (not (string? current))
+ (set! current ""))
+ (string-append
+ current "\n"
+ (qif-file:parse-string self value)))))
+
+ ;; N : check number / transaction number /xtn direction
+ ;; this could be a number or a string; no point in
+ ;; keeping it numeric just yet.
+ ((eq? tag #\N)
+ (qif-xtn:set-number!
+ current-xtn (qif-file:parse-string self value)))
+
+ ;; C : cleared flag
+ ((eq? tag #\C)
+ (qif-xtn:set-cleared!
+ current-xtn (qif-file:parse-cleared-field self value)))
+
+ ;; M : memo
+ ((eq? tag #\M)
+ (qif-split:set-memo! default-split
+ (qif-file:parse-string self value)))
+
+ ;; I : share price (stock transactions)
+ ((eq? tag #\I)
+ (qif-xtn:set-share-price!
+ current-xtn (qif-file:parse-value self value)))
+
+ ;; Q : share price (stock transactions)
+ ((eq? tag #\Q)
+ (qif-xtn:set-num-shares!
+ current-xtn (qif-file:parse-value self value))
+ (qif-xtn:set-bank-xtn?! current-xtn #f))
+
+ ;; Y : name of security (stock transactions)
+ ((eq? tag #\Y)
+ (qif-xtn:set-security-name!
+ current-xtn (qif-file:parse-string self value)))
+
+ ;; O : adjustment (stock transactions)
+ ((eq? tag #\O)
+ (qif-xtn:set-adjustment!
+ current-xtn (qif-file:parse-value self value)))
+
+ ;; L : category
+ ((eq? tag #\L)
+ (qif-split:set-category!
+ default-split (qif-file:parse-string self value)))
+
+ ;; S : split category
+ ((eq? tag #\S)
+ (set! current-split (make-qif-split))
+ (qif-split:set-category!
+ current-split (qif-file:parse-string self value))
+ (qif-xtn:set-splits!
+ current-xtn
+ (cons current-split (qif-xtn:splits current-xtn))))
+
+ ;; E : split memo (?)
+ ((eq? tag #\E)
+ (qif-split:set-memo!
+ current-split (qif-file:parse-string self value)))
+
+ ;; $ : split amount (if there are splits)
+ ((eq? tag #\$)
+ ;; if this is 'Type:Invst, I can't figure out
+ ;; what the $ signifies. I'll do it later.
+ (if (eq? qstate-type 'type:bank)
+ (qif-split:set-amount!
+ current-split (qif-file:parse-value self value))))
+
+ ;; ^ : end-of-record
+ ((eq? tag #\^)
+ (if (and (qif-xtn:date current-xtn)
+ (qif-split:amount default-split))
+ (begin
+ (if (null? (qif-xtn:splits current-xtn))
+ (qif-xtn:set-splits! current-xtn
+ (list default-split)))
+ (qif-file:add-xtn! self current-xtn))
+ (begin
+ (display "qif-file:read-file : discarding xtn")
+ (newline)
+ (qif-xtn:print current-xtn)))
+
+ (if (and first-xtn
+ (string? (qif-xtn:payee current-xtn))
+ (string=? (qif-xtn:payee current-xtn)
+ "Opening Balance")
+ (eq? (length (qif-xtn:splits current-xtn)) 1)
+ (qif-split:category-is-account?
+ (car (qif-xtn:splits current-xtn))))
+ (begin
+ (qif-file:set-account!
+ self (qif-split:category
+ (car (qif-xtn:splits current-xtn))))
+ (qif-split:set-category!
+ (car (qif-xtn:splits current-xtn))
+ "Opening Balance")))
+
+ ;; some special love for stock transactions
+ (if (and (qif-xtn:security-name current-xtn)
+ (string? (qif-xtn:number current-xtn)))
+ (begin
+ (cond
+ ((and
+ (or (string=? (qif-xtn:number current-xtn)
+ "ReinvDiv")
+ (string=? (qif-xtn:number current-xtn)
+ "ReinvLg")
+ (string=? (qif-xtn:number current-xtn)
+ "ReinvSh")
+ (string=? (qif-xtn:number current-xtn)
+ "Div"))
+ (string=?
+ "" (qif-split:category
+ (car
+ (qif-xtn:splits current-xtn)))))
+ (qif-split:set-category!
+ (car (qif-xtn:splits current-xtn))
+ "Dividend")
+ ;; KLUDGE! for brokerage accounts
+ ;; where Dividend pays into the
+ ;; brokerage account.
+ (if (and (qif-xtn:bank-xtn? current-xtn)
+ (string?
+ (qif-xtn:security-name
+ current-xtn)))
+ (qif-xtn:set-payee!
+ current-xtn (qif-xtn:security-name
+ current-xtn))))
+
+ ((or (string=? (qif-xtn:number current-xtn)
+ "SellX")
+ (string=? (qif-xtn:number current-xtn)
+ "Sell"))
+ (qif-xtn:set-num-shares!
+ current-xtn
+ (string-append
+ "-" (qif-xtn:num-shares current-xtn)))))))
+
+ (set! first-xtn #f)
+ (set! current-xtn (make-qif-xtn))
+ (set! default-split (make-qif-split)))
+
+ (#t
+ (display "qif-file:read-file : unknown Bank slot ")
+ (display tag) (newline))))
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;; Class transactions
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ((eq? qstate-type 'type:class)
+ (cond
+ ;; N : name
+ ((eq? tag #\N)
+ (qif-class:set-name! current-xtn
+ (qif-file:parse-string self value)))
+
+ ;; D : description
+ ((eq? tag #\D)
+ (qif-class:set-description!
+ current-xtn (qif-file:parse-string self value)))
+
+ ;; end-of-record
+ ((eq? tag #\^)
+ (qif-file:add-class! self current-xtn)
+; (qif-class:print current-xtn)
+ (set! current-xtn (make-qif-class)))
+
+ (#t
+ (display "qif-file:read-file : unknown Class slot ")
+ (display tag) (newline))))
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;; Account definitions
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ((eq? qstate-type 'account)
+ (cond
+ ((eq? tag #\N)
+ (qif-acct:set-name! current-xtn
+ (qif-file:parse-string self value)))
+ ((eq? tag #\D)
+ (qif-acct:set-description!
+ current-xtn (qif-file:parse-string self value)))
+
+ ((eq? tag #\T)
+ (qif-acct:set-type!
+ current-xtn (qif-file:parse-acct-type self value)))
+
+ ((eq? tag #\L)
+ (qif-acct:set-limit!
+ current-xtn (qif-file:parse-value self value)))
+
+ ((eq? tag #\^)
+ (qif-file:add-account! self current-xtn)
+; (qif-acct:print current-xtn)
+ (set! current-xtn (make-qif-acct)))
+
+ (#t
+ (display "qif-file:read-file : unknown Account slot ")
+ (display tag) (newline))))
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;; Category (Cat) transactions
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ ((eq? qstate-type 'type:cat)
+ (cond
+ ;; N : category name
+ ((eq? tag #\N)
+ (qif-cat:set-name! current-xtn
+ (qif-file:parse-string self value)))
+
+ ;; D : category description
+ ((eq? tag #\D)
+ (qif-cat:set-description! current-xtn
+ (qif-file:parse-string
+ self value)))
+
+ ;; E : is this a taxable category?
+ ((eq? tag #\T)
+ (qif-cat:set-taxable! current-xtn #t))
+
+ ;; E : is this an expense category?
+ ((eq? tag #\E)
+ (qif-cat:set-expense-cat! current-xtn #t))
+
+ ;; I : is this an income category?
+ ((eq? tag #\I)
+ (qif-cat:set-income-cat! current-xtn #t))
+
+ ;; R : what is the tax rate (from some table?
+ ;; seems to be an integer)
+ ((eq? tag #\R)
+ (qif-cat:set-tax-rate!
+ current-xtn (qif-file:parse-value self value)))
+
+ ;; B : budget amount. not really supported.
+ ((eq? tag #\B)
+ (qif-cat:set-budget-amt!
+ current-xtn (qif-file:parse-value self value)))
+
+ ;; end-of-record
+ ((eq? tag #\^)
+ (qif-file:add-cat! self current-xtn)
+; (qif-cat:print current-xtn)
+ (set! current-xtn (make-qif-cat)))
+
+ (#t
+ (display "qif-file:read-file : unknown Cat slot ")
+ (display tag) (newline))))
+
+ ;; trying to sneak on by, eh?
+ (#t
+ (if (not qstate-type)
+ (begin
+ (display "line = ") (display line) (newline)
+ (display "qif-file:read-file : ")
+ (display "file does not appear to be a QIF file.")
+ (newline)
+ (set! heinous-error #t)))))
+
+ ;; this is if we read a normal (non-null, non-eof) line...
+ (if (not heinous-error)
+ (line-loop)))
+
+ ;; and this is if we read a null or eof line
+ (if (and (not heinous-error)
+ (not (eof-object? line)))
+ (line-loop))))))
+
+ (if (not heinous-error)
+ (begin
+ ;; now that the file is read in, figure out if either
+ ;; the date or radix format has made itself clear from the
+ ;; values.
+ (if (and
+ (eq? (qif-file:radix-format self) 'unknown)
+ (not (eq? (qif-file:guessed-radix-format self) 'unknown))
+ (not (eq? (qif-file:guessed-radix-format self) 'inconsistent)))
+ (qif-file:set-radix-format!
+ self
+ (qif-file:guessed-radix-format self)))
+
+ (if (and
+ (eq? (qif-file:date-format self) 'unknown)
+ (not (eq? (qif-file:guessed-date-format self) 'unknown))
+ (not (eq? (qif-file:guessed-date-format self) 'inconsistent)))
+ (qif-file:set-date-format! self
+ (qif-file:guessed-date-format self)))
+
+ ;; if the account hasn't been found from an Opening Balance line,
+ ;; just set it to the filename and force the user to specify it.
+ (if (eq? 'unknown (qif-file:account self))
+ (qif-file:set-account!
+ self (qif-file:path-to-accountname self)))
+
+ ;; reparse values and dates if we figured out the format.
+ (for-each
+ (lambda (xtn)
+ (qif-xtn:reparse xtn self))
+ (qif-file:xtns self))
+
+ (for-each
+ (lambda (cat)
+ (qif-cat:reparse cat self))
+ (qif-file:cats self))
+
+ (for-each
+ (lambda (acct)
+ (qif-acct:reparse acct self))
+ (qif-file:accounts self))
+ #t)
+ (begin
+ (display "There was a heinous error. Failed to read file.")
+ (newline)
+ #f))))
+
+
+
+
+
+
diff --git a/src/scm/qif-import/qif-guess-map.scm b/src/scm/qif-import/qif-guess-map.scm
new file mode 100644
index 0000000000..ebab258e82
--- /dev/null
+++ b/src/scm/qif-import/qif-guess-map.scm
@@ -0,0 +1,281 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; qif-guess-map.scm
+;;; guess (or load from prefs) mappings from QIF cats/accts to gnc
+;;;
+;;; Bill Gribble 20 Feb 2000
+;;; $Id$
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(gnc:support "qif-guess-map.scm")
+
+(define GNC-BANK-TYPE 0)
+(define GNC-CASH-TYPE 1)
+(define GNC-ASSET-TYPE 2)
+(define GNC-LIABILITY-TYPE 4)
+(define GNC-CCARD-TYPE 3)
+(define GNC-STOCK-TYPE 5)
+(define GNC-MUTUAL-TYPE 6)
+(define GNC-INCOME-TYPE 8)
+(define GNC-EXPENSE-TYPE 9)
+(define GNC-EQUITY-TYPE 10)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-import:load-map-prefs
+;; load the saved mappings file, and make a table of all the
+;; accounts with their full names and pointers for later
+;; guessing of a mapping.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-import:load-map-prefs)
+ (define (extract-all-account-info agroup root-name)
+ (if (pointer-token-null? agroup)
+ '()
+ (let ((children (gnc:get-accounts agroup))
+ (children-list '())
+ (names '()))
+ ;; convert an array object to a list
+ ;; seems that equal? works as a predicate on pointer
+ ;; equality.... that bugs me. the test is to weed out
+ ;; all but immediate children.
+ (let loop ((count (pointer-array-length children)))
+ (if (> count 0)
+ (let ((acct (pointer-array-ref children (- count 1))))
+ (if (equal? agroup (gnc:account-get-parent acct))
+ (set! children-list
+ (cons acct
+ children-list)))
+ (loop (- count 1)))))
+
+ ;; now descend the tree of child accounts.
+ (for-each
+ (lambda (child-acct)
+ (let* ((name (gnc:account-get-name child-acct))
+ (fullname
+ (if (string? root-name)
+ (string-append root-name ":" name)
+ name)))
+ (set! names
+ (append (cons (list name fullname child-acct)
+ (extract-all-account-info
+ (gnc:account-get-children child-acct)
+ fullname))
+ names))))
+ children-list)
+ names)))
+
+ ;; we'll be returning a list of 3 elements:
+ ;; - a list of all the known gnucash accounts in
+ ;; (shortname fullname account) format.
+ ;; - a hash of QIF account name to gnucash account info
+ ;; - a hash of QIF category to gnucash account info
+ (let ((pref-filename (build-path (getenv "HOME")
+ ".gnucash" "qif-accounts-map"))
+ (results '()))
+
+ ;; first, read the account map and category map from the
+ ;; user's qif-accounts-map file.
+ (if (access? pref-filename R_OK)
+ (with-input-from-file pref-filename
+ (lambda ()
+ (let ((qif-account-hash #f)
+ (qif-cat-hash #f))
+ (set! qif-account-hash (read))
+ (if (not (vector? qif-account-hash))
+ (set! qif-account-hash (make-hash-table 20)))
+
+ (set! qif-cat-hash (read))
+ (if (not (vector? qif-cat-hash))
+ (set! qif-cat-hash (make-hash-table 20)))
+ (set! results (list qif-account-hash qif-cat-hash)))))
+ (begin
+ (set! results (list (make-hash-table 20)
+ (make-hash-table 20)))))
+
+ ;; now build the list of all known account names
+ (let* ((all-accounts (gnc:get-current-group))
+ (all-account-info (extract-all-account-info all-accounts #f)))
+ (set! results (cons all-account-info results)))
+
+; (display " ** load prefs **")(newline)
+; (write results)(newline)
+ 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,
+;; so your selections get lost if you do Cancel.
+;; we initialize the number of transactions to 0 here so
+;; bogus accounts don't get created if you have funny stuff
+;; in your map.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-import:save-map-prefs prefs)
+ (let ((pref-filename (build-path (getenv "HOME")
+ ".gnucash" "qif-accounts-map"))
+ (acct-map (cadr prefs))
+ (cat-map (caddr prefs)))
+ (for-each
+ (lambda (bin)
+ (for-each
+ (lambda (hashpair)
+ (list-set! (cdr hashpair) 4 0))
+ bin))
+ (vector->list acct-map))
+ (for-each
+ (lambda (bin)
+ (for-each
+ (lambda (hashpair)
+ (list-set! (cdr hashpair) 4 0))
+ bin))
+ (vector->list cat-map))
+
+
+ (with-output-to-file pref-filename
+ (lambda ()
+ (display ";;; qif-accounts-map") (newline)
+ (display ";;; automatically generated by GNUcash. DO NOT EDIT")
+ (newline)
+ (display ";;; map from QIF accounts to GNC accounts") (newline)
+ (write acct-map) (newline)
+ (display ";;; map from QIF categories to GNC accounts") (newline)
+ (write cat-map) (newline)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; here's where we do all the guessing. We really want to find the
+;; match in the hash table, but failing that we guess intelligently
+;; and then (failing that) not so intelligently. called in the
+;; dialog routines to rebuild the category and account map pages.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; guess-acct
+;; find an existing gnc acct of the right type and name, or
+;; specify a type and name for a new one.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-import:guess-acct acct-name allowed-types gnc-map-info)
+ ;; see if there's a saved mapping in the hash table or an
+ ;; existing gnucash account with a name that could reasonably
+ ;; be said to be the same name (i.e. ABC Bank == abc bank)
+ (let* ((mapped-gnc-acct
+ (or
+ ;; best alternative: an entry in the map.
+ (hash-ref (cadr gnc-map-info) acct-name)
+
+ ;; second choice: a "similar" account (close name,
+ ;; same type, etc)
+ (qif-import:find-similar-acct acct-name allowed-types
+ gnc-map-info))))
+
+ (if mapped-gnc-acct
+ ;; ok, we've found an existing account that
+ ;; seems to work OK name-wise.
+ (begin
+; (write mapped-gnc-acct) (newline)
+ (list acct-name
+ (list-ref mapped-gnc-acct 1)
+ (list-ref mapped-gnc-acct 2) #f))
+
+ ;; we haven't found a match, so by default just create a new
+ ;; one. Try to put the new account in a similar place in
+ ;; the hierarchy if there is one.
+ (let ((new-acct-info
+ (qif-import:find-new-acct acct-name allowed-types
+ gnc-map-info)))
+ (list acct-name
+ (car new-acct-info)
+ (cadr new-acct-info) #t)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-import:find-similar-acct
+;; guess a translation from QIF info
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-import:find-similar-acct qif-acct-name allowed-types gnc-map-info)
+ (let* ((same-type-accts '())
+ (matching-name-accts '())
+ (retval #f))
+ (for-each
+ (lambda (gnc-acct)
+ ;; check against allowed-types
+ (let ((acct-matches? #f))
+ (for-each
+ (lambda (type)
+ (if (eq? type (gnc:account-get-type (caddr gnc-acct)))
+ (set! acct-matches? #t)))
+ allowed-types)
+ (if acct-matches?
+ (set! same-type-accts (cons gnc-acct same-type-accts)))))
+ (car gnc-map-info))
+
+ ;; now find one in the same-type-list with a similar name.
+ (for-each
+ (lambda (gnc-acct)
+ (if (qif-import:possibly-matching-name?
+ qif-acct-name gnc-acct)
+ (set! matching-name-accts
+ (cons gnc-acct matching-name-accts))))
+ same-type-accts)
+
+ ;; now we have either nothing, something, or too much :)
+ ;; return the full-name of the first name-matching account
+ (if (not (null? matching-name-accts))
+ (set! retval (list qif-acct-name
+ (cadr (car matching-name-accts))
+ (gnc:account-get-type
+ (caddr (car matching-name-accts)))))
+ #f)
+ retval))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-import:possibly-matching-name? qif-acct gnc-acct
+;; try various normalizations and permutations of the names
+;; to see if they could be the same.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-import:possibly-matching-name? qif-acct-name gnc-acct)
+ (or
+ ;; the QIF acct is the same name as the short name of the
+ ;; gnc acct [ignoring case] (likely)
+ (string=? (string-downcase qif-acct-name)
+ (string-downcase (car gnc-acct)))
+
+ ;; the QIF acct is the same name as the long name of the
+ ;; gnc acct [ignoring case] (not so likely)
+ (string=? (string-downcase qif-acct-name)
+ (string-downcase (cadr gnc-acct)))
+
+ ;; the QIF name is a substring of the gnc full name.
+ ;; this happens if you have the same tree but a different
+ ;; top-level structure. (i.e. expenses:tax vs. QIF tax)
+ (string-match (string-downcase qif-acct-name)
+ (string-downcase (cadr gnc-acct)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-import:find-new-acct
+;; Come up with a logical name for a new account based on
+;; the Quicken name and type of the account
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-import:find-new-acct qif-acct allowed-types gnc-map-info)
+ (cond ((and (string? qif-acct)
+ (string=? qif-acct "Opening Balance"))
+ (let ((existing-equity
+ (qif-import:find-similar-acct "Retained Earnings"
+ (list GNC-EQUITY-TYPE)
+ gnc-map-info)))
+ (if existing-equity
+ (cdr existing-equity)
+ (list "Retained Earnings" GNC-EQUITY-TYPE))))
+ ((and (string? qif-acct)
+ (not (string=? qif-acct "")))
+ (list qif-acct (car allowed-types)))
+ (#t
+ (list "Unspecified" (car allowed-types)))))
diff --git a/src/scm/qif-import/qif-import.scm b/src/scm/qif-import/qif-import.scm
new file mode 100644
index 0000000000..a7bc26ebf6
--- /dev/null
+++ b/src/scm/qif-import/qif-import.scm
@@ -0,0 +1,19 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; qif-import.scm
+;;; virtual loader for QIF import facility
+;;;
+;;; Bill Gribble 20 Feb 2000
+;;; $Id$
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(gnc:depend "simple-obj.scm")
+(gnc:depend "qif-objects.scm") ;; class definitions
+(gnc:depend "qif-parse.scm") ;; string-to-value, date parsing
+(gnc:depend "qif-utils.scm")
+(gnc:depend "qif-file.scm") ;; actual file reading
+(gnc:depend "qif-dialog-utils.scm") ;; build displays for dialog
+(gnc:depend "qif-guess-map.scm") ;; build QIF->gnc acct mappings
+(gnc:depend "qif-to-gnc.scm") ;; conv QIF xtns/acct to GNC xtns/acct
+
+(gnc:support "qif-import.scm")
+
diff --git a/src/scm/qif-import/qif-objects.scm b/src/scm/qif-import/qif-objects.scm
new file mode 100644
index 0000000000..8e3b34b10f
--- /dev/null
+++ b/src/scm/qif-import/qif-objects.scm
@@ -0,0 +1,542 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; qif-objects.scm
+;;; representations for parts of an imported Quicken file.
+;;;
+;;; Bill Gribble 20 Feb 2000
+;;; $Id$
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(gnc:depend "simple-obj.scm")
+
+(gnc:support "qif-objects.scm")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-file class
+;; radix-format : one of 'decimal 'comma or 'unspecified
+;; date-format : one of 'd-m-y, 'm-d-y, 'y-m-d, 'y-d-m, 'unspecified
+;; currency : a string representing the file's currency unit
+;; xtns : list of
+;; accounts : list of
+;; cats : list of
+;; classes : list of
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define
+ (make-simple-class
+ 'qif-file
+ '(path ;; where file was loaded
+ account ;; guessed or specified
+ account-type ;; either GNC-BANK-TYPE or GNC-STOCK-TYPE
+ radix-format
+ guessed-radix-format
+ date-format
+ guessed-date-format
+ y2k-threshold
+ currency ;; this is a string.. no checking
+ xtns ;;
+ accounts
+ cats
+ classes)))
+
+(define (qif-file? self)
+ (eq? (simple-obj-type self) 'qif-file))
+
+(define (qif-file:path self)
+ (simple-obj-getter self 'path))
+
+(define (qif-file:account self)
+ (simple-obj-getter self 'account))
+
+(define (qif-file:set-account! self value)
+ (simple-obj-setter self 'account value))
+
+(define (qif-file:account-type self)
+ (simple-obj-getter self 'account-type))
+
+(define (qif-file:set-account-type! self value)
+ (simple-obj-setter self 'account-type value))
+
+(define (qif-file:set-path! self value)
+ (simple-obj-setter self 'path value))
+
+(define (qif-file:radix-format self)
+ (simple-obj-getter self 'radix-format))
+
+(define (qif-file:set-radix-format! self value)
+ (simple-obj-setter self 'radix-format value))
+
+(define (qif-file:guessed-radix-format self)
+ (simple-obj-getter self 'guessed-radix-format))
+
+(define (qif-file:set-guessed-radix-format! self value)
+ (simple-obj-setter self 'guessed-radix-format value))
+
+(define (qif-file:date-format self)
+ (simple-obj-getter self 'date-format))
+
+(define (qif-file:set-date-format! self value)
+ (simple-obj-setter self 'date-format value))
+
+(define (qif-file:guessed-date-format self)
+ (simple-obj-getter self 'guessed-date-format))
+
+(define (qif-file:set-guessed-date-format! self value)
+ (simple-obj-setter self 'guessed-date-format value))
+
+(define (qif-file:y2k-threshold self)
+ (simple-obj-getter self 'y2k-threshold))
+
+(define (qif-file:set-y2k-threshold! self value)
+ (simple-obj-setter self 'y2k-threshold value))
+
+(define (qif-file:currency self)
+ (simple-obj-getter self 'currency))
+
+(define (qif-file:set-currency! self value)
+ (simple-obj-setter self 'currency value))
+
+(define (qif-file:cats self)
+ (simple-obj-getter self 'cats))
+
+(define (qif-file:set-cats! self value)
+ (simple-obj-setter self 'cats value))
+
+(define (qif-file:classes self)
+ (simple-obj-getter self 'classes))
+
+(define (qif-file:set-classes! self value)
+ (simple-obj-setter self 'classes value))
+
+(define (qif-file:xtns self)
+ (simple-obj-getter self 'xtns))
+
+(define (qif-file:set-xtns! self value)
+ (simple-obj-setter self 'xtns value))
+
+(define (qif-file:accounts self)
+ (simple-obj-getter self 'accounts))
+
+(define (qif-file:set-accounts! self value)
+ (simple-obj-setter self 'accounts value))
+
+(define (make-qif-file account radix-format date-format currency)
+ (let ((self (make-simple-obj )))
+ (qif-file:set-account! self account)
+ (qif-file:set-radix-format! self radix-format)
+ (qif-file:set-guessed-radix-format! self radix-format)
+ (qif-file:set-date-format! self date-format)
+ (qif-file:set-guessed-date-format! self date-format)
+ (qif-file:set-currency! self currency)
+ (qif-file:set-y2k-threshold! self 50)
+ (qif-file:set-xtns! self '())
+ (qif-file:set-accounts! self '())
+ (qif-file:set-cats! self '())
+ (qif-file:set-classes! self '())
+ self))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-split class
+;; this is for bank/ccard accounts only.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define
+ (make-simple-class
+ 'qif-split
+ '(category class memo amount category-is-account? mark)))
+
+(define (qif-split:category self)
+ (simple-obj-getter self 'category))
+
+(define (qif-split:set-category! self value)
+ (let* ((cat-info
+ (qif-split:parse-category self value))
+ (cat-name (list-ref cat-info 0))
+ (is-account? (list-ref cat-info 1))
+ (class-name (list-ref cat-info 2)))
+ (simple-obj-setter self 'category cat-name)
+ (simple-obj-setter self 'class class-name)
+ (simple-obj-setter self 'category-is-account? is-account?)))
+; (if (not is-account?)
+; (simple-obj-setter self 'mark #t))))
+
+(define (qif-split:class self)
+ (simple-obj-getter self 'class))
+
+(define (qif-split:set-class! self value)
+ (simple-obj-setter self 'class value))
+
+(define (qif-split:memo self)
+ (simple-obj-getter self 'memo))
+
+(define (qif-split:set-memo! self value)
+ (simple-obj-setter self 'memo value))
+
+(define (qif-split:amount self)
+ (simple-obj-getter self 'amount))
+
+(define (qif-split:set-amount! self value)
+ (simple-obj-setter self 'amount value))
+
+(define (qif-split:mark self)
+ (simple-obj-getter self 'mark))
+
+(define (qif-split:set-mark! self value)
+ (simple-obj-setter self 'mark value))
+
+(define (qif-split:category-is-account? self)
+ (simple-obj-getter self 'category-is-account?))
+
+(define (qif-split:set-category-is-account?! self value)
+ (simple-obj-setter self 'category-is-account? value))
+
+(define (make-qif-split)
+ (let ((self (make-simple-obj )))
+ (qif-split:set-category! self "")
+ self))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-xtn class
+;; [D] date : parsed.
+;; [P] payee : string
+;; [N] number (check number, sell, or buy)
+;; [C] cleared : parsed (x/X/*) ;
+;; [T] amount : parsed, units are currency from .
+;; [M] memo : string
+;; [I] share price : parsed
+;; [Q] number of shares
+;; [Y] name of security
+;; [O] adjustment (parsed)
+;; [L] category : string
+;; [S]/[E]/[$] splits : a list of
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define
+ (make-simple-class
+ 'qif-xtn
+ '(date payee address number cleared memo
+ share-price num-shares security-name adjustment
+ splits bank-xtn? mark)))
+
+(define (qif-xtn? self)
+ (eq? (simple-obj-type self) 'qif-xtn))
+
+(define (qif-xtn:date self)
+ (simple-obj-getter self 'date))
+
+(define (qif-xtn:set-date! self value)
+ (simple-obj-setter self 'date value))
+
+(define (qif-xtn:payee self)
+ (simple-obj-getter self 'payee))
+
+(define (qif-xtn:set-payee! self value)
+ (simple-obj-setter self 'payee value))
+
+(define (qif-xtn:address self)
+ (simple-obj-getter self 'address))
+
+(define (qif-xtn:set-address! self value)
+ (simple-obj-setter self 'address value))
+
+(define (qif-xtn:number self)
+ (simple-obj-getter self 'number))
+
+(define (qif-xtn:set-number! self value)
+ (simple-obj-setter self 'number value))
+
+(define (qif-xtn:cleared self)
+ (simple-obj-getter self 'cleared))
+
+(define (qif-xtn:set-cleared! self value)
+ (simple-obj-setter self 'cleared value))
+
+(define (qif-xtn:share-price self)
+ (simple-obj-getter self 'share-price))
+
+(define (qif-xtn:set-share-price! self value)
+ (simple-obj-setter self 'share-price value))
+
+(define (qif-xtn:num-shares self)
+ (simple-obj-getter self 'num-shares))
+
+(define (qif-xtn:set-num-shares! self value)
+ (simple-obj-setter self 'num-shares value))
+
+(define (qif-xtn:security-name self)
+ (simple-obj-getter self 'security-name))
+
+(define (qif-xtn:set-security-name! self value)
+ (simple-obj-setter self 'security-name value))
+
+(define (qif-xtn:adjustment self)
+ (simple-obj-getter self 'adjustment))
+
+(define (qif-xtn:set-adjustment! self value)
+ (simple-obj-setter self 'adjustment value))
+
+(define (qif-xtn:splits self)
+ (simple-obj-getter self 'splits))
+
+(define (qif-xtn:set-splits! self value)
+ (simple-obj-setter self 'splits value))
+
+(define (qif-xtn:mark self)
+ (simple-obj-getter self 'mark))
+
+(define (qif-xtn:set-mark! self value)
+ (simple-obj-setter self 'mark value))
+
+(define (qif-xtn:bank-xtn? self)
+ (simple-obj-getter self 'bank-xtn?))
+
+(define (qif-xtn:set-bank-xtn?! self value)
+ (simple-obj-setter self 'bank-xtn? value))
+
+(define (make-qif-xtn)
+ (let ((self (make-simple-obj )))
+ (qif-xtn:set-bank-xtn?! self #t)
+ (qif-xtn:set-mark! self #f)
+ (qif-xtn:set-splits! self '())
+ self))
+
+(define (qif-xtn:reparse self qif-file)
+ ;; share price
+ (if (string? (qif-xtn:share-price self))
+ (qif-xtn:set-share-price!
+ self
+ (qif-file:parse-value qif-file (qif-xtn:share-price self))))
+
+ ;; number of shares
+ (if (string? (qif-xtn:num-shares self))
+ (qif-xtn:set-num-shares!
+ self
+ (qif-file:parse-value qif-file (qif-xtn:num-shares self))))
+
+ ;; adjustment
+ (if (string? (qif-xtn:adjustment self))
+ (qif-xtn:set-adjustment!
+ self
+ (qif-file:parse-value qif-file (qif-xtn:adjustment self))))
+
+ ;; reparse the amount of each split
+ (for-each
+ (lambda (split)
+ (if (string? (qif-split:amount split))
+ (qif-split:set-amount!
+ split
+ (qif-file:parse-value qif-file (qif-split:amount split)))))
+ (qif-xtn:splits self))
+
+ ;; reparse the date
+ (if (string? (qif-xtn:date self))
+ (qif-xtn:set-date! self
+ (qif-file:parse-date qif-file
+ (qif-xtn:date self)))))
+
+(define (qif-xtn:print self)
+ (simple-obj-print self ))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; [N] name : string
+;; [T] type : string
+;; [D] description : string
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define
+ (make-simple-class
+ 'qif-acct
+ '(name type description limit)))
+
+(define (qif-acct:name self)
+ (simple-obj-getter self 'name))
+
+(define (qif-acct:set-name! self value)
+ (simple-obj-setter self 'name value))
+
+(define (qif-acct:type self)
+ (simple-obj-getter self 'type))
+
+(define (qif-acct:set-type! self value)
+ (simple-obj-setter self 'type value))
+
+(define (qif-acct:description self)
+ (simple-obj-getter self 'description))
+
+(define (qif-acct:set-description! self value)
+ (simple-obj-setter self 'description value))
+
+(define (qif-acct:limit self)
+ (simple-obj-getter self 'limit))
+
+(define (qif-acct:set-limit! self value)
+ (simple-obj-setter self 'limit value))
+
+(define (make-qif-acct)
+ (make-simple-obj ))
+
+(define (qif-acct? self)
+ (eq? (simple-obj-type self) 'qif-acct))
+
+(define (qif-acct:print self)
+ (simple-obj-print self ))
+
+(define (qif-acct:reparse self file)
+ (if (string? (qif-acct:limit self))
+ (qif-acct:set-limit!
+ self (qif-file:parse-value file (qif-acct:limit self)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; [N] name : string
+;; [D] description : string
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define
+ (make-simple-class
+ 'qif-class
+ '(name description)))
+
+(define (qif-class:name self)
+ (simple-obj-getter self 'name))
+
+(define (qif-class:set-name! self value)
+ (simple-obj-setter self 'name value))
+
+(define (qif-class:description self)
+ (simple-obj-getter self 'description))
+
+(define (qif-class:set-description! self value)
+ (simple-obj-setter self 'description value))
+
+(define (qif-class:print self)
+ (simple-obj-print self ))
+
+(define (make-qif-class)
+ (make-simple-obj ))
+
+(define (qif-class? self)
+ (eq? (simple-obj-type self) 'qif-class))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; : a "Cat" or category transaction
+;; [N] name : string
+;; [D] description : string
+;; [T] taxable : boolean
+;; [E] expense? : boolean
+;; [I] income? : boolean
+;; [R] tax rate : number
+;; [B] budget amt : number
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(define
+ (make-simple-class
+ 'qif-cat
+ '(name description taxable expense-cat income-cat tax-rate budget-amt)))
+
+(define (qif-cat:name self)
+ (simple-obj-getter self 'name))
+
+(define (qif-cat:set-name! self value)
+ (simple-obj-setter self 'name value))
+
+(define (qif-cat:description self)
+ (simple-obj-getter self 'description))
+
+(define (qif-cat:set-description! self value)
+ (simple-obj-setter self 'description value))
+
+(define (qif-cat:taxable self)
+ (simple-obj-getter self 'taxable))
+
+(define (qif-cat:set-taxable! self value)
+ (simple-obj-setter self 'taxable value))
+
+(define (qif-cat:expense-cat self)
+ (simple-obj-getter self 'expense-cat))
+
+(define (qif-cat:set-expense-cat! self value)
+ (simple-obj-setter self 'expense-cat value))
+
+(define (qif-cat:income-cat self)
+ (simple-obj-getter self 'income-cat))
+
+(define (qif-cat:set-income-cat! self value)
+ (simple-obj-setter self 'income-cat value))
+
+(define (qif-cat:tax-rate self)
+ (simple-obj-getter self 'tax-rate))
+
+(define (qif-cat:set-tax-rate! self value)
+ (simple-obj-setter self 'tax-rate value))
+
+(define (qif-cat:budget-amt self)
+ (simple-obj-getter self 'budget-amt))
+
+(define (qif-cat:set-budget-amt! self value)
+ (simple-obj-setter self 'budget-amt value))
+
+(define (make-qif-cat)
+ (make-simple-obj ))
+
+(define (qif-cat? obj)
+ (eq? (simple-obj-type obj) 'qif-cat))
+
+(define (qif-cat:print self)
+ (simple-obj-print self ))
+
+(define (qif-cat:reparse self file)
+ (if (string? (qif-cat:tax-rate self))
+ (qif-cat:set-tax-rate!
+ self (qif-file:parse-value file (qif-cat:tax-rate self))))
+
+ (if (string? (qif-cat:budget-amt self))
+ (qif-cat:set-budget-amt!
+ self (qif-file:parse-value file (qif-cat:budget-amt self)))))
+
+
+(define (qif-file:add-xtn! self xtn)
+ (qif-file:set-xtns! self
+ (cons xtn (qif-file:xtns self))))
+
+(define (qif-file:add-cat! self cat)
+ (qif-file:set-cats! self
+ (cons cat (qif-file:cats self))))
+
+(define (qif-file:add-class! self class)
+ (qif-file:set-classes! self
+ (cons class (qif-file:classes self))))
+
+(define (qif-file:add-account! self account)
+ (qif-file:set-accounts! self
+ (cons account (qif-file:accounts self))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; munge the QIF filename to create a simple default account name
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-file:path-to-accountname self)
+ (let ((namestring (qif-file:path self)))
+ (if (and (string? namestring)
+ (> (string-length namestring) 0))
+ (begin
+ (set! namestring
+ (substring namestring
+ (let ((last-slash (string-rindex namestring #\/)))
+ (if last-slash
+ (+ 1 last-slash)
+ 0))
+ (let ((last-dot (string-rindex namestring #\.)))
+ (if last-dot
+ last-dot
+ (string-length namestring)))))
+ (set! namestring (string-replace-char! namestring #\- #\space))
+ (set! namestring (string-replace-char! namestring #\_ #\space))
+ namestring)
+ "QIF Import")))
diff --git a/src/scm/qif-import/qif-parse.scm b/src/scm/qif-import/qif-parse.scm
new file mode 100644
index 0000000000..add6c01f28
--- /dev/null
+++ b/src/scm/qif-import/qif-parse.scm
@@ -0,0 +1,475 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; qif-parse.scm
+;;; routines to parse values and dates in QIF files.
+;;;
+;;; Bill Gribble 20 Feb 2000
+;;; $Id$
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(gnc:support "qif-parse.scm")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-split:parse-category
+;; this one just gets nastier and nastier.
+;; ATM we return a list of 3 elements: parsed category name
+;; (without [] if it was an account name), bool stating if it
+;; was an account name, and string representing the class name
+;; (or #f if no class).
+;; gosh, I love regular expressions.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define qif-category-compiled-rexp
+ (make-regexp "(\\[)?([^]/]*)(]?)(/?)(.*)"))
+
+(define (qif-split:parse-category self value)
+ (let ((match (regexp-exec qif-category-compiled-rexp value)))
+ (if match
+ (begin
+ (list (match:substring match 2)
+ (if (and (match:substring match 1)
+ (match:substring match 3))
+ #t #f)
+ (if (match:substring match 4)
+ (match:substring match 5)
+ #f)))
+ (begin
+ (display "qif-split:parse-category : can't parse ")
+ (display value) (newline)
+ (list "" #f #f)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-file:fix-year
+;; this is where we handle y2k fixes etc. input is a string
+;; containing the year ("00", "2000", and "19100" all mean the same
+;; thing). output is an integer representing the year in the C.E.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-file:fix-year self year-string)
+ (let ((fixed-string #f)
+ (post-read-value #f)
+ (y2k-fixed-value #f))
+
+ ;; quicken prints 2000 as "' 0" for at least some versions.
+ ;; thanks dave p for reporting this.
+ (if (eq? (string-ref year-string 0) #\')
+ (begin
+ (display "qif-file:fix-year : found a weird QIF Y2K year : |")
+ (display year-string)
+ (display "|") (newline)
+ (set! fixed-string
+ (substring year-string 2 (string-length year-string))))
+ (set! fixed-string year-string))
+
+ ;; now the string should just have a number in it plus some
+ ;; optional trailing space.
+ (set! post-read-value
+ (with-input-from-string fixed-string
+ (lambda () (read))))
+
+ (cond
+ ;; 2-digit numbers less than the window size are interpreted to
+ ;; be post-2000.
+ ((and (integer? post-read-value)
+ (< post-read-value (qif-file:y2k-threshold self)))
+ (set! y2k-fixed-value (+ 2000 post-read-value)))
+
+ ;; there's a common bug in printing post-2000 dates that
+ ;; prints 2000 as 19100 etc.
+ ((and (integer? post-read-value)
+ (> post-read-value 19000))
+ (set! y2k-fixed-value (+ 1900 (- post-read-value 19000))))
+
+ ;; normal dates represented in unix years (i.e. year-1900, so
+ ;; 2000 => 100.) We also want to allow full year specifications,
+ ;; (i.e. 1999, 2001, etc) and there's a point at which you can't
+ ;; determine which is which. this should eventually be another
+ ;; field in the qif-file struct but not yet. mktime in scheme
+ ;; doesn't deal with dates before December 14, 1901, at least for
+ ;; now, so let's give ourselves until at least 3802 before this
+ ;; does the wrong thing.
+ ((and (integer? post-read-value)
+ (< post-read-value 1902))
+ (set! y2k-fixed-value (+ 1900 post-read-value)))
+
+ ;; this is a normal, 4-digit year spec (1999, 2000, etc).
+ ((integer? post-read-value)
+ (set! y2k-fixed-value post-read-value))
+
+ ;; No idea what the string represents. Maybe a new bug in Quicken!
+ (#t
+ (display "qif-file:fix-year : ay caramba! What is this? |")
+ (display year-string)
+ (display "|") (newline)))
+
+ y2k-fixed-value))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; parse-acct-type : set the type of the account, using gnucash
+;; conventions.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-file:parse-acct-type self read-value)
+ (let ((mangled-string
+ (string-downcase! (string-remove-trailing-space
+ (string-remove-leading-space read-value)))))
+ (cond
+ ((string=? mangled-string "bank")
+ GNC-BANK-TYPE)
+ ((string=? mangled-string "cash")
+ GNC-CASH-TYPE)
+ ((string=? mangled-string "ccard")
+ GNC-CCARD-TYPE)
+ ((string=? mangled-string "invst")
+ GNC-STOCK-TYPE)
+ ((string=? mangled-string "oth a")
+ GNC-ASSET-TYPE)
+ ((string=? mangled-string "oth l")
+ GNC-LIABILITY-TYPE)
+ (#t read-value))))
+
+(define (qif-file:state-to-account-type self qstate)
+ (cond ((eq? qstate 'type:bank)
+ GNC-BANK-TYPE)
+ ((eq? qstate 'type:cash)
+ GNC-CASH-TYPE)
+ ((eq? qstate 'type:ccard)
+ GNC-CCARD-TYPE)
+ ((eq? qstate 'type:invst)
+ GNC-STOCK-TYPE)
+ ((eq? qstate '#{type:oth\ a}#)
+ GNC-ASSET-TYPE)
+ ((eq? qstate '#{type:oth\ l}#)
+ GNC-LIABILITY-TYPE)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; parse-bang-field : the bang fields switch the parse context for
+;; the qif file.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-file:parse-bang-field self read-value)
+ (string->symbol (string-downcase!
+ (string-remove-trailing-space read-value))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; parse-cleared-field : in a C (cleared) field in a QIF transaction,
+;; * means cleared, x or X means reconciled, and ! or ? mean some
+;; budget related stuff I don't understand.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-file:parse-cleared-field self read-value)
+
+ (if (and (string? read-value)
+ (> (string-length read-value) 0))
+ (let ((secondchar (string-ref read-value 0)))
+ (cond ((eq? secondchar #\*)
+ 'cleared)
+ ((or (eq? secondchar #\x)
+ (eq? secondchar #\X))
+ 'reconciled)
+ ((or (eq? secondchar #\?)
+ (eq? secondchar #\!))
+ 'budgeted)
+ (#t
+ #f)))
+ #f))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-file:parse-date
+;;
+;; If the date format is specified, use that; otherwise, try to guess
+;; the format. When the format is being guessed, I don't actually do
+;; any translation to a numeric format; that's saved for a second
+;; pass (calling qif-bank-xtn:reparse on every transaction)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-file:parse-date self date-string)
+ (if (or (not (string? date-string))
+ (not (> (string-length date-string) 0)))
+ (begin
+ (display "qif-import: very bogus QIF date in transaction.") (newline)
+ (display "qif-import: Substituting 1/1/2999 for date.") (newline)
+ (set! date-string "1/1/2999")))
+
+ (let ((date-parts '())
+ (numeric-date-parts '())
+ (retval date-string)
+ (match
+ (string-match "([0-9]+) *[-/.'] *([0-9]+) *[-/.'] *([0-9]+)"
+ date-string)))
+ (if match
+ (set! date-parts (list (match:substring match 1)
+ (match:substring match 2)
+ (match:substring match 3))))
+
+ ;; get the strings into numbers (but keep the strings around)
+ (set! numeric-date-parts
+ (map (lambda (elt)
+ (with-input-from-string elt
+ (lambda () (read))))
+ date-parts))
+
+ (cond
+ ;; if the date parts list doesn't have 3 parts, we're in
+ ;; trouble
+ ((not (eq? 3 (length date-parts)))
+ (begin
+ (display "qif-file:parse-date : can't interpret date ")
+ (display date-string) (newline)))
+
+ ;; if the format is unknown, don't try to fully interpret the
+ ;; number, just look for a good guess or an inconsistency with
+ ;; the current guess.
+ ((and (eq? (qif-file:date-format self) 'unknown)
+ (not (eq? (qif-file:guessed-date-format self)
+ 'inconsistent)))
+ (cond
+ ;; we currently think the date format is m/d/y
+ ((eq? (qif-file:guessed-date-format self) 'm-d-y)
+ (let ((m (car numeric-date-parts))
+ (d (cadr numeric-date-parts)))
+ (if (or (not (number? m)) (not (number? d)) (> m 12) (> d 31))
+ (qif-file:set-guessed-date-format! self 'inconsistent))))
+
+ ;; current guess is d/m/y
+ ((eq? (qif-file:guessed-date-format self) 'd-m-y)
+ (let ((d (car numeric-date-parts))
+ (m (cadr numeric-date-parts)))
+ (if (or (not (number? m)) (not (number? d)) (> m 12) (> d 31))
+ (qif-file:set-guessed-date-format! self 'inconsistent))))
+
+ ;; current guess is y/m/d
+ ((eq? (qif-file:guessed-date-format self) 'y-m-d)
+ (let ((m (cadr numeric-date-parts))
+ (d (caddr numeric-date-parts)))
+ (if (or (not (number? m)) (not (number? d)) (> m 12) (> d 31))
+ (qif-file:set-guessed-date-format! self 'inconsistent))))
+
+ ;; current guess is y/d/m (is this really possible?)
+ ((eq? (qif-file:guessed-date-format self) 'y-m-d)
+ (let ((d (cadr numeric-date-parts))
+ (m (caddr numeric-date-parts)))
+ (if (or (not (number? m)) (not (number? d)) (> m 12) (> d 31))
+ (qif-file:set-guessed-date-format! self 'inconsistent))))
+
+ ;; no guess currently. See if we can find a smoking gun in
+ ;; the date format. For dates like 11-9-11 just don't try to
+ ;; guess.
+ ((eq? (qif-file:guessed-date-format self) 'unknown)
+ (let ((possibilities '(m-d-y d-m-y y-m-d y-d-m))
+ (n1 (car numeric-date-parts))
+ (n2 (cadr numeric-date-parts))
+ (n3 (caddr numeric-date-parts)))
+
+ ;; filter the possibilities to eliminate (hopefully)
+ ;; all but one
+ (if (or (not (number? n1)) (> n1 12))
+ (set! possibilities (delq 'm-d-y possibilities)))
+ (if (or (not (number? n1)) (> n1 31))
+ (set! possibilities (delq 'd-m-y possibilities)))
+
+ (if (or (not (number? n2)) (> n2 12))
+ (begin
+ (set! possibilities (delq 'd-m-y possibilities))
+ (set! possibilities (delq 'y-m-d possibilities))))
+ (if (or (not (number? n2)) (> n2 31))
+ (begin
+ (set! possibilities (delq 'm-d-y possibilities))
+ (set! possibilities (delq 'y-d-m possibilities))))
+
+ (if (or (not (number? n3)) (> n3 12))
+ (set! possibilities (delq 'y-d-m possibilities)))
+ (if (or (not (number? n3)) (> n3 31))
+ (set! possibilities (delq 'y-m-d possibilities)))
+
+ ;; if there's exactly one possibility left, we've got a good
+ ;; guess. if there are no possibilities left, the date
+ ;; is somehow inconsistent. More than one, do nothing.
+ (cond ((eq? (length possibilities) 1)
+ (qif-file:set-guessed-date-format! self (car possibilities)))
+ ((eq? (length possibilities) 0)
+ (display "qif-file:parse-date : can't interpret date ")
+ (display date-string)
+ (newline)
+ (qif-file:set-guessed-date-format! self 'inconsistent)))))))
+
+ ;; we think we know the date format. Make sure the data is
+ ;; consistent with that.
+ ((eq? (qif-file:date-format self) 'd-m-y)
+ (let ((d (car numeric-date-parts))
+ (m (cadr numeric-date-parts))
+ (y (qif-file:fix-year self (caddr date-parts))))
+ (if (and (integer? d) (integer? m) (integer? y)
+ (<= m 12) (<= d 31))
+ (set! retval (list d m y))
+ (begin
+ (display "qif-file:parse-date : format is d/m/y, but date is ")
+ (display date-string) (newline)))))
+
+ ((eq? (qif-file:date-format self) 'm-d-y)
+ (let ((m (car numeric-date-parts))
+ (d (cadr numeric-date-parts))
+ (y (qif-file:fix-year self (caddr date-parts))))
+ (if (and (integer? d) (integer? m) (integer? y)
+ (<= m 12) (<= d 31))
+ (set! retval (list d m y))
+ (begin
+ (display "qif-file:parse-date : format is m/d/y, but date is ")
+ (display date-string) (newline)))))
+
+ ((eq? (qif-file:date-format self) 'y-m-d)
+ (let ((y (qif-file:fix-year self (car date-parts)))
+ (m (cadr numeric-date-parts))
+ (d (caddr numeric-date-parts))))
+ (if (and (integer? d) (integer? m) (integer? y)
+ (<= m 12) (<= d 31))
+ (set! retval (list d m y))
+ (begin
+ (display "qif-file:parse-date : format is y/m/d, but date is ")
+ (display date-string) (newline))))
+
+ ((eq? (qif-file:date-format self) 'y-d-m)
+ (let ((y (qif-file:fix-year self (car date-parts)))
+ (d (cadr numeric-date-parts))
+ (m (caddr numeric-date-parts))))
+ (if (and (integer? d) (integer? m) (integer? y)
+ (<= m 12) (<= d 31))
+ (set! retval (list d m y))
+ (begin
+ (display "qif-file:parse-date : format is y/m/d, but date is ")
+ (display date-string) (newline)))))
+ retval))
+
+(define (qif-file:parse-string self str)
+ (if (or (not (string? str))
+ (not (> (string-length str) 0)))
+ (set! str " "))
+
+ (string-remove-leading-space (string-remove-trailing-space str)))
+
+(define (qif-file:parse-value self value-string)
+ (if (or (not (string? value-string))
+ (not (> (string-length value-string) 0)))
+ (set! value-string "0"))
+
+ (let ((comma-index (string-rindex value-string #\,))
+ (decimal-index (string-rindex value-string #\.))
+ (comma-count (string-char-count value-string #\,))
+ (decimal-count (string-char-count value-string #\.)))
+
+ ;; if we don't know the radix format, it might be appropriate to
+ ;; guess. guessed radix format doesn't affect parsing at all
+ ;; until you set the radix-format from the guessed-radix-format
+ ;; and call reparse-values on all the values.
+
+ (if (and (eq? (qif-file:radix-format self) 'unknown)
+ (not (eq? (qif-file:guessed-radix-format self) 'inconsistent)))
+ (cond
+ ;; already think it's decimal
+ ((eq? (qif-file:guessed-radix-format self) 'decimal)
+ (if (or (> decimal-count 1)
+ (and decimal-index comma-index
+ (> comma-index decimal-index)))
+ (begin
+ (qif-file:set-guessed-radix-format! self 'inconsistent)
+ (display "this QIF file has inconsistent radix notation!")
+ (newline))))
+
+ ;; already think it's comma
+ ((eq? (qif-file:guessed-radix-format self) 'comma)
+ (if (or (> comma-count 1)
+ (and decimal-index comma-index
+ (> decimal-index comma-index)))
+ (begin
+ (qif-file:set-guessed-radix-format! self 'inconsistent)
+ (display "this QIF file has inconsistent radix notation!")
+ (newline))))
+
+ ;; don't know : look for numbers that are giveaways.
+ ((eq? (qif-file:guessed-radix-format self) 'unknown)
+ ;; case 1: there's a decimal and a comma, and the
+ ;; decimal is to the right of the comma, and there's
+ ;; only one decimal : it's a decimal number.
+ (if (and decimal-index comma-index
+ (> decimal-index comma-index)
+ (eq? decimal-count 1))
+ (qif-file:set-guessed-radix-format! self 'decimal))
+
+ ;; case 2: the opposite.
+ (if (and decimal-index comma-index
+ (> comma-index decimal-index)
+ (eq? comma-count 1))
+ (qif-file:set-guessed-radix-format! self 'comma))
+
+ ;; case 3: there's no decimal and more than one comma:
+ ;; it's a decimal number. I wish I had more transactions
+ ;; like this!
+ (if (and (eq? decimal-count 0)
+ (> comma-count 1))
+ (qif-file:set-guessed-radix-format! self 'decimal))
+
+ ;; case 4: the opposite (no comma, multiple decimals)
+ (if (and (eq? comma-count 0)
+ (> decimal-count 1))
+ (qif-file:set-guessed-radix-format! self 'comma))
+
+ ;; case 5: one decimal, no commas, and not-3 digits
+ ;; after it --> decimal.
+ (if (and (eq? comma-count 0)
+ (eq? decimal-count 1)
+ (not (eq? (- (string-length value-string)
+ decimal-index)
+ 4)))
+ (qif-file:set-guessed-radix-format! self 'decimal))
+
+ ;; case 6: the opposite --> comma
+ (if (and (eq? comma-count 1)
+ (eq? decimal-count 0)
+ (not (eq? (- (string-length value-string)
+ comma-index)
+ 4)))
+ (begin
+ (display "hey!") (display comma-count)
+ (display comma-index) (display (string-length value-string))
+ (newline)
+ (qif-file:set-guessed-radix-format! self 'comma))))))
+
+ (cond
+ ;; decimal radix (US format)
+ ;; number can't have more than one ., and the rightmost
+ ;; . must be to the right of the rightmost ,
+ ;; , are ignored otherwise
+ ((eq? 'decimal (qif-file:radix-format self))
+ (if (or (and decimal-count
+ (> decimal-count 1))
+ (and decimal-index comma-index
+ (> comma-index decimal-index)))
+ (error "badly-formed decimal-radix number" value-string)
+ (+ 0.0
+ (with-input-from-string (string-remove-char value-string #\,)
+ (lambda () (read))))))
+
+ ;; comma radix (German format)
+ ;; number can't have more than one , and the rightmost
+ ;; , must be to the right of the rightmost .
+ ;; . are ignored otherwise. Substitute . for , before
+ ;; parsing.
+ ((eq? 'comma (qif-file:radix-format self))
+ (if (or (and comma-count
+ (> comma-count 1))
+ (and decimal-index comma-index
+ (> decimal-index comma-index)))
+ (error "badly formed comma-radix number" value-string)
+ (+ 0.0
+ (with-input-from-string (string-replace-char!
+ (string-remove-char value-string #\.)
+ #\, #\.)
+ (lambda () (read))))))
+
+ ;; unknown radix - store the string and we can process it
+ ;; later.
+ (#t
+ value-string))))
+
diff --git a/src/scm/qif-import/qif-to-gnc.scm b/src/scm/qif-import/qif-to-gnc.scm
new file mode 100644
index 0000000000..c2e985de4e
--- /dev/null
+++ b/src/scm/qif-import/qif-to-gnc.scm
@@ -0,0 +1,479 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; qif-to-gnc.scm
+;;; this is where QIF transactions are transformed into a
+;;; Gnucash account tree.
+;;;
+;;; Bill Gribble 20 Feb 2000
+;;; $Id$
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(gnc:support "qif-to-gnc.scm")
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; find-or-make-acct:
+;; given a colon-separated account path, return an Account* to
+;; an existing or new account.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-import:find-or-make-acct gnc-name gnc-acct-hash
+ gnc-type qif-info acct-group)
+ (let ((existing-account (hash-ref gnc-acct-hash gnc-name))
+ (same-gnc-account (gnc:get-account-from-full-name acct-group
+ gnc-name
+ #\:))
+ (check-full-name #f)
+ (make-new-acct #f))
+
+ (if (or (pointer-token-null? same-gnc-account)
+ (and (not (pointer-token-null? same-gnc-account))
+ (not (string=?
+ (gnc:account-get-full-name same-gnc-account)
+ gnc-name))))
+ (set! make-new-acct #t))
+
+ (if (and make-new-acct
+ (not (pointer-token-null? same-gnc-account)))
+ (begin (display " BUG IN get-account-from-full-name !!")(newline)))
+
+ (if existing-account
+ existing-account
+ (let ((new-acct (gnc:malloc-account))
+ (parent-acct #f)
+ (parent-name #f)
+ (acct-name #f)
+ (last-colon #f))
+ (set! last-colon (string-rindex gnc-name #\:))
+
+ (gnc:init-account new-acct)
+ (gnc:account-begin-edit new-acct 1)
+
+ ;; if this is a copy of an existing gnc account,
+ ;; copy the account properties
+ (if (not make-new-acct)
+ (begin
+ (gnc:account-set-name
+ new-acct (gnc:account-get-name same-gnc-account))
+ (gnc:account-set-description
+ new-acct (gnc:account-get-description same-gnc-account))
+ (gnc:account-set-type
+ new-acct (gnc:account-get-type same-gnc-account))
+ (gnc:account-set-currency
+ new-acct (gnc:account-get-currency same-gnc-account))
+ (gnc:account-set-notes
+ new-acct (gnc:account-get-notes same-gnc-account))
+ (gnc:account-set-code
+ new-acct (gnc:account-get-code same-gnc-account))
+ (gnc:account-set-security
+ new-acct (gnc:account-get-security same-gnc-account))))
+
+
+ ;; make sure that if this is a nested account foo:bar:baz,
+ ;; foo:bar and foo exist also.
+ (if last-colon
+ (begin
+ (set! parent-name (substring gnc-name 0 last-colon))
+ (set! acct-name (substring gnc-name (+ 1 last-colon)
+ (string-length gnc-name)))
+ (set! parent-acct (qif-import:find-or-make-acct
+ parent-name gnc-acct-hash
+ gnc-type qif-info
+ acct-group))
+
+ ;; if this is a new account, use the
+ ;; parameters passed in
+ (if make-new-acct
+ (begin
+ (gnc:account-set-name new-acct acct-name)
+ (if gnc-type (gnc:account-set-type new-acct gnc-type))
+ (cond ((and (qif-acct? qif-info)
+ (qif-acct:description qif-info))
+ (gnc:account-set-description
+ new-acct (qif-acct:description qif-info)))
+ ((and (qif-cat? qif-info)
+ (qif-cat:description qif-info))
+ (gnc:account-set-description
+ new-acct (qif-cat:description qif-info)))
+ ((and (qif-xtn? qif-info)
+ (not (qif-xtn:bank-xtn? qif-info)))
+ (gnc:account-set-security
+ (qif-xtn:security-name qif-info)))
+ ((string? qif-info)
+ (gnc:account-set-description
+ new-acct qif-info)))))
+
+ (gnc:account-commit-edit new-acct)
+ (gnc:insert-subaccount parent-acct new-acct))
+ (begin
+ (if make-new-acct
+ (begin
+ (gnc:account-set-name new-acct gnc-name)
+ (cond ((and (qif-acct? qif-info)
+ (qif-acct:description qif-info))
+ (gnc:account-set-description
+ new-acct (qif-acct:description qif-info)))
+ ((and (qif-cat? qif-info)
+ (qif-cat:description qif-info))
+ (gnc:account-set-description
+ new-acct (qif-cat:description qif-info)))
+ ((string? qif-info)
+ (gnc:account-set-description
+ new-acct qif-info)))
+ (if gnc-type (gnc:account-set-type new-acct gnc-type))))
+
+ (gnc:account-commit-edit new-acct)
+ (gnc:group-insert-account acct-group new-acct)))
+ (hash-set! gnc-acct-hash gnc-name new-acct)
+ new-acct))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-import:qif-to-gnc
+;; this is the top-level of the back end conversion from
+;; QIF to GNC. all the account mappings and so on should be
+;; done before this is called.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-import:qif-to-gnc qif-files-list mapping-data)
+ (let* ((existing-gnc-accts (car mapping-data))
+ (qif-acct-map (cadr mapping-data))
+ (qif-cat-map (caddr mapping-data))
+ (account-group (gnc:get-current-group))
+ (gnc-acct-hash (make-hash-table 20))
+ (existing-gnc-accounts #f)
+ (sorted-qif-files-list
+ (sort qif-files-list
+ (lambda (a b)
+ (> (length (qif-file:xtns a))
+ (length (qif-file:xtns b)))))))
+
+ ;; 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, building the gnc-acct-hash as we go.
+ (for-each
+ (lambda (bin)
+ (for-each
+ (lambda (hashpair)
+ (let* ((acctinfo (cdr hashpair))
+ (qif-name (list-ref acctinfo 0))
+ (gnc-name (list-ref acctinfo 1))
+ (gnc-type (list-ref acctinfo 2))
+ (gnc-new (list-ref acctinfo 3))
+ (gnc-xtns (list-ref acctinfo 4))
+ (qif-info (list-ref acctinfo 5)))
+ (if (> gnc-xtns 0)
+ (qif-import:find-or-make-acct gnc-name gnc-acct-hash
+ gnc-type qif-info
+ account-group))))
+ bin))
+ (vector->list qif-acct-map))
+
+ (for-each
+ (lambda (bin)
+ (for-each
+ (lambda (hashpair)
+ (let* ((acctinfo (cdr hashpair))
+ (qif-name (list-ref acctinfo 0))
+ (gnc-name (list-ref acctinfo 1))
+ (gnc-type (list-ref acctinfo 2))
+ (gnc-new (list-ref acctinfo 3))
+ (gnc-xtns (list-ref acctinfo 4))
+ (qif-info (list-ref acctinfo 5)))
+ (if (> gnc-xtns 0)
+ (qif-import:find-or-make-acct gnc-name gnc-acct-hash
+ gnc-type qif-info
+ account-group))))
+ bin))
+ (vector->list qif-cat-map))
+
+ ;; iterate over files. Going in the sort order by number of
+ ;; transactions should give us a small speed advantage.
+ (for-each
+ (lambda (qif-file)
+ ;; within the file, iterate over transactions. key things to
+ ;; remember: if the L line in the transaction is a category,
+ ;; it's a single-entry xtn and no need to look for the other
+ ;; end. if it's an account, search for a QIF file with that
+ ;; account name and find the xtn to mark.
+ (for-each
+ (lambda (xtn)
+ (if (not (qif-xtn:mark xtn))
+ (begin
+ ;; mark the transaction and find any other QIF
+ ;; xtns that refer to the same xtn
+ (qif-xtn:set-mark! xtn #t)
+ (qif-import:mark-matching-xtns xtn qif-file qif-files-list)
+
+ ;; create and fill in the GNC transaction
+ (let ((gnc-xtn (gnc:transaction-create)))
+ (gnc:transaction-init gnc-xtn)
+ (gnc:transaction-begin-edit gnc-xtn 1)
+
+ ;; destroy any automagic splits in the transaction
+ (let ((numsplits (gnc:transaction-get-split-count gnc-xtn)))
+ (if (not (eqv? 0 numsplits))
+ (let splitloop ((ind (- numsplits 1)))
+ (gnc:split-destroy
+ (gnc:transaction-get-split gnc-xtn ind))
+ (if (> ind 0)
+ (loop (- ind 1))))))
+
+ ;; build the transaction
+ (qif-import:qif-xtn-to-gnc-xtn
+ xtn qif-file gnc-xtn gnc-acct-hash mapping-data)
+
+ ;; rebalance and commit everything
+ (gnc:transaction-commit-edit gnc-xtn)))))
+
+ (qif-file:xtns qif-file)))
+ sorted-qif-files-list)
+
+ ;; now take the new account tree and merge it in with the
+ ;; existing gnucash account tree.
+ (gnc:merge-accounts account-group)
+ (gnc:refresh-main-window)
+ ))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-import:qif-xtn-to-gnc-xtn
+;; translate a single transaction to a set of gnucash splits and
+;; a gnucash transaction structure.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-import:qif-xtn-to-gnc-xtn qif-xtn qif-file gnc-xtn
+ gnc-acct-hash mapping-data)
+ (let ((splits (qif-xtn:splits qif-xtn))
+ (qif-cat-map (caddr mapping-data))
+ (qif-acct-map (cadr mapping-data))
+ (near-acct-info #f)
+ (near-acct-name #f)
+ (near-acct #f))
+
+ ;; set properties of the whole transaction
+ (apply gnc:transaction-set-date gnc-xtn (qif-xtn:date qif-xtn))
+
+ (if (qif-xtn:payee qif-xtn)
+ (gnc:transaction-set-description gnc-xtn (qif-xtn:payee qif-xtn)))
+ (if (qif-xtn:number qif-xtn)
+ (gnc:transaction-set-xnum gnc-xtn (qif-xtn:number qif-xtn)))
+
+ ;; find the GNC account for the near end of the transaction
+ ;; (all splits have the same near end)
+ (if (qif-xtn:bank-xtn? qif-xtn)
+ (begin
+ (set! near-acct-info
+ (hash-ref qif-acct-map
+ (qif-file:account qif-file)))
+ (set! near-acct-name
+ (list-ref near-acct-info 1))
+ (set! near-acct (hash-ref gnc-acct-hash near-acct-name)))
+ (begin
+ (set! near-acct-info
+ (hash-ref qif-acct-map
+ (qif-xtn:security-name qif-xtn)))
+ (set! near-acct-name
+ (list-ref near-acct-info 1))
+ (set! near-acct (hash-ref gnc-acct-hash near-acct-name))))
+
+ ;; iterate over QIF splits
+ (for-each
+ (lambda (qif-split)
+ (let ((gnc-near-split (gnc:split-create))
+ (gnc-far-split (gnc:split-create))
+ (far-acct-info #f)
+ (far-acct-name #f)
+ (far-acct-type #f)
+ (far-acct #f))
+
+ ;; fill the splits in (near first). This handles files in
+ ;; multiple currencies by pulling the currency value from the
+ ;; file import.
+ (gnc:split-set-base-value gnc-near-split
+ (qif-split:amount qif-split)
+ (qif-file:currency qif-file))
+ (gnc:split-set-base-value gnc-far-split
+ (- (qif-split:amount qif-split))
+ (qif-file:currency qif-file))
+
+ (if (qif-split:memo qif-split)
+ (begin
+ (gnc:split-set-memo gnc-near-split (qif-split:memo qif-split))
+ (gnc:split-set-memo gnc-far-split (qif-split:memo qif-split))))
+
+ ;; my guess is that you can't have Quicken splits
+ ;; on stock transactions. This will break if you can.
+ (if (qif-xtn:share-price qif-xtn)
+ (begin
+ (if (> (length splits) 1)
+ (begin
+ (display "qif-import:qif-xtn-to-gnc-xtn : ")
+ (display "splits in stock transaction!") (newline)))
+ (gnc:split-set-share-price gnc-near-split
+ (qif-xtn:share-price qif-xtn))
+ (gnc:split-set-share-price gnc-far-split
+ (qif-xtn:share-price qif-xtn)))
+ (begin
+ (gnc:split-set-share-price gnc-near-split 1.0)
+ (gnc:split-set-share-price gnc-far-split 1.0)))
+
+ (if (qif-xtn:num-shares qif-xtn)
+ (begin
+ (if (> (length splits) 1)
+ (begin
+ (display "qif-import:qif-xtn-to-gnc-xtn : ")
+ (display "splits in stock transaction!") (newline)))
+
+ (gnc:split-set-share-amount gnc-near-split
+ (qif-xtn:num-shares qif-xtn))
+ (gnc:split-set-share-amount gnc-far-split
+ (- (qif-xtn:num-shares qif-xtn)))))
+
+ ;; find the GNC account on the far end of the split
+ (cond
+ ;; this is a stock xtn with no specified category, which
+ ;; generally means this account is a brokerage account
+ ;; description.
+ ((and (not (qif-xtn:bank-xtn? qif-xtn))
+ (string=? (qif-split:category qif-split) ""))
+ (set! far-acct-info
+ (hash-ref qif-acct-map
+ (qif-file:account qif-file)))
+ (set! far-acct-name
+ (list-ref far-acct-info 1))
+ (set! far-acct (hash-ref gnc-acct-hash far-acct-name)))
+
+ ;; this is a normal stock or bank transfer to another
+ ;; account
+ ((qif-split:category-is-account? qif-split)
+ (set! far-acct-info
+ (hash-ref qif-acct-map
+ (qif-split:category qif-split)))
+ (set! far-acct-name
+ (list-ref far-acct-info 1))
+ (set! far-acct (hash-ref gnc-acct-hash far-acct-name)))
+
+ ;; otherwise the category is a category and won't have a
+ ;; matching split in the QIF world.
+ (#t
+ (set! far-acct-info
+ (hash-ref qif-cat-map
+ (qif-split:category qif-split)))
+ (set! far-acct-name
+ (list-ref far-acct-info 1))
+ (set! far-acct (hash-ref gnc-acct-hash far-acct-name))))
+
+ ;; finally, plug the splits into the accounts
+ (gnc:transaction-append-split gnc-xtn gnc-near-split)
+ (gnc:transaction-append-split gnc-xtn gnc-far-split)
+ (gnc:account-insert-split near-acct gnc-near-split)
+ (gnc:account-insert-split far-acct gnc-far-split)))
+
+ splits)
+
+ ;; return the modified transaction (though it's ignored).
+ gnc-xtn))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-import:mark-matching-xtns
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-import:mark-matching-xtns xtn qif-file qif-files)
+ (for-each
+ (lambda (split)
+ (if (not (qif-split:mark split))
+ (if (qif-split:category-is-account? split)
+ (begin
+ (qif-split:set-mark! split #t)
+ (qif-import:mark-matching-split split xtn qif-file qif-files))
+ (qif-split:set-mark! split #t))))
+ (qif-xtn:splits xtn))
+ (qif-xtn:set-mark! xtn #t))
+
+(define (qif-import:mark-matching-split split xtn qif-file qif-files)
+ (let ((near-acct-name #f)
+ (far-acct-name (qif-split:category split))
+ (date (qif-xtn:date xtn))
+ (amount (- (qif-split:amount split)))
+ (memo (qif-split:memo split))
+ (bank-xtn? (qif-xtn:bank-xtn? xtn))
+ (done #f))
+
+ (if bank-xtn?
+ (set! near-acct-name (qif-file:account qif-file))
+ (set! near-acct-name (qif-xtn:security-name xtn)))
+
+
+;; (display "mark-matching-split : near-acct = ")
+;; (write near-acct-name)
+;; (display " far-acct = ")
+;; (write far-acct-name)
+;; (display " date = ")
+;; (write date)
+;; (newline)
+
+ ;; this is the grind loop. Go over every unmarked split of every
+ ;; unmarked transaction of every file that's not this one.
+ (let file-loop ((files qif-files))
+ (if (and (not (eq? qif-file (car files)))
+ (or (not bank-xtn?)
+ (string=? far-acct-name
+ (qif-file:account (car files)))))
+ (let xtn-loop ((xtns (qif-file:xtns (car files))))
+ (if (not (qif-xtn:mark (car xtns)))
+ (let split-loop ((splits (qif-xtn:splits (car xtns))))
+ (if (qif-split:split-matches?
+ (car splits) (car xtns)
+ near-acct-name date amount memo)
+ (begin
+;; (display "found ")(write (car splits))(newline)
+ (qif-split:set-mark! (car splits) #t)
+ (set! done #t)
+ (let ((all-marked #t))
+ (for-each
+ (lambda (s) (if (not (qif-split:mark s))
+ (set! all-marked #f)))
+ (qif-xtn:splits (car xtns)))
+ (if all-marked (qif-xtn:set-mark!
+ (car xtns) #t)))))
+ (if (and (not done)
+ (not (null? (cdr splits))))
+ (split-loop (cdr splits)))))
+ (if (and (not done)
+ (not (null? (cdr xtns))))
+ (xtn-loop (cdr xtns)))))
+ (if (and (not done)
+ (not (null? (cdr files))))
+ (file-loop (cdr files))))))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; qif-split:split-matches?
+;; check if a split matches date, amount, and other criteria
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (qif-split:split-matches? split xtn acct-name date amount memo)
+ (and
+ ;; account name matches
+ (string=? acct-name (qif-split:category split))
+
+ ;; is the amount right?
+ (eqv? amount (qif-split:amount split))
+
+ ;; is the date the same?
+ (let ((self-date (qif-xtn:date xtn)))
+ (and (pair? self-date)
+ (pair? date)
+ (eq? (length self-date) 3)
+ (eq? (length date) 3)
+ (eqv? (car self-date) (car date))
+ (eqv? (cadr self-date) (cadr date))
+ (eqv? (caddr self-date) (caddr date))))
+
+ ;; is the memo the same? (is this true?)
+ ;; ignore it for now
+ ))
+
+
+
diff --git a/src/scm/qif-import/qif-utils.scm b/src/scm/qif-import/qif-utils.scm
new file mode 100644
index 0000000000..b31981743e
--- /dev/null
+++ b/src/scm/qif-import/qif-utils.scm
@@ -0,0 +1,65 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; qif-utils.scm
+;;; string munging and other utility routines
+;;;
+;;; Bill Gribble 20 Feb 2000
+;;; $Id$
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(gnc:support "qif-utils.scm")
+
+(define (simple-filter pred list)
+ (let ((retval '()))
+ (map (lambda (elt)
+ (if (pred elt)
+ (set! retval (cons elt retval))))
+ list)
+ (reverse retval)))
+
+(define remove-trailing-space-rexp
+ (make-regexp "^(.*[^ ]+) *$"))
+
+(define remove-leading-space-rexp
+ (make-regexp "^ *([^ ].*)$"))
+
+(define (string-remove-trailing-space str)
+ (if (eq? (string-ref str (- (string-length str) 1)) #\cr)
+ (string-set! str (- (string-length str) 1) #\space))
+
+ (let ((match (regexp-exec remove-trailing-space-rexp str)))
+ (if match
+ (string-copy (match:substring match 1))
+ "")))
+
+(define (string-remove-leading-space str)
+ (let ((match (regexp-exec remove-leading-space-rexp str)))
+ (if match
+ (string-copy (match:substring match 1))
+ "")))
+
+(define (string-remove-char str char)
+ (let ((rexpstr (make-string 1 char)))
+ (regexp-substitute/global #f rexpstr str 'pre 'post)))
+
+(define (string-char-count str char)
+ (length (simple-filter (lambda (elt) (eq? elt char))
+ (string->list str))))
+
+(define (string-replace-char! str old new)
+ (let ((rexpstr (make-string 1 old))
+ (newstr (make-string 1 new)))
+ (regexp-substitute/global #f rexpstr str 'pre newstr 'post)))
+
+(define (string-split-on str char)
+ (let ((parts '())
+ (first-char #f))
+ (let loop ((last-char (string-length str)))
+ (set! first-char (string-rindex str char 0 last-char))
+ (if first-char
+ (begin
+ (set! parts (cons (substring str (+ 1 first-char) last-char)
+ parts))
+ (loop first-char))
+ (set! parts (cons (substring str 0 last-char) parts))))
+ parts))
+
diff --git a/src/scm/qif-import/simple-obj.scm b/src/scm/qif-import/simple-obj.scm
new file mode 100644
index 0000000000..04e45135d3
--- /dev/null
+++ b/src/scm/qif-import/simple-obj.scm
@@ -0,0 +1,101 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; simple-obj.scm
+;;; rudimentary "class" system for straight Scheme
+;;;
+;;; Bill Gribble 20 Feb 2000
+;;; $Id$
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(gnc:support "simple-obj.scm")
+
+;; this is an extremely rudimentary object system. Each object is a
+;; cons cell, where the car is a symbol with the class name and the
+;; cdr is a vector of the slots.
+;;
+;; the "class object" is an instance of simple-class which just has
+;; the name of the class and an alist of slot names to vector indices
+;; as its slots.
+;;
+;; by convention, I name class objects (defined with make-simple-class)
+;; with class-smybol 'class-name. For example,
+;;
+;; (define (make-simple-class 'test-class '(slot-1 slot-2)))
+;; (define t (make-simple-obj ))
+;; t ==> (test-class . #(#f #f))
+
+;; the 'simple-class' class.
+(define (make-simple-class class-symbol slot-names)
+ (let ((slots (make-vector 3))
+ (slot-hash (make-hash-table 11))
+ (slot-counter 0))
+ (vector-set! slots 0 class-symbol)
+ (vector-set! slots 1 slot-hash)
+ (vector-set! slots 2 slot-names)
+ (for-each
+ (lambda (elt)
+ (hash-set! slot-hash elt slot-counter)
+ (set! slot-counter (+ 1 slot-counter)))
+ slot-names)
+ (cons 'simple-class slots)))
+
+(define (simple-class? self)
+ (and (pair? self) (eq? (car self) 'simple-class)))
+
+(define (simple-obj-getter obj class slot)
+ (let ((slot-num (hash-ref (vector-ref (cdr class) 1) slot)))
+ (vector-ref (cdr obj) slot-num)))
+
+;; (if (and (pair? obj)
+;; (simple-class? class))
+;; (if (eq? (vector-ref (cdr class) 0) (car obj))
+;; (let ((slot-num-pair (assq slot (vector-ref (cdr class) 1))))
+;; (if slot-num-pair
+;; (if (vector? (cdr obj))
+;; (vector-ref (cdr obj) (cdr slot-num-pair))
+;; (error "simple-obj-getter: data field not a vector??"))
+;; (error "simple-obj-getter: no slot " slot " in class "
+;; class)))
+;; (error "simple-obj-getter: object " obj " is not of class "
+;; class))
+;; (error "simple-obj-getter: bad object/class " obj class)))
+
+(define (simple-obj-setter obj class slot value)
+ (let ((slot-num (hash-ref (vector-ref (cdr class) 1) slot)))
+ (vector-set! (cdr obj) slot-num value)))
+
+;; (if (and (pair? obj)
+;; (simple-class? class))
+;; (if (eq? (vector-ref (cdr class) 0) (car obj))
+;; (let ((slot-num-pair (assq slot (vector-ref (cdr class) 1))))
+;; (if slot-num-pair
+;; (if (vector? (cdr obj))
+;; (vector-set! (cdr obj) (cdr slot-num-pair) value)
+;; (error "simple-obj-setter: data field not a vector??"))
+;; (error "simple-obj-setter: no slot " slot " in class "
+;; class)))
+;; (error "simple-obj-setter: object " obj " is not of class "
+;; class))
+;; (error "simple-obj-setter: bad object/class " obj class)))
+
+
+(define (simple-obj-print obj class)
+ (display ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;") (newline)
+ (for-each
+ (lambda (slot)
+ (display " ")
+ (display slot)
+ (display " : ")
+ (display (simple-obj-getter obj class slot))
+ (newline))
+ (vector-ref (cdr class) 2)))
+
+(define (simple-obj-type obj)
+ (if (pair? obj)
+ (car obj)
+ #f))
+
+(define (make-simple-obj class)
+ (if (simple-class? class)
+ (cons (vector-ref (cdr class) 0)
+ (make-vector (length (vector-ref (cdr class) 2)) #f))))
+
diff --git a/src/top-level.h b/src/top-level.h
index 26ae9f5ce1..4f5748b8c8 100644
--- a/src/top-level.h
+++ b/src/top-level.h
@@ -40,6 +40,7 @@
#define HH_GPL "xacc-gpl.html"
#define HH_GLOBPREFS "xacc-globalprefs.html"
#define HH_ACCEDIT "xacc-accountedit.html"
+#define HH_QIFIMPORT "xacc-qif-import.html"
/** STRUCTS *********************************************************/