├── .gitignore
├── COPYING.LESSER
├── LICENSE
├── README.md
├── build.xml
├── build
├── built-jar.properties
└── classes
│ └── com
│ └── moneydance
│ └── modules
│ └── features
│ └── mdcsvimporter
│ ├── OtherActionsDialog.form-hide
│ ├── OtherActionsDialog.java-hide
│ └── import.png
├── dist
├── README.TXT
├── lib
│ ├── moneydance.jar
│ └── swing-layout-1.0.3.jar
└── mdcsvimporter.mxt
├── externals
├── junit
│ └── junit-4.5.jar
├── moneydance
│ ├── extadmin.jar
│ └── moneydance.jar
└── swing-layout
│ ├── swing-layout-1.0.3-doc.zip
│ ├── swing-layout-1.0.3-src.zip
│ └── swing-layout-1.0.3.jar
├── nbproject
├── build-impl.xml
├── genfiles.properties
├── private
│ ├── config.properties
│ ├── private.properties
│ └── private.xml
├── project.properties
└── project.xml
├── src
└── com
│ └── moneydance
│ └── modules
│ └── features
│ └── mdcsvimporter
│ ├── CSVData.java
│ ├── CSVReader.java
│ ├── CustomReaderData.java
│ ├── CustomReaderDialog.form
│ ├── CustomReaderDialog.java
│ ├── CustomTableCellRenderer.java
│ ├── CustomTableCellRenderer1.java
│ ├── DataField.java
│ ├── DateGuesser.java
│ ├── ImportDialog.form
│ ├── ImportDialog.java
│ ├── Main.java
│ ├── OtherActionsDialog.form-hide
│ ├── OtherActionsDialog.java-hide
│ ├── PreviewImportTblModel.java
│ ├── PreviewImportWin.form
│ ├── PreviewImportWin.java
│ ├── RegexReader.java
│ ├── SecureFileDeleter.java
│ ├── Settings.java
│ ├── StringUtils.java
│ ├── TransactionReader.java
│ ├── Util.java
│ ├── WinProps.java
│ ├── formats
│ └── CustomReader.java
│ ├── import.png
│ ├── meta_info.dict
│ └── package-info.java
└── test
└── com
└── moneydance
└── modules
└── features
└── mdcsvimporter
├── CSVDataTest.java
├── CSVReaderTest.java
├── CustomReaderDialogTest.java
├── DateGuesserTest.java
├── MainTest.java
├── aa-test.csv
└── dateGuesser.csv
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | ##*.jar
8 | ##*.war
9 | ##*.ear
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 | /build/
14 | nbproject/private/private.xml
15 | user.properties
16 |
--------------------------------------------------------------------------------
/COPYING.LESSER:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
167 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mdcsvimporter2015
2 | Moneydance plug-in to import transactions from CSV files. You can define, simply, on a screen, any number of 'Custom Readers' yourself, one for each Account file.
3 | - You define the order and fields that will be imported into MD, like Date, Amount, Description, Category, etc...
4 | - You can ignore fields, and specify that certain fields "Can Be Blank" (otherwise the cannot be blank).
5 | - You can test if a file parses properly,
6 | - and have it find and list files to import that are tied by file name to a Custom Reader.
7 | - You can do Regex parsing of csv files for tricky situations.
8 | - And importantly, it will not import transactions that you previously imported, by doing matching.
9 | - There is a How To doc you can download with an example of how to define your own custom readers.
10 |
11 | Latest version: only from here - version right in Money Dance is: 15.7.7 at this time, so if you want the latest, get it from here.
12 | Remove old version. Restart. Install via 'Add From File'.
13 |
14 | The plug-in is still considered BETA, however, it works well for people who have tried it.
15 |
16 | It is distributed under GNU LGPL. Among other things this means that it is free, but that the authors cannot take any responsibility for you using this code.
17 |
18 | ** Quick Usage:
19 | This is a top down window process. I might look at getting rid of 'Date Format', but when I have time.
20 | You have to define a reader first of all and tell it how to match filenames. An improvement I plan to make is to tell people if they do not have one and that they need to create one first.
21 |
22 | * 1.) So, what I do is download a new trans list csv file from my bank (XYZ)
23 | * 2.) in MD do, "Import File" (my extension)
24 | * 3.) I have say 6 defined so I pick the "File Reader" for my bank (XYZ).
25 | * 4.) I hit button "Find Import File(s) for this Reader."
26 | It populates "Select Import File:" dropdown with my list of files that match my reader "filename matcher". It also gives the number of files that match. Hopefully 1. If not I pick the file I want to import.
27 | * 5.) Hit "Preview Import" so it validates the importing transactions.
28 | * 6.) "Process" button becomes enabled. Hit it to do the import.
29 | - Done.
30 |
31 | ** How to Set Up 'Filename Matcher': (you match with a regex, regular expression, look that up)
32 | `Here are some examples:`
33 |
34 | `.*\.(csv|CSV) .* means match anything, then it has to end with a dot "\." and either csv or CSV`
35 | `(this|that) matches "this" or "that"`
36 |
37 | `download.*\.(csv|CSV) almost the same but it has to begin with "download" then anything, then .csv or .CSV`
38 |
39 | `for VISA: `
40 | `Transactions_\d+_\d+.csv matches Transactions_(1 or more numbers)_(1 or more numbers).csv`
41 | `like: Transactions_20170325_214425.csv`
42 |
43 | `for Discover: `
44 | `(DFS-|Discover).*\.(csv|CSV) matches DFS- or Discover, then anything, then .csv or .CSV`
45 | `like DFS-whatever.csv or Discover.1234.CSV`
46 |
47 | ** regex field parsing changed in v21 to hopefully give more flexibility. you need to use "named capture groups", as in:
48 |
49 | value = what string you want to pull out for the field value.
50 | rest = is left over line to parse next.
51 |
52 | ```java
53 | "?(?.*?)"?(?:[,]|\Z)(?(.*|\Z)) will handle basic csv parsing
54 |
55 | "(?.*?)"(?:[,]|\Z)(?(.*|\Z)) I had to do this to get amount within "123,456.78"
56 |
57 | "?(?.*?)"?(?:[,]|\Z) final list for "ignore rest"
58 |
59 | (?:CHECK[ ](?\d*)|(.{0,0}))(?.*) This actually adds an extra column.
60 |
61 | it will parse
62 | 04/10/2018,CHECK 0001234,,"($530.46)","$123"
63 | 04/04/2018,Insurance,PREM,"($467.30)","$5"
64 |
65 | into
66 | 04/10/2018,1234, , ,"($530.46)","$123"
67 | 04/04/2018, ,Insurance,PREM,"($467.30)","$5"
68 |
69 |
70 | How it parses a whole line:
71 |
72 | if you have this line:
73 | 01/14/2018,check 3000,My Store,$123.40,whatever
74 |
75 | it will parse like this:
76 | get value = 01/14/2018
77 | rest = check 3000,My Store,$123.40,whatever
78 |
79 | get value = check 3000
80 | rest = My Store,$123.40,whatever
81 |
82 | get value = My Store
83 | rest = $123.40,whatever
84 |
85 | get value = $123.40
86 | rest = whatever
87 |
88 | get value = whatever
89 | rest =
90 | ```
91 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Builds, tests, and runs the project mdcsvimporter.
12 |
13 |
14 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/build/built-jar.properties:
--------------------------------------------------------------------------------
1 | #Thu, 23 May 2024 19:57:09 -0400
2 |
3 |
4 | /net2/github/mdcsvimporter2015=
5 |
--------------------------------------------------------------------------------
/build/classes/com/moneydance/modules/features/mdcsvimporter/OtherActionsDialog.form-hide:
--------------------------------------------------------------------------------
1 |
2 |
3 |
53 |
--------------------------------------------------------------------------------
/build/classes/com/moneydance/modules/features/mdcsvimporter/OtherActionsDialog.java-hide:
--------------------------------------------------------------------------------
1 | package com.moneydance.modules.features.mdcsvimporter;
2 |
3 | import com.moneydance.apps.md.model.DateReminderPair;
4 | import com.moneydance.apps.md.model.Reminder;
5 | import com.moneydance.apps.md.model.ReminderSet;
6 | import com.moneydance.apps.md.model.RootAccount;
7 | import java.text.DateFormat;
8 | import java.text.SimpleDateFormat;
9 | import java.util.Calendar;
10 | import java.util.Iterator;
11 | import java.util.Vector;
12 |
13 | /**
14 | *
15 | * @author stan
16 | */
17 |
18 |
19 | public class OtherActionsDialog extends javax.swing.JDialog {
20 |
21 | ImportDialog parent = null;
22 | Main main = null;
23 |
24 | /**
25 | * Creates new form otherActionsDialog
26 | */
27 | //public otherActionsDialog(java.awt.Frame parent, boolean modal) {
28 | public OtherActionsDialog( ImportDialog parent, boolean modal) {
29 | super(parent, modal);
30 | this.parent = parent;
31 | //super(parent, modal);
32 | initComponents();
33 | }
34 |
35 | public void setMain( Main main )
36 | {
37 | this.main = main;
38 | }
39 |
40 | /**
41 | * This method is called from within the constructor to initialize the form.
42 | * WARNING: Do NOT modify this code. The content of this method is always
43 | * regenerated by the Form Editor.
44 | */
45 | @SuppressWarnings("unchecked")
46 | // //GEN-BEGIN:initComponents
47 | private void initComponents() {
48 |
49 | jButton1 = new javax.swing.JButton();
50 |
51 | setTitle("Other Actions");
52 |
53 | jButton1.setText("Delete Overdue Reminders");
54 | jButton1.addActionListener(new java.awt.event.ActionListener() {
55 | public void actionPerformed(java.awt.event.ActionEvent evt) {
56 | jButton1ActionPerformed(evt);
57 | }
58 | });
59 |
60 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
61 | getContentPane().setLayout(layout);
62 | layout.setHorizontalGroup(
63 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
64 | .addGroup(layout.createSequentialGroup()
65 | .addGap(31, 31, 31)
66 | .addComponent(jButton1)
67 | .addContainerGap(204, Short.MAX_VALUE))
68 | );
69 | layout.setVerticalGroup(
70 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
71 | .addGroup(layout.createSequentialGroup()
72 | .addGap(39, 39, 39)
73 | .addComponent(jButton1)
74 | .addContainerGap(238, Short.MAX_VALUE))
75 | );
76 |
77 | pack();
78 | }// //GEN-END:initComponents
79 |
80 | private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
81 | //java.util.Calendar today = new java.util.Calendar(
82 | DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
83 | Calendar cal = Calendar.getInstance();
84 | Util.logTerminal(dateFormat.format(cal.getTime()));
85 | RootAccount rootAccount = main.getRootAccount();
86 | ReminderSet reminderSet = rootAccount.getReminderSet();
87 | Vector remindersOverdueVec = reminderSet.getOverdueItems( cal );
88 |
89 | //get an Iterator object for Vector using iterator() method.
90 | Iterator itr = remindersOverdueVec.iterator();
91 |
92 | //use hasNext() and next() methods of Iterator to iterate through the elements
93 | Util.logTerminal("Iterating through Vector elements...");
94 | while(itr.hasNext())
95 | {
96 | DateReminderPair rem = (DateReminderPair) itr.next();
97 | //reminderSet.removeReminder( rem );
98 |
99 | Util.logTerminal( "rem.desc =" + rem. + "=" );
100 | }
101 | }//GEN-LAST:event_jButton1ActionPerformed
102 |
103 | /**
104 | * @param args the command line arguments
105 | */
106 | public static void main(String args[]) {
107 | /*
108 | * Set the Nimbus look and feel
109 | */
110 | //
111 | /*
112 | * If Nimbus (introduced in Java SE 6) is not available, stay with the
113 | * default look and feel. For details see
114 | * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
115 | */
116 | try {
117 | for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
118 | if ("Nimbus".equals(info.getName())) {
119 | javax.swing.UIManager.setLookAndFeel(info.getClassName());
120 | break;
121 | }
122 | }
123 | } catch (ClassNotFoundException ex) {
124 | java.util.logging.Logger.getLogger(OtherActionsDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
125 | } catch (InstantiationException ex) {
126 | java.util.logging.Logger.getLogger(OtherActionsDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
127 | } catch (IllegalAccessException ex) {
128 | java.util.logging.Logger.getLogger(OtherActionsDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
129 | } catch (javax.swing.UnsupportedLookAndFeelException ex) {
130 | java.util.logging.Logger.getLogger(OtherActionsDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
131 | }
132 | //
133 |
134 | /*
135 | * Create and display the dialog
136 | */
137 | java.awt.EventQueue.invokeLater(new Runnable() {
138 |
139 | public void run() {
140 | OtherActionsDialog dialog = new OtherActionsDialog(null, true);
141 | dialog.addWindowListener(new java.awt.event.WindowAdapter() {
142 |
143 | @Override
144 | public void windowClosing(java.awt.event.WindowEvent e) {
145 | System.exit(0);
146 | }
147 | });
148 | dialog.setVisible(true);
149 | }
150 | });
151 | }
152 | // Variables declaration - do not modify//GEN-BEGIN:variables
153 | private javax.swing.JButton jButton1;
154 | // End of variables declaration//GEN-END:variables
155 | }
156 |
--------------------------------------------------------------------------------
/build/classes/com/moneydance/modules/features/mdcsvimporter/import.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/build/classes/com/moneydance/modules/features/mdcsvimporter/import.png
--------------------------------------------------------------------------------
/dist/README.TXT:
--------------------------------------------------------------------------------
1 | ========================
2 | BUILD OUTPUT DESCRIPTION
3 | ========================
4 |
5 | When you build an Java application project that has a main class, the IDE
6 | automatically copies all of the JAR
7 | files on the projects classpath to your projects dist/lib folder. The IDE
8 | also adds each of the JAR files to the Class-Path element in the application
9 | JAR files manifest file (MANIFEST.MF).
10 |
11 | To run the project from the command line, go to the dist folder and
12 | type the following:
13 |
14 | java -jar "mdcsvimporter.mxt"
15 |
16 | To distribute this project, zip up the dist folder (including the lib folder)
17 | and distribute the ZIP file.
18 |
19 | Notes:
20 |
21 | * If two JAR files on the project classpath have the same name, only the first
22 | JAR file is copied to the lib folder.
23 | * Only JAR files are copied to the lib folder.
24 | If the classpath contains other types of files or folders, these files (folders)
25 | are not copied.
26 | * If a library on the projects classpath also has a Class-Path element
27 | specified in the manifest,the content of the Class-Path element has to be on
28 | the projects runtime path.
29 | * To set a main class in a standard Java project, right-click the project node
30 | in the Projects window and choose Properties. Then click Run and enter the
31 | class name in the Main Class field. Alternatively, you can manually type the
32 | class name in the manifest Main-Class element.
33 |
--------------------------------------------------------------------------------
/dist/lib/moneydance.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/dist/lib/moneydance.jar
--------------------------------------------------------------------------------
/dist/lib/swing-layout-1.0.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/dist/lib/swing-layout-1.0.3.jar
--------------------------------------------------------------------------------
/dist/mdcsvimporter.mxt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/dist/mdcsvimporter.mxt
--------------------------------------------------------------------------------
/externals/junit/junit-4.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/externals/junit/junit-4.5.jar
--------------------------------------------------------------------------------
/externals/moneydance/extadmin.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/externals/moneydance/extadmin.jar
--------------------------------------------------------------------------------
/externals/moneydance/moneydance.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/externals/moneydance/moneydance.jar
--------------------------------------------------------------------------------
/externals/swing-layout/swing-layout-1.0.3-doc.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/externals/swing-layout/swing-layout-1.0.3-doc.zip
--------------------------------------------------------------------------------
/externals/swing-layout/swing-layout-1.0.3-src.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/externals/swing-layout/swing-layout-1.0.3-src.zip
--------------------------------------------------------------------------------
/externals/swing-layout/swing-layout-1.0.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/externals/swing-layout/swing-layout-1.0.3.jar
--------------------------------------------------------------------------------
/nbproject/genfiles.properties:
--------------------------------------------------------------------------------
1 | build.xml.data.CRC32=f4bff2ce
2 | build.xml.script.CRC32=1ba685f9
3 | build.xml.stylesheet.CRC32=958a1d3e
4 | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
5 | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
6 | nbproject/build-impl.xml.data.CRC32=277518bf
7 | nbproject/build-impl.xml.script.CRC32=3d9ed023
8 | nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.102.0.48
9 |
--------------------------------------------------------------------------------
/nbproject/private/config.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/nbproject/private/config.properties
--------------------------------------------------------------------------------
/nbproject/private/private.properties:
--------------------------------------------------------------------------------
1 | compile.on.save=false
2 | do.depend=false
3 | do.jar=true
4 | do.jlink=false
5 | javac.debug=true
6 | javadoc.preview=true
7 | jlink.strip=false
8 | user.properties.file=/home/stan/.netbeans/13/build.properties
9 |
--------------------------------------------------------------------------------
/nbproject/private/private.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/nbproject/project.properties:
--------------------------------------------------------------------------------
1 | annotation.processing.enabled=true
2 | annotation.processing.enabled.in.editor=false
3 | annotation.processing.processors.list=
4 | annotation.processing.run.all.processors=true
5 | application.title=mdcsvimporter
6 | application.vendor=Stan Towianski
7 | auxiliary.org-netbeans-spi-editor-hints-projects.perProjectHintSettingsFile=nbproject/cfg_hints.xml
8 | build.classes.dir=${build.dir}/classes
9 | build.classes.excludes=**/*.java,**/*.form
10 | # This directory is removed when the project is cleaned:
11 | build.dir=build
12 | build.generated.dir=${build.dir}/generated
13 | build.generated.sources.dir=${build.dir}/generated-sources
14 | # Only compile against the classpath explicitly listed here:
15 | build.sysclasspath=ignore
16 | build.test.classes.dir=${build.dir}/test/classes
17 | build.test.results.dir=${build.dir}/test/results
18 | # Uncomment to specify the preferred debugger connection transport:
19 | #debug.transport=dt_socket
20 | debug.classpath=\
21 | ${run.classpath}
22 | debug.modulepath=\
23 | ${run.modulepath}
24 | debug.test.classpath=\
25 | ${run.test.classpath}
26 | debug.test.modulepath=\
27 | ${run.test.modulepath}
28 | # This directory is removed when the project is cleaned:
29 | dist.dir=dist
30 | dist.jar=${dist.dir}/mdcsvimporter.mxt
31 | dist.javadoc.dir=${dist.dir}/javadoc
32 | endorsed.classpath=
33 | excludes=
34 | file.reference.extadmin.jar=externals/moneydance/extadmin.jar
35 | file.reference.junit-4.5.jar=./externals/junit/junit-4.5.jar
36 | file.reference.moneydance.jar=externals/moneydance/moneydance.jar
37 | file.reference.swing-layout-1.0.3.jar=externals/swing-layout/swing-layout-1.0.3.jar
38 | includes=**
39 | jar.archive.disabled=${jnlp.enabled}
40 | jar.compress=true
41 | jar.index=${jnlp.enabled}
42 | javac.classpath=\
43 | ${file.reference.swing-layout-1.0.3.jar}:\
44 | ${file.reference.extadmin.jar}:\
45 | ${file.reference.moneydance.jar}
46 | # Space-separated list of extra javac options
47 | javac.compilerargs=
48 | javac.deprecation=false
49 | javac.external.vm=false
50 | javac.modulepath=
51 | javac.processormodulepath=
52 | javac.processorpath=\
53 | ${javac.classpath}
54 | javac.source=11
55 | javac.target=11
56 | javac.fork=true
57 | javac.test.classpath=\
58 | ${javac.classpath}:\
59 | ${build.classes.dir}:\
60 | ${file.reference.junit-4.5.jar}
61 | javac.test.modulepath=\
62 | ${javac.modulepath}
63 | javadoc.additionalparam=
64 | javadoc.author=false
65 | javadoc.encoding=${source.encoding}
66 | javadoc.html5=false
67 | javadoc.noindex=false
68 | javadoc.nonavbar=false
69 | javadoc.notree=false
70 | javadoc.private=false
71 | javadoc.splitindex=true
72 | javadoc.use=true
73 | javadoc.version=false
74 | javadoc.windowtitle=
75 | jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api"
76 | jlink.launcher=false
77 | jlink.launcher.name=mdcsvImporter2015
78 | jnlp.codebase.type=local
79 | jnlp.codebase.url="file:${dist.dir}"
80 | jnlp.descriptor=application
81 | jnlp.enabled=false
82 | jnlp.mixed.code=default
83 | jnlp.offline-allowed=false
84 | jnlp.signed=false
85 | jnlp.signing=
86 | jnlp.signing.alias=
87 | jnlp.signing.keystore=
88 | main.class=Moneydance
89 | # Optional override of default Application-Library-Allowable-Codebase attribute identifying the locations where your signed RIA is expected to be found.
90 | manifest.custom.application.library.allowable.codebase=
91 | # Optional override of default Caller-Allowable-Codebase attribute identifying the domains from which JavaScript code can make calls to your RIA without security prompts.
92 | manifest.custom.caller.allowable.codebase=
93 | # Optional override of default Codebase manifest attribute, use to prevent RIAs from being repurposed
94 | manifest.custom.codebase=
95 | # Optional override of default Permissions manifest attribute (supported values: sandbox, all-permissions)
96 | manifest.custom.permissions=
97 | meta.inf.dir=${src.dir}/META-INF
98 | mkdist.disabled=false
99 | platform.active=default_platform
100 | run.classpath=\
101 | ${javac.classpath}:\
102 | ${build.classes.dir}
103 | # Space-separated list of JVM arguments used when running the project
104 | # (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
105 | # or test-sys-prop.name=value to set system properties for unit tests):
106 | run.jvmargs=
107 | run.modulepath=\
108 | ${javac.modulepath}
109 | run.test.classpath=\
110 | ${javac.test.classpath}:\
111 | ${build.test.classes.dir}
112 | run.test.modulepath=\
113 | ${javac.test.modulepath}
114 | source.encoding=UTF-8
115 | src.dir=src
116 | test.src.dir=test
117 | project.license=LGPL
118 |
--------------------------------------------------------------------------------
/nbproject/project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | org.netbeans.modules.java.j2seproject
4 |
5 |
6 | mdcsvImporter2015
7 | 1.6.5
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/CSVData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This program is free software: you can redistribute it and/or modify
3 | * it under the terms of the Lesser GNU General Public License as published by
4 | * the Free Software Foundation, either version 3 of the License, or
5 | * (at your option) any later version.
6 | *
7 | * This program is distributed in the hope that it will be useful,
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | * GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License
13 | * along with this program. If not, see .
14 | */
15 | package com.moneydance.modules.features.mdcsvimporter;
16 |
17 | import java.io.IOException;
18 | import java.util.ArrayList;
19 |
20 | /**
21 | *
22 | * @author miki and Stan Towianski
23 | */
24 | public class CSVData
25 | {
26 | private String[][] data;
27 | private String[][] dataErr = { { "" } };
28 | private int currentLineIndex = -1;
29 | private int currentFieldIndex = -1;
30 |
31 | public CSVReader reader;
32 |
33 | public CSVData( CSVReader readerArg )
34 | {
35 | this.reader = readerArg;
36 | }
37 |
38 | public void reset()
39 | {
40 | currentLineIndex = -1;
41 | currentFieldIndex = -1;
42 | //reader.reset(); NOT SUPPORTED
43 | }
44 |
45 | public String[][] getData()
46 | {
47 | return data;
48 | }
49 |
50 | public String[][] getDataErr()
51 | {
52 | return dataErr;
53 | }
54 |
55 | public void parseIntoLines( CustomReaderData customReaderData )
56 | throws IOException
57 | {
58 | ArrayList line = new ArrayList();
59 | ArrayList file = new ArrayList();
60 | int fieldSeparator = customReaderData.getFieldSeparatorChar();
61 | int maxFoundCols = 0;
62 |
63 | if ( customReaderData != null )
64 | {
65 | reader.setFieldSeparator( fieldSeparator );
66 | }
67 |
68 | while ( reader.nextLine() )
69 | {
70 | for ( String s = reader.nextField(); s != null; s = reader.nextField() )
71 | {
72 | //Util.logConsole( " line.add string =" + s + "=" );
73 | line.add( s );
74 | }
75 |
76 | Util.logConsole( " line.size() =" + line.size() + "=\n" );
77 | if ( line.size() > maxFoundCols )
78 | {
79 | maxFoundCols = line.size();
80 | }
81 | String[] newLine = new String[ line.size() ];
82 | line.toArray( newLine );
83 | file.add( newLine );
84 | line.clear();
85 | }
86 |
87 | data = new String[file.size()][];
88 | file.toArray( data );
89 | Util.logConsole( " parsed lines total =" + file.size() + "= maxFoundCols =" + maxFoundCols );
90 | currentLineIndex = -1;
91 | currentFieldIndex = -1;
92 |
93 | int maxr = file.size();
94 | dataErr = new String[maxr][];
95 | //Util.logConsole( " reset maxr =" + maxr );
96 | for ( int r = 0; r < maxr; r++ )
97 | {
98 | int maxc = maxFoundCols + 1;
99 | String[] newLine = new String[ maxFoundCols + 1 ];
100 | for ( int c = 0; c < maxc; c++ )
101 | {
102 | //Util.logConsole( " reset r =" + r + " c =" + c );
103 | newLine[c] = "";
104 | }
105 | dataErr[r] = newLine;
106 | }
107 |
108 | // Util.logConsole( "PRINT OUT RESET dataErr" );
109 | // maxr = dataErr.length;
110 | // Util.logConsole( " reset maxr =" + maxr );
111 | // for ( int r = 0; r < maxr; r++ )
112 | // {
113 | // int maxc = dataErr[r].length;
114 | // Util.logConsole( " reset maxc =" + maxc );
115 | // for ( int c = 0; c < maxc; c++ )
116 | // {
117 | // Util.logConsole( "dataErr blank [" + r + "][" + c +"] =" + dataErr[r][c] );
118 | // }
119 | // }
120 | }
121 |
122 | public void reverseListRangeOrder( long beg, long end )
123 | {
124 | //Util.logConsole( "hasZeroFields() ---- currentLineIndex =" + currentLineIndex + "= data.length =" + data.length );
125 | Util.logConsole( "revLine beg: " + beg );
126 | Util.logConsole( "revLine end: " + end );
127 | if ( end <= beg )
128 | {
129 | return;
130 | }
131 |
132 | int begInt = (int)beg;
133 | int endInt = (int)end;
134 |
135 | String[] strArr = null;
136 |
137 | for ( ; endInt > begInt; endInt--, begInt++ )
138 | {
139 | strArr = data[ endInt ];
140 | data[ endInt ] = data[ begInt ];
141 | data[ begInt ] = strArr;
142 | }
143 | }
144 |
145 | public boolean nextLine()
146 | {
147 | if ( currentLineIndex < data.length )
148 | {
149 | ++currentLineIndex;
150 | currentFieldIndex = -1;
151 | }
152 |
153 | //Util.logConsole( "nextLine() ---- currentLineIndex =" + currentLineIndex + "= data.length =" + data.length + " ans =" + (currentLineIndex < data.length ? "true" : "false" ) );
154 | return currentLineIndex < data.length;
155 | }
156 |
157 | public boolean hasEnoughFieldsPerCurrentLine( int neededFields )
158 | {
159 | Util.logConsole( "fieldsPerCurrentLine() data[currentLineIndex].length + 1 =" + (data[currentLineIndex].length + 1) + " >= neededFields =" + neededFields );
160 | return data[currentLineIndex].length + 1 >= neededFields;
161 | }
162 |
163 | public boolean nextField()
164 | {
165 | //Util.logConsole( "nextField() ---- currentLineIndex =" + currentLineIndex + "= data.length =" + data.length );
166 | if ( currentLineIndex < 0 || currentLineIndex >= data.length )
167 | {
168 | //Util.logConsole( "nextField() ---- return false" );
169 | return false;
170 | }
171 |
172 | if ( currentFieldIndex < data[currentLineIndex].length )
173 | {
174 | ++currentFieldIndex;
175 | }
176 |
177 | //Util.logConsole( "nextField()2 ---- currentLineIndex =" + currentLineIndex + "= data.length =" + data.length + " ans =" + (currentFieldIndex < data[currentLineIndex].length ? "true" : "false" ) );
178 | return currentFieldIndex < data[currentLineIndex].length;
179 | }
180 |
181 | public boolean hasZeroFields()
182 | {
183 | //Util.logConsole( "hasZeroFields() ---- currentLineIndex =" + currentLineIndex + "= data.length =" + data.length );
184 | if ( currentLineIndex < 0 || currentLineIndex >= data.length )
185 | {
186 | //Util.logConsole( "hasZeroFields() ---- return false" );
187 | return false;
188 | }
189 |
190 | //Util.logConsole( "hasZeroFields()2 ---- currentLineIndex =" + currentLineIndex + "= data.length =" + data.length + " ans =" + (0 < data[currentLineIndex].length ? "true" : "false" ) );
191 | return 0 < data[currentLineIndex].length;
192 | }
193 |
194 | public String getField()
195 | {
196 | if ( currentLineIndex < 0 || currentLineIndex >= data.length )
197 | {
198 | return "";
199 | }
200 | if ( currentFieldIndex < 0 || currentFieldIndex >= data[currentLineIndex].length )
201 | {
202 | return "";
203 | }
204 |
205 | return data[currentLineIndex][currentFieldIndex];
206 | }
207 |
208 | public String getFieldErr()
209 | {
210 | //Util.logConsole( "getFieldErr current ptr [" + currentLineIndex + "][" + currentFieldIndex + "]" );
211 | if ( currentLineIndex < 0 || currentLineIndex >= dataErr.length )
212 | {
213 | return "";
214 | }
215 | if ( currentFieldIndex < 0 || currentFieldIndex >= dataErr[currentLineIndex].length )
216 | {
217 | return "";
218 | }
219 |
220 | return dataErr[currentLineIndex][currentFieldIndex];
221 | }
222 |
223 | public void setFieldErr( String errStr )
224 | {
225 | //Util.logConsole( "setFieldErr current ptr [" + currentLineIndex + "][" + currentFieldIndex + "]" );
226 | if ( currentLineIndex < 0 || currentLineIndex >= dataErr.length )
227 | {
228 | return;
229 | }
230 | if ( currentFieldIndex < 0 || currentFieldIndex >= dataErr[currentLineIndex].length )
231 | {
232 | return;
233 | }
234 |
235 | dataErr[currentLineIndex][currentFieldIndex] = errStr;
236 | }
237 |
238 | public String getFieldErr( int row, int col )
239 | {
240 | //Util.logConsole( "getFieldErr [" + row + "][" + col + "]" );
241 | if ( row < 0 || row >= dataErr.length )
242 | {
243 | return "";
244 | }
245 | if ( col < 0 || col >= dataErr[row].length )
246 | {
247 | return "";
248 | }
249 |
250 | return dataErr[row][col];
251 | }
252 |
253 | public void setFieldErr( int row, int col, String errStr )
254 | {
255 | //Util.logConsole( "setFieldErr [" + row + "][" + col + "]" );
256 | if ( row < 0 || row >= dataErr.length )
257 | {
258 | return;
259 | }
260 | if ( col < 0 || col >= dataErr[row].length )
261 | {
262 | return;
263 | }
264 |
265 | dataErr[row][col] = errStr;
266 | }
267 |
268 | public int getCurrentLineIndex()
269 | {
270 | return currentLineIndex;
271 | }
272 |
273 | public int getCurrentFieldIndex()
274 | {
275 | return currentFieldIndex;
276 | }
277 |
278 | public int getCurrentLineIndexWithinBounds()
279 | {
280 | if ( currentLineIndex < 0 )
281 | {
282 | return 0;
283 | }
284 | if ( currentLineIndex >= data.length )
285 | {
286 | return data.length - 1;
287 | }
288 | return currentLineIndex;
289 | }
290 |
291 | public int getCurrentFieldIndexWithinBounds()
292 | {
293 | if ( currentFieldIndex < 0 )
294 | {
295 | return 0;
296 | }
297 | if ( currentFieldIndex >= data[currentLineIndex].length )
298 | {
299 | return data[currentLineIndex].length - 1;
300 | }
301 | return currentFieldIndex;
302 | }
303 |
304 | public String printCurrentLine()
305 | {
306 | if ( currentLineIndex < 0 || currentLineIndex >= data.length )
307 | {
308 | Util.logConsoleAppend( "currentLineIndex out of range =" + currentLineIndex );
309 | return "";
310 | }
311 |
312 | Util.logConsoleAppend( "\n curr line >" );
313 | try {
314 | for ( int i = 0; i < data[currentLineIndex].length; i ++ )
315 | {
316 | if ( i > 0 )
317 | Util.logConsoleAppend( "|" );
318 | Util.logConsoleAppend( data[currentLineIndex][currentFieldIndex] );
319 | }
320 | }
321 | catch( Exception ex )
322 | {
323 | Util.logConsoleAppend( "*** Error in printCurrentLine at currentLineIndex =" + currentLineIndex + " currentFieldIndex =" + currentFieldIndex );
324 | }
325 | Util.logConsoleAppend( "< curr line." );
326 | return "";
327 | }
328 |
329 | public void printFile()
330 | {
331 | Util.logConsoleAppend( "\n ------------- PRINT FILE ---------------" );
332 | int maxRows = data.length;
333 | for ( int row = 0; row < maxRows; row++ )
334 | {
335 | Util.logConsoleAppend( "\n line [" + row + "] >" );
336 | for ( int fieldIndex = 0; fieldIndex < data[ row ].length; fieldIndex++ )
337 | {
338 | if ( fieldIndex > 0 )
339 | Util.logConsoleAppend( "|" );
340 | Util.logConsoleAppend( data[ row ][ fieldIndex ] );
341 | }
342 | Util.logConsoleAppend( "<" );
343 | }
344 | Util.logConsoleAppend( "\n ------------- END PRINT FILE ---------------" );
345 | }
346 |
347 | public CSVReader getReader() {
348 | return this.reader;
349 | }
350 |
351 | public void setReader(CSVReader reader) {
352 | this.reader = reader;
353 | }
354 |
355 | }
356 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/CSVReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This program is free software: you can redistribute it and/or modify
3 | * it under the terms of the GNU Lesser General Public License as published by
4 | * the Free Software Foundation, either version 3 of the License, or
5 | * (at your option) any later version.
6 | *
7 | * This program is distributed in the hope that it will be useful,
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | * GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License
13 | * along with this program. If not, see .
14 | */
15 | package com.moneydance.modules.features.mdcsvimporter;
16 |
17 | import java.io.IOException;
18 | import java.io.Reader;
19 |
20 | /**
21 | *
22 | * @author miki
23 | * modified by: Stan Towianski
24 | */
25 | public class CSVReader
26 | {
27 | /**
28 | * Carriage-Return
29 | */
30 | private static final int CR = 13;
31 | /**
32 | * Line-Feed
33 | */
34 | private static final int LF = 10;
35 | /**
36 | * Space
37 | */
38 | private static final int SPACE = 32;
39 | /**
40 | * Tab
41 | */
42 | private static final int TAB = 8;
43 | /**
44 | * Character used as a separator of individual fields.
45 | */
46 | private int fieldSeparator = ',';
47 | /**
48 | * Character used to start and end quoted sequences.
49 | */
50 | private int quoteCharacter = '"';
51 | /**
52 | * Character used to mark comment lines.
53 | */
54 | private int commentCharacter = '#';
55 | /**
56 | * Character used to mark pragma lines.
57 | */
58 | private int pragmaCharacter = '$';
59 | /**
60 | * True if the fields values should be trimmed before return. Equivalent of returning
61 | * nextField().trim().
62 | */
63 | private boolean trimFields = true;
64 | /**
65 | * True if empty lines should be skipped and not reported as data rows.
66 | */
67 | private boolean skipEmptyLines = false;
68 | /**
69 | * Reference to the reader.
70 | */
71 | private Reader reader;
72 | private CustomReaderData customReaderData;
73 | /**
74 | * The last char read from the reader. Also it stores the next character to be parsed.
75 | * <0 if end of file is reached. Code is currently written so that initializing
76 | * this to LF is the proper way to start parsing.
77 | */
78 | private int lastChar = LF;
79 | /**
80 | * Temporary buffer used to build field values before hey are returned.
81 | */
82 | private StringBuilder builder = new StringBuilder();
83 |
84 | public CSVReader()
85 | throws IOException
86 | {
87 | }
88 |
89 | /**
90 | * Constructs a new CSV file reader.
91 | * @param reader must be a valid reference to a reader providing CSV data to parse.
92 | * @throws java.io.IOException
93 | */
94 | public CSVReader( Reader reader, CustomReaderData customReaderData )
95 | throws IOException
96 | {
97 | if ( reader == null || !reader.ready() )
98 | {
99 | throw new IllegalArgumentException( "Reader must be a valid object." );
100 | }
101 | this.reader = reader;
102 | this.customReaderData = customReaderData;
103 | }
104 |
105 | /**
106 | * Closes the input reader and releases all object references. No other calls to this
107 | * instance should be made.
108 | * @throws java.io.IOException IOException might be thrown by referenced reader. See
109 | * Reader.close().
110 | */
111 | public void close()
112 | throws IOException
113 | {
114 | reader.close();
115 | reader = null;
116 | lastChar = -1;
117 | }
118 |
119 | // THIS IS NOT SUPPORTED
120 | // protected final void reset()
121 | // {
122 | // try {
123 | // this.reader.reset();
124 | // } catch (IOException ex) {
125 | // Logger.getLogger(CSVReader.class.getName()).log(Level.SEVERE, null, ex);
126 | // }
127 | // }
128 |
129 | /**
130 | * Used to move to the next line in the CSV file. It must be called before the each
131 | * line is processed, including before the very first line in the file. Any fields on
132 | * the current line that have not been retrieved, will be skipped.
133 | * @return true if the file contains another line.
134 | * @throws java.io.IOException if data cannot be read.
135 | */
136 | public boolean nextLine()
137 | throws IOException
138 | {
139 | while ( nextField() != null )
140 | {
141 | }
142 |
143 | // skip EOL; possible combinations are CR, CR+LF, LF
144 | if ( lastChar == CR )
145 | {
146 | lastChar = reader.read();
147 | }
148 | if ( lastChar == LF )
149 | {
150 | lastChar = reader.read();
151 | }
152 |
153 | // skip whitespace at the beginning
154 | if ( trimFields )
155 | {
156 | while ( isWhitespace( lastChar ) && !isEof( lastChar ) )
157 | {
158 | lastChar = reader.read();
159 | }
160 | }
161 |
162 | // skip comment lines
163 | if ( lastChar == commentCharacter )
164 | {
165 | do
166 | {
167 | lastChar = reader.read();
168 | } while ( !isEof( lastChar ) && lastChar != CR && lastChar != LF );
169 | return nextLine();
170 | }
171 |
172 | // handle pragma lines
173 | if ( lastChar == pragmaCharacter )
174 | {
175 | throw new IOException( "Pragma lines (starting with " + pragmaCharacter +
176 | ") are currently not supported. If you need to use this character surround " +
177 | "the field with quotes." );
178 | }
179 |
180 | // skip empty lines if so requested
181 | if ( skipEmptyLines && isEol( lastChar ) )
182 | {
183 | return nextLine();
184 | }
185 |
186 | // end of file
187 | if ( isEof( lastChar ) )
188 | {
189 | return false;
190 | }
191 | return true;
192 | }
193 |
194 | /**
195 | * Retrieves next field on the current line. If the field value was quoted, the quotes
196 | * are stripped. If the reader has been configured to trim fields, then all whitespaces
197 | * at the beginning and end of the field are stripped before returning.
198 | * @return field value or null if no more fields on the current line.
199 | * @throws java.io.IOException if data cannot be read.
200 | */
201 | public String nextField()
202 | throws IOException
203 | {
204 | //Util.logConsole( "nextField() fieldSeparator =" + (char)fieldSeparator + "=" );
205 |
206 | if ( isEol( lastChar ) || isEof( lastChar ) )
207 | {
208 | //Util.logConsole( "nextField() return null for Eol or Eof" );
209 | return null;
210 | }
211 |
212 | builder.setLength( 0 );
213 |
214 | if ( isQuote( lastChar ) )
215 | {
216 | // quoted field
217 | lastChar = reader.read();
218 | while ( !isQuote( lastChar ) && !isEol( lastChar ) && !isEof( lastChar ) )
219 | {
220 | builder.appendCodePoint( lastChar );
221 | lastChar = reader.read();
222 | //Util.logConsole( "lastChar =" + lastChar + "=" );
223 | }
224 | //Util.logConsole( "end field" );
225 | //Util.logConsole( "read field =" + builder.toString() + "=" );
226 |
227 | if ( !isQuote( lastChar ) )
228 | {
229 | throw new IOException( "Unexpected end of line." );
230 | }
231 |
232 | // skip quote
233 | lastChar = reader.read();
234 | // skip spaces
235 | while ( isWhitespace( lastChar ) )
236 | {
237 | lastChar = reader.read();
238 | }
239 | // and the next field separator
240 | if ( isFieldSeparator( lastChar ) )
241 | {
242 | lastChar = reader.read();
243 | }
244 | }
245 | else
246 | {
247 | // plain value
248 | while ( !isFieldSeparator( lastChar ) && !isEol( lastChar ) &&
249 | !isEof( lastChar ) )
250 | {
251 | builder.appendCodePoint( lastChar );
252 | lastChar = reader.read();
253 | }
254 | if ( isFieldSeparator( lastChar ) )
255 | {
256 | lastChar = reader.read();
257 | }
258 | }
259 |
260 | // TODO: skip separator
261 |
262 | if ( trimFields )
263 | {
264 | //Util.logConsole( "CSVReader return nextField trim =" + builder.toString().trim() + "=" );
265 | return builder.toString().trim();
266 | }
267 | else
268 | {
269 | //Util.logConsole( "CSVReader return nextField =" + builder.toString() + "=" );
270 | return builder.toString();
271 | }
272 | }
273 |
274 | public void setFieldSeparator( int fieldSeparator )
275 | {
276 | //Util.logConsole( "CSVReader.setFieldSeparator =" + (char)fieldSeparator + "=" );
277 | this.fieldSeparator = fieldSeparator;
278 | }
279 |
280 | public int getFieldSeparator()
281 | {
282 | return fieldSeparator;
283 | }
284 |
285 | public void setQuoteCharacter( int quoteCharacter )
286 | {
287 | this.quoteCharacter = quoteCharacter;
288 | }
289 |
290 | public int getQuoteCharacter()
291 | {
292 | return quoteCharacter;
293 | }
294 |
295 | public void setCommentCharacter( int commentCharacter )
296 | {
297 | this.commentCharacter = commentCharacter;
298 | }
299 |
300 | public int getCommentCharacter()
301 | {
302 | return commentCharacter;
303 | }
304 |
305 | public void setPragmaCharacter( int pragmaCharacter )
306 | {
307 | this.pragmaCharacter = pragmaCharacter;
308 | }
309 |
310 | public int getPragmaCharacter()
311 | {
312 | return pragmaCharacter;
313 | }
314 |
315 | public void setTrimFields( boolean trimFields )
316 | {
317 | this.trimFields = trimFields;
318 | }
319 |
320 | public boolean getTrimFields()
321 | {
322 | return trimFields;
323 | }
324 |
325 | public void setSkipEmptyLines( boolean skipEmptyLines )
326 | {
327 | this.skipEmptyLines = skipEmptyLines;
328 | }
329 |
330 | public boolean getSkipEmptyLines()
331 | {
332 | return skipEmptyLines;
333 | }
334 |
335 | protected final boolean isWhitespace( int ch )
336 | {
337 | return (ch == SPACE || ch == TAB) && !isQuote( ch ) && !isFieldSeparator( ch );
338 | }
339 |
340 | protected final boolean isQuote( int ch )
341 | {
342 | return ch == quoteCharacter;
343 | }
344 |
345 | protected final boolean isFieldSeparator( int ch )
346 | {
347 | return ch == fieldSeparator;
348 | }
349 |
350 | protected final boolean isEol( int ch )
351 | {
352 | return (ch == LF || ch == CR) && !isQuote( ch ) && !isFieldSeparator( ch );
353 | }
354 |
355 | protected final boolean isEof( int ch )
356 | {
357 | return ch < 0;
358 | }
359 | }
360 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/CustomReaderData.java:
--------------------------------------------------------------------------------
1 | package com.moneydance.modules.features.mdcsvimporter;
2 |
3 | import java.util.ArrayList;
4 |
5 | /**
6 | *
7 | * @author Stan Towianski
8 | */
9 |
10 |
11 | public class CustomReaderData {
12 |
13 | // ArrayList dataTypesList = new ArrayList( 10 );
14 | // ArrayList emptyFlagsList = new ArrayList( 10 );
15 | ArrayList regexsList = new ArrayList( 10 );
16 | ArrayList dataTypesList = new ArrayList( 10 );
17 | ArrayList emptyFlagsList = new ArrayList( 10 );
18 | //ArrayList dateFormatList = new ArrayList( 10 );
19 | int fieldSeparatorChar = ',';
20 | int headerLines = 0;
21 | int footerLines = 0;
22 | int amountCurrencyChar = '$';
23 | int amountDecimalSignChar = '.';
24 | int amountGroupingSeparatorChar = ',';
25 | String amountFormat = "#,###,###,##0.00;(#)";
26 | boolean importReverseOrderFlg = false;
27 | boolean useRegexFlag = false;
28 | String readerName = "";
29 | String dateFormatString = "MM/DD/YY";
30 | String fileEncoding = TransactionReader.DEFAULT_ENCODING;
31 | String filenameMatcher = ".*\\.[Cc][Ss][Vv]";
32 |
33 |
34 | public ArrayList getRegexsList() {
35 | return regexsList;
36 | }
37 |
38 | public String getRegexsListEncoded() {
39 | StringBuffer sbuf = new StringBuffer();
40 | sbuf.append( "[" );
41 | for( String str : regexsList )
42 | {
43 | sbuf.append( str );
44 | sbuf.append( "a" );
45 | }
46 | sbuf.append( "]" );
47 | return sbuf.toString();
48 | }
49 |
50 | public void setRegexsList(ArrayList regexsList) {
51 | this.regexsList = regexsList;
52 | }
53 |
54 | public String getRegexsListEle( int c ) {
55 | return regexsList.get( c );
56 | }
57 |
58 | public void setRegexsListEle( int c, String regex) {
59 | this.regexsList.set( c, regex );
60 | }
61 |
62 | public ArrayList getDataTypesList() {
63 | return dataTypesList;
64 | }
65 |
66 | public void setDataTypesList(ArrayList dataTypesList) {
67 | this.dataTypesList = dataTypesList;
68 | }
69 |
70 | public ArrayList getEmptyFlagsList() {
71 | return emptyFlagsList;
72 | }
73 |
74 | public void setEmptyFlagsList(ArrayList emptyFlagsList) {
75 | this.emptyFlagsList = emptyFlagsList;
76 | }
77 |
78 | public int getFieldSeparatorChar() {
79 | return fieldSeparatorChar;
80 | }
81 |
82 | public void setFieldSeparatorChar(int fieldSeparatorChar) {
83 | this.fieldSeparatorChar = fieldSeparatorChar;
84 | }
85 |
86 | public int getHeaderLines() {
87 | return headerLines;
88 | }
89 |
90 | public void setHeaderLines(int headerLines) {
91 | this.headerLines = headerLines;
92 | }
93 |
94 | public String getReaderName() {
95 | return readerName;
96 | }
97 |
98 | public void setReaderName(String readerName) {
99 | this.readerName = readerName;
100 | }
101 |
102 | public String getDateFormatString() {
103 | return dateFormatString;
104 | }
105 |
106 | public void setDateFormatString(String dateFormatString) {
107 | this.dateFormatString = dateFormatString;
108 | }
109 |
110 | public int getNumberOfCustomReaderFieldsUsed()
111 | {
112 | int c = 0;
113 | int max = dataTypesList.size();
114 |
115 | for ( ; c < max; c++ )
116 | {
117 | //Util.logConsole( "(String) dataTypesList.get(" + c + ") =" + (String) dataTypesList.get( c ) + "=" );
118 | if ( ((String) dataTypesList.get( c )).equalsIgnoreCase( "" ) )
119 | return c;
120 | }
121 | return c;
122 | }
123 |
124 | public int getFooterLines() {
125 | return footerLines;
126 | }
127 |
128 | public void setFooterLines(int footerLines) {
129 | this.footerLines = footerLines;
130 | }
131 |
132 | public int getAmountCurrencyChar() {
133 | return amountCurrencyChar;
134 | }
135 |
136 | public void setAmountCurrencyChar(int amountCurrencyChar) {
137 | this.amountCurrencyChar = amountCurrencyChar;
138 | }
139 |
140 | public int getAmountDecimalSignChar() {
141 | return amountDecimalSignChar;
142 | }
143 |
144 | public void setAmountDecimalSignChar(int amountDecimalSignChar) {
145 | this.amountDecimalSignChar = amountDecimalSignChar;
146 | }
147 |
148 | public String getAmountFormat() {
149 | return amountFormat;
150 | }
151 |
152 | public void setAmountFormat(String amountFormat) {
153 | this.amountFormat = amountFormat;
154 | }
155 |
156 | public int getAmountGroupingSeparatorChar() {
157 | return amountGroupingSeparatorChar;
158 | }
159 |
160 | public void setAmountGroupingSeparatorChar(int amountGroupingSeparatorChar) {
161 | this.amountGroupingSeparatorChar = amountGroupingSeparatorChar;
162 | }
163 |
164 | public boolean getImportReverseOrderFlg() {
165 | return importReverseOrderFlg;
166 | }
167 |
168 | public void setImportReverseOrderFlg(boolean importReverseOrderFlg) {
169 | this.importReverseOrderFlg = importReverseOrderFlg;
170 | }
171 |
172 | public boolean getUseRegexFlag() {
173 | return useRegexFlag;
174 | }
175 |
176 | public void setUseRegexFlag(boolean useRegexFlag) {
177 | this.useRegexFlag = useRegexFlag;
178 | }
179 |
180 | public String getFileEncoding() {
181 | return fileEncoding;
182 | }
183 |
184 | public void setFileEncoding(String fileEncoding) {
185 | this.fileEncoding = fileEncoding;
186 | }
187 |
188 | public String getFilenameMatcher() {
189 | return filenameMatcher;
190 | }
191 |
192 | public void setFilenameMatcher(String filenameMatcher) {
193 | this.filenameMatcher = filenameMatcher;
194 | }
195 |
196 | }
197 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/CustomTableCellRenderer.java:
--------------------------------------------------------------------------------
1 | package com.moneydance.modules.features.mdcsvimporter;
2 |
3 | import java.awt.Color;
4 | import java.awt.Component;
5 | import java.util.HashMap;
6 | import java.util.HashSet;
7 | import javax.swing.JLabel;
8 | import javax.swing.JTable;
9 | import javax.swing.table.DefaultTableCellRenderer;
10 |
11 | /**
12 | *
13 | * @author stan
14 | */
15 |
16 |
17 | public class CustomTableCellRenderer extends DefaultTableCellRenderer {
18 |
19 | int forRow = -1;
20 | int forCol = -1;
21 | HashMap errCells = new HashMap();
22 | HashSet rowSet = new HashSet();
23 | HashMap toolTip = new HashMap();
24 |
25 | public void setForRowCol( int row, int col, String cellToolTip )
26 | {
27 | forRow = row;
28 | forCol = col;
29 | if ( errCells.containsKey( row ) )
30 | {
31 | rowSet = errCells.get( row );
32 | }
33 | else
34 | {
35 | rowSet = new HashSet();
36 | errCells.put( row, rowSet );
37 | Util.logConsole( "ERROR RED Cell " + row + ", " + col );
38 | }
39 | rowSet.add( col );
40 | toolTip.put( row + "," + col, cellToolTip );
41 | }
42 |
43 | @Override
44 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col)
45 | {
46 | JLabel lbl = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
47 |
48 | if ( table.isRowSelected( row ) )
49 | {
50 | setForeground( Color.BLACK );
51 | }
52 |
53 | if ( errCells.containsKey( row ) )
54 | {
55 | rowSet = errCells.get( row );
56 | if ( rowSet.contains( col ) )
57 | {
58 | lbl.setBackground( Color.YELLOW );
59 | lbl.setToolTipText( toolTip.get( row + "," + col ) );
60 | return lbl;
61 | }
62 | }
63 |
64 | //lbl.setBackground( javax.swing.UIManager.getColor( "Table.dropCellBackground" ) );
65 | lbl.setBackground( Color.WHITE );
66 | lbl.setToolTipText( null );
67 | //Return the JLabel which renders the cell.
68 | return lbl;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/CustomTableCellRenderer1.java:
--------------------------------------------------------------------------------
1 | package com.moneydance.modules.features.mdcsvimporter;
2 |
3 | import java.awt.Color;
4 | import java.awt.Component;
5 | import java.util.HashMap;
6 | import java.util.HashSet;
7 | import javax.swing.JLabel;
8 | import javax.swing.JTable;
9 | import javax.swing.table.TableCellRenderer;
10 |
11 | /**
12 | *
13 | * @author stan
14 | */
15 |
16 |
17 | public class CustomTableCellRenderer1 extends JLabel implements TableCellRenderer {
18 |
19 | int forRow = -1;
20 | int forCol = -1;
21 | HashMap errCells = new HashMap();
22 | HashSet rowSet = new HashSet();
23 | HashMap toolTip = new HashMap();
24 |
25 | public void setForRowCol( int row, int col, String cellToolTip )
26 | {
27 | forRow = row;
28 | forCol = col;
29 | if ( errCells.containsKey( row ) )
30 | {
31 | rowSet = errCells.get( row );
32 | }
33 | else
34 | {
35 | rowSet = new HashSet();
36 | errCells.put( row, rowSet );
37 | Util.logConsole( "ADD ERROR YELLOW Cell " + row + ", " + col );
38 | }
39 | rowSet.add( col );
40 | toolTip.put( row + "," + col, cellToolTip );
41 | }
42 |
43 | @Override
44 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col)
45 | {
46 | if ( errCells.containsKey( row ) )
47 | {
48 | rowSet = errCells.get( row );
49 | if ( rowSet.contains( col ) )
50 | {
51 | setBackground( Color.YELLOW );
52 | setToolTipText( row + "," + col + toolTip.get( row + "," + col ) );
53 | return this;
54 | }
55 | }
56 |
57 | //lbl.setBackground( javax.swing.UIManager.getColor( "Table.dropCellBackground" ) );
58 | setBackground( Color.WHITE );
59 | //Return the JLabel which renders the cell.
60 | return this;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/DataField.java:
--------------------------------------------------------------------------------
1 | // Error reading included file Templates/Beans/../Licenses/license-LGPL.txt
2 | package com.moneydance.modules.features.mdcsvimporter;
3 |
4 | import java.beans.*;
5 | import java.io.Serializable;
6 |
7 | /**
8 | *
9 | * @author stowians
10 | */
11 | public class DataField implements Serializable {
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/DateGuesser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This program is free software: you can redistribute it and/or modify
3 | * it under the terms of the GNU Lesser General Public License as published by
4 | * the Free Software Foundation, either version 3 of the License, or
5 | * (at your option) any later version.
6 | *
7 | * This program is distributed in the hope that it will be useful,
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | * GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License
13 | * along with this program. If not, see .
14 | */
15 | package com.moneydance.modules.features.mdcsvimporter;
16 |
17 | import java.io.IOException;
18 | import java.io.Reader;
19 | import java.io.StringReader;
20 | import java.util.Comparator;
21 | import java.util.HashMap;
22 | import java.util.Map;
23 | import java.util.SortedMap;
24 | import java.util.TreeMap;
25 |
26 | /**
27 | *
28 | * @author miki
29 | */
30 | public class DateGuesser
31 | {
32 | private static final int EOF = -1;
33 | private static final String D = "D";
34 | private static final String DD = "DD";
35 | private static final String M = "M";
36 | private static final String MM = "MM";
37 | private static final String YY = "YY";
38 | private static final String YYYY = "YYYY";
39 | private Map results = new HashMap();
40 | private int datesDetected = 0;
41 | private String[] possibleFormats;
42 | private double bestFormatProbability;
43 | private StringBuilder field1 = new StringBuilder();
44 | private int field1Value;
45 | private String field1Format;
46 | private int separator1;
47 | private StringBuilder field2 = new StringBuilder();
48 | private int field2Value;
49 | private String field2Format;
50 | private int separator2;
51 | private StringBuilder field3 = new StringBuilder();
52 | private int field3Value;
53 | private String field3Format;
54 | private StringBuilder format = new StringBuilder();
55 |
56 | public void checkDateString( String date )
57 | {
58 | try
59 | {
60 | date = date.trim();
61 | StringReader reader = new StringReader( date );
62 |
63 | separator1 = parseField( reader, field1 );
64 | separator2 = parseField( reader, field2 );
65 | int eof = parseField( reader, field3 );
66 |
67 | if ( field1.length() == 0 || field2.length() == 0 || field3.length() == 0 ||
68 | !isEof( eof ) )
69 | {
70 | return;
71 | }
72 |
73 | field1Value = Integer.parseInt( field1.toString() );
74 | field2Value = Integer.parseInt( field2.toString() );
75 | field3Value = Integer.parseInt( field3.toString() );
76 |
77 | if ( checkPossibleFormats() )
78 | {
79 | ++datesDetected;
80 | }
81 | }
82 | catch ( Exception x )
83 | {
84 | // ignore errors, simply means this is probably not a date string
85 | }
86 | }
87 |
88 | private boolean checkPossibleFormats()
89 | {
90 | boolean retVal = false;
91 |
92 | // check if its possible to be a day
93 | if ( field1Value >= 1 && field1Value <= 31 && field1.length() <= 2 )
94 | {
95 | if ( field1.length() == 1 )
96 | {
97 | field1Format = D;
98 | retVal |= checkPossibleFormats2();
99 | }
100 | else
101 | {
102 | field1Format = DD;
103 | retVal |= checkPossibleFormats2();
104 | if ( field1Value < 10 ) // >= 10 )
105 | {
106 | field1Format = D;
107 | retVal |= checkPossibleFormats2();
108 | }
109 | }
110 | }
111 |
112 | // check if its possible to be a month
113 | if ( field1Value >= 1 && field1Value <= 12 && field1.length() <= 2 )
114 | {
115 | if ( field1.length() == 1 )
116 | {
117 | field1Format = M;
118 | retVal |= checkPossibleFormats2();
119 | }
120 | else
121 | {
122 | field1Format = MM;
123 | retVal |= checkPossibleFormats2();
124 | if ( field1Value < 10 ) // >= 10 )
125 | {
126 | field1Format = M;
127 | retVal |= checkPossibleFormats2();
128 | }
129 | }
130 | }
131 |
132 | // check if its possible to be a year
133 | if ( field1.length() == 2 )
134 | {
135 | field1Format = YY;
136 | retVal |= checkPossibleFormats2();
137 | }
138 | else if ( field1.length() == 4 )
139 | {
140 | field1Format = YYYY;
141 | retVal |= checkPossibleFormats2();
142 | }
143 |
144 | return retVal;
145 | }
146 |
147 | private boolean checkPossibleFormats2()
148 | {
149 | boolean retVal = false;
150 |
151 | // check if its possible to be a day
152 | if ( field1Format != D && field1Format != DD )
153 | {
154 | if ( field2Value >= 1 && field2Value <= 31 && field2.length() <= 2 )
155 | {
156 | if ( field2.length() == 1 )
157 | {
158 | field2Format = D;
159 | retVal |= checkPossibleFormats3();
160 | }
161 | else
162 | {
163 | field2Format = DD;
164 | retVal |= checkPossibleFormats3();
165 | if ( field2Value < 10 ) // >= 10 )
166 | {
167 | field2Format = D;
168 | retVal |= checkPossibleFormats3();
169 | }
170 | }
171 | }
172 | }
173 |
174 | // check if its possible to be a month
175 | if ( field1Format != M && field1Format != MM )
176 | {
177 | if ( field2Value >= 1 && field2Value <= 12 && field2.length() <= 2 )
178 | {
179 | if ( field2.length() == 1 )
180 | {
181 | field2Format = M;
182 | retVal |= checkPossibleFormats3();
183 | }
184 | else
185 | {
186 | field2Format = MM;
187 | retVal |= checkPossibleFormats3();
188 | if ( field2Value < 10 ) // >= 10 )
189 | {
190 | field2Format = M;
191 | retVal |= checkPossibleFormats3();
192 | }
193 | }
194 | }
195 | }
196 |
197 | // check if its possible to be a year
198 | if ( field1Format != YY && field1Format != YYYY )
199 | {
200 | if ( field2.length() == 2 )
201 | {
202 | field2Format = YY;
203 | retVal |= checkPossibleFormats3();
204 | }
205 | else if ( field2.length() == 4 )
206 | {
207 | field2Format = YYYY;
208 | retVal |= checkPossibleFormats3();
209 | }
210 | }
211 |
212 | return retVal;
213 | }
214 |
215 | private boolean checkPossibleFormats3()
216 | {
217 | boolean retVal = false;
218 |
219 | // check if its possible to be a day
220 | if ( field1Format != D && field1Format != DD && field2Format != D && field2Format !=
221 | DD )
222 | {
223 | if ( field3Value >= 1 && field3Value <= 31 && field3.length() <= 2 )
224 | {
225 | if ( field3.length() == 1 )
226 | {
227 | field3Format = D;
228 | retVal = true;
229 | registerFormat();
230 | }
231 | else
232 | {
233 | field3Format = DD;
234 | retVal = true;
235 | registerFormat();
236 | if ( field3Value < 10 ) // >= 10 )
237 | {
238 | field3Format = D;
239 | registerFormat();
240 | }
241 | }
242 | }
243 | }
244 |
245 | // check if its possible to be a month
246 | if ( field1Format != M && field1Format != MM && field2Format != M && field2Format !=
247 | MM )
248 | {
249 | if ( field3Value >= 1 && field3Value <= 12 && field3.length() <= 2 )
250 | {
251 | if ( field3.length() == 1 )
252 | {
253 | field3Format = M;
254 | retVal = true;
255 | registerFormat();
256 | }
257 | else
258 | {
259 | field3Format = MM;
260 | retVal = true;
261 | registerFormat();
262 | if ( field3Value < 10 ) // >= 10 )
263 | {
264 | field3Format = M;
265 | registerFormat();
266 | }
267 | }
268 | }
269 | }
270 |
271 | // check if its possible to be a year
272 | if ( field1Format != YY && field1Format != YYYY && field2Format != YY &&
273 | field2Format != YYYY )
274 | {
275 | if ( field3.length() == 2 )
276 | {
277 | field3Format = YY;
278 | retVal = true;
279 | registerFormat();
280 | }
281 | else if ( field3.length() == 4 )
282 | {
283 | field3Format = YYYY;
284 | retVal = true;
285 | registerFormat();
286 | }
287 | }
288 |
289 | return retVal;
290 | }
291 |
292 | private void registerFormat()
293 | {
294 | clearResults();
295 |
296 | format.setLength( 0 );
297 | format.append( field1Format );
298 | format.appendCodePoint( separator1 );
299 | format.append( field2Format );
300 | format.appendCodePoint( separator2 );
301 | format.append( field3Format );
302 |
303 | String key = format.toString();
304 |
305 | Integer count = results.get( key );
306 | if ( count == null )
307 | {
308 | Util.logConsole( "saving format key =" + key + "= count =" + 1 );
309 | results.put( key, 1 );
310 | }
311 | else
312 | {
313 | Util.logConsole( "saving format key =" + key + "= count =" + (count + 1) );
314 | results.put( key, count + 1 );
315 | }
316 | }
317 |
318 | public String getBestFormat()
319 | {
320 | calculateResults();
321 |
322 | if ( possibleFormats.length > 0 )
323 | {
324 | return possibleFormats[0];
325 | }
326 | else
327 | {
328 | return null;
329 | }
330 | }
331 |
332 | public double getBestFormatProbability()
333 | {
334 | calculateResults();
335 |
336 | return bestFormatProbability;
337 | }
338 |
339 | public String[] getPossibleFormats()
340 | {
341 | calculateResults();
342 |
343 | return possibleFormats;
344 | }
345 |
346 | private void clearResults()
347 | {
348 | possibleFormats = null;
349 | bestFormatProbability = 0;
350 | }
351 |
352 | private void calculateResults()
353 | {
354 | if ( possibleFormats != null )
355 | { // are results already calculated?
356 | return;
357 | }
358 |
359 | SortedMap sortedResults = new TreeMap(
360 | new Comparator()
361 | {
362 | public int compare( Integer o1, Integer o2 )
363 | {
364 | return o2 - o1;
365 | }
366 | } );
367 |
368 | for ( Map.Entry entry : results.entrySet() )
369 | {
370 | Util.logConsole( "results before sort entry.getValue() =" + entry.getValue() + "= entry.getKey() =" + entry.getKey() + "=" );
371 | sortedResults.put( entry.getValue(), entry.getKey() );
372 | }
373 |
374 | possibleFormats = new String[sortedResults.size()];
375 | sortedResults.values().toArray( possibleFormats );
376 |
377 | for ( String tmp : possibleFormats )
378 | {
379 | Util.logConsole( "possibleFormats =" + tmp + "=" );
380 | }
381 |
382 | if ( datesDetected == 0 )
383 | {
384 | bestFormatProbability = 0;
385 | }
386 | else
387 | {
388 | bestFormatProbability = sortedResults.firstKey().doubleValue() /
389 | (double) datesDetected;
390 | }
391 | }
392 |
393 | protected static final int parseField( Reader reader, StringBuilder fieldValue )
394 | throws IOException
395 | {
396 | fieldValue.setLength( 0 );
397 |
398 | if ( !reader.ready() )
399 | {
400 | return -1;
401 | }
402 |
403 | int ch;
404 | for ( ch = reader.read(); isDigit( ch ); ch = reader.read() )
405 | {
406 | fieldValue.appendCodePoint( ch );
407 | }
408 |
409 | return ch;
410 | }
411 |
412 | private static final boolean isDigit( int ch )
413 | {
414 | return ch >= '0' && ch <= '9';
415 | }
416 |
417 | private static final boolean isEof( int ch )
418 | {
419 | return ch == EOF;
420 | }
421 | }
422 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/Main.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This program is free software: you can redistribute it and/or modify
3 | * it under the terms of the GNU Lesser General Public License as published by
4 | * the Free Software Foundation, either version 3 of the License, or
5 | * (at your option) any later version.
6 | *
7 | * This program is distributed in the hope that it will be useful,
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | * GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License
13 | * along with this program. If not, see .
14 | */
15 |
16 | // Fixed by Stuart Beesley - April 2023
17 | // Build: 1000 - Upgraded/fixed/enhanced by Stuart Beesley
18 | // Fixed filenames check when null in ImportDialog.java
19 | // Tweaked with some more up-to-date MD API calls
20 | // Fixed calls to StringUtils for MD2023...
21 | // Fixed calls to JFileChooser for Mac; also so that FileDialog gets called instead...
22 | // Fixed other NPEs found...
23 | // Fixed minimum screen width on main screen so that the ... file browser button is not hidden
24 | // Changed extension build version to 1000
25 | // Fixed another NPE on main dialog screen...
26 | // Build: 1001 - Fixed display issue on Windows. Selected filename not appearing in the GUI (caused Exception).
27 |
28 | package com.moneydance.modules.features.mdcsvimporter;
29 |
30 | import com.infinitekind.moneydance.model.AccountBook;
31 | import com.moneydance.apps.md.controller.FeatureModule;
32 | import com.moneydance.apps.md.controller.FeatureModuleContext;
33 | import com.moneydance.apps.md.view.gui.MoneydanceGUI;
34 |
35 | import java.awt.Dimension;
36 | import java.awt.Image;
37 | import java.io.IOException;
38 | import java.util.ArrayList;
39 | import java.util.HashMap;
40 | import java.util.StringTokenizer;
41 | import javax.imageio.ImageIO;
42 | import javax.swing.JFrame;
43 |
44 | public class Main extends FeatureModule
45 | {
46 |
47 | public static boolean DEBUG = false;
48 |
49 | public static final int MIN_MD_BUILD = 1372; // Runs on MD2015.8(1372) onwards...
50 | public static final String EXTN_ID = "mdcsvimporter2015";
51 | public static final String EXTN_NAME = "CSV Importer";
52 |
53 | public static com.moneydance.apps.md.controller.Main MD_REF;
54 |
55 | // private static final int VERSION = 23;
56 | // protected static final String VERSION_STRING = " " + VERSION + " for MD2022";
57 | // private static final String NAME = "CSV Importer";
58 | // private static final String VENDOR = "Stan Towianski";
59 | // private static final String URL = "https://github.com/stant/mdcsvimporter2015";
60 | // private static final String DESCRIPTION =
61 | // "Let's you create configs for say: Discover card, VISA, your private bank, etc... " +
62 | // "You denote columns like: -Payment-, -Deposit-, date, amount, memo, etc... " +
63 | // "It can test your file, giving you a list of all the readers that can handle your file. " +
64 | // "Importing does matching to skip duplicate entries."
65 | // ;
66 |
67 | // private static Image image;
68 |
69 | private ArrayList errCodeList = null;
70 |
71 | // {
72 | // try
73 | // {
74 | // image = ImageIO.read( Main.class.getResourceAsStream( "import.png" ) );
75 | // }
76 | // catch ( IOException x )
77 | // {
78 | // // ignore error; nothing we can do about it
79 | // }
80 | // }
81 |
82 | public Main()
83 | {
84 | }
85 |
86 | /*
87 | public static void main(String args[])
88 | {
89 | String amt = "($157.86)";
90 | Util.logTerminal( "converted amount =" + amt.replaceAll( "\\((.*)\\)", "-$1" ) );
91 |
92 | amt = "$123.86";
93 | Util.logTerminal( "converted amount =" + amt.replaceAll( "\\((.*)\\)", "-$1" ) );
94 | }
95 | */
96 |
97 | @Override
98 | public void init() {
99 | FeatureModuleContext context = getContext();
100 | if (context == null) {
101 | Util.logConsole("*** Error: got context == null");
102 | return;
103 | }
104 |
105 | MD_REF = (com.moneydance.apps.md.controller.Main) context;
106 |
107 | if (context.getBuild() < MIN_MD_BUILD) {
108 | Util.logConsole("ALERT: This extension/widget is only supported on MD2015.8(1372) onwards... Quitting.....");
109 | return;
110 | }
111 |
112 | context.registerFeature(this, "import", null, EXTN_NAME);
113 | Util.logConsole(EXTN_NAME + " >> Initialised... Build:" + getBuild());
114 | }
115 |
116 | AccountBook getAccountBook()
117 | {
118 | FeatureModuleContext context = getContext();
119 | return context.getCurrentAccountBook();
120 | }
121 |
122 | public static com.moneydance.apps.md.controller.Main getMDMain() {
123 | return MD_REF;
124 | }
125 |
126 | public static MoneydanceGUI getMDGUI() {
127 | return (MoneydanceGUI) getMDMain().getUI();
128 | }
129 |
130 | public FeatureModuleContext getMainContext()
131 | {
132 | return getContext();
133 | }
134 |
135 | JFrame getMoneydanceWindow() { return getMDGUI().getFirstMainFrame();}
136 |
137 | // JFrame getMoneydanceWindow()
138 | // {
139 | // return getMDGUI().getFirstMainFrame();
140 | //
141 | // // Using undocumented feature. This way our windows and dialogs can have a parent,
142 | // // and behave more conformingly. Alternative is just returning null. Effects should
143 | // // be minor visual inconsistencies.
144 | //
145 | // FeatureModuleContext context = getContext();
146 | // com.moneydance.apps.md.controller.Main main =
147 | // (com.moneydance.apps.md.controller.Main) context;
148 | // if ( main == null )
149 | // {
150 | // return null;
151 | // }
152 | // com.moneydance.apps.md.view.gui.MoneydanceGUI gui =
153 | // (com.moneydance.apps.md.view.gui.MoneydanceGUI) main.getUI();
154 | // if ( gui == null )
155 | // {
156 | // return null;
157 | // }
158 | // return gui.getTopLevelFrame();
159 | // }
160 |
161 | @Override
162 | public String getName()
163 | {
164 | return EXTN_NAME;
165 | }
166 |
167 | // @Override
168 | // public int getBuild()
169 | // {
170 | // return VERSION;
171 | // }
172 |
173 | // @Override
174 | // public String getDescription()
175 | // {
176 | // return DESCRIPTION;
177 | // }
178 |
179 | @Override
180 | public void invoke( String uri )
181 | {
182 | /*
183 | uri = ImportDialog.RUN_ARGS_FILE + "=/home/aaa/Downloads/aa-test.csv"
184 | + "&fileformat=Discover Card"
185 | + "&importaccount=IMPORT BANK"
186 | + "&deletecsvfileflag"
187 | + "&importtype=online"
188 | ;
189 | */
190 |
191 | /*
192 | argsHM.put( "file", "/home/aaa/Downloads/aa-test.csv" );
193 | argsHM.put( "fileformat", "Discover Card" );
194 | //argsHM.put( "dateformat", "MM/DD/YYYY" );
195 | argsHM.put( "importaccount", "IMPORT BANK" );
196 | argsHM.put( "importtype", "online" );
197 | argsHM.put( "deletecsvfileflag", null );
198 | */
199 |
200 | Util.logConsole("Received .invoke() command: '" + uri + "'");
201 | StringTokenizer tokenizer = new StringTokenizer( uri, "&" );
202 | HashMap argsHM = new HashMap();
203 |
204 | //filename="file"&fileformat="file format"&dateformat="date format"&importaccount="my account"
205 | //deletecsvfileflag&importtype="online|regular"
206 |
207 | //int count = tokenizer.countTokens();
208 | //String url = count + " tokens(";
209 | // Util.logConsole( "uri string =" + uri + "=" );
210 |
211 | while ( tokenizer.hasMoreTokens() )
212 | {
213 | //url = url.concat( tokenizer.nextToken() );
214 | String [] pcs = tokenizer.nextToken().split( "=" );
215 | Util.logConsole( "arg token [0] =" + pcs[0] + "= token[1] =" + (pcs.length < 2 ? "" : pcs[1]) + "=" );
216 | if ( pcs.length > 1 )
217 | {
218 | if ( pcs[1].startsWith( "\"" ) )
219 | {
220 | argsHM.put( pcs[0].toLowerCase(), pcs[1].substring( 1, pcs[1].length() - 1 ) );
221 | Util.logConsole("arg key =" + pcs[0].toLowerCase() + "= value =" + pcs[1].substring( 1, pcs[1].length() - 1 ) + "=" );
222 | }
223 | else
224 | {
225 | argsHM.put( pcs[0].toLowerCase(), pcs[1] );
226 | Util.logConsole("arg key =" + pcs[0].toLowerCase() + "= value =" + pcs[1] + "=" );
227 | }
228 | }
229 | else
230 | {
231 | argsHM.put( pcs[0].toLowerCase(), null );
232 | Util.logConsole("arg key =" + pcs[0].toLowerCase() + "= value =" + null + "=" );
233 | }
234 | }
235 | argsHM.remove( "import" ); // This seems to be passed in and I do not know why.
236 |
237 | ImportDialog dialog = new ImportDialog( this, argsHM );
238 |
239 | //------- This is for passing in arguments to do auto processing. -------
240 | errCodeList = dialog.processRunArguments();
241 |
242 | //dialog.setLocationRelativeTo( null );
243 |
244 | if ( ! dialog.isAutoProcessedAFile() && ! argsHM.containsKey( "junitflag" ) )
245 | {
246 | dialog.pack();
247 | WinProps winProps = Settings.getWinProps( true, "winprops.ImportDialog" );
248 | dialog.setLocation( winProps.getAtX(), winProps.getAtY() );
249 | dialog.setSize( new Dimension( winProps.getWidth(), winProps.getHeight() ) );
250 | //Util.logConsole( "winProps.getWidth() =" + winProps.getWidth() + "=" );
251 | //Util.logConsole( "winProps.getHeight() =" + winProps.getHeight() + "=" );
252 |
253 | dialog.setVisible( true );
254 | }
255 | }
256 |
257 | public ArrayList getErrCodeList() {
258 | return errCodeList;
259 | }
260 |
261 | // @Override
262 | // public String getVendorURL()
263 | // {
264 | // return URL;
265 | // }
266 |
267 | // @Override
268 | // public String getVendor()
269 | // {
270 | // return VENDOR;
271 | // }
272 |
273 | // @Override
274 | // public Image getIconImage()
275 | // {
276 | // return image;
277 | // }
278 |
279 | }
280 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/OtherActionsDialog.form-hide:
--------------------------------------------------------------------------------
1 |
2 |
3 |
53 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/OtherActionsDialog.java-hide:
--------------------------------------------------------------------------------
1 | package com.moneydance.modules.features.mdcsvimporter;
2 |
3 | import com.moneydance.apps.md.model.DateReminderPair;
4 | import com.moneydance.apps.md.model.Reminder;
5 | import com.moneydance.apps.md.model.ReminderSet;
6 | import com.moneydance.apps.md.model.RootAccount;
7 | import java.text.DateFormat;
8 | import java.text.SimpleDateFormat;
9 | import java.util.Calendar;
10 | import java.util.Iterator;
11 | import java.util.Vector;
12 |
13 | /**
14 | *
15 | * @author stan
16 | */
17 |
18 |
19 | public class OtherActionsDialog extends javax.swing.JDialog {
20 |
21 | ImportDialog parent = null;
22 | Main main = null;
23 |
24 | /**
25 | * Creates new form otherActionsDialog
26 | */
27 | //public otherActionsDialog(java.awt.Frame parent, boolean modal) {
28 | public OtherActionsDialog( ImportDialog parent, boolean modal) {
29 | super(parent, modal);
30 | this.parent = parent;
31 | //super(parent, modal);
32 | initComponents();
33 | }
34 |
35 | public void setMain( Main main )
36 | {
37 | this.main = main;
38 | }
39 |
40 | /**
41 | * This method is called from within the constructor to initialize the form.
42 | * WARNING: Do NOT modify this code. The content of this method is always
43 | * regenerated by the Form Editor.
44 | */
45 | @SuppressWarnings("unchecked")
46 | // //GEN-BEGIN:initComponents
47 | private void initComponents() {
48 |
49 | jButton1 = new javax.swing.JButton();
50 |
51 | setTitle("Other Actions");
52 |
53 | jButton1.setText("Delete Overdue Reminders");
54 | jButton1.addActionListener(new java.awt.event.ActionListener() {
55 | public void actionPerformed(java.awt.event.ActionEvent evt) {
56 | jButton1ActionPerformed(evt);
57 | }
58 | });
59 |
60 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
61 | getContentPane().setLayout(layout);
62 | layout.setHorizontalGroup(
63 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
64 | .addGroup(layout.createSequentialGroup()
65 | .addGap(31, 31, 31)
66 | .addComponent(jButton1)
67 | .addContainerGap(204, Short.MAX_VALUE))
68 | );
69 | layout.setVerticalGroup(
70 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
71 | .addGroup(layout.createSequentialGroup()
72 | .addGap(39, 39, 39)
73 | .addComponent(jButton1)
74 | .addContainerGap(238, Short.MAX_VALUE))
75 | );
76 |
77 | pack();
78 | }// //GEN-END:initComponents
79 |
80 | private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
81 | //java.util.Calendar today = new java.util.Calendar(
82 | DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
83 | Calendar cal = Calendar.getInstance();
84 | Util.logTerminal(dateFormat.format(cal.getTime()));
85 | RootAccount rootAccount = main.getRootAccount();
86 | ReminderSet reminderSet = rootAccount.getReminderSet();
87 | Vector remindersOverdueVec = reminderSet.getOverdueItems( cal );
88 |
89 | //get an Iterator object for Vector using iterator() method.
90 | Iterator itr = remindersOverdueVec.iterator();
91 |
92 | //use hasNext() and next() methods of Iterator to iterate through the elements
93 | Util.logTerminal("Iterating through Vector elements...");
94 | while(itr.hasNext())
95 | {
96 | DateReminderPair rem = (DateReminderPair) itr.next();
97 | //reminderSet.removeReminder( rem );
98 |
99 | Util.logTerminal( "rem.desc =" + rem. + "=" );
100 | }
101 | }//GEN-LAST:event_jButton1ActionPerformed
102 |
103 | /**
104 | * @param args the command line arguments
105 | */
106 | public static void main(String args[]) {
107 | /*
108 | * Set the Nimbus look and feel
109 | */
110 | //
111 | /*
112 | * If Nimbus (introduced in Java SE 6) is not available, stay with the
113 | * default look and feel. For details see
114 | * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
115 | */
116 | try {
117 | for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
118 | if ("Nimbus".equals(info.getName())) {
119 | javax.swing.UIManager.setLookAndFeel(info.getClassName());
120 | break;
121 | }
122 | }
123 | } catch (ClassNotFoundException ex) {
124 | java.util.logging.Logger.getLogger(OtherActionsDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
125 | } catch (InstantiationException ex) {
126 | java.util.logging.Logger.getLogger(OtherActionsDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
127 | } catch (IllegalAccessException ex) {
128 | java.util.logging.Logger.getLogger(OtherActionsDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
129 | } catch (javax.swing.UnsupportedLookAndFeelException ex) {
130 | java.util.logging.Logger.getLogger(OtherActionsDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
131 | }
132 | //
133 |
134 | /*
135 | * Create and display the dialog
136 | */
137 | java.awt.EventQueue.invokeLater(new Runnable() {
138 |
139 | public void run() {
140 | OtherActionsDialog dialog = new OtherActionsDialog(null, true);
141 | dialog.addWindowListener(new java.awt.event.WindowAdapter() {
142 |
143 | @Override
144 | public void windowClosing(java.awt.event.WindowEvent e) {
145 | System.exit(0);
146 | }
147 | });
148 | dialog.setVisible(true);
149 | }
150 | });
151 | }
152 | // Variables declaration - do not modify//GEN-BEGIN:variables
153 | private javax.swing.JButton jButton1;
154 | // End of variables declaration//GEN-END:variables
155 | }
156 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/PreviewImportTblModel.java:
--------------------------------------------------------------------------------
1 | package com.moneydance.modules.features.mdcsvimporter;
2 |
3 | import java.util.ArrayList;
4 | import javax.swing.table.AbstractTableModel;
5 |
6 | /**
7 | *
8 | * @author stan
9 | */
10 |
11 |
12 | public class PreviewImportTblModel extends AbstractTableModel
13 | {
14 | private ArrayListcolNames;
15 | private String[][] data;
16 | private int colCount;
17 |
18 | public PreviewImportTblModel( ArrayList colNamesArg, String[][] dataArg, int colCountArg )
19 | {
20 | colNames = colNamesArg;
21 | data = dataArg;
22 | //headerCount = headerCountArg;
23 | colCount = colCountArg;
24 |
25 | Util.logConsole( "row count =" + data.length );
26 | Util.logConsole( "col count =" + colCount );
27 | }
28 |
29 | public int getColumnCount() { return colCount; }
30 | public int getRowCount() { return data.length;}
31 | public Object getValueAt(int row, int col)
32 | {
33 | //Util.logConsole( "getValueAt row =" + row + " col =" + col );
34 | try {
35 | if ( data[row][col] == "" )
36 | {
37 | //Util.logConsole( "NOT EXISTS getValueAt row =" + row + " col =" + col );
38 | }
39 | }
40 | catch( Exception ex )
41 | {
42 | return "";
43 | }
44 | return data[row][col];
45 | }
46 |
47 | public String getColumnName(int col) {
48 | return colNames.get( col );
49 | }
50 |
51 | /*
52 | public int getColumnCount() { return 10; }
53 | public int getRowCount() { return 10;}
54 | public Object getValueAt(int row, int col) { return new Integer(row*col); }
55 | */
56 | }
57 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/PreviewImportWin.form:
--------------------------------------------------------------------------------
1 |
2 |
3 |
138 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/PreviewImportWin.java:
--------------------------------------------------------------------------------
1 | package com.moneydance.modules.features.mdcsvimporter;
2 |
3 | import static com.moneydance.modules.features.mdcsvimporter.formats.CustomReader.DATA_TYPE_IGNORE;
4 | import static com.moneydance.modules.features.mdcsvimporter.formats.CustomReader.DATA_TYPE_IGNORE_REST;
5 | import java.awt.Desktop;
6 | import java.awt.event.ActionEvent;
7 | import java.awt.event.ActionListener;
8 | import java.awt.event.KeyEvent;
9 | import java.awt.event.WindowEvent;
10 | import java.io.File;
11 | import java.io.FileInputStream;
12 | import java.io.IOException;
13 | import java.io.InputStreamReader;
14 | import java.nio.charset.Charset;
15 | import java.util.ArrayList;
16 | import java.util.Arrays;
17 | import java.util.logging.Level;
18 | import java.util.logging.Logger;
19 | import javax.swing.JComponent;
20 | import javax.swing.JFrame;
21 | import javax.swing.JOptionPane;
22 | import javax.swing.KeyStroke;
23 |
24 | /**
25 | *
26 | * @author stan
27 | */
28 |
29 |
30 | public class PreviewImportWin extends javax.swing.JFrame {
31 |
32 | private ImportDialog importDialog = null;
33 | private TransactionReader transReader = null;
34 | private CSVData csvData = null;
35 | private CSVReader csvReader = null;
36 |
37 | /**
38 | * Creates new form PreviewImportWin
39 | */
40 | public PreviewImportWin() {
41 | try {
42 | initComponents();
43 | this.setSize( 800, 600 );
44 | this.setLocationRelativeTo( getRootPane() );
45 | this.setVisible( true );
46 | this.validate();
47 | this.addEscapeListener( this );
48 | }
49 | catch( Exception fex )
50 | {
51 | ;
52 | }
53 | }
54 |
55 | public void myInit( ImportDialog importDialog, TransactionReader transReaderArg ) //, CSVData csvDataArg, CSVReader csvReader )
56 | {
57 | Util.logConsole( "entered PreviewImportWin.myInit()" + "< ==============================" );
58 | this.importDialog = importDialog;
59 | transReader = transReaderArg;
60 | selectedFile.setText( importDialog.getSelectedFile().getPath() );
61 |
62 | parseFile();
63 | }
64 |
65 | public void parseFile()
66 | {
67 | boolean gotError = false;
68 |
69 | try {
70 | CSVReader csvReader = null;
71 |
72 | if ( transReader.getCustomReaderData().getUseRegexFlag() )
73 | {
74 | Util.logConsole( "\n================ Regex Reader" );
75 | csvReader = new RegexReader( new InputStreamReader( new FileInputStream( importDialog.getSelectedFile() ), Charset.forName( (String) transReader.getCustomReaderData().getFileEncoding() )), transReader.getCustomReaderData() );
76 | }
77 | else
78 | {
79 | Util.logConsole( "\n================ Csv Reader" );
80 | csvReader = new CSVReader( new InputStreamReader( new FileInputStream( importDialog.getSelectedFile() ), Charset.forName( (String) transReader.getCustomReaderData().getFileEncoding() )), transReader.getCustomReaderData() );
81 | }
82 |
83 | CSVData csvData = new CSVData( csvReader );
84 |
85 | //Util.logConsole( "btnProcessActionPerformed customReaderDialog.getFieldSeparatorChar() =" + (char)customReaderDialog.getFieldSeparatorChar() + "=" );
86 | //csvData.getReader().setFieldSeparator( customReaderDialog.getFieldSeparatorChar() );
87 |
88 | csvData.reset();
89 | if ( transReader.canParse( csvData, TransactionReader.PARSE_THRU_ERRORS_CONTINUE ) )
90 | {
91 | this.setTitle( "For Reader: " + transReader.toString() + " - Parse file works having " + csvData.getData().length + " rows" );
92 | importDialog.btnProcess.setEnabled( true );
93 | processBtn.setEnabled( true );
94 | processBtn.requestFocusInWindow();
95 | Util.logConsole( "=============== at canparse WORKS for >" + transReader.getFormatName() + "< ===============" );
96 | }
97 | else
98 | {
99 | this.setTitle( "For Reader: " + transReader.toString() + " - Parse file does not work!" );
100 | importDialog.btnProcess.setEnabled( false );
101 | processBtn.setEnabled( false );
102 | parseFileBtn.requestFocusInWindow();
103 | Util.logConsole( "=============== at canparse NOT WORK for >" + transReader.getFormatName() + " at row,col "
104 | + csvData.getCurrentLineIndex() + "," + csvData.getCurrentFieldIndex() + "< ===============" );
105 | gotError = true;
106 | }
107 |
108 | //csvData.parseIntoLines( transReader.getCustomReaderData().getFieldSeparatorChar() );
109 | Util.logConsole( "after parse row count =" + csvData.getData().length );
110 | Util.logConsole( "after parse col count =" + (csvData.getData())[ transReader.getHeaderCount() ].length );
111 |
112 | // Find and Insert User DataTypes as a Header row to show if they line up:
113 |
114 | int fieldIndex = 0;
115 | int colCount = 0;
116 | int maxFieldIndex = transReader.getCustomReaderData().getNumberOfCustomReaderFieldsUsed();
117 | Util.logConsole( "maxFieldIndex =" + maxFieldIndex );
118 | ArrayList headerDataTypesList = new ArrayList();
119 |
120 | for ( ; fieldIndex < maxFieldIndex; fieldIndex ++ )
121 | {
122 | String dataTypeExpecting = transReader.getCustomReaderData().getDataTypesList().get( fieldIndex );
123 | //Util.logConsole( "dataTypeExpecting =" + dataTypeExpecting + "= fieldIndex = " + fieldIndex );
124 |
125 | if ( dataTypeExpecting.equalsIgnoreCase( DATA_TYPE_IGNORE_REST ) )
126 | {
127 | headerDataTypesList.add( dataTypeExpecting );
128 | colCount++;
129 | break;
130 | }
131 | else if ( dataTypeExpecting.equalsIgnoreCase( DATA_TYPE_IGNORE ) )
132 | {
133 | int x = 1;
134 | try
135 | {
136 | x = Integer.parseInt( transReader.getCustomReaderData().getEmptyFlagsList().get( fieldIndex ).trim() );
137 | Util.logConsole( "ignore " + x + " lines" );
138 | }
139 | catch ( Exception ex )
140 | {
141 | Util.logConsole( "assume ignore 1 column on field =" + transReader.getCustomReaderData().getEmptyFlagsList().get( fieldIndex ).trim() + "=" );
142 | }
143 | int cnt = x;
144 | headerDataTypesList.add( dataTypeExpecting + "-" + cnt );
145 | colCount++;
146 | while ( x > 1 )
147 | {
148 | headerDataTypesList.add( dataTypeExpecting + "-" + cnt );
149 | colCount++;
150 | x--;
151 | }
152 | }
153 | else
154 | {
155 | headerDataTypesList.add( dataTypeExpecting );
156 | colCount++;
157 | }
158 | }
159 | Util.logConsole( "after parse col count =" + colCount );
160 | previewImportTbl.setModel( new PreviewImportTblModel( headerDataTypesList, csvData.getData(), colCount ) );
161 |
162 | CustomTableCellRenderer customTableCellRenderer = new CustomTableCellRenderer();
163 | // previewImportTbl.setDefaultRenderer( Object.class, customTableCellRenderer );
164 | previewImportTbl.setDefaultRenderer( Object.class, customTableCellRenderer );
165 |
166 | // Colorize errors
167 | int totalErrs = 0;
168 | int maxr = csvData.getDataErr().length;
169 | for ( int r = 0; r < maxr; r++ )
170 | {
171 | //Util.logConsole( "Check Data Err row =" + r );
172 | int maxc = (csvData.getDataErr())[r].length;
173 | for ( int c = 0; c < maxc; c++ )
174 | {
175 | //Util.logConsole( "Check Data Err col =" + c );
176 | if ( ! csvData.getFieldErr(r, c).equals( "" ) )
177 | {
178 | Util.logConsole( "dataErr [" + r + "][" + c + "] =" + csvData.getFieldErr(r, c) );
179 | customTableCellRenderer.setForRowCol( r, c, csvData.getFieldErr(r, c) );
180 | totalErrs++;
181 | //previewImportTbl.getColumnModel().getColumn( csvData.getCurrentFieldIndexWithinBounds() ).setCellRenderer( customTableCellRenderer );
182 | }
183 | }
184 | }
185 | message.setText( "Errors =" + totalErrs );
186 |
187 | // if ( 1 == 2 && gotError )
188 | // {
189 | // //csvData.getCurrentLineIndex() + "," + csvData.getCurrentFieldIndex()
190 | // CustomTableCellRenderer customTableCellRenderer = new CustomTableCellRenderer();
191 | // customTableCellRenderer.setForRowCol( csvData.getCurrentLineIndex(), csvData.getCurrentFieldIndex() );
192 | // //previewImportTbl.getColumnModel().getColumn( csvData.getCurrentFieldIndexWithinBounds() ).setCellRenderer( customTableCellRenderer );
193 | // previewImportTbl.setDefaultRenderer( Object.class, customTableCellRenderer );
194 | // }
195 | }
196 | catch (Exception ex)
197 | {
198 | //Logger.getLogger(CustomReader.class.getName()).log(Level.SEVERE, null, ex);
199 | //return false;
200 | }
201 | }
202 |
203 | public void addEscapeListener(final JFrame win) {
204 | ActionListener escListener = new ActionListener() {
205 |
206 | @Override
207 | public void actionPerformed(ActionEvent e) {
208 | try {
209 | //Util.logConsole( "previewImportWin formWindow dispose()" );
210 | if (csvReader != null) {
211 | csvReader.close();
212 | }
213 | csvData = null;
214 | transReader = null;
215 | } catch (IOException ex) {
216 | Logger.getLogger(PreviewImportWin.class.getName()).log(Level.SEVERE, null, ex);
217 | }
218 | finally
219 | {
220 | win.dispatchEvent( new WindowEvent( win, WindowEvent.WINDOW_CLOSING ));
221 | win.dispose();
222 | }
223 | }
224 | };
225 |
226 | win.getRootPane().registerKeyboardAction(escListener,
227 | KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
228 | JComponent.WHEN_IN_FOCUSED_WINDOW);
229 | }
230 |
231 | public void desktopEdit( File file )
232 | {
233 | //File file = fpath.toFile();
234 | //first check if Desktop is supported by Platform or not
235 | if ( ! Desktop.isDesktopSupported() )
236 | {
237 | Util.logTerminal("Desktop is not supported");
238 | return;
239 | }
240 |
241 | Desktop desktop = Desktop.getDesktop();
242 | try {
243 | if ( file.exists() )
244 | {
245 | desktop.edit( file );
246 | }
247 | }
248 | catch (Exception ex)
249 | {
250 | //logger.log(Level.SEVERE, null, ex);
251 | JOptionPane.showMessageDialog( this, "Edit not supported in this desktop.\nWill try Open.", "Error", JOptionPane.ERROR_MESSAGE );
252 | desktopOpen( file );
253 | }
254 | }
255 |
256 | public void desktopOpen( File file )
257 | {
258 | //File file = fpath.toFile();
259 | //first check if Desktop is supported by Platform or not
260 | if ( ! Desktop.isDesktopSupported() )
261 | {
262 | Util.logTerminal("Desktop is not supported");
263 | return;
264 | }
265 |
266 | Desktop desktop = Desktop.getDesktop();
267 | try {
268 | if ( file.exists() )
269 | {
270 | desktop.open( file );
271 | }
272 | }
273 | catch (Exception ex)
274 | {
275 | //logger.log(Level.SEVERE, null, ex);
276 | JOptionPane.showMessageDialog( this, "Open not supported in this desktop", "Error", JOptionPane.ERROR_MESSAGE );
277 | }
278 |
279 | // //let's try to open PDF file
280 | // fpath = new File("/Users/pankaj/java.pdf");
281 | // if(fpath.exists()) desktop.open(fpath);
282 |
283 | // //let's try to open PDF file
284 | // fpath = new File("/Users/pankaj/java.pdf");
285 | // if(fpath.exists()) desktop.open(fpath);
286 |
287 | // //let's try to open PDF file
288 | // fpath = new File("/Users/pankaj/java.pdf");
289 | // if(fpath.exists()) desktop.open(fpath);
290 |
291 | // //let's try to open PDF file
292 | // fpath = new File("/Users/pankaj/java.pdf");
293 | // if(fpath.exists()) desktop.open(fpath);
294 | }
295 |
296 | /**
297 | * @param args the command line arguments
298 | */
299 | public static void main(String args[]) {
300 | java.awt.EventQueue.invokeLater(new Runnable() {
301 |
302 | public void run() {
303 | PreviewImportWin dialog = new PreviewImportWin();
304 | dialog.addWindowListener(new java.awt.event.WindowAdapter() {
305 |
306 | public void windowClosing(java.awt.event.WindowEvent e) {
307 | System.exit(0);
308 | }
309 | });
310 | ArrayList header = new ArrayList(Arrays.asList( "H1", "H2", "H3" ) );
311 | String[][] data = {
312 | {"User", "Password", "Age"},
313 | {"1", "2", "3"},
314 | {"10", "20", "30"},
315 | };
316 |
317 | //dialog.myInit( null, null );
318 | dialog.previewImportTbl.setModel( new PreviewImportTblModel( header, data, 3 ) );
319 | dialog.setSize( 800, 600 );
320 | dialog.setVisible(true);
321 | dialog.addEscapeListener( dialog );
322 | }
323 | });
324 | }
325 |
326 | /**
327 | * This method is called from within the constructor to initialize the form.
328 | * WARNING: Do NOT modify this code. The content of this method is always
329 | * regenerated by the Form Editor.
330 | */
331 | @SuppressWarnings("unchecked")
332 | // //GEN-BEGIN:initComponents
333 | private void initComponents() {
334 | java.awt.GridBagConstraints gridBagConstraints;
335 |
336 | jScrollPane1 = new javax.swing.JScrollPane();
337 | previewImportTbl = new javax.swing.JTable();
338 | processBtn = new javax.swing.JButton();
339 | deleteFileBtn = new javax.swing.JButton();
340 | parseFileBtn = new javax.swing.JButton();
341 | message = new javax.swing.JLabel();
342 | selectedFile = new javax.swing.JLabel();
343 | jButton1 = new javax.swing.JButton();
344 |
345 | setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
346 | addWindowListener(new java.awt.event.WindowAdapter() {
347 | public void windowClosing(java.awt.event.WindowEvent evt) {
348 | formWindowClosing(evt);
349 | }
350 | });
351 | getContentPane().setLayout(new java.awt.GridBagLayout());
352 |
353 | previewImportTbl.setModel(new javax.swing.table.DefaultTableModel(
354 | new Object [][] {
355 | {null, null, null, null},
356 | {null, null, null, null},
357 | {null, null, null, null},
358 | {null, null, null, null}
359 | },
360 | new String [] {
361 | "Title 1", "Title 2", "Title 3", "Title 4"
362 | }
363 | ));
364 | jScrollPane1.setViewportView(previewImportTbl);
365 |
366 | gridBagConstraints = new java.awt.GridBagConstraints();
367 | gridBagConstraints.gridx = 0;
368 | gridBagConstraints.gridy = 1;
369 | gridBagConstraints.gridwidth = 6;
370 | gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
371 | gridBagConstraints.ipadx = 456;
372 | gridBagConstraints.ipady = 400;
373 | gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
374 | gridBagConstraints.weightx = 1.0;
375 | gridBagConstraints.weighty = 1.0;
376 | gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
377 | getContentPane().add(jScrollPane1, gridBagConstraints);
378 |
379 | processBtn.setText("Process");
380 | processBtn.addActionListener(new java.awt.event.ActionListener() {
381 | public void actionPerformed(java.awt.event.ActionEvent evt) {
382 | processBtnActionPerformed(evt);
383 | }
384 | });
385 | gridBagConstraints = new java.awt.GridBagConstraints();
386 | gridBagConstraints.gridx = 2;
387 | gridBagConstraints.gridy = 0;
388 | gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 0);
389 | getContentPane().add(processBtn, gridBagConstraints);
390 |
391 | deleteFileBtn.setText("Delete File");
392 | deleteFileBtn.addActionListener(new java.awt.event.ActionListener() {
393 | public void actionPerformed(java.awt.event.ActionEvent evt) {
394 | deleteFileBtnActionPerformed(evt);
395 | }
396 | });
397 | gridBagConstraints = new java.awt.GridBagConstraints();
398 | gridBagConstraints.gridx = 0;
399 | gridBagConstraints.gridy = 2;
400 | gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0);
401 | getContentPane().add(deleteFileBtn, gridBagConstraints);
402 |
403 | parseFileBtn.setText("Parse File");
404 | parseFileBtn.addActionListener(new java.awt.event.ActionListener() {
405 | public void actionPerformed(java.awt.event.ActionEvent evt) {
406 | parseFileBtnActionPerformed(evt);
407 | }
408 | });
409 | gridBagConstraints = new java.awt.GridBagConstraints();
410 | gridBagConstraints.gridx = 0;
411 | gridBagConstraints.gridy = 0;
412 | gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 0);
413 | getContentPane().add(parseFileBtn, gridBagConstraints);
414 |
415 | message.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
416 | message.setText(" ");
417 | message.setMaximumSize(new java.awt.Dimension(9999, 23));
418 | message.setMinimumSize(new java.awt.Dimension(90, 23));
419 | message.setPreferredSize(new java.awt.Dimension(90, 23));
420 | gridBagConstraints = new java.awt.GridBagConstraints();
421 | gridBagConstraints.gridx = 4;
422 | gridBagConstraints.gridy = 0;
423 | gridBagConstraints.gridwidth = 2;
424 | getContentPane().add(message, gridBagConstraints);
425 |
426 | selectedFile.setText(" ");
427 | gridBagConstraints = new java.awt.GridBagConstraints();
428 | gridBagConstraints.gridx = 2;
429 | gridBagConstraints.gridy = 2;
430 | gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
431 | gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
432 | gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0);
433 | getContentPane().add(selectedFile, gridBagConstraints);
434 |
435 | jButton1.setText("Open");
436 | jButton1.addActionListener(new java.awt.event.ActionListener() {
437 | public void actionPerformed(java.awt.event.ActionEvent evt) {
438 | jButton1ActionPerformed(evt);
439 | }
440 | });
441 | gridBagConstraints = new java.awt.GridBagConstraints();
442 | gridBagConstraints.gridx = 1;
443 | gridBagConstraints.gridy = 2;
444 | gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0);
445 | getContentPane().add(jButton1, gridBagConstraints);
446 | }// //GEN-END:initComponents
447 |
448 | private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
449 | try {
450 | Util.logConsole( "previewImportWin formWindowClosing()" );
451 | } catch (Exception ex) {
452 | Logger.getLogger(PreviewImportWin.class.getName()).log(Level.SEVERE, null, ex);
453 | }
454 | }//GEN-LAST:event_formWindowClosing
455 |
456 | private void deleteFileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteFileBtnActionPerformed
457 | importDialog.deleteCsvFile();
458 | }//GEN-LAST:event_deleteFileBtnActionPerformed
459 |
460 | private void processBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_processBtnActionPerformed
461 | importDialog.processActionPerformed( evt );
462 | this.dispose();
463 | }//GEN-LAST:event_processBtnActionPerformed
464 |
465 | private void parseFileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_parseFileBtnActionPerformed
466 | //csvData.reset();
467 | parseFile();
468 | }//GEN-LAST:event_parseFileBtnActionPerformed
469 |
470 | private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
471 | desktopEdit( new File( selectedFile.getText() ) );
472 | }//GEN-LAST:event_jButton1ActionPerformed
473 |
474 |
475 | // Variables declaration - do not modify//GEN-BEGIN:variables
476 | private javax.swing.JButton deleteFileBtn;
477 | private javax.swing.JButton jButton1;
478 | private javax.swing.JScrollPane jScrollPane1;
479 | private javax.swing.JLabel message;
480 | private javax.swing.JButton parseFileBtn;
481 | private javax.swing.JTable previewImportTbl;
482 | private javax.swing.JButton processBtn;
483 | private javax.swing.JLabel selectedFile;
484 | // End of variables declaration//GEN-END:variables
485 | }
486 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/RegexReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This program is free software: you can redistribute it and/or modify
3 | * it under the terms of the GNU Lesser General Public License as published by
4 | * the Free Software Foundation, either version 3 of the License, or
5 | * (at your option) any later version.
6 | *
7 | * This program is distributed in the hope that it will be useful,
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | * GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License
13 | * along with this program. If not, see .
14 | */
15 | package com.moneydance.modules.features.mdcsvimporter;
16 |
17 | import java.io.IOException;
18 | import java.io.LineNumberReader;
19 | import java.io.Reader;
20 | import java.util.ArrayList;
21 | import java.util.regex.Matcher;
22 | import java.util.regex.Pattern;
23 |
24 | /**
25 | *
26 | * @author miki
27 | * modified by: Stan Towianski
28 | */
29 | public class RegexReader extends CSVReader
30 | {
31 | /**
32 | * Carriage-Return
33 | */
34 | private static final int CR = 13;
35 | /**
36 | * Line-Feed
37 | */
38 | private static final int LF = 10;
39 | /**
40 | * Space
41 | */
42 | private static final int SPACE = 32;
43 | /**
44 | * Tab
45 | */
46 | private static final int TAB = 8;
47 | /**
48 | * Character used as a separator of individual fields.
49 | */
50 | private int fieldSeparator = ',';
51 | /**
52 | * Character used to start and end quoted sequences.
53 | */
54 | private int quoteCharacter = '"';
55 | /**
56 | * Character used to mark comment lines.
57 | */
58 | private int commentCharacter = '#';
59 | /**
60 | * Character used to mark pragma lines.
61 | */
62 | private int pragmaCharacter = '$';
63 | /**
64 | * True if the fields values should be trimmed before return. Equivalent of returning
65 | * nextField().trim().
66 | */
67 | private boolean trimFields = true;
68 | /**
69 | * True if empty lines should be skipped and not reported as data rows.
70 | */
71 | private boolean skipEmptyLines = false;
72 | /**
73 | * Reference to the reader.
74 | */
75 | private Reader reader;
76 | private CustomReaderData customReaderData;
77 | /**
78 | * The last char read from the reader. Also it stores the next character to be parsed.
79 | * <0 if end of file is reached. Code is currently written so that initializing
80 | * this to LF is the proper way to start parsing.
81 | */
82 | private int lastChar = LF;
83 | /**
84 | * Temporary buffer used to build field values before hey are returned.
85 | */
86 | private StringBuilder builder = new StringBuilder();
87 |
88 | private LineNumberReader lineReader;
89 | private String rgLine = "";
90 | private int rgFieldCnt = 0;
91 |
92 | public RegexReader()
93 | throws IOException
94 | {
95 | }
96 |
97 | /**
98 | * Constructs a new CSV file reader.
99 | * @param reader must be a valid reference to a reader providing CSV data to parse.
100 | * @throws java.io.IOException
101 | */
102 | public RegexReader( Reader reader, CustomReaderData customReaderData )
103 | throws IOException
104 | {
105 | if ( reader == null || !reader.ready() )
106 | {
107 | throw new IllegalArgumentException( "Reader must be a valid object." );
108 | }
109 | this.reader = reader;
110 | this.customReaderData = customReaderData;
111 | lineReader = new LineNumberReader( reader );
112 | }
113 |
114 | /**
115 | * Closes the input reader and releases all object references. No other calls to this
116 | * instance should be made.
117 | * @throws java.io.IOException IOException might be thrown by referenced reader. See
118 | * Reader.close().
119 | */
120 | public void close()
121 | throws IOException
122 | {
123 | reader.close();
124 | reader = null;
125 | lastChar = -1;
126 | }
127 |
128 | /**
129 | * Used to move to the next line in the CSV file. It must be called before the each
130 | * line is processed, including before the very first line in the file. Any fields on
131 | * the current line that have not been retrieved, will be skipped.
132 | * @return true if the file contains another line.
133 | * @throws java.io.IOException if data cannot be read.
134 | */
135 | public boolean nextLine_HIDE()
136 | throws IOException
137 | {
138 | while ( nextField() != null )
139 | {
140 | }
141 |
142 | // skip EOL; possible combinations are CR, CR+LF, LF
143 | if ( lastChar == CR )
144 | {
145 | lastChar = reader.read();
146 | }
147 | if ( lastChar == LF )
148 | {
149 | lastChar = reader.read();
150 | }
151 |
152 | // skip whitespace at the beginning
153 | if ( trimFields )
154 | {
155 | while ( isWhitespace( lastChar ) && !isEof( lastChar ) )
156 | {
157 | lastChar = reader.read();
158 | }
159 | }
160 |
161 | // skip comment lines
162 | if ( lastChar == commentCharacter )
163 | {
164 | do
165 | {
166 | lastChar = reader.read();
167 | } while ( !isEof( lastChar ) && lastChar != CR && lastChar != LF );
168 | return nextLine();
169 | }
170 |
171 | // handle pragma lines
172 | if ( lastChar == pragmaCharacter )
173 | {
174 | throw new IOException( "Pragma lines (starting with " + pragmaCharacter +
175 | ") are currently not supported. If you need to use this character surround " +
176 | "the field with quotes." );
177 | }
178 |
179 | // skip empty lines if so requested
180 | if ( skipEmptyLines && isEol( lastChar ) )
181 | {
182 | return nextLine();
183 | }
184 |
185 | // end of file
186 | if ( isEof( lastChar ) )
187 | {
188 | return false;
189 | }
190 | return true;
191 | }
192 |
193 | /**
194 | * Retrieves next field on the current line. If the field value was quoted, the quotes
195 | * are stripped. If the reader has been configured to trim fields, then all whitespaces
196 | * at the beginning and end of the field are stripped before returning.
197 | * @return field value or null if no more fields on the current line.
198 | * @throws java.io.IOException if data cannot be read.
199 | */
200 | public String nextField()
201 | throws IOException
202 | {
203 | //Pattern and Matcher are used here, not String.matches(regexp),
204 | //since String.matches(regexp) would repeatedly compile the same
205 | //regular expression
206 | //String pat42 = "([^,]*([,]|\\Z)).*";
207 | //String pat5 = "Check[ ]#(\\d*)[^,]*|([^,]*)([,]|\\Z).*";
208 | /* was used
209 | String pat42 = "([^,]*([,]|\\Z)).*";
210 | String pat5 = "(?:Check[ ]#(\\d*)|([^,]*)([,]|\\Z)).*";
211 |
212 | Pattern regexp = Pattern.compile( pat42 );
213 | Pattern regexp2 = Pattern.compile( pat5 );
214 | */
215 |
216 | ArrayList matcherAl = new ArrayList();
217 | /*
218 | matcherAl.add( regexp.matcher("") );
219 | matcherAl.add( regexp.matcher("") );
220 | matcherAl.add( regexp2.matcher("") );
221 | matcherAl.add( regexp.matcher("") );
222 | matcherAl.add( regexp.matcher("") );
223 | matcherAl.add( regexp.matcher("") );
224 | matcherAl.add( regexp.matcher("") );
225 | Matcher matcher = regexp.matcher("");
226 | */
227 | for ( String patString : customReaderData.getRegexsList() )
228 | {
229 | matcherAl.add( Pattern.compile( patString ).matcher("") );
230 | //Util.logConsole( "patString =" + patString + "=" );
231 | }
232 | Matcher matcher = matcherAl.get( 0 );
233 |
234 | String item = null;
235 |
236 | //Util.logConsole( "\nnextField() fieldSeparator =" + (char)fieldSeparator + "=" );
237 |
238 | // if ( isEol( lastChar ) || isEof( lastChar ) )
239 | // {
240 | // //Util.logConsole( "nextField() return null for Eol or Eof" );
241 | // return null;
242 | // }
243 |
244 | if ( ! rgLine.isEmpty() )
245 | {
246 | try {
247 | Util.logConsole( "\n----- left =" + rgLine + "= use regex [" + rgFieldCnt + "] =" + matcherAl.get( rgFieldCnt ).pattern() + "=" );
248 | matcher = (matcherAl.get( rgFieldCnt ));
249 | matcher.reset( rgLine ); //reset the input
250 | if ( matcher.matches() )
251 | {
252 | //Util.logConsole("Num groups: " + matcher.groupCount());
253 | try {
254 | item = matcher.group("value") == null ? "" : matcher.group("value");
255 | }
256 | catch( Exception exc )
257 | {
258 | exc.printStackTrace();
259 | Util.logConsole("regex probably does not exist.");
260 | item = "";
261 | }
262 | // rgLine = rgLine.substring( item.length() );
263 | try {
264 | rgLine = matcher.group("rest") == null ? "" : matcher.group("rest");
265 | }
266 | catch( Exception exc )
267 | {
268 | exc.printStackTrace();
269 | Util.logConsole("regex probably does not exist.");
270 | rgLine = "";
271 | }
272 | // if ( item.endsWith( "," ) )
273 | // item = item.substring( 0, item.length() - 1 );
274 | Util.logConsole( "rgFieldCnt =" + rgFieldCnt + " item >" + item + "< item2 to become leftover line >" + rgLine + "<" );
275 | }
276 | }
277 | catch( Exception exc )
278 | {
279 | exc.printStackTrace();
280 | Util.logConsole("Input does not match pattern.");
281 | rgLine = "";
282 | return null;
283 | }
284 | rgFieldCnt++;
285 | }
286 | else
287 | {
288 | Util.logConsole( "No more fields left." );
289 | rgLine = "";
290 | return null;
291 | }
292 |
293 | // TODO: skip separator
294 |
295 | if ( trimFields )
296 | {
297 | Util.logConsole( "RegexReader return nextField trim =" + item.trim() + "=" );
298 | return item.trim();
299 | }
300 | else
301 | {
302 | Util.logConsole( "RegexReader return nextField =" + item + "=" );
303 | return item;
304 | }
305 | }
306 |
307 | public boolean nextLine()
308 | throws IOException
309 | //public void regexParseIntoLines(String aFileName)
310 | {
311 | //Path path = Paths.get(aFileName);
312 | try
313 | //(
314 | //BufferedReader reader = Files.newBufferedReader(path, ENCODING);
315 | //LineNumberReader lineReader = new LineNumberReader( reader );
316 | //)
317 | {
318 | Util.logConsole( "entered RegexReader.nextLine()" );
319 | if ((rgLine = lineReader.readLine()) != null)
320 | {
321 | Util.logConsole( "\n---------- line =" + rgLine + "=" );
322 | rgFieldCnt = 0;
323 | return true;
324 | }
325 | }
326 | catch (IOException ex){
327 | ex.printStackTrace();
328 | }
329 | return false;
330 | }
331 |
332 | public void setFieldSeparator( int fieldSeparator )
333 | {
334 | //Util.logConsole( "CSVReader.setFieldSeparator =" + (char)fieldSeparator + "=" );
335 | this.fieldSeparator = fieldSeparator;
336 | }
337 |
338 | public int getFieldSeparator()
339 | {
340 | return fieldSeparator;
341 | }
342 |
343 | public void setQuoteCharacter( int quoteCharacter )
344 | {
345 | this.quoteCharacter = quoteCharacter;
346 | }
347 |
348 | public int getQuoteCharacter()
349 | {
350 | return quoteCharacter;
351 | }
352 |
353 | public void setCommentCharacter( int commentCharacter )
354 | {
355 | this.commentCharacter = commentCharacter;
356 | }
357 |
358 | public int getCommentCharacter()
359 | {
360 | return commentCharacter;
361 | }
362 |
363 | public void setPragmaCharacter( int pragmaCharacter )
364 | {
365 | this.pragmaCharacter = pragmaCharacter;
366 | }
367 |
368 | public int getPragmaCharacter()
369 | {
370 | return pragmaCharacter;
371 | }
372 |
373 | public void setTrimFields( boolean trimFields )
374 | {
375 | this.trimFields = trimFields;
376 | }
377 |
378 | public boolean getTrimFields()
379 | {
380 | return trimFields;
381 | }
382 |
383 | public void setSkipEmptyLines( boolean skipEmptyLines )
384 | {
385 | this.skipEmptyLines = skipEmptyLines;
386 | }
387 |
388 | public boolean getSkipEmptyLines()
389 | {
390 | return skipEmptyLines;
391 | }
392 |
393 | }
394 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/SecureFileDeleter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This program is free software: you can redistribute it and/or modify
3 | * it under the terms of the GNU Lesser General Public License as published by
4 | * the Free Software Foundation, either version 3 of the License, or
5 | * (at your option) any later version.
6 | *
7 | * This program is distributed in the hope that it will be useful,
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | * GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License
13 | * along with this program. If not, see .
14 | */
15 | package com.moneydance.modules.features.mdcsvimporter;
16 |
17 | import java.io.File;
18 | import java.io.FileOutputStream;
19 | import java.io.IOException;
20 | import java.io.OutputStream;
21 | import java.util.Random;
22 |
23 | /**
24 | *
25 | * @author miki
26 | */
27 | public class SecureFileDeleter
28 | {
29 | private static final int CHUNK_SIZE = 65536;
30 |
31 | /**
32 | * Securely deletes the specified file. This is done by overwriting the file three
33 | * times, by 0xFF's, random values and 0's, and finally deleting the file.
34 | * @param file File to delete.
35 | * @throws java.io.IOException IOException is thrown if file does not exist, if it is a directory,
36 | * cannot be written to or if any other IO erroroccurs.
37 | */
38 | public static void delete( File file )
39 | throws IOException
40 | {
41 | if ( !file.exists() || !file.isFile() || !file.canWrite() )
42 | {
43 | throw new IOException( "Unable to securely delete specified file." );
44 | }
45 |
46 | Random random = new Random();
47 | byte[] buffer = new byte[CHUNK_SIZE];
48 |
49 | // fill file with 0xFF
50 | for ( int i = 0; i < CHUNK_SIZE; ++i )
51 | {
52 | buffer[i] = (byte) 0xFF;
53 | }
54 | long fileLength = file.length();
55 | OutputStream output = new FileOutputStream( file );
56 | while ( fileLength > 0 )
57 | {
58 | int chunkSize = fileLength > CHUNK_SIZE ? CHUNK_SIZE : (int) fileLength;
59 | output.write( buffer, 0, chunkSize );
60 | fileLength -= chunkSize;
61 | }
62 | output.close();
63 |
64 | // fill file with random values
65 | fileLength = file.length();
66 | output = new FileOutputStream( file );
67 | while ( fileLength > 0 )
68 | {
69 | int chunkSize = fileLength > CHUNK_SIZE ? CHUNK_SIZE : (int) fileLength;
70 | random.nextBytes( buffer );
71 | output.write( buffer, 0, chunkSize );
72 | fileLength -= chunkSize;
73 | }
74 | output.close();
75 |
76 | // fill file with 0's
77 | for ( int i = 0; i < CHUNK_SIZE; ++i )
78 | {
79 | buffer[i] = (byte) 0;
80 | }
81 | fileLength = file.length();
82 | output = new FileOutputStream( file );
83 | while ( fileLength > 0 )
84 | {
85 | int chunkSize = fileLength > CHUNK_SIZE ? CHUNK_SIZE : (int) fileLength;
86 | random.nextBytes( buffer );
87 | output.write( buffer, 0, chunkSize );
88 | fileLength -= chunkSize;
89 | }
90 | output.close();
91 |
92 | if ( !file.delete() )
93 | {
94 | throw new IOException( "Failed to delete file." );
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/Settings.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This program is free software: you can redistribute it and/or modify
3 | * it under the terms of the Lesser GNU General Public License as published by
4 | * the Free Software Foundation, either version 3 of the License, or
5 | * (at your option) any later version.
6 | *
7 | * This program is distributed in the hope that it will be useful,
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | * GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License
13 | * along with this program. If not, see .
14 | */
15 | package com.moneydance.modules.features.mdcsvimporter;
16 |
17 | import com.moneydance.modules.features.mdcsvimporter.formats.CustomReader;
18 | import java.io.File;
19 | import java.io.FileInputStream;
20 | import java.io.FileNotFoundException;
21 | import java.io.FileOutputStream;
22 | import java.io.IOException;
23 | import java.io.InputStream;
24 | import java.io.OutputStream;
25 | import java.util.ArrayList;
26 | import java.util.Arrays;
27 | import java.util.Enumeration;
28 | import java.util.HashMap;
29 | import java.util.Properties;
30 | import java.util.logging.Level;
31 | import java.util.logging.Logger;
32 | import javax.swing.JOptionPane;
33 |
34 | /**
35 | *
36 | * @author miki and Stan Towianski
37 | */
38 | public final class Settings
39 | {
40 | static HashMap ReaderConfigsHM = null;
41 | static HashMap ReaderHM = null;
42 | static Properties currentProps = new Properties();
43 | static String emptyArrayProperty = "[,,,, , , , , , ]";
44 | // static String emptyRegexsArrayProperty = "[\u001F \u001F \u001F \u001F \u001F \u001F \u001F \u001F \u001F ]";
45 | //static String emptyRegexsArrayProperty = "[ a a a a a a a a a ]";
46 | public static File getFilename()
47 | {
48 | Util.logConsole(true, "os.name =" + System.getProperty( "os.name" ) + "=" );
49 | File moneydanceHome = null;
50 | File moneydanceHome1 = null;
51 | File moneydanceHome2 = null;
52 | File moneydanceHome3 = null;
53 | File moneydanceHome4 = null;
54 | String missingHomeErrMsg = "";
55 |
56 | if ( System.getProperty( "os.name" ).toLowerCase().startsWith( "mac" ) )
57 | {
58 | moneydanceHome1 = new File( System.getProperty( "user.home" ) + "/Library/Application Support", "Moneydance" );
59 | Util.logConsole(true, "try moneydanceHome folder =" + moneydanceHome1 + "=" );
60 | if ( moneydanceHome1.exists() )
61 | {
62 | moneydanceHome = moneydanceHome1;
63 | }
64 | else
65 | {
66 | moneydanceHome2 = new File( System.getProperty( "user.home" ) + "/Library/Preferences", "Moneydance" );
67 | Util.logConsole(true,"try moneydanceHome folder =" + moneydanceHome2 + "=" );
68 | if ( moneydanceHome2.exists() )
69 | {
70 | moneydanceHome = moneydanceHome2;
71 | }
72 | else
73 | {
74 | moneydanceHome3 = new File( "/Library/Preferences", "Moneydance" );
75 | Util.logConsole(true,"try moneydanceHome folder =" + moneydanceHome3 + "=" );
76 | if ( moneydanceHome3.exists() )
77 | {
78 | moneydanceHome = moneydanceHome3;
79 | }
80 | else
81 | {
82 | moneydanceHome4 = new File( System.getProperty( "user.home" ) + "/Library", "Moneydance" );
83 | Util.logConsole(true,"try moneydanceHome folder =" + moneydanceHome4 + "=" );
84 | if ( moneydanceHome4.exists() )
85 | moneydanceHome = moneydanceHome4;
86 | } // 3
87 | } // 2
88 | } // 1
89 |
90 | // I am assuming at this point that these Mac folders do exist.
91 |
92 | if ( moneydanceHome == null )
93 | {
94 | Util.logConsole(true,"Could not find so assuming moneydanceHome folder =" + moneydanceHome1 + "=" );
95 | moneydanceHome = moneydanceHome1;
96 | missingHomeErrMsg = "\n\nI looked in these 4 places in this order: \n\n"
97 | + moneydanceHome1 + "\n"
98 | + moneydanceHome2 + "\n"
99 | + moneydanceHome3 + "\n"
100 | + moneydanceHome4 + "\n";
101 | }
102 | }
103 | else // windows + Linux : test for moneydance folder
104 | {
105 | moneydanceHome1 = new File( System.getProperty( "user.home" ), ".moneydance" );
106 | Util.logConsole(true,"try moneydanceHome folder =" + moneydanceHome1 + "=" );
107 | if ( moneydanceHome1.exists() )
108 | moneydanceHome = moneydanceHome1;
109 |
110 | if ( moneydanceHome == null )
111 | {
112 | Util.logConsole(true,"Could not find so assuming moneydanceHome folder =" + moneydanceHome1 + "=" );
113 | moneydanceHome = moneydanceHome1;
114 | missingHomeErrMsg = ""; //\n\nI looked in this place: \n\n"
115 | //+ moneydanceHome + "\n";
116 | }
117 | }
118 |
119 | // for all os's
120 | if ( ! moneydanceHome.exists() )
121 | {
122 | boolean ok = moneydanceHome.mkdirs();
123 | JOptionPane.showMessageDialog( null, "Importer could not find a Moneydance Home directory so I created one here: \n\n" + moneydanceHome
124 | + missingHomeErrMsg
125 | );
126 | if ( ! ok )
127 | {
128 | JOptionPane.showMessageDialog( null, "*** Error creating Moneydance Home directory: \n\n" + moneydanceHome );
129 | }
130 | }
131 | moneydanceHome = new File( moneydanceHome, "mdcsvimporter.props" );
132 |
133 | // all systems - moneydanceHome now includes properties file path
134 | try {
135 | if ( ! moneydanceHome.exists() )
136 | {
137 | moneydanceHome.createNewFile();
138 | JOptionPane.showMessageDialog( null, "Importer could not find its properties files so I created one here: \n\n" + moneydanceHome
139 | );
140 | }
141 | }
142 | catch (IOException ex)
143 | {
144 | Logger.getLogger(Settings.class.getName()).log(Level.SEVERE, null, ex);
145 | }
146 |
147 | return moneydanceHome;
148 | }
149 |
150 | private static Properties load()
151 | throws IOException
152 | {
153 | currentProps = new Properties();
154 |
155 | InputStream is;
156 | try
157 | {
158 | is = new FileInputStream( getFilename() );
159 | }
160 | catch ( FileNotFoundException ex )
161 | {
162 | return currentProps; // no file is normal condition to start with empty props object
163 | }
164 | try
165 | {
166 | currentProps.load( is );
167 | }
168 | finally
169 | {
170 | is.close();
171 | }
172 | return currentProps;
173 | }
174 |
175 | private static void save( Properties props )
176 | throws IOException
177 | {
178 | OutputStream os = new FileOutputStream( getFilename() ); //, Charset.forName( "UTF-8" ) ); //(String) transReader.getCustomReaderData().getFileEncoding() ) );
179 | try
180 | {
181 | //Util.logConsole(true, "DOING SAVE TO PROPS FILE" );
182 | props.store( os, "MDCSVImporter - Moneydance CSV Importer" );
183 | }
184 | finally
185 | {
186 | os.close();
187 | load();
188 | }
189 | }
190 |
191 | public static String get( boolean loadProps, String name )
192 | {
193 | try
194 | {
195 | if ( loadProps )
196 | {
197 | load();
198 | }
199 | return currentProps.getProperty( name );
200 | }
201 | catch ( IOException ex )
202 | {
203 | Logger.getLogger( Settings.class.getName() ).log( Level.SEVERE, null, ex );
204 | return null;
205 | }
206 | }
207 |
208 | public static String get( boolean loadProps, String name, String defaultValue )
209 | {
210 | String retVal = get( loadProps, name );
211 | if ( retVal == null )
212 | {
213 | return defaultValue;
214 | }
215 | return retVal;
216 | }
217 |
218 | public static void set( String name, String value )
219 | {
220 | try
221 | {
222 | Properties props = load();
223 |
224 | setOnly( props, name, value );
225 |
226 | save( props );
227 | }
228 | catch ( IOException ex )
229 | {
230 | Logger.getLogger( Settings.class.getName() ).log( Level.SEVERE, null, ex );
231 | ex.printStackTrace();
232 | }
233 | }
234 |
235 | public static void setOnly( Properties props, String name, String value )
236 | {
237 | // skip if values match (I am sorry for not optimizing the condition, it is early morning...)
238 | String oldValue = props.getProperty( name );
239 | if ( (oldValue != null && oldValue.equals( value )) ||
240 | (value != null && value.equals( oldValue )) )
241 | {
242 | return;
243 | }
244 |
245 | props.setProperty( name, value );
246 | }
247 |
248 | public static boolean getBoolean( boolean loadProps, String name )
249 | {
250 | return getBoolean( loadProps, name, false );
251 | }
252 |
253 | public static boolean getBoolean( boolean loadProps, String name, boolean defaultValue )
254 | {
255 | String value = get( loadProps, name );
256 | if ( value == null )
257 | {
258 | return defaultValue;
259 | }
260 |
261 | if ( value.equalsIgnoreCase( "true" ) || value.equalsIgnoreCase( "yes" ) ||
262 | value.equalsIgnoreCase( "1" ) )
263 | {
264 | return true;
265 | }
266 | else
267 | {
268 | return false;
269 | }
270 | }
271 |
272 | public static void setBoolean( String name, boolean value )
273 | {
274 | set( name, value ? "true" : "false" );
275 | }
276 |
277 | public static void setYesNo( String name, boolean value )
278 | {
279 | set( name, value ? "yes" : "no" );
280 | }
281 |
282 | public static int getInteger( boolean loadProps, String name )
283 | {
284 | return getInteger( loadProps, name, 0 );
285 | }
286 |
287 | public static int getInteger( boolean loadProps, String name, int defaultValue )
288 | {
289 | String value = get( loadProps, name );
290 | if ( value == null )
291 | {
292 | return defaultValue;
293 | }
294 |
295 | return Integer.parseInt( value );
296 | }
297 |
298 | public static void setInteger( String name, int value )
299 | {
300 | set( name, Integer.toString( value ) );
301 | }
302 |
303 | public static WinProps getWinProps( boolean loadProps, String name )
304 | {
305 | String value = get( loadProps, name );
306 | //Util.logConsole(true, "getWinProps(" + name + ") value =" + value + "=" );
307 | if ( value == null )
308 | {
309 | //Util.logConsole(true, "getWinProps() string value is null" );
310 | return new WinProps();
311 | }
312 |
313 | ArrayList tmpList = new ArrayList(Arrays.asList( value.trim().split( "[\\[\\],]" ) ) );
314 | tmpList.remove( 0 );
315 | ArrayList numList = new ArrayList();
316 | for ( String one : tmpList )
317 | {
318 | //Util.logConsole(true, "one =" + one + "=" );
319 | numList.add( Integer.parseInt( one.trim() ) );
320 | //Util.logConsole(true, "getWinProps set name =" + name + "= list value =" + one.getWinPropsAsList().toString() + "=" );
321 | }
322 | return new WinProps( numList );
323 | }
324 |
325 | public static void setWinProps( String name, WinProps value )
326 | {
327 | set( name, value.getWinPropsAsList().toString() );
328 | //Util.logConsole(true, ƒ"set name =" + name + "= list value =" + value.getWinPropsAsList().toString() + "=" );
329 | }
330 |
331 | public static HashMap createReaderConfigsHM()
332 | {
333 | ReaderConfigsHM = new HashMap();
334 | ReaderHM = new HashMap();
335 |
336 | try
337 | {
338 | Properties props = load();
339 |
340 | for ( Enumeration enu = props.propertyNames(); enu.hasMoreElements(); )
341 | {
342 | String key = (String) enu.nextElement();
343 | Util.logTerminal( "props key =" + key + "=" );
344 | if ( key.startsWith( "reader:" ) && key.endsWith( ".Name" ) )
345 | {
346 | String readerName = key.replaceAll( "reader\\:(.*)\\..*", "reader:$1" );
347 | Util.logConsole("readerName >" + readerName + "<" );
348 |
349 | CustomReaderData customReaderData = new CustomReaderData();
350 | customReaderData.setReaderName( props.getProperty( readerName + ".Name" ) );
351 | customReaderData.setFieldSeparatorChar( getInteger( false, readerName + ".FieldSeparator", ',' ) );
352 | customReaderData.setDateFormatString( props.getProperty( readerName + ".DateFormatString" ) );
353 | customReaderData.setFileEncoding( props.getProperty( readerName + ".FileEncodingString" ) );
354 |
355 | customReaderData.setHeaderLines( getInteger( false, readerName + ".HeaderLines", 0 ) );
356 | customReaderData.setFooterLines( getInteger( false, readerName + ".FooterLines", 0 ) );
357 |
358 | customReaderData.setAmountCurrencyChar( getInteger( false, readerName + ".AmountCurrencyChar", '$' ) );
359 | customReaderData.setAmountDecimalSignChar( getInteger( false, readerName + ".AmountDecimalSignChar", '.' ) );
360 | customReaderData.setAmountGroupingSeparatorChar( getInteger( false, readerName + ".AmountGroupingSeparatorChar", ',' ) );
361 | customReaderData.setAmountFormat( props.getProperty( readerName + ".AmountFormat" ) );
362 | customReaderData.setImportReverseOrderFlg( getBoolean( false, readerName + ".ImportReverseOrderFlag", false ) );
363 | customReaderData.setUseRegexFlag(getBoolean( false, readerName + ".UseRegexFlag", false ) );
364 | customReaderData.setFilenameMatcher(props.getProperty( readerName + ".FilenameMatcher" ) );
365 |
366 | //customReaderData.setRegexsList( new ArrayList(Arrays.asList( props.getProperty( readerName + ".RegexsList", emptyRegexsArrayProperty ).split( "[\\[\\]a]" ) ) ) );
367 | //customReaderData.setRegexsList( new ArrayList( 10 ) );
368 | customReaderData.setRegexsList( new ArrayList(Arrays.asList( "", "", "", "", "", "", "", "", "", "" ) ) );
369 | customReaderData.setDataTypesList( new ArrayList(Arrays.asList( props.getProperty( readerName + ".DataTypesList", emptyArrayProperty ).split( "[\\[\\],]" ) ) ) );
370 | customReaderData.setEmptyFlagsList( new ArrayList(Arrays.asList( props.getProperty( readerName + ".EmptyFlagsList", emptyArrayProperty ).split( "[\\[\\],]" ) ) ) );
371 |
372 | int max = customReaderData.getDataTypesList().size();
373 | Util.logConsole(true, "props customReaderData.getRegexsList().size() =" + customReaderData.getRegexsList().size() + "= max =" + max );
374 | for ( int c = 1; c < max; c++ )
375 | {
376 | customReaderData.getRegexsList().set( c - 1, props.getProperty( readerName + ".RegexsList." + (c-1), "" ) );
377 | //customReaderData.getRegexsList().set( c - 1,customReaderData.getRegexsList().get( c ).trim() );
378 | customReaderData.getDataTypesList().set( c - 1,customReaderData.getDataTypesList().get( c ).trim() );
379 | customReaderData.getEmptyFlagsList().set( c - 1,customReaderData.getEmptyFlagsList().get( c ).trim() );
380 | }
381 |
382 | /*
383 | if ( props.getProperty( readerName + ".DateFormatList" ) != null )
384 | {
385 | customReaderData.setDateFormatList( new ArrayList(Arrays.asList( props.getProperty( readerName + ".DateFormatList" ).split( "[\\[\\],]" ) ) ) );
386 | }
387 | else
388 | {
389 | customReaderData.setDateFormatList( new ArrayList() );
390 | }
391 | max = customReaderData.getDateFormatList().size();
392 | for ( int c = 1; c < max; c++ )
393 | {
394 | customReaderData.getDateFormatList().set( c - 1,customReaderData.getDateFormatList().get( c ).trim() );
395 | }
396 | */
397 | Util.logConsole( "props readerName =" + customReaderData.getReaderName() + "=" );
398 | Util.logConsole( "props getFieldSeparatorChar() =" + customReaderData.getFieldSeparatorChar() + "=" );
399 | Util.logConsole( "props getFileEncoding() =" + customReaderData.getFileEncoding() + "=" );
400 | Util.logConsole( "props getDateFormatString() =" + customReaderData.getDateFormatString()+ "=" );
401 | Util.logConsole( "props getHeaderLines() =" + customReaderData.getHeaderLines() + "=" );
402 | Util.logConsole( "props getRegexsList() =" + customReaderData.getRegexsList() + "=" );
403 | Util.logConsole( "props getDataTypesList() =" + customReaderData.getDataTypesList() + "=" );
404 | Util.logConsole( "props getEmptyFlagsList() =" + customReaderData.getEmptyFlagsList() + "=" );
405 |
406 | ReaderConfigsHM.put( props.getProperty( readerName + ".Name" ), customReaderData );
407 |
408 | CustomReader customReader = new CustomReader( customReaderData );
409 | ReaderHM.put( props.getProperty( readerName + ".Name" ), customReader );
410 |
411 | customReader.createSupportedDateFormats( customReaderData.getDateFormatString() );
412 | }
413 | }
414 | }
415 | catch ( IOException ex )
416 | {
417 | Logger.getLogger( Settings.class.getName() ).log( Level.SEVERE, null, ex );
418 | return null;
419 | }
420 |
421 | return ReaderConfigsHM;
422 | }
423 |
424 | public static HashMap getReaderHM() {
425 | return ReaderHM;
426 | }
427 |
428 | public static void setCustomReaderConfig( CustomReaderData customReaderData )
429 | {
430 | try
431 | {
432 | Properties props = load();
433 |
434 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".Name", customReaderData.getReaderName() );
435 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".HeaderLines", Integer.toString( customReaderData.getHeaderLines() ) );
436 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".FooterLines", Integer.toString( customReaderData.getFooterLines() ) );
437 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".FieldSeparator", Integer.toString( customReaderData.getFieldSeparatorChar() ) );
438 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".FileEncodingString", customReaderData.getFileEncoding() );
439 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".DateFormatString", customReaderData.getDateFormatString() );
440 | //setOnly( props, "reader:" + customReaderData.getReaderName() + ".RegexsList", customReaderData.getRegexsListEncoded() );
441 | for( int c = 0; c < 10; c++ )
442 | {
443 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".RegexsList." + c, customReaderData.getRegexsListEle( c ) );
444 | }
445 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".DataTypesList", customReaderData.getDataTypesList().toString() );
446 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".EmptyFlagsList", customReaderData.getEmptyFlagsList().toString() );
447 | //setOnly( props, "reader:" + customReaderData.getReaderName() + ".DateFormatList", customReaderData.getDateFormatList().toString() );
448 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".AmountCurrencyChar", Integer.toString( customReaderData.getAmountCurrencyChar() ) );
449 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".AmountDecimalSignChar", Integer.toString( customReaderData.getAmountDecimalSignChar() ) );
450 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".AmountGroupingSeparatorChar", Integer.toString( customReaderData.getAmountGroupingSeparatorChar() ) );
451 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".AmountFormat", customReaderData.getAmountFormat() );
452 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".ImportReverseOrderFlag", Boolean.toString( customReaderData.getImportReverseOrderFlg() ) );
453 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".UseRegexFlag", Boolean.toString( customReaderData.getUseRegexFlag() ) );
454 | setOnly( props, "reader:" + customReaderData.getReaderName() + ".FilenameMatcher", customReaderData.getFilenameMatcher() );
455 |
456 | save( props );
457 | }
458 | catch ( IOException ex )
459 | {
460 | Logger.getLogger( Settings.class.getName() ).log( Level.SEVERE, null, ex );
461 | }
462 | }
463 |
464 | public static void removeCustomReaderConfig( CustomReaderData customReaderData )
465 | {
466 | try
467 | {
468 | Properties props = load();
469 |
470 | props.remove( "reader:" + customReaderData.getReaderName() + ".Name" );
471 | props.remove( "reader:" + customReaderData.getReaderName() + ".HeaderLines" );
472 | props.remove( "reader:" + customReaderData.getReaderName() + ".FooterLines" );
473 | props.remove( "reader:" + customReaderData.getReaderName() + ".FieldSeparator" );
474 | props.remove( "reader:" + customReaderData.getReaderName() + ".DateFormatString" );
475 | props.remove( "reader:" + customReaderData.getReaderName() + ".RegexsList" );
476 | props.remove( "reader:" + customReaderData.getReaderName() + ".DataTypesList" );
477 | props.remove( "reader:" + customReaderData.getReaderName() + ".EmptyFlagsList" );
478 | //props.remove( "reader:" + customReaderData.getReaderName() + ".DateFormatList" );
479 | props.remove( "reader:" + customReaderData.getReaderName() + ".FooterLines" );
480 | props.remove( "reader:" + customReaderData.getReaderName() + ".AmountCurrencyChar" );
481 | props.remove( "reader:" + customReaderData.getReaderName() + ".AmountDecimalSignChar" );
482 | props.remove( "reader:" + customReaderData.getReaderName() + ".AmountGroupingSeparatorChar" );
483 | props.remove( "reader:" + customReaderData.getReaderName() + ".AmountFormat" );
484 | props.remove( "reader:" + customReaderData.getReaderName() + ".ImportReverseOrderFlag" );
485 |
486 | save( props );
487 | }
488 | catch ( IOException ex )
489 | {
490 | Logger.getLogger( Settings.class.getName() ).log( Level.SEVERE, null, ex );
491 | }
492 | }
493 | }
494 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/StringUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package com.moneydance.modules.features.mdcsvimporter;
7 |
8 | import java.util.ArrayList;
9 |
10 | /**
11 | * Unescapes a string that contains standard Java escape sequences.
12 | *
13 | * - \b \f \n \r \t \" \' :
14 | * BS, FF, NL, CR, TAB, double and single quote.
15 | * - \X \XX \XXX : Octal character
16 | * specification (0 - 377, 0x00 - 0xFF).
17 | * - \ uXXXX : Hexadecimal based Unicode character.
18 | *
19 | *
20 | */
21 |
22 | public class StringUtils
23 | {
24 | public static ArrayList UnescapeJavaString(String st) {
25 |
26 | StringBuilder sb = new StringBuilder(st.length());
27 | ArrayList charList = new ArrayList();
28 | String fsb = "";
29 | Util.logTerminal( "in string =" + st + "=" );
30 | Util.logTerminal( "in string length =" + st.length() + "=" );
31 |
32 | Character ch = ' ';
33 |
34 | for (int i = 0; i < st.length(); i++) {
35 | Util.logTerminal( "at char index =" + i + "=" );
36 |
37 | //char ch = st.charAt(i);
38 | ch = st.charAt(i);
39 | if (ch == '\\') {
40 | Util.logTerminal( "found char \\\\" );
41 | char nextChar = (i == st.length() - 1) ? '\\' : st
42 | .charAt(i + 1);
43 | // Octal escape?
44 | if (nextChar >= '0' && nextChar <= '7') {
45 | Util.logTerminal( "found octal" );
46 | String code = "" + nextChar;
47 | i++;
48 | if ((i < st.length() - 1) && st.charAt(i + 1) >= '0'
49 | && st.charAt(i + 1) <= '7') {
50 | code += st.charAt(i + 1);
51 | i++;
52 | if ((i < st.length() - 1) && st.charAt(i + 1) >= '0'
53 | && st.charAt(i + 1) <= '7') {
54 | code += st.charAt(i + 1);
55 | i++;
56 | }
57 | }
58 | //sb.append((char) Integer.parseInt(code, 8));
59 | ch = (char) Integer.parseInt(code, 8);
60 | charList.add( ch );
61 | //Util.logTerminal( "at octal char index =" + i + "=" );
62 | continue;
63 | }
64 | //Util.logTerminal( "do switch" );
65 |
66 | switch (nextChar) {
67 | case '\\':
68 | ch = '\\';
69 | break;
70 | case 'b':
71 | ch = '\b';
72 | break;
73 | case 'f':
74 | ch = '\f';
75 | break;
76 | case 'n':
77 | ch = '\n';
78 | break;
79 | case 'r':
80 | ch = '\r';
81 | break;
82 | case 't':
83 | //Util.logTerminal( "found \\ t" );
84 | ch = '\t';
85 | break;
86 | case '\"':
87 | ch = '\"';
88 | break;
89 | case '\'':
90 | ch = '\'';
91 | break;
92 | // Hex Unicode: u????
93 | case 'u':
94 | Util.logTerminal( "found unicode u" );
95 | if (i >= st.length() - 5) {
96 | ch = 'u';
97 | break;
98 | }
99 | int code = Integer.parseInt(
100 | "" + st.charAt(i + 2) + st.charAt(i + 3)
101 | + st.charAt(i + 4) + st.charAt(i + 5), 16);
102 | //sb.append(Character.toChars(code));
103 | Util.logTerminal( "Character.toChars(code) =" + Character.toChars(code) + "<" );
104 | ch = Character.toChars(code)[0];
105 | charList.add( ch );
106 | i += 5;
107 | continue;
108 | }
109 | Util.logTerminal( "after switch" );
110 | i++;
111 | }
112 | Util.logTerminal( "append char as int >" + (int) ch + "< index i =" + i);
113 | Util.logTerminal( "character ch =" + ch + "<" );
114 | Util.logTerminal( "String.valueOf(ch) =" + String.valueOf(ch) + "<" );
115 |
116 | //sb.append( ch );
117 | // sb.append( String.valueOf(ch) );
118 | //fsb = String.valueOf(ch);
119 | charList.add( ch );
120 | }
121 | //return sb.toString();
122 | //return ch;
123 | return charList;
124 | // return String.valueOf(ch);
125 | } // end of method
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/Util.java:
--------------------------------------------------------------------------------
1 | package com.moneydance.modules.features.mdcsvimporter;
2 |
3 | import java.awt.*;
4 |
5 | public class Util {
6 |
7 | public static void logConsole(String message) {
8 | logConsole(false, message);
9 | }
10 |
11 | public static void logConsole(Object objMessage) {
12 | logConsole(false, objMessage.toString());
13 | }
14 |
15 | public static void logConsole(Boolean onlyWhenDebug, String message) {
16 | if (onlyWhenDebug && !Main.DEBUG) return;
17 | System.err.println(Main.EXTN_ID + ": " + message);
18 | }
19 |
20 | public static void logConsoleAppend(String appendSequence) {
21 | System.err.append(appendSequence);
22 | }
23 |
24 | public static void logTerminal(String message) {
25 | logTerminal(true, message);
26 | }
27 |
28 | public static void logTerminal(Object objMessage) {
29 | logTerminal(true, objMessage.toString());
30 | }
31 |
32 | public static void logTerminal(Boolean onlyWhenDebug, String message) {
33 | if (onlyWhenDebug && !Main.DEBUG) return;
34 | System.out.println(Main.EXTN_ID + ": " + message);
35 | }
36 |
37 | public static Color getPositiveGreen() {
38 | return Main.getMDGUI().getColors().budgetHealthyColor;
39 | }
40 |
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/WinProps.java:
--------------------------------------------------------------------------------
1 | package com.moneydance.modules.features.mdcsvimporter;
2 |
3 | import java.awt.Dimension;
4 | import java.awt.GraphicsConfiguration;
5 | import java.awt.GraphicsEnvironment;
6 | import java.awt.Point;
7 | import java.awt.Rectangle;
8 | import java.util.ArrayList;
9 |
10 | /**
11 | *
12 | * @author stan
13 | */
14 |
15 |
16 | public class WinProps {
17 |
18 | int width = 800;
19 | int height = 500;
20 | int atX = 0;
21 | int atY = 0;
22 |
23 | public WinProps()
24 | {
25 | //GraphicsConfiguration gc = getGraphicsConfiguration_NoClientCode();
26 | //Rectangle gcBounds = gc.getBounds();
27 | //Dimension windowSize = getSize();
28 |
29 | GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
30 | GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
31 | Rectangle gcBounds = gc.getBounds();
32 | Point centerPoint = ge.getCenterPoint();
33 | atX = centerPoint.x - width / 2;
34 | atY = centerPoint.y - height / 2;
35 | }
36 |
37 | public WinProps( int width, int height, int atX, int atY )
38 | {
39 | this.width = width;
40 | this.height = height;
41 | this.atX = atX;
42 | this.atY = atY;
43 | }
44 |
45 | public WinProps( ArrayList winprops )
46 | {
47 | width = winprops.get(0);
48 | height = winprops.get(1);
49 | atX = winprops.get(2);
50 | atY = winprops.get(3);
51 | }
52 |
53 | public ArrayList getWinPropsAsList( )
54 | {
55 | ArrayList winprops = new ArrayList();
56 | winprops.add( width );
57 | winprops.add( height );
58 | winprops.add( atX );
59 | winprops.add( atY );
60 |
61 | return winprops;
62 | }
63 |
64 | public int getWidth() {
65 | return width;
66 | }
67 |
68 | public void setWidth(int width) {
69 | this.width = width;
70 | }
71 |
72 | public int getHeight() {
73 | return height;
74 | }
75 |
76 | public void setHeight(int height) {
77 | this.height = height;
78 | }
79 |
80 | public int getAtX() {
81 | return atX;
82 | }
83 |
84 | public void setAtX(int atX) {
85 | this.atX = atX;
86 | }
87 |
88 | public int getAtY() {
89 | return atY;
90 | }
91 |
92 | public void setAtY(int atY) {
93 | this.atY = atY;
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/import.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stant/mdcsvimporter2015/8f1bbda0803f5e874a6fbdc140c41299821e96d3/src/com/moneydance/modules/features/mdcsvimporter/import.png
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/meta_info.dict:
--------------------------------------------------------------------------------
1 | {
2 | "id" = "mdcsvimporter2015"
3 | "vendor" = "Stan Towianski - MD code Updates by Stuart Beesley StuWareSoftSystems"
4 | "module_build" = "25"
5 | "minbuild" = "1372"
6 | "vendor.url" = "https://github.com/stant/mdcsvimporter2015/releases"
7 | "module_name" = "CSV Importer"
8 | "desc" = "Let's you create configs for say: Discover card, VISA, your private bank, etc... You denote columns like: -Payment-, -Deposit-, date, amount, memo, etc... It can test your file, giving you a list of all the readers that can handle your file. Importing does matching to skip duplicate entries."
9 | }
10 |
--------------------------------------------------------------------------------
/src/com/moneydance/modules/features/mdcsvimporter/package-info.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Contains the main class.
4 | */
5 | package com.moneydance.modules.features.mdcsvimporter;
6 |
--------------------------------------------------------------------------------
/test/com/moneydance/modules/features/mdcsvimporter/CSVDataTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this template, choose Tools | Templates
3 | * and open the template in the editor.
4 | */
5 | package com.moneydance.modules.features.mdcsvimporter;
6 |
7 | import com.infinitekind.moneydance.model.*;
8 | import java.io.FileReader;
9 | import java.io.IOException;
10 | import java.io.StringReader;
11 | import org.junit.After;
12 | import org.junit.AfterClass;
13 | import org.junit.Before;
14 | import org.junit.BeforeClass;
15 | import org.junit.Test;
16 | import static org.junit.Assert.*;
17 | import org.junit.Ignore;
18 |
19 | /**
20 | *
21 | * @author miki
22 | */
23 | public class CSVDataTest
24 | {
25 | public CSVDataTest()
26 | {
27 | }
28 |
29 | @BeforeClass
30 | public static void setUpClass()
31 | throws Exception
32 | {
33 | }
34 |
35 | @AfterClass
36 | public static void tearDownClass()
37 | throws Exception
38 | {
39 | }
40 |
41 | @Before
42 | public void setUp()
43 | {
44 | }
45 |
46 | @After
47 | public void tearDown()
48 | {
49 | }
50 |
51 | private final String test1 = "\"Column 1\",\"Column 2\"\n\"value 11\",\"value 12\"\n" +
52 | "\"value 21\",\"value 22\"";
53 |
54 | @Test
55 | public void noopTest()
56 | throws IOException
57 | {
58 | System.out.println( "finished noopTest() test." );
59 | }
60 |
61 | // @Test
62 | @Ignore
63 | public void simpleTest1()
64 | throws IOException
65 | {
66 | StringReader data = new StringReader( test1 );
67 | CustomReaderData readerData = new CustomReaderData();
68 | CSVReader csvReader = new CSVReader( data, readerData);
69 | CSVData csvData = new CSVData( csvReader );
70 |
71 | csvData.parseIntoLines( readerData );
72 |
73 | System.out.println( "finished transReader.parse" );
74 |
75 | doTest1( csvData );
76 | csvReader.close();
77 | }
78 |
79 | private void doTest1( CSVData reader )
80 | throws IOException
81 | {
82 | assertFalse( reader.nextField() );
83 | assertTrue( reader.nextLine() );
84 | assertTrue( reader.nextField() );
85 | assertEquals( reader.getField(), "Column 1" );
86 | assertTrue( reader.nextField() );
87 | assertEquals( reader.getField(), "Column 2" );
88 | assertFalse( reader.nextField() );
89 | assertTrue( reader.nextLine() );
90 | assertTrue( reader.nextField() );
91 | assertEquals( reader.getField(), "value 11" );
92 | assertTrue( reader.nextField() );
93 | assertEquals( reader.getField(), "value 12" );
94 | assertFalse( reader.nextField() );
95 | assertTrue( reader.nextLine() );
96 | assertTrue( reader.nextField() );
97 | assertEquals( reader.getField(), "value 21" );
98 | assertTrue( reader.nextField() );
99 | assertEquals( reader.getField(), "value 22" );
100 | assertFalse( reader.nextField() );
101 | assertFalse( reader.nextLine() );
102 | assertFalse( reader.nextField() );
103 |
104 | }
105 | }
--------------------------------------------------------------------------------
/test/com/moneydance/modules/features/mdcsvimporter/CSVReaderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this template, choose Tools | Templates
3 | * and open the template in the editor.
4 | */
5 | package com.moneydance.modules.features.mdcsvimporter;
6 |
7 | import java.io.IOException;
8 | import java.io.StringReader;
9 | import org.junit.After;
10 | import org.junit.AfterClass;
11 | import org.junit.Before;
12 | import org.junit.BeforeClass;
13 | import org.junit.Test;
14 | import static org.junit.Assert.*;
15 | import org.junit.Ignore;
16 |
17 | /**
18 | *
19 | * @author miki
20 | */
21 | public class CSVReaderTest
22 | {
23 | public CSVReaderTest()
24 | {
25 | }
26 |
27 | @BeforeClass
28 | public static void setUpClass()
29 | throws Exception
30 | {
31 | }
32 |
33 | @AfterClass
34 | public static void tearDownClass()
35 | throws Exception
36 | {
37 | }
38 |
39 | @Before
40 | public void setUp()
41 | {
42 | }
43 |
44 | @After
45 | public void tearDown()
46 | {
47 | }
48 | private final String test1 = "\"Column 1\",\"Column 2\"\n\"value 11\",\"value 12\"\n" +
49 | "\"value 21\",\"value 22\"";
50 |
51 | @Test
52 | public void noopTest()
53 | throws IOException
54 | {
55 | System.out.println( "finished noopTest() test." );
56 | }
57 |
58 | // @Test
59 | @Ignore
60 | public void simpleTest1()
61 | throws IOException
62 | {
63 | StringReader data = new StringReader( test1 );
64 | CustomReaderData parseParameters = new CustomReaderData();
65 | CSVReader cvsReader = new CSVReader( data, parseParameters );
66 | doTest1( cvsReader );
67 | }
68 |
69 | private void doTest1( CSVReader reader )
70 | throws IOException
71 | {
72 | assertNull( reader.nextField() );
73 | assertTrue( reader.nextLine() );
74 | assertEquals( reader.nextField(), "Column 1" );
75 | assertEquals( reader.nextField(), "Column 2" );
76 | assertNull( reader.nextField() );
77 | assertTrue( reader.nextLine() );
78 | assertEquals( reader.nextField(), "value 11" );
79 | assertEquals( reader.nextField(), "value 12" );
80 | assertNull( reader.nextField() );
81 | assertTrue( reader.nextLine() );
82 | assertEquals( reader.nextField(), "value 21" );
83 | assertEquals( reader.nextField(), "value 22" );
84 | assertNull( reader.nextField() );
85 | assertFalse( reader.nextLine() );
86 | assertNull( reader.nextField() );
87 | }
88 | }
--------------------------------------------------------------------------------
/test/com/moneydance/modules/features/mdcsvimporter/CustomReaderDialogTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this template, choose Tools | Templates
3 | * and open the template in the editor.
4 | */
5 | package com.moneydance.modules.features.mdcsvimporter;
6 |
7 | import java.net.URL;
8 | import java.io.IOException;
9 | import java.io.InputStreamReader;
10 | import java.io.Reader;
11 | import org.junit.After;
12 | import org.junit.AfterClass;
13 | import org.junit.Before;
14 | import org.junit.BeforeClass;
15 | import org.junit.Ignore;
16 | import org.junit.Test;
17 | import static org.junit.Assert.*;
18 |
19 | /**
20 | *
21 | * @author Stan Towianski
22 | * NOTE: Cannot test everything I want to because I cannot get FeatureModuleContext() because
23 | * I do not know how to 'start' Moneydance itself, so I cannot get account lists or anything.
24 | */
25 | public class CustomReaderDialogTest
26 | {
27 | Main main1 = new Main();
28 | //MoneydanceGUI mdgui = new MoneydanceGUI();
29 | /*
30 | FeatureModuleContext context = new FeatureModuleContext() {
31 |
32 | public RootAccount getRootAccount() {
33 | throw new UnsupportedOperationException("Not supported yet.");
34 | }
35 |
36 | public String getVersion() {
37 | throw new UnsupportedOperationException("Not supported yet.");
38 | }
39 |
40 | public int getBuild() {
41 | throw new UnsupportedOperationException("Not supported yet.");
42 | }
43 |
44 | public void showURL(String string) {
45 | throw new UnsupportedOperationException("Not supported yet.");
46 | }
47 |
48 | public void registerFeature(FeatureModule fm, String string, Image image, String string1) {
49 | throw new UnsupportedOperationException("Not supported yet.");
50 | }
51 |
52 | public void registerHomePageView(FeatureModule fm, HomePageView hpv) {
53 | throw new UnsupportedOperationException("Not supported yet.");
54 | }
55 |
56 | public void registerAccountEditor(FeatureModule fm, int i, AccountEditor ae) {
57 | throw new UnsupportedOperationException("Not supported yet.");
58 | }
59 | };
60 | */
61 |
62 | public CustomReaderDialogTest()
63 | {
64 | }
65 |
66 | @BeforeClass
67 | public static void setUpClass()
68 | throws Exception
69 | {
70 | }
71 |
72 | @AfterClass
73 | public static void tearDownClass()
74 | throws Exception
75 | {
76 | }
77 |
78 | @Before
79 | public void setUp()
80 | {
81 | // main1.init();
82 | }
83 |
84 | @After
85 | public void tearDown()
86 | {
87 | }
88 |
89 | @Test
90 | public void noopTest()
91 | throws IOException
92 | {
93 | System.out.println( "finished noopTest() test." );
94 | }
95 |
96 | /**
97 | * Test
98 | */
99 | @Ignore
100 | public void expectDateProblem()
101 | throws IOException
102 | {
103 | URL url = MainTest.class.getResource( "aa-test.csv" );
104 | System.out.println( "url filepath =" + url.getFile() + "=" );
105 |
106 | String testUri = ImportDialog.RUN_ARGS_FILE + "=" + url.getFile()
107 | //String testUri = ImportDialog.RUN_ARGS_FILE + "=./aa-test.csv"
108 | + "&fileformat=eu date test"
109 | + "&importaccount=IMPORT BANK"
110 | + "&importtype=online&JUNITFLAG2"
111 | ;
112 |
113 | main1.invoke( testUri );
114 |
115 | }
116 |
117 | // @Test
118 | @Ignore
119 | public void dummySoItHasOneTest()
120 | {
121 |
122 | }
123 |
124 | }
--------------------------------------------------------------------------------
/test/com/moneydance/modules/features/mdcsvimporter/DateGuesserTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this template, choose Tools | Templates
3 | * and open the template in the editor.
4 | */
5 | package com.moneydance.modules.features.mdcsvimporter;
6 |
7 | import com.moneydance.modules.features.mdcsvimporter.DateGuesser;
8 | import com.moneydance.modules.features.mdcsvimporter.CSVReader;
9 | import java.io.IOException;
10 | import java.io.InputStreamReader;
11 | import java.io.Reader;
12 | import org.junit.After;
13 | import org.junit.AfterClass;
14 | import org.junit.Before;
15 | import org.junit.BeforeClass;
16 | import org.junit.Test;
17 | import static org.junit.Assert.*;
18 | import org.junit.Ignore;
19 |
20 | /**
21 | *
22 | * @author miki
23 | */
24 | public class DateGuesserTest
25 | {
26 | public DateGuesserTest()
27 | {
28 | }
29 |
30 | @BeforeClass
31 | public static void setUpClass()
32 | throws Exception
33 | {
34 | }
35 |
36 | @AfterClass
37 | public static void tearDownClass()
38 | throws Exception
39 | {
40 | }
41 |
42 | @Before
43 | public void setUp()
44 | {
45 | }
46 |
47 | @After
48 | public void tearDown()
49 | {
50 | }
51 |
52 | @Test
53 | public void noopTest()
54 | throws IOException
55 | {
56 | System.out.println( "finished noopTest() test." );
57 | }
58 |
59 | /**
60 | * Test of class DateGuesser.
61 | */
62 | // @Test
63 | @Ignore
64 | public void testCheckDateString()
65 | throws IOException
66 | {
67 | Reader file = new InputStreamReader(
68 | DateGuesserTest.class.getResourceAsStream( "dateGuesser.csv" ) );
69 | CSVReader reader = new CSVReader( );
70 | DateGuesser guesser = new DateGuesser();
71 |
72 | while ( reader.nextLine() ) {
73 | for ( String s = reader.nextField(); s != null; s = reader.nextField() ) {
74 | guesser.checkDateString( s );
75 | }
76 | }
77 |
78 | guesser.getBestFormatProbability();
79 | }
80 | }
--------------------------------------------------------------------------------
/test/com/moneydance/modules/features/mdcsvimporter/MainTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this template, choose Tools | Templates
3 | * and open the template in the editor.
4 | */
5 | package com.moneydance.modules.features.mdcsvimporter;
6 |
7 | import java.net.URL;
8 | import java.io.IOException;
9 | import java.io.InputStreamReader;
10 | import java.io.Reader;
11 | import org.junit.After;
12 | import org.junit.AfterClass;
13 | import org.junit.Before;
14 | import org.junit.BeforeClass;
15 | import org.junit.Ignore;
16 | import org.junit.Test;
17 | import static org.junit.Assert.*;
18 |
19 | /**
20 | *
21 | * @author Stan Towianski
22 | * NOTE: Cannot test everything I want to because I cannot get FeatureModuleContext() because
23 | * I do not know how to 'start' Moneydance itself, so I cannot get account lists or anything.
24 | */
25 | public class MainTest
26 | {
27 | Main main1 = new Main();
28 | //MoneydanceGUI mdgui = new MoneydanceGUI();
29 | /*
30 | FeatureModuleContext context = new FeatureModuleContext() {
31 |
32 | public RootAccount getRootAccount() {
33 | throw new UnsupportedOperationException("Not supported yet.");
34 | }
35 |
36 | public String getVersion() {
37 | throw new UnsupportedOperationException("Not supported yet.");
38 | }
39 |
40 | public int getBuild() {
41 | throw new UnsupportedOperationException("Not supported yet.");
42 | }
43 |
44 | public void showURL(String string) {
45 | throw new UnsupportedOperationException("Not supported yet.");
46 | }
47 |
48 | public void registerFeature(FeatureModule fm, String string, Image image, String string1) {
49 | throw new UnsupportedOperationException("Not supported yet.");
50 | }
51 |
52 | public void registerHomePageView(FeatureModule fm, HomePageView hpv) {
53 | throw new UnsupportedOperationException("Not supported yet.");
54 | }
55 |
56 | public void registerAccountEditor(FeatureModule fm, int i, AccountEditor ae) {
57 | throw new UnsupportedOperationException("Not supported yet.");
58 | }
59 | };
60 | */
61 |
62 | public MainTest()
63 | {
64 | }
65 |
66 | @BeforeClass
67 | public static void setUpClass()
68 | throws Exception
69 | {
70 | }
71 |
72 | @AfterClass
73 | public static void tearDownClass()
74 | throws Exception
75 | {
76 | }
77 |
78 | @Before
79 | public void setUp()
80 | {
81 | main1.init();
82 | }
83 |
84 | @After
85 | public void tearDown()
86 | {
87 | }
88 |
89 | @Test
90 | public void noopTest()
91 | throws IOException
92 | {
93 | System.out.println( "finished noopTest() test." );
94 | }
95 |
96 | /**
97 | * Test
98 | */
99 | // @Test
100 | @Ignore
101 | public void expectInvalidFileAndImportaccount()
102 | throws IOException
103 | {
104 | String testUri = ImportDialog.RUN_ARGS_FILE + "=/zzz111222qqq.csv"
105 | + "&fileformat=Discover Card"
106 | + "&importaccount=IMPORT BANK"
107 | + "&deletecsvfileflag"
108 | + "&importtype=online&JUNITFLAG&processFlag"
109 | ;
110 |
111 | main1.invoke( testUri );
112 |
113 | assertEquals( (Integer) main1.getErrCodeList().get( 0 ), (Integer) ImportDialog.RUN_ARGS_ERRORCODE_INVALID_FILE );
114 | assertEquals( (Integer) main1.getErrCodeList().get( 1 ), (Integer) ImportDialog.RUN_ARGS_ERRORCODE_INVALID_IMPORTACCOUNT );
115 | }
116 |
117 | @Ignore
118 | public void expectInvalidFileformat()
119 | throws IOException
120 | {
121 | // Reader file = new InputStreamReader(
122 | // MainTest.class.getResourceAsStream( "dateGuesser.csv" ) );
123 |
124 | URL url = MainTest.class.getResource( "dateGuesser.csv" );
125 | System.out.println( "url filepath =" + url.getFile() + "=" );
126 |
127 | String testUri = ImportDialog.RUN_ARGS_FILE + "=" + url.getFile()
128 | + "&fileformat=Discover Card"
129 | + "&deletecsvfileflag"
130 | + "&importtype=online&JUNITFLAG&processFlag"
131 | ;
132 |
133 | main1.invoke( testUri );
134 |
135 | assertEquals( (Integer) main1.getErrCodeList().get( 0 ), (Integer) ImportDialog.RUN_ARGS_ERRORCODE_INVALID_FILEFORMAT_FOR_FILE );
136 | }
137 |
138 | // @Test
139 | @Ignore
140 | public void expectMissingFileArg()
141 | throws IOException
142 | {
143 | String testUri = "importaccount=1232zxzcx"
144 | + "&deletecsvfileflag"
145 | + "&importtype=online&JUNITFLAG&processFlag"
146 | ;
147 |
148 | main1.invoke( testUri );
149 |
150 | assertEquals( (Integer) main1.getErrCodeList().get( 0 ), (Integer) ImportDialog.RUN_ARGS_ERRORCODE_REQUIRES_FILE );
151 | }
152 |
153 | }
--------------------------------------------------------------------------------
/test/com/moneydance/modules/features/mdcsvimporter/aa-test.csv:
--------------------------------------------------------------------------------
1 | "Dato";"Tekst";"Beløb";"Saldo";"Status";"Afstemt"
2 | "30.08.2011";"Valutahandel";"6,819.74";"6,819.74";"Udført";"Nej"
3 | "30.08.2011";"Kontantvaluta";"-35.00";"6,784.74";"Udført";"Nej"
4 | "05.09.2011";"Udbetaling";"-5.000.00";"1,784.74";"Udført";"Nej"
5 | "13.09.2011";"Panidraetdk";"-100.00";"1,684.74";"Udført";"Nej"
--------------------------------------------------------------------------------
/test/com/moneydance/modules/features/mdcsvimporter/dateGuesser.csv:
--------------------------------------------------------------------------------
1 | Transaction Date,Posting Date,Description,Amount
2 | "02/02/2009","02/02/2009","Transaction Description","-5,082.82"
3 | "01/15/2009","01/16/2009","Transaction Description","30.00"
4 | "01/15/2009","01/16/2009","Transaction Description","84.53"
5 | "01/16/2009","01/20/2009","Transaction Description","24.00"
6 | "01/16/2009","01/19/2009","Transaction Description","19.81"
7 | "01/17/2009","01/19/2009","Transaction Description","195.00"
8 | "01/17/2009","01/19/2009","Transaction Description","31.34"
9 | "01/17/2009","01/19/2009","Transaction Description","63.53"
10 | "01/17/2009","01/19/2009","Transaction Description","11.30"
11 | "01/20/2009","01/27/2009","Transaction Description","32.00"
12 | "01/20/2009","01/21/2009","Transaction Description","51.83"
13 | "01/20/2009","01/21/2009","Transaction Description","21.00"
14 | "01/20/2009","01/21/2009","Transaction Description","76.34"
15 | "01/21/2009","01/23/2009","Transaction Description","28.00"
16 | "01/21/2009","01/22/2009","Transaction Description","46.45"
17 | "01/21/2009","01/23/2009","Transaction Description","15.98"
18 | "01/22/2009","01/24/2009","Transaction Description","39.02"
19 | "01/22/2009","01/23/2009","Transaction Description","60.00"
20 | "01/25/2009","01/26/2009","Transaction Description","153.05"
21 | "01/28/2009","01/29/2009","Transaction Description","17.98"
22 | "01/31/2009","02/02/2009","Transaction Description","15.84"
23 | "01/31/2009","02/02/2009","Transaction Description","10.00"
24 | "01/31/2009","02/02/2009","Transaction Description","40.00"
25 | "02/01/2009","02/02/2009","Transaction Description","41.00"
26 | "02/01/2009","02/02/2009","Transaction Description","144.39"
27 | "02/02/2009","02/03/2009","Transaction Description","30.50"
28 | "02/02/2009","02/03/2009","Transaction Description","23.00"
29 | "02/02/2009","02/03/2009","Transaction Description","93.77"
30 | "02/03/2009","02/05/2009","Transaction Description","7.33"
31 | "02/03/2009","02/04/2009","Transaction Description","21.00"
32 | "02/03/2009","02/04/2009","Transaction Description","41.47"
33 | "02/03/2009","02/04/2009","Transaction Description","36.50"
34 | "02/03/2009","02/05/2009","Transaction Description","56.49"
35 | "02/03/2009","02/04/2009","Transaction Description","40.97"
36 | "02/05/2009","02/09/2009","Transaction Description","87.24"
37 | "02/05/2009","02/06/2009","Transaction Description","33.02"
38 | "02/06/2009","02/09/2009","Transaction Description","40.00"
39 | "02/06/2009","02/07/2009","Transaction Description","30.00"
40 | "02/07/2009","02/10/2009","Transaction Description","296.35"
41 | "02/08/2009","02/09/2009","Transaction Description","144.15"
42 | "02/08/2009","02/09/2009","Transaction Description","214.36"
43 | "02/08/2009","02/11/2009","Transaction Description","77.24"
44 | "02/09/2009","02/11/2009","Transaction Description","39.19"
45 | "02/10/2009","02/12/2009","Transaction Description","56.31"
46 | "02/10/2009","02/12/2009","Transaction Description","10.00"
47 | "02/10/2009","02/11/2009","Transaction Description","54.36"
48 | "02/11/2009","02/12/2009","Transaction Description","63.17"
49 | "02/11/2009","02/12/2009","Transaction Description","89.94"
50 | "02/2009/11","02/13/2009","Transaction Description","65.00"
51 |
52 | Date downloaded:,"02/17/2009"
53 |
--------------------------------------------------------------------------------