├── .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 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
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 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
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 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
49 |
50 |
51 |
52 |
53 |
54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 |
137 | 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 | --------------------------------------------------------------------------------