Merge lp:~s-mika/financisto/csv_import into lp:~financisto-dev/financisto/trunk
- csv_import
- Merge into trunk
Proposed by
smika
Status: | Merged |
---|---|
Merge reported by: | smika |
Merged at revision: | not available |
Proposed branch: | lp:~s-mika/financisto/csv_import |
Merge into: | lp:~financisto-dev/financisto/trunk |
Diff against target: |
1201 lines (+952/-53) 16 files modified
.classpath (+14/-13) .project (+40/-33) AndroidManifest.xml (+3/-1) default.properties (+2/-0) res/layout/csv_import.xml (+70/-0) res/values-de/strings.xml (+10/-0) res/values/common.xml (+2/-1) res/values/strings.xml (+14/-1) src/ru/orangesoftware/financisto/activity/AbstractImportActivity.java (+125/-0) src/ru/orangesoftware/financisto/activity/CsvImportActivity.java (+306/-0) src/ru/orangesoftware/financisto/activity/MainActivity.java (+78/-3) src/ru/orangesoftware/financisto/db/DatabaseAdapter.java (+31/-0) src/ru/orangesoftware/financisto/export/ImportExportAsyncTask.java (+1/-0) src/ru/orangesoftware/financisto/export/csv/Csv.java (+1/-1) src/ru/orangesoftware/financisto/imports/csv/CsvImport.java (+200/-0) src/ru/orangesoftware/financisto/imports/csv/CsvImportOptions.java (+55/-0) |
To merge this branch: | bzr merge lp:~s-mika/financisto/csv_import |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Financisto Developers | Pending | ||
Review via email: mp+80151@code.launchpad.net |
Commit message
Description of the change
Hi,
this is my first release for csv import function.
I am working now for some weeks with this import feature and it works for me.
Got no feedback from function requestor but think its worth for merging review.
Any feedback is welcome.
Regards
Sebastian
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.classpath' |
2 | --- .classpath 2011-06-29 17:46:15 +0000 |
3 | +++ .classpath 2011-10-23 17:45:27 +0000 |
4 | @@ -1,13 +1,14 @@ |
5 | -<?xml version="1.0" encoding="UTF-8"?> |
6 | -<classpath> |
7 | - <classpathentry kind="src" path="gen"/> |
8 | - <classpathentry kind="src" path="src"/> |
9 | - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/Android 2.2 Google APIs"/> |
10 | - <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> |
11 | - <classpathentry kind="lib" path="lib/trace-0.2.0.jar"/> |
12 | - <classpathentry exported="true" kind="lib" path="lib/rfc2445-no-joda.jar" sourcepath="H:/Work/Java/Android/google-rfc-2445-read-only/src"/> |
13 | - <classpathentry kind="lib" path="lib/GDocsAPI.jar"/> |
14 | - <classpathentry kind="lib" path="lib/CWAC-WakefulIntentService.jar"/> |
15 | - <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/Android 2.2 Google APIs"/> |
16 | - <classpathentry kind="output" path="bin"/> |
17 | -</classpath> |
18 | +<?xml version="1.0" encoding="UTF-8"?> |
19 | +<classpath> |
20 | + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/Java SE 6 (MacOS X Default)"/> |
21 | + <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> |
22 | + <classpathentry kind="lib" path="lib/trace-0.2.0.jar"/> |
23 | + <classpathentry exported="true" kind="lib" path="lib/rfc2445-no-joda.jar" sourcepath="H:/Work/Java/Android/google-rfc-2445-read-only/src"/> |
24 | + <classpathentry kind="lib" path="lib/GDocsAPI.jar"/> |
25 | + <classpathentry kind="lib" path="lib/CWAC-WakefulIntentService.jar"/> |
26 | + <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/Android 2.2 Google APIs"/> |
27 | + <classpathentry kind="src" path="src"/> |
28 | + <classpathentry kind="src" path="gen"/> |
29 | + <classpathentry kind="src" path="GreenDroid_src"/> |
30 | + <classpathentry kind="output" path="bin"/> |
31 | +</classpath> |
32 | |
33 | === modified file '.project' |
34 | --- .project 2011-02-20 19:39:08 +0000 |
35 | +++ .project 2011-10-23 17:45:27 +0000 |
36 | @@ -1,33 +1,40 @@ |
37 | -<?xml version="1.0" encoding="UTF-8"?> |
38 | -<projectDescription> |
39 | - <name>Financisto</name> |
40 | - <comment></comment> |
41 | - <projects> |
42 | - </projects> |
43 | - <buildSpec> |
44 | - <buildCommand> |
45 | - <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> |
46 | - <arguments> |
47 | - </arguments> |
48 | - </buildCommand> |
49 | - <buildCommand> |
50 | - <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> |
51 | - <arguments> |
52 | - </arguments> |
53 | - </buildCommand> |
54 | - <buildCommand> |
55 | - <name>org.eclipse.jdt.core.javabuilder</name> |
56 | - <arguments> |
57 | - </arguments> |
58 | - </buildCommand> |
59 | - <buildCommand> |
60 | - <name>com.android.ide.eclipse.adt.ApkBuilder</name> |
61 | - <arguments> |
62 | - </arguments> |
63 | - </buildCommand> |
64 | - </buildSpec> |
65 | - <natures> |
66 | - <nature>com.android.ide.eclipse.adt.AndroidNature</nature> |
67 | - <nature>org.eclipse.jdt.core.javanature</nature> |
68 | - </natures> |
69 | -</projectDescription> |
70 | +<?xml version="1.0" encoding="UTF-8"?> |
71 | +<projectDescription> |
72 | + <name>Financisto</name> |
73 | + <comment></comment> |
74 | + <projects> |
75 | + </projects> |
76 | + <buildSpec> |
77 | + <buildCommand> |
78 | + <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> |
79 | + <arguments> |
80 | + </arguments> |
81 | + </buildCommand> |
82 | + <buildCommand> |
83 | + <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> |
84 | + <arguments> |
85 | + </arguments> |
86 | + </buildCommand> |
87 | + <buildCommand> |
88 | + <name>org.eclipse.jdt.core.javabuilder</name> |
89 | + <arguments> |
90 | + </arguments> |
91 | + </buildCommand> |
92 | + <buildCommand> |
93 | + <name>com.android.ide.eclipse.adt.ApkBuilder</name> |
94 | + <arguments> |
95 | + </arguments> |
96 | + </buildCommand> |
97 | + </buildSpec> |
98 | + <natures> |
99 | + <nature>com.android.ide.eclipse.adt.AndroidNature</nature> |
100 | + <nature>org.eclipse.jdt.core.javanature</nature> |
101 | + </natures> |
102 | + <linkedResources> |
103 | + <link> |
104 | + <name>GreenDroid_src</name> |
105 | + <type>2</type> |
106 | + <locationURI>_android_GreenDroid_612cb559/src</locationURI> |
107 | + </link> |
108 | + </linkedResources> |
109 | +</projectDescription> |
110 | |
111 | === modified file 'AndroidManifest.xml' |
112 | --- AndroidManifest.xml 2011-09-19 12:45:09 +0000 |
113 | +++ AndroidManifest.xml 2011-10-23 17:45:27 +0000 |
114 | @@ -183,7 +183,9 @@ |
115 | |
116 | <activity android:name=".activity.SplitTransactionActivity" android:label="@string/split_transaction" /> |
117 | <activity android:name=".activity.SplitTransferActivity" android:label="@string/split_transfer"/> |
118 | - |
119 | + <activity android:name=".activity.CsvImportActivity" android:label="@string/csv_import" |
120 | + android:theme="@android:style/Theme.Dialog" android:configChanges="orientation|keyboardHidden"/> |
121 | + |
122 | </application> |
123 | |
124 | <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="5"/> |
125 | |
126 | === modified file 'default.properties' |
127 | --- default.properties 2011-02-20 19:39:08 +0000 |
128 | +++ default.properties 2011-10-23 17:45:27 +0000 |
129 | @@ -12,3 +12,5 @@ |
130 | # Project target. |
131 | target=Google Inc.:Google APIs:8 |
132 | apk-configurations= |
133 | +android.library=false |
134 | +android.library.reference.1=../../workspace/GreenDroid |
135 | |
136 | === added file 'res/drawable/ic_launcher_folder_small.png' |
137 | Binary files res/drawable/ic_launcher_folder_small.png 1970-01-01 00:00:00 +0000 and res/drawable/ic_launcher_folder_small.png 2011-10-23 17:45:27 +0000 differ |
138 | === added file 'res/layout/csv_import.xml' |
139 | --- res/layout/csv_import.xml 1970-01-01 00:00:00 +0000 |
140 | +++ res/layout/csv_import.xml 2011-10-23 17:45:27 +0000 |
141 | @@ -0,0 +1,70 @@ |
142 | +<!-- |
143 | + Copyright (c) 2010 Denis Solonenko. |
144 | + All rights reserved. This program and the accompanying materials |
145 | + are made available under the terms of the GNU Public License v2.0 |
146 | + which accompanies this distribution, and is available at |
147 | + http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
148 | + |
149 | + Contributors: |
150 | + Denis Solonenko - initial API and implementation |
151 | +--> |
152 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
153 | + android:layout_width="fill_parent" android:layout_height="fill_parent" |
154 | + android:orientation="vertical" android:padding="3dp"> |
155 | + <View android:layout_height="1dp" android:background="@drawable/divider_horizontal_dark" |
156 | + android:layout_width="fill_parent" android:layout_marginLeft="10dp" |
157 | + android:layout_marginRight="10dp" /> |
158 | + <TextView android:layout_height="wrap_content" |
159 | + android:layout_width="fill_parent" android:layout_marginLeft="3dp" android:text="@string/file_name"/> |
160 | + <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> |
161 | + <EditText android:layout_weight="1" android:layout_width="0dip" android:layout_height="wrap_content" android:id="@+id/edFilename"> |
162 | + <requestFocus></requestFocus> |
163 | + </EditText> |
164 | + <ImageButton android:layout_width="wrap_content" android:layout_gravity="center_vertical" android:src="@drawable/ic_launcher_folder_small" android:id="@+id/btn_browse" android:layout_height="wrap_content"></ImageButton> |
165 | + </LinearLayout> |
166 | + <TextView android:layout_height="wrap_content" |
167 | + android:layout_width="fill_parent" android:layout_marginLeft="3dp" |
168 | + android:text="@string/accounts"/> |
169 | + <Button android:layout_height="wrap_content" android:id="@+id/bAccounts" |
170 | + android:layout_width="fill_parent" android:text="@string/choose_account"/> |
171 | + <View android:layout_height="1dp" android:background="@drawable/divider_horizontal_dark" |
172 | + android:layout_width="fill_parent" android:layout_marginLeft="10dp" |
173 | + android:layout_marginRight="10dp" /> |
174 | + |
175 | + <TableLayout android:layout_height="wrap_content" |
176 | + android:layout_width="fill_parent" |
177 | + android:stretchColumns="*"> |
178 | + <TableRow> |
179 | + <TextView android:layout_marginLeft="3dp" |
180 | + android:text="@string/decimals"/> |
181 | + <TextView android:layout_marginLeft="3dp" |
182 | + android:text="@string/decimal_separator"/> |
183 | + <TextView android:layout_marginLeft="3dp" |
184 | + android:text="@string/group_separator"/> |
185 | + </TableRow> |
186 | + <TableRow> |
187 | + <Spinner android:id="@+id/spinnerDecimals" |
188 | + android:entries="@array/decimals"/> |
189 | + <Spinner android:id="@+id/spinnerDecimalSeparators" |
190 | + android:entries="@array/decimal_separators"/> |
191 | + <Spinner android:id="@+id/spinnerGroupSeparators" |
192 | + android:entries="@array/group_separators"/> |
193 | + </TableRow> |
194 | + <TableRow> |
195 | + <TextView android:layout_marginLeft="3dp" android:text="@string/field_separator"></TextView> |
196 | + </TableRow> |
197 | + <TableRow> |
198 | + <Spinner android:entries="@array/field_separators" android:id="@+id/spinnerFieldSeparator"></Spinner> |
199 | + </TableRow> |
200 | + <View android:layout_height="1dp" android:background="@drawable/divider_horizontal_dark" |
201 | + android:layout_width="fill_parent" android:layout_marginLeft="10dp" |
202 | + android:layout_marginRight="10dp" /> |
203 | + </TableLayout> |
204 | + <TextView android:layout_height="wrap_content" |
205 | + android:layout_width="fill_parent" android:layout_marginLeft="3dp" |
206 | + android:text="@string/date_format"/> |
207 | + <Spinner android:layout_height="wrap_content" android:layout_width="fill_parent" |
208 | + android:id="@+id/spinnerDateFormats" android:entries="@array/date_format_values"/> |
209 | + |
210 | + <include layout="@layout/ok_cancel_buttons" /> |
211 | +</LinearLayout> |
212 | \ No newline at end of file |
213 | |
214 | === modified file 'res/values-de/strings.xml' |
215 | --- res/values-de/strings.xml 2011-09-12 22:55:24 +0000 |
216 | +++ res/values-de/strings.xml 2011-10-23 17:45:27 +0000 |
217 | @@ -653,6 +653,11 @@ |
218 | <string name="date_format">Datumsformat</string> |
219 | <string name="pin_protection_lock_transaction">Neue(n) Transaktion\\Transfer sperren</string> |
220 | <string name="pin_protection_lock_transaction_summary">\'Neue Transaktion\'- und \'Neuer Transfer\'-Bildschirm mit PIN sperren</string> |
221 | + <string name="file_name">Dateiname</string> |
222 | + <string name="chosse_account">Wähle Konto</string> |
223 | + <string name="no_filemanager_installed">Kein Dateimanager installiert</string> |
224 | + <string name="csv_import">CSV Import</string> |
225 | + <string name="csv_import_inprogress">CSV Import in Bearbeitung</string> |
226 | |
227 | <string name="split">[Split-Buchung...]</string> |
228 | <string name="split_transaction">[Split-Transaktion]</string> |
229 | @@ -670,5 +675,10 @@ |
230 | <string name="unsplit_adjust_last_summary">Letzte Buchung anpassen</string> |
231 | |
232 | <string name="add_transfer">Transfer hinzufügen</string> |
233 | + <string name="select_filename">Wähle Import Dateiname</string> |
234 | + <string name="import_file_not_found">Import Datei nicht gefunden</string> |
235 | + <string name="import_unknown_category">Unbekannte Kategorie in Importdatei</string> |
236 | + <string name="import_unknown_project">Unbekanntes Projekt in Importdatei</string> |
237 | + <string name="import_wrong_currency">Falsche Währung in Importdatei</string> |
238 | |
239 | </resources> |
240 | |
241 | === modified file 'res/values/common.xml' |
242 | --- res/values/common.xml 2011-07-25 17:44:44 +0000 |
243 | +++ res/values/common.xml 2011-10-23 17:45:27 +0000 |
244 | @@ -154,7 +154,8 @@ |
245 | <string-array name="date_format_values"> |
246 | <item>dd/MM/yyyy</item> |
247 | <item>MM/dd/yyyy</item> |
248 | - <item>yyyy-MM-dd</item> |
249 | + <item>yyyy-MM-dd</item> |
250 | + <item>dd.MM.yyyy</item> |
251 | </string-array> |
252 | |
253 | <string-array name="unsplit_quick_action_items"> |
254 | |
255 | === modified file 'res/values/strings.xml' |
256 | --- res/values/strings.xml 2011-07-25 17:44:44 +0000 |
257 | +++ res/values/strings.xml 2011-10-23 17:45:27 +0000 |
258 | @@ -659,6 +659,19 @@ |
259 | <string name="unsplit_adjust_last">Last</string> |
260 | <string name="unsplit_adjust_last_summary">Adjust last</string> |
261 | |
262 | - <string name="add_transfer">Add Transfer</string> |
263 | + <string name="add_transfer">Add Transfer</string> |
264 | + <string name="file_name">File name</string> |
265 | + <string name="choose_account">Choose account</string> |
266 | + <string name="no_filemanager_installed">No filemanager installed</string> |
267 | + <string name="csv_import">CSV Import</string> |
268 | + <string name="csv_import_inprogress">CSV Import in progress</string> |
269 | + <string name="select_filename">Select Import filename</string> |
270 | + <string name="import_file_not_found">Import file not found</string> |
271 | + <string name="import_unknown_category">Unknown category in import file</string> |
272 | + <string name="import_unknown_project">Unknown project in import file</string> |
273 | + <string name="import_wrong_currency">Wrong currency in import file</string> |
274 | + <string name="import_illegal_argument_exception">Illegal argument exception</string> |
275 | + <string name="import_parse_error">Parsing error in import file</string> |
276 | + <string name="csv_import_error">CSV import error</string> |
277 | |
278 | </resources> |
279 | |
280 | === added file 'src/ru/orangesoftware/financisto/activity/AbstractImportActivity.java' |
281 | --- src/ru/orangesoftware/financisto/activity/AbstractImportActivity.java 1970-01-01 00:00:00 +0000 |
282 | +++ src/ru/orangesoftware/financisto/activity/AbstractImportActivity.java 2011-10-23 17:45:27 +0000 |
283 | @@ -0,0 +1,125 @@ |
284 | +/******************************************************************************* |
285 | + * Copyright (c) 2010 Denis Solonenko. |
286 | + * All rights reserved. This program and the accompanying materials |
287 | + * are made available under the terms of the GNU Public License v2.0 |
288 | + * which accompanies this distribution, and is available at |
289 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
290 | + * |
291 | + * Contributors: |
292 | + * Denis Solonenko - initial API and implementation |
293 | + ******************************************************************************/ |
294 | +package ru.orangesoftware.financisto.activity; |
295 | + |
296 | +import android.app.Activity; |
297 | +import android.content.ActivityNotFoundException; |
298 | +import android.content.Intent; |
299 | +import android.net.Uri; |
300 | +import android.os.Bundle; |
301 | +import android.util.Log; |
302 | +import android.view.View; |
303 | +import android.view.View.OnClickListener; |
304 | +import android.widget.Button; |
305 | +import android.widget.EditText; |
306 | +import android.widget.ImageButton; |
307 | +import android.widget.Toast; |
308 | +import ru.orangesoftware.financisto.R; |
309 | +import ru.orangesoftware.financisto.blotter.WhereFilter; |
310 | +import ru.orangesoftware.financisto.blotter.WhereFilter.DateTimeCriteria; |
311 | +import ru.orangesoftware.financisto.utils.DateUtils; |
312 | +import ru.orangesoftware.financisto.utils.PinProtection; |
313 | +import ru.orangesoftware.financisto.utils.DateUtils.Period; |
314 | +import ru.orangesoftware.financisto.utils.DateUtils.PeriodType; |
315 | + |
316 | +import java.text.DateFormat; |
317 | +import java.util.Date; |
318 | + |
319 | +public abstract class AbstractImportActivity extends Activity { |
320 | + |
321 | + public static final int IMPORT_FILENAME_REQUESTCODE=0xff; |
322 | + public static final int IMPORT_XSLFILENAME_REQUESTCODE=0xfe; |
323 | + |
324 | + private final int layoutId; |
325 | + private DateFormat df; |
326 | + protected ImageButton bBrowse; |
327 | + protected EditText edFilename; |
328 | + |
329 | + |
330 | + public AbstractImportActivity(int layoutId) { |
331 | + this.layoutId = layoutId; |
332 | + } |
333 | + |
334 | + @Override |
335 | + protected void onCreate(Bundle savedInstanceState) { |
336 | + super.onCreate(savedInstanceState); |
337 | + setContentView(layoutId); |
338 | + |
339 | + df = DateUtils.getShortDateFormat(this); |
340 | + |
341 | + bBrowse = (ImageButton) findViewById(R.id.btn_browse); |
342 | + bBrowse.setOnClickListener(new View.OnClickListener() { |
343 | + @Override |
344 | + public void onClick(View v) { |
345 | + openFile(); |
346 | + } |
347 | + }); |
348 | + edFilename=(EditText) findViewById(R.id.edFilename); |
349 | + |
350 | + internalOnCreate(); |
351 | + } |
352 | + |
353 | + protected void openFile() { |
354 | + String filename = edFilename.getText().toString(); |
355 | + |
356 | + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); |
357 | + intent.addCategory(Intent.CATEGORY_OPENABLE); |
358 | + |
359 | + intent.setData(Uri.parse("file://" + filename)); |
360 | + intent.setType("*/*"); |
361 | + |
362 | + try { |
363 | + startActivityForResult(intent,IMPORT_FILENAME_REQUESTCODE); |
364 | + } catch (ActivityNotFoundException e) { |
365 | + // No compatible file manager was found. |
366 | + Toast.makeText(this, R.string.no_filemanager_installed, Toast.LENGTH_SHORT).show(); |
367 | + } |
368 | + |
369 | + } |
370 | + |
371 | + |
372 | + protected abstract void internalOnCreate(); |
373 | + |
374 | + protected abstract void updateResultIntentFromUi(Intent data); |
375 | + |
376 | + |
377 | + @Override |
378 | + protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
379 | + if (requestCode ==IMPORT_FILENAME_REQUESTCODE) { |
380 | + if (resultCode == RESULT_OK && data != null) { |
381 | + String filename = data.getDataString(); |
382 | + if (filename != null) { |
383 | + if (filename.startsWith("file://")) { |
384 | + filename = filename.substring(7); |
385 | + } |
386 | + filename = Uri.decode(filename); |
387 | + edFilename.setText(filename); |
388 | + savePreferences(); |
389 | + } |
390 | + } |
391 | + } |
392 | + |
393 | + } |
394 | + |
395 | + @Override |
396 | + protected void onPause() { |
397 | + super.onPause(); |
398 | + PinProtection.lock(this); |
399 | + } |
400 | + |
401 | + @Override |
402 | + protected void onResume() { |
403 | + super.onResume(); |
404 | + PinProtection.unlock(this); |
405 | + } |
406 | + |
407 | + abstract void savePreferences(); |
408 | +} |
409 | |
410 | === added file 'src/ru/orangesoftware/financisto/activity/CsvImportActivity.java' |
411 | --- src/ru/orangesoftware/financisto/activity/CsvImportActivity.java 1970-01-01 00:00:00 +0000 |
412 | +++ src/ru/orangesoftware/financisto/activity/CsvImportActivity.java 2011-10-23 17:45:27 +0000 |
413 | @@ -0,0 +1,306 @@ |
414 | +/******************************************************************************* |
415 | + * Copyright (c) 2010 Denis Solonenko. |
416 | + * All rights reserved. This program and the accompanying materials |
417 | + * are made available under the terms of the GNU Public License v2.0 |
418 | + * which accompanies this distribution, and is available at |
419 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
420 | + * |
421 | + * Contributors: |
422 | + * Denis Solonenko - initial API and implementation |
423 | + ******************************************************************************/ |
424 | +package ru.orangesoftware.financisto.activity; |
425 | + |
426 | +import java.util.ArrayList; |
427 | +import java.util.List; |
428 | + |
429 | +import ru.orangesoftware.financisto.R; |
430 | +import ru.orangesoftware.financisto.db.DatabaseAdapter; |
431 | +import ru.orangesoftware.financisto.model.Account; |
432 | +import ru.orangesoftware.financisto.model.MultiChoiceItem; |
433 | +import ru.orangesoftware.financisto.utils.CurrencyExportPreferences; |
434 | +import ru.orangesoftware.financisto.view.NodeInflater; |
435 | +import android.app.AlertDialog; |
436 | +import android.app.ProgressDialog; |
437 | +import android.content.ActivityNotFoundException; |
438 | +import android.content.Context; |
439 | +import android.content.DialogInterface; |
440 | +import android.content.Intent; |
441 | +import android.content.SharedPreferences; |
442 | +import android.net.Uri; |
443 | +import android.text.TextUtils; |
444 | +import android.view.LayoutInflater; |
445 | +import android.view.View; |
446 | +import android.view.View.OnClickListener; |
447 | +import android.widget.Button; |
448 | +import android.widget.EditText; |
449 | +import android.widget.ImageButton; |
450 | +import android.widget.ListAdapter; |
451 | +import android.widget.Spinner; |
452 | +import android.widget.Toast; |
453 | + |
454 | + |
455 | + |
456 | +public class CsvImportActivity extends AbstractImportActivity implements ActivityLayoutListener { |
457 | + |
458 | + public static final String CSV_IMPORT_SELECTED_ACCOUNT = "CSV_IMPORT_SELECTED_ACCOUNT"; |
459 | + public static final String CSV_IMPORT_DATE_FORMAT = "CSV_IMPORT_DATE_FORMAT"; |
460 | + public static final String CSV_IMPORT_FILENAME="CSV_IMPORT_FILENAME"; |
461 | + public static final String CSV_IMPORT_FIELD_SEPARATOR="CSV_IMPORT_FIELD_SEPARATOR"; |
462 | + |
463 | + private final CurrencyExportPreferences currencyPreferences = new CurrencyExportPreferences("csv"); |
464 | + |
465 | + private DatabaseAdapter db; |
466 | + private ArrayList<Account> accounts; |
467 | + private int checkedAccount=1; |
468 | + private Button bAccounts; |
469 | + |
470 | + |
471 | + public CsvImportActivity() { |
472 | + super(R.layout.csv_import); |
473 | + } |
474 | + |
475 | + @Override |
476 | + protected void internalOnCreate() { |
477 | + LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
478 | + NodeInflater nodeInflater = new NodeInflater(layoutInflater); |
479 | + final ActivityLayout activityLayout = new ActivityLayout(nodeInflater, this); |
480 | + |
481 | + db = new DatabaseAdapter(this); |
482 | + db.open(); |
483 | + |
484 | + accounts = db.em().getAllAccountsList(); |
485 | + |
486 | + |
487 | + bAccounts = (Button)findViewById(R.id.bAccounts); |
488 | + bAccounts.setOnClickListener(new View.OnClickListener() { |
489 | + @Override |
490 | + public void onClick(View view) { |
491 | + int count = accounts.size(); |
492 | + String[] accountsTitles = new String[count]; |
493 | + for (int i=0; i<count; i++) { |
494 | + accountsTitles[i] = accounts.get(i).getTitle(); |
495 | + if (accounts.get(i).isChecked()){ |
496 | + checkedAccount=i; |
497 | + } |
498 | + } |
499 | + |
500 | + AlertDialog show = new AlertDialog.Builder(CsvImportActivity.this) |
501 | + .setTitle(R.string.accounts) |
502 | + .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener(){ |
503 | + public void onClick(DialogInterface dialog, int which) { |
504 | + for (int i=0; i<accounts.size(); i++) { |
505 | + if (i==checkedAccount){ |
506 | + accounts.get(i).setChecked(true); |
507 | + }else |
508 | + accounts.get(i).setChecked(false); |
509 | + } |
510 | + bAccounts.setText(accounts.get(checkedAccount).getTitle()); |
511 | + savePreferences(); |
512 | + } |
513 | + |
514 | + }) |
515 | + .setSingleChoiceItems(accountsTitles, checkedAccount, new DialogInterface.OnClickListener(){ |
516 | + public void onClick(DialogInterface dialog, int which) { |
517 | + checkedAccount=which; |
518 | + } |
519 | + }) |
520 | + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener(){ |
521 | + @Override |
522 | + public void onClick(DialogInterface dialog, int which) { |
523 | + |
524 | + } |
525 | + }) |
526 | + .show(); |
527 | + |
528 | + } |
529 | + }); |
530 | + |
531 | + Button bOk = (Button)findViewById(R.id.bOK); |
532 | + bOk.setOnClickListener(new OnClickListener() { |
533 | + public void onClick(View view) { |
534 | + if (edFilename.getText().toString().equals("")) { |
535 | + Toast.makeText(CsvImportActivity.this, R.string.select_filename, Toast.LENGTH_SHORT).show(); |
536 | + return; |
537 | + } |
538 | + if (checkedAccount==-1) { |
539 | + Toast.makeText(CsvImportActivity.this, R.string.choose_account, Toast.LENGTH_SHORT).show(); |
540 | + return; |
541 | + } |
542 | + |
543 | + Intent data = new Intent(); |
544 | + updateResultIntentFromUi(data); |
545 | + setResult(RESULT_OK, data); |
546 | + finish(); |
547 | + } |
548 | + }); |
549 | + |
550 | + Button bCancel = (Button)findViewById(R.id.bCancel); |
551 | + bCancel.setOnClickListener(new OnClickListener() { |
552 | + public void onClick(View view) { |
553 | + setResult(RESULT_CANCELED); |
554 | + finish(); |
555 | + } |
556 | + }); |
557 | + |
558 | + } |
559 | + |
560 | + |
561 | + |
562 | + @Override |
563 | + protected void onDestroy() { |
564 | + db.close(); |
565 | + super.onDestroy(); |
566 | + } |
567 | + |
568 | + @Override |
569 | + public void onSelected(int id, List<? extends MultiChoiceItem> items) { |
570 | + List<Account> selectedAccounts = getSelectedAccounts(); |
571 | + if (selectedAccounts.size() == 0 || selectedAccounts.size() == accounts.size()) { |
572 | + bAccounts.setText(R.string.choose_account); |
573 | + checkedAccount=-1; |
574 | + } else { |
575 | + StringBuilder sb = new StringBuilder(); |
576 | + for (Account a : selectedAccounts) { |
577 | + appendItemTo(sb, a.title); |
578 | + checkedAccount=1; |
579 | + } |
580 | + bAccounts.setText(sb.toString()); |
581 | + } |
582 | + } |
583 | + |
584 | + private ArrayList<Account> getSelectedAccounts() { |
585 | + ArrayList<Account> selected = new ArrayList<Account>(); |
586 | + for (MultiChoiceItem i : accounts) { |
587 | + if (i.isChecked()) { |
588 | + selected.add((Account)i); |
589 | + } |
590 | + } |
591 | + return selected; |
592 | + } |
593 | + |
594 | + private void appendItemTo(StringBuilder sb, String s) { |
595 | + if (sb.length() > 0) { |
596 | + sb.append(", "); |
597 | + } |
598 | + sb.append(s); |
599 | + } |
600 | + |
601 | + @Override |
602 | + public void onSelectedPos(int id, int selectedPos) { |
603 | + } |
604 | + |
605 | + @Override |
606 | + public void onSelectedId(int id, long selectedId) { |
607 | + } |
608 | + |
609 | + @Override |
610 | + public void onClick(View view) { |
611 | + } |
612 | + |
613 | + @Override |
614 | + protected void updateResultIntentFromUi(Intent data) { |
615 | + currencyPreferences.updateIntentFromUI(this, data); |
616 | + long[] selectedIds = getSelectedAccountsIds(); |
617 | + if (selectedIds.length > 0) { |
618 | + data.putExtra(CSV_IMPORT_SELECTED_ACCOUNT, selectedIds); |
619 | + } |
620 | + Spinner dateFormats = (Spinner)findViewById(R.id.spinnerDateFormats); |
621 | + data.putExtra(CSV_IMPORT_DATE_FORMAT, dateFormats.getSelectedItem().toString()); |
622 | + data.putExtra(CSV_IMPORT_FILENAME, edFilename.getText().toString()); |
623 | + Spinner fieldSeparator = (Spinner)findViewById(R.id.spinnerFieldSeparator); |
624 | + data.putExtra(CSV_IMPORT_FIELD_SEPARATOR, fieldSeparator.getSelectedItem().toString().charAt(1)); |
625 | + |
626 | + } |
627 | + |
628 | + private long[] getSelectedAccountsIds() { |
629 | + List<Long> selectedAccounts = new ArrayList<Long>(accounts.size()); |
630 | + for (Account account : accounts) { |
631 | + if (account.isChecked()) { |
632 | + selectedAccounts.add(account.id); |
633 | + } |
634 | + } |
635 | + int count = selectedAccounts.size(); |
636 | + long[] ids = new long[count]; |
637 | + for (int i=0; i<count; i++) { |
638 | + ids[i] = selectedAccounts.get(i); |
639 | + } |
640 | + return ids; |
641 | + } |
642 | + |
643 | + @Override |
644 | + protected void onPause() { |
645 | + super.onPause(); |
646 | + savePreferences(); |
647 | + } |
648 | + |
649 | + @Override |
650 | + protected void onResume() { |
651 | + super.onResume(); |
652 | + restorePreferences(); |
653 | + } |
654 | + |
655 | + void savePreferences() { |
656 | + SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit(); |
657 | + |
658 | + currencyPreferences.savePreferences(this, editor); |
659 | + |
660 | + long[] selectedIds = getSelectedAccountsIds(); |
661 | + if (selectedIds.length > 0) { |
662 | + editor.putString(CSV_IMPORT_SELECTED_ACCOUNT, joinSelectedAccounts(selectedIds)); |
663 | + } |
664 | + |
665 | + Spinner dateFormats = (Spinner)findViewById(R.id.spinnerDateFormats); |
666 | + editor.putInt(CSV_IMPORT_DATE_FORMAT, dateFormats.getSelectedItemPosition()); |
667 | + editor.putString(CSV_IMPORT_FILENAME, edFilename.getText().toString()); |
668 | + Spinner fieldSeparator = (Spinner)findViewById(R.id.spinnerFieldSeparator); |
669 | + editor.putInt(CSV_IMPORT_FIELD_SEPARATOR, fieldSeparator.getSelectedItemPosition()); |
670 | + editor.commit(); |
671 | + } |
672 | + |
673 | + private String joinSelectedAccounts(long[] selectedIds) { |
674 | + StringBuilder sb = new StringBuilder(); |
675 | + for (long selectedId : selectedIds) { |
676 | + if (sb.length() > 0) sb.append(","); |
677 | + sb.append(selectedId); |
678 | + } |
679 | + return sb.toString(); |
680 | + } |
681 | + |
682 | + private void restorePreferences() { |
683 | + SharedPreferences preferences = getPreferences(MODE_PRIVATE); |
684 | + |
685 | + currencyPreferences.restorePreferences(this, preferences); |
686 | + |
687 | + String selectedIds = preferences.getString(CSV_IMPORT_SELECTED_ACCOUNT, ""); |
688 | + parseSelectedAccounts(selectedIds); |
689 | + onSelected(-1, accounts); |
690 | + |
691 | + Spinner dateFormats = (Spinner)findViewById(R.id.spinnerDateFormats); |
692 | + dateFormats.setSelection(preferences.getInt(CSV_IMPORT_DATE_FORMAT, 0)); |
693 | + edFilename=(EditText)findViewById(R.id.edFilename); |
694 | + edFilename.setText(preferences.getString(CSV_IMPORT_FILENAME,"")); |
695 | + Spinner fieldSeparator = (Spinner)findViewById(R.id.spinnerFieldSeparator); |
696 | + fieldSeparator.setSelection(preferences.getInt(CSV_IMPORT_FIELD_SEPARATOR, 0)); |
697 | + } |
698 | + |
699 | + private void parseSelectedAccounts(String selectedIds) { |
700 | + try { |
701 | + TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(','); |
702 | + splitter.setString(selectedIds); |
703 | + for (String s : splitter) { |
704 | + long id = Long.parseLong(s); |
705 | + for (Account account : accounts) { |
706 | + if (account.id == id) { |
707 | + account.setChecked(true); |
708 | + break; |
709 | + } |
710 | + } |
711 | + } |
712 | + } catch (Exception ex) { |
713 | + // ignore |
714 | + } |
715 | + } |
716 | + |
717 | + |
718 | + |
719 | +} |
720 | |
721 | === modified file 'src/ru/orangesoftware/financisto/activity/MainActivity.java' |
722 | --- src/ru/orangesoftware/financisto/activity/MainActivity.java 2011-07-25 17:44:44 +0000 |
723 | +++ src/ru/orangesoftware/financisto/activity/MainActivity.java 2011-10-23 17:45:27 +0000 |
724 | @@ -57,6 +57,8 @@ |
725 | import ru.orangesoftware.financisto.export.csv.CsvExportTask; |
726 | import ru.orangesoftware.financisto.export.qif.QifExportOptions; |
727 | import ru.orangesoftware.financisto.export.qif.QifExportTask; |
728 | +import ru.orangesoftware.financisto.imports.csv.CsvImport; |
729 | +import ru.orangesoftware.financisto.imports.csv.CsvImportOptions; |
730 | import ru.orangesoftware.financisto.utils.*; |
731 | |
732 | import java.io.IOException; |
733 | @@ -68,7 +70,8 @@ |
734 | |
735 | private static final int ACTIVITY_CSV_EXPORT = 2; |
736 | private static final int ACTIVITY_QIF_EXPORT = 3; |
737 | - |
738 | + private static final int ACTIVITY_CSV_IMPORT = 4; |
739 | + |
740 | private static final int MENU_PREFERENCES = Menu.FIRST+1; |
741 | private static final int MENU_ABOUT = Menu.FIRST+2; |
742 | private static final int MENU_BACKUP = Menu.FIRST+3; |
743 | @@ -81,7 +84,8 @@ |
744 | private static final int MENU_MASS_OP = Menu.FIRST+10; |
745 | private static final int MENU_DONATE = Menu.FIRST+11; |
746 | private static final int MENU_QIF_EXPORT = Menu.FIRST+12; |
747 | - |
748 | + private static final int MENU_CSV_IMPORT = Menu.FIRST+13; |
749 | + |
750 | private final HashMap<String, Boolean> started = new HashMap<String, Boolean>(); |
751 | |
752 | @Override |
753 | @@ -139,7 +143,12 @@ |
754 | QifExportOptions options = QifExportOptions.fromIntent(data); |
755 | doQifExport(options); |
756 | } |
757 | - } |
758 | + } else if (requestCode == ACTIVITY_CSV_IMPORT) { |
759 | + if (resultCode == RESULT_OK) { |
760 | + CsvImportOptions options = CsvImportOptions.fromIntent(data); |
761 | + doCsvImport(options); |
762 | + } |
763 | + } |
764 | } |
765 | |
766 | private void doCsvExport(CsvExportOptions options) { |
767 | @@ -147,6 +156,12 @@ |
768 | new CsvExportTask(this, progressDialog, options).execute(); |
769 | } |
770 | |
771 | + private void doCsvImport(CsvImportOptions options) { |
772 | + ProgressDialog progressDialog = ProgressDialog.show(this, null, getString(R.string.csv_import_inprogress), true); |
773 | + new CsvImportTask(this, progressDialog, options).execute(); |
774 | + } |
775 | + |
776 | + |
777 | private void doQifExport(QifExportOptions options) { |
778 | ProgressDialog progressDialog = ProgressDialog.show(this, null, getString(R.string.qif_export_inprogress), true); |
779 | new QifExportTask(this, progressDialog, options).execute(); |
780 | @@ -246,6 +261,7 @@ |
781 | menu.addSubMenu(0, MENU_BACKUP_GDOCS, 0, R.string.backup_database_gdocs); |
782 | menu.addSubMenu(0, MENU_RESTORE_GDOCS, 0, R.string.restore_database_gdocs); |
783 | menu.addSubMenu(0, MENU_CSV_EXPORT, 0, R.string.csv_export); |
784 | + menu.addSubMenu(0, MENU_CSV_IMPORT, 0, R.string.csv_import); |
785 | menu.addSubMenu(0, MENU_QIF_EXPORT, 0, R.string.qif_export); |
786 | menu.addSubMenu(0, MENU_DONATE, 0, R.string.donate); |
787 | menu.addSubMenu(0, MENU_ABOUT, 0, R.string.about); |
788 | @@ -305,6 +321,9 @@ |
789 | case MENU_RESTORE_GDOCS: |
790 | doImportFromGoogleDocs(); |
791 | break; |
792 | + case MENU_CSV_IMPORT: |
793 | + doCsvImport(); |
794 | + break; |
795 | } |
796 | return false; |
797 | } |
798 | @@ -394,6 +413,11 @@ |
799 | startActivityForResult(intent, ACTIVITY_CSV_EXPORT); |
800 | } |
801 | |
802 | + private void doCsvImport() { |
803 | + Intent intent = new Intent(this, CsvImportActivity.class); |
804 | + startActivityForResult(intent, ACTIVITY_CSV_IMPORT); |
805 | + } |
806 | + |
807 | private void doQifExport() { |
808 | Intent intent = new Intent(this, QifExportActivity.class); |
809 | startActivityForResult(intent, ACTIVITY_QIF_EXPORT); |
810 | @@ -653,6 +677,57 @@ |
811 | |
812 | } |
813 | |
814 | + public class CsvImportTask extends ImportExportAsyncTask { |
815 | + |
816 | + private final CsvImportOptions options; |
817 | + |
818 | + public CsvImportTask(Context context, ProgressDialog dialog, CsvImportOptions options) { |
819 | + |
820 | + //super(context, dialog, null); |
821 | + super(MainActivity.this, dialog, new ImportExportAsyncTaskListener(){ |
822 | + public void onCompleted() { |
823 | + onTabChanged(getTabHost().getCurrentTabTag()); |
824 | + } |
825 | + }); |
826 | + |
827 | + this.options = options; |
828 | + } |
829 | + |
830 | + |
831 | + @Override |
832 | + protected Object work(Context context, DatabaseAdapter db, String...params) throws Exception { |
833 | + try{ |
834 | + CsvImport csvimport = new CsvImport(db, options,context); |
835 | + return csvimport.doImport(); |
836 | + }catch(Exception e) |
837 | + { |
838 | + if(e.getMessage().equals("Import file not found")) |
839 | + handler.sendEmptyMessage(R.string.import_file_not_found); |
840 | + else if(e.getMessage().equals("Unknown category in import line")) |
841 | + handler.sendEmptyMessage(R.string.import_unknown_category); |
842 | + else if(e.getMessage().equals("Unknown project in import line")) |
843 | + handler.sendEmptyMessage(R.string.import_unknown_project); |
844 | + else if(e.getMessage().equals("Wrong currency in import line")) |
845 | + handler.sendEmptyMessage(R.string.import_wrong_currency); |
846 | + else if(e.getMessage().equals("IllegalArgumentException")) |
847 | + handler.sendEmptyMessage(R.string.import_illegal_argument_exception); |
848 | + else if(e.getMessage().equals("ParseException")) |
849 | + handler.sendEmptyMessage(R.string.import_parse_error); |
850 | + else |
851 | + handler.sendEmptyMessage(R.string.csv_import_error); |
852 | + throw e; |
853 | + } |
854 | + |
855 | + } |
856 | + |
857 | + @Override |
858 | + protected String getSuccessMessage(Object result) { |
859 | + return String.valueOf(result); |
860 | + } |
861 | + |
862 | + } |
863 | + |
864 | + |
865 | private enum MenuEntities implements EntityEnum { |
866 | |
867 | CURRENCIES(R.string.currencies, R.drawable.menu_entities_currencies, CurrencyListActivity.class), |
868 | |
869 | === modified file 'src/ru/orangesoftware/financisto/db/DatabaseAdapter.java' |
870 | --- src/ru/orangesoftware/financisto/db/DatabaseAdapter.java 2011-09-02 18:49:54 +0000 |
871 | +++ src/ru/orangesoftware/financisto/db/DatabaseAdapter.java 2011-10-23 17:45:27 +0000 |
872 | @@ -596,6 +596,37 @@ |
873 | } |
874 | } |
875 | |
876 | + public Category getCategory(String title) { |
877 | + Cursor c = db.query(V_CATEGORY, CategoryViewColumns.NORMAL_PROJECTION, |
878 | + CategoryViewColumns.title+"=?", new String[]{String.valueOf(title)}, null, null, null); |
879 | + try { |
880 | + if (c.moveToNext()) { |
881 | + Category cat = new Category(); |
882 | + cat.id = c.getInt(CategoryViewColumns._id.ordinal()); |
883 | + cat.title = title; |
884 | + cat.level = c.getInt(CategoryViewColumns.level.ordinal()); |
885 | + cat.left = c.getInt(CategoryViewColumns.left.ordinal()); |
886 | + cat.right = c.getInt(CategoryViewColumns.right.ordinal()); |
887 | + cat.type = c.getInt(CategoryViewColumns.type.ordinal()); |
888 | + String s = String.valueOf(cat.id); |
889 | + Cursor c2 = db.query(GET_PARENT_SQL, new String[]{CategoryColumns._id.name()}, null, new String[]{s,s}, |
890 | + null, null, null, "1"); |
891 | + try { |
892 | + if (c2.moveToFirst()) { |
893 | + cat.parent = new Category(c2.getLong(0)); |
894 | + } |
895 | + } finally { |
896 | + c2.close(); |
897 | + } |
898 | + return cat; |
899 | + } else { |
900 | + return null; |
901 | + } |
902 | + } finally { |
903 | + c.close(); |
904 | + } |
905 | + } |
906 | + |
907 | public Category getCategoryByLeft(long left) { |
908 | Cursor c = db.query(V_CATEGORY, CategoryViewColumns.NORMAL_PROJECTION, |
909 | CategoryViewColumns.left+"=?", new String[]{String.valueOf(left)}, null, null, null); |
910 | |
911 | === modified file 'src/ru/orangesoftware/financisto/export/ImportExportAsyncTask.java' |
912 | --- src/ru/orangesoftware/financisto/export/ImportExportAsyncTask.java 2011-02-20 19:39:08 +0000 |
913 | +++ src/ru/orangesoftware/financisto/export/ImportExportAsyncTask.java 2011-10-23 17:45:27 +0000 |
914 | @@ -17,6 +17,7 @@ |
915 | import android.content.Context; |
916 | import android.os.AsyncTask; |
917 | import android.util.Log; |
918 | +import android.widget.Toast; |
919 | |
920 | public abstract class ImportExportAsyncTask extends AsyncTask<String, Void, Object> { |
921 | |
922 | |
923 | === modified file 'src/ru/orangesoftware/financisto/export/csv/Csv.java' |
924 | --- src/ru/orangesoftware/financisto/export/csv/Csv.java 2011-02-20 19:39:08 +0000 |
925 | +++ src/ru/orangesoftware/financisto/export/csv/Csv.java 2011-10-23 17:45:27 +0000 |
926 | @@ -215,7 +215,7 @@ |
927 | return result; |
928 | } |
929 | |
930 | - private String unmarkDoubleQuotes(String s) { return s.replace(impossibleString, "\""); } |
931 | + private String unmarkDoubleQuotes(String s) { return s.replace(impossibleString, "\"\""); } |
932 | private String markDoubleQuotes(String s) { return s.replace("\"\"", impossibleString); } |
933 | |
934 | private String removeLeadingSpaces(String s) { return s.replaceFirst(" +", ""); } |
935 | |
936 | === added directory 'src/ru/orangesoftware/financisto/imports' |
937 | === added directory 'src/ru/orangesoftware/financisto/imports/csv' |
938 | === added file 'src/ru/orangesoftware/financisto/imports/csv/CsvImport.java' |
939 | --- src/ru/orangesoftware/financisto/imports/csv/CsvImport.java 1970-01-01 00:00:00 +0000 |
940 | +++ src/ru/orangesoftware/financisto/imports/csv/CsvImport.java 2011-10-23 17:45:27 +0000 |
941 | @@ -0,0 +1,200 @@ |
942 | +package ru.orangesoftware.financisto.imports.csv; |
943 | + |
944 | +import static ru.orangesoftware.financisto.db.DatabaseHelper.ACCOUNT_TABLE; |
945 | +import static ru.orangesoftware.financisto.db.DatabaseHelper.V_BLOTTER_FOR_ACCOUNT; |
946 | + |
947 | +import java.io.File; |
948 | +import java.io.FileNotFoundException; |
949 | +import java.io.FileReader; |
950 | +import java.io.IOException; |
951 | +import java.lang.reflect.Field; |
952 | +import java.text.ParseException; |
953 | +import java.text.ParsePosition; |
954 | +import java.text.SimpleDateFormat; |
955 | +import java.util.Date; |
956 | +import java.util.HashMap; |
957 | +import java.util.List; |
958 | + |
959 | +import javax.xml.parsers.ParserConfigurationException; |
960 | +import javax.xml.parsers.SAXParser; |
961 | +import javax.xml.parsers.SAXParserFactory; |
962 | + |
963 | +import org.xml.sax.SAXException; |
964 | +import org.xml.sax.helpers.DefaultHandler; |
965 | + |
966 | +import android.app.AlertDialog; |
967 | +import android.content.ContentValues; |
968 | +import android.content.Context; |
969 | +import android.database.Cursor; |
970 | +import android.os.Looper; |
971 | +import android.util.Log; |
972 | +import android.widget.Toast; |
973 | + |
974 | +import ru.orangesoftware.financisto.R; |
975 | +import ru.orangesoftware.financisto.activity.AccountActivity; |
976 | +import ru.orangesoftware.financisto.db.DatabaseAdapter; |
977 | +import ru.orangesoftware.financisto.db.DatabaseHelper.AccountColumns; |
978 | +import ru.orangesoftware.financisto.db.DatabaseHelper.BlotterColumns; |
979 | +import ru.orangesoftware.financisto.export.csv.Csv; |
980 | +import ru.orangesoftware.financisto.model.Account; |
981 | +import ru.orangesoftware.financisto.model.Category; |
982 | +import ru.orangesoftware.financisto.model.Project; |
983 | +import ru.orangesoftware.financisto.model.Transaction; |
984 | + |
985 | +public class CsvImport { |
986 | + private final DatabaseAdapter db; |
987 | + private final CsvImportOptions options; |
988 | + private final Account account; |
989 | + private Context context; |
990 | + private char decimalSeparator; |
991 | + private char groupSeparator; |
992 | + |
993 | + public CsvImport(DatabaseAdapter db, CsvImportOptions options, |
994 | + Context context) { |
995 | + this.db = db; |
996 | + this.options = options; |
997 | + this.account = db.em().getAccount(options.selectedAccounts[0]); |
998 | + this.context = context; |
999 | + this.decimalSeparator = options.currency.decimalSeparator.charAt(1); |
1000 | + this.groupSeparator = options.currency.groupSeparator.charAt(1); |
1001 | + } |
1002 | + |
1003 | + public Object doImport() throws Exception { |
1004 | + String csvFilename = options.filename; |
1005 | + Csv.Reader reader; |
1006 | + Boolean isTableHeadLine = false; |
1007 | + List<String> tableHeadLine = null; |
1008 | + List<Project> projectList = db.em().list(Project.class); |
1009 | + try { |
1010 | + reader = new Csv.Reader(new FileReader(csvFilename)).delimiter( |
1011 | + options.fieldSeparator).ignoreComments(true); |
1012 | + List<String> line; |
1013 | + int countLine = 0; |
1014 | + while ((line = reader.readLine()) != null) { |
1015 | + // get table head line |
1016 | + countLine = countLine++; |
1017 | + if (isTableHeadLine) { |
1018 | + Transaction transaction = new Transaction(); |
1019 | + transaction.dateTime = 0; |
1020 | + transaction.fromAccountId=this.account.id; |
1021 | + long time = 0; |
1022 | + |
1023 | + int countOfColumns = line.size(); |
1024 | + for (int i = 0; i < countOfColumns; i++) { |
1025 | + String transactionField = tableHeadLine.get(i); |
1026 | + /* |
1027 | + * ToDo:workaround needed for reimport of files from CsvExport function - first column (date) in header shows nonprintable |
1028 | + * Character which is not replaceable by "trim" function. Have to look in CsvExport function |
1029 | + */ |
1030 | + transactionField = myTrim(transactionField); |
1031 | + if (!transactionField.equals("")) { |
1032 | + Log.d("CsvImport", |
1033 | + transactionField + ":" + line.get(i) + " "); |
1034 | + try { |
1035 | + String fieldValue = line.get(i); |
1036 | + if (!fieldValue.equals("")) { |
1037 | + |
1038 | + if (transactionField.equals("date")) { |
1039 | + transaction.dateTime = options.dateFormat |
1040 | + .parse(fieldValue).getTime(); |
1041 | + Log.d("CsvImport", "date:" |
1042 | + + transaction.dateTime); |
1043 | + } else if (transactionField.equals("time")) { |
1044 | + SimpleDateFormat format = new SimpleDateFormat( |
1045 | + "HH:mm:ss"); |
1046 | + ParsePosition p = new ParsePosition(0); |
1047 | + time = format.parse(fieldValue, p) |
1048 | + .getTime(); |
1049 | + Log.d("CsvImport", "time:" + time); |
1050 | + |
1051 | + } else if (transactionField |
1052 | + .equals("amount")) { |
1053 | + fieldValue = fieldValue.replace( |
1054 | + groupSeparator+"", ""); |
1055 | + fieldValue = fieldValue.replace( |
1056 | + decimalSeparator, '.'); |
1057 | + double fromAmount = Double |
1058 | + .parseDouble(fieldValue); |
1059 | + Double fromAmountDouble = new Double( |
1060 | + fromAmount) * 100.0; |
1061 | + long amount = fromAmountDouble |
1062 | + .longValue(); |
1063 | + transaction.fromAmount = amount; |
1064 | + } else if (transactionField.equals("payee")) { |
1065 | + transaction.payeeId = db |
1066 | + .insertPayee(fieldValue); |
1067 | + } else if (transactionField |
1068 | + .equals("category")) { |
1069 | + Category cat = db |
1070 | + .getCategory(fieldValue); |
1071 | + if (cat != null) { |
1072 | + transaction.categoryId = cat.id; |
1073 | + } else { |
1074 | + throw new Exception( |
1075 | + "Unknown category in import line"); |
1076 | + } |
1077 | + } else if (transactionField.equals("note")) { |
1078 | + transaction.note = fieldValue; |
1079 | + } else if (transactionField |
1080 | + .equals("project")) { |
1081 | + //Test for "No project" just to be compatible for importing of files from CsvExport function |
1082 | + if (!fieldValue.equals("No project")) { |
1083 | + for (int i1 = 0; i1 < projectList |
1084 | + .size(); i1++) { |
1085 | + if (projectList.get(i1) |
1086 | + .getTitle() |
1087 | + .equals(fieldValue)) { |
1088 | + transaction.projectId = projectList |
1089 | + .get(i1).getId(); |
1090 | + break; |
1091 | + } |
1092 | + } |
1093 | + if (transaction.projectId == 0) { |
1094 | + throw new Exception( |
1095 | + "Unknown project in import line"); |
1096 | + } |
1097 | + } |
1098 | + |
1099 | + } else if (transactionField |
1100 | + .equals("currency")) { |
1101 | + if (!account.currency.name |
1102 | + .equals(fieldValue)) { |
1103 | + throw new Exception( |
1104 | + "Wrong currency in import line"); |
1105 | + } |
1106 | + } |
1107 | + } |
1108 | + } catch (IllegalArgumentException e) { |
1109 | + throw new Exception("IllegalArgumentException"); |
1110 | + } catch (ParseException e) { |
1111 | + throw new Exception("ParseException"); |
1112 | + } |
1113 | + } |
1114 | + } |
1115 | + transaction.dateTime = transaction.dateTime + time; |
1116 | + long id = db.insertOrUpdate(transaction); |
1117 | + Log.d("CsvImport", "Insert transactionId:" + id); |
1118 | + } else { |
1119 | + // first line of csv-file is table headline |
1120 | + isTableHeadLine = true; |
1121 | + tableHeadLine = line; |
1122 | + } |
1123 | + } |
1124 | + } catch (FileNotFoundException e) { |
1125 | + throw new Exception("Import file not found"); |
1126 | + } |
1127 | + |
1128 | + return options.filename + " imported!"; |
1129 | + } |
1130 | + |
1131 | + //Workaround function which is needed for reimport of CsvExport files |
1132 | + public String myTrim(String s) { |
1133 | + if (Character.isLetter(s.charAt(0))) { |
1134 | + return s; |
1135 | + } else { |
1136 | + return s.substring(1); |
1137 | + } |
1138 | + |
1139 | + } |
1140 | + |
1141 | +} |
1142 | |
1143 | === added file 'src/ru/orangesoftware/financisto/imports/csv/CsvImportOptions.java' |
1144 | --- src/ru/orangesoftware/financisto/imports/csv/CsvImportOptions.java 1970-01-01 00:00:00 +0000 |
1145 | +++ src/ru/orangesoftware/financisto/imports/csv/CsvImportOptions.java 2011-10-23 17:45:27 +0000 |
1146 | @@ -0,0 +1,55 @@ |
1147 | +/* |
1148 | + * Copyright (c) 2011 Denis Solonenko. |
1149 | + * All rights reserved. This program and the accompanying materials |
1150 | + * are made available under the terms of the GNU Public License v2.0 |
1151 | + * which accompanies this distribution, and is available at |
1152 | + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
1153 | + */ |
1154 | + |
1155 | +package ru.orangesoftware.financisto.imports.csv; |
1156 | + |
1157 | +import android.content.Intent; |
1158 | +import ru.orangesoftware.financisto.activity.CsvExportActivity; |
1159 | +import ru.orangesoftware.financisto.activity.CsvImportActivity; |
1160 | +import ru.orangesoftware.financisto.blotter.WhereFilter; |
1161 | +import ru.orangesoftware.financisto.model.Currency; |
1162 | +import ru.orangesoftware.financisto.utils.CurrencyExportPreferences; |
1163 | + |
1164 | +import java.text.SimpleDateFormat; |
1165 | + |
1166 | +/** |
1167 | + * Created by IntelliJ IDEA. |
1168 | + * User: Denis Solonenko |
1169 | + * Date: 7/10/11 7:01 PM |
1170 | + */ |
1171 | +public class CsvImportOptions { |
1172 | + |
1173 | + public static final String DEFAULT_DATE_FORMAT = "dd.MM.yyyy"; |
1174 | + |
1175 | + public final Currency currency; |
1176 | + public final SimpleDateFormat dateFormat; |
1177 | + public final char fieldSeparator; |
1178 | + public final WhereFilter filter; |
1179 | + public final long[] selectedAccounts; |
1180 | + public final String filename; |
1181 | + |
1182 | + public CsvImportOptions(Currency currency, String dateFormat, long[] selectedAccounts, WhereFilter filter,String filename,char fieldSeparator) { |
1183 | + this.currency = currency; |
1184 | + this.dateFormat = new SimpleDateFormat(dateFormat); |
1185 | + this.selectedAccounts = selectedAccounts; |
1186 | + this.filter = filter; |
1187 | + this.filename=filename; |
1188 | + this.fieldSeparator=fieldSeparator; |
1189 | + } |
1190 | + |
1191 | + public static CsvImportOptions fromIntent(Intent data) { |
1192 | + WhereFilter filter = WhereFilter.fromIntent(data); |
1193 | + Currency currency = CurrencyExportPreferences.fromIntent(data, "csv"); |
1194 | + char fieldSeparator = data.getCharExtra(CsvImportActivity.CSV_IMPORT_FIELD_SEPARATOR, ','); |
1195 | + String dateFormat = data.getStringExtra(CsvImportActivity.CSV_IMPORT_DATE_FORMAT); |
1196 | + long[] selectedAccounts = data.getLongArrayExtra(CsvImportActivity.CSV_IMPORT_SELECTED_ACCOUNT); |
1197 | + String filename =data.getStringExtra(CsvImportActivity.CSV_IMPORT_FILENAME); |
1198 | + return new CsvImportOptions(currency, dateFormat, selectedAccounts, filter,filename,fieldSeparator); |
1199 | + } |
1200 | + |
1201 | +} |