author | ulf69 <ulf69> | 2004-10-22 18:48:35 (UTC) |
---|---|---|
committer | ulf69 <ulf69> | 2004-10-22 18:48:35 (UTC) |
commit | a5274f27dc71e1a0ffae73f32f84f4dd013b4b76 (patch) (unidiff) | |
tree | 5c2e3e105fa9df8999752a314455d0f424bf474b | |
parent | 163b74a23d102074fc0adefddba5b4fa9d4dd2a5 (diff) | |
download | kdepimpi-a5274f27dc71e1a0ffae73f32f84f4dd013b4b76.zip kdepimpi-a5274f27dc71e1a0ffae73f32f84f4dd013b4b76.tar.gz kdepimpi-a5274f27dc71e1a0ffae73f32f84f4dd013b4b76.tar.bz2 |
added csv import/export
-rw-r--r-- | pwmanager/pwmanager/csv.cpp | 428 | ||||
-rw-r--r-- | pwmanager/pwmanager/csv.h | 91 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwm.cpp | 85 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwm.h | 4 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmanagerE.pro | 2 |
5 files changed, 608 insertions, 2 deletions
diff --git a/pwmanager/pwmanager/csv.cpp b/pwmanager/pwmanager/csv.cpp new file mode 100644 index 0000000..194edf2 --- a/dev/null +++ b/pwmanager/pwmanager/csv.cpp | |||
@@ -0,0 +1,428 @@ | |||
1 | /*************************************************************************** | ||
2 | * * | ||
3 | * copyright (C) 2004 by Michael Buesch * | ||
4 | * email: mbuesch@freenet.de * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License version 2 * | ||
8 | * as published by the Free Software Foundation. * | ||
9 | * * | ||
10 | ***************************************************************************/ | ||
11 | |||
12 | /*************************************************************************** | ||
13 | * copyright (C) 2004 by Ulf Schenk | ||
14 | * This file is originaly based on version 1.1 of pwmanager | ||
15 | * and was modified to run on embedded devices that run microkde | ||
16 | * The original file version was 1.2 | ||
17 | * $Id$ | ||
18 | **************************************************************************/ | ||
19 | |||
20 | #include "csv.h" | ||
21 | #include "pwmdoc.h" | ||
22 | #include "pwmexception.h" | ||
23 | |||
24 | #include <kmessagebox.h> | ||
25 | #include <klocale.h> | ||
26 | |||
27 | #define MAX_CSV_FILE_SIZE(50 * 1024 * 1024) // bytes | ||
28 | |||
29 | |||
30 | Csv::Csv(QWidget *_parent) | ||
31 | : parent (_parent) | ||
32 | { | ||
33 | } | ||
34 | |||
35 | Csv::~Csv() | ||
36 | { | ||
37 | } | ||
38 | |||
39 | bool Csv::importData(const QString &filepath, | ||
40 | PwMDoc *doc) | ||
41 | { | ||
42 | bool ret = true; | ||
43 | QByteArray d; | ||
44 | QFile f(filepath); | ||
45 | if (!f.open(IO_ReadOnly)) { | ||
46 | KMessageBox::error(parent, | ||
47 | i18n("Could not open file.\n" | ||
48 | "Does the file exist?"), | ||
49 | i18n("Open error.")); | ||
50 | ret = false; | ||
51 | goto out; | ||
52 | } | ||
53 | if (f.size() > MAX_CSV_FILE_SIZE) { | ||
54 | KMessageBox::error(parent, | ||
55 | i18n("File too big.\nMaximum file size is 1 Byte.", "File too big.\nMaximum file size is %n Bytes.", MAX_CSV_FILE_SIZE), | ||
56 | i18n("File too big.")); | ||
57 | ret = false; | ||
58 | goto out_close; | ||
59 | } | ||
60 | d = f.readAll(); | ||
61 | if (d.isEmpty()) { | ||
62 | KMessageBox::error(parent, | ||
63 | i18n("Could not read file or file empty."), | ||
64 | i18n("Reading failed.")); | ||
65 | ret = false; | ||
66 | goto out_close; | ||
67 | } | ||
68 | if (!doImport(d, doc)) { | ||
69 | KMessageBox::error(parent, | ||
70 | i18n("Import failed.\n" | ||
71 | "Corrupt CSV data format."), | ||
72 | i18n("File corrupt.")); | ||
73 | ret = false; | ||
74 | goto out_close; | ||
75 | } | ||
76 | |||
77 | out_close: | ||
78 | f.close(); | ||
79 | out: | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | bool Csv::doImport(const QByteArray &d, | ||
84 | PwMDoc *doc) | ||
85 | { | ||
86 | PwMDataItem di; | ||
87 | //US ENH: initialize all members: | ||
88 | di.clear(); | ||
89 | |||
90 | int refIndex = 0; | ||
91 | int ret; | ||
92 | QCString s, curCat; | ||
93 | int fieldIndex = 0; | ||
94 | bool inRecord = false; | ||
95 | /* fieldIndex is a reference count to see which | ||
96 | * value we are attaching to di. | ||
97 | * Valid counts are: | ||
98 | * 0 -> category | ||
99 | * 1 -> desc | ||
100 | * 2 -> name | ||
101 | * 3 -> pw | ||
102 | * 4 -> url | ||
103 | * 5 -> launcher | ||
104 | * 6 -> comment | ||
105 | */ | ||
106 | |||
107 | while (1) { | ||
108 | ret = nextField(&s, d, inRecord, &refIndex); | ||
109 | switch (ret) { | ||
110 | case 0: | ||
111 | // successfully got next field. | ||
112 | inRecord = true; | ||
113 | switch (fieldIndex) { | ||
114 | case 0: // category | ||
115 | if (s.isEmpty()) { | ||
116 | /* This is special case. It's the category | ||
117 | * list terminating empty field. | ||
118 | */ | ||
119 | ++fieldIndex; | ||
120 | } else | ||
121 | curCat = s; | ||
122 | break; | ||
123 | case 1:// desc | ||
124 | di.desc = s; | ||
125 | ++fieldIndex; | ||
126 | break; | ||
127 | case 2: // name | ||
128 | di.name = s; | ||
129 | ++fieldIndex; | ||
130 | break; | ||
131 | case 3: // pw | ||
132 | di.pw = s; | ||
133 | ++fieldIndex; | ||
134 | break; | ||
135 | case 4: // url | ||
136 | di.url = s; | ||
137 | ++fieldIndex; | ||
138 | break; | ||
139 | case 5: // launcher | ||
140 | di.launcher = s; | ||
141 | ++fieldIndex; | ||
142 | break; | ||
143 | case 6: // comment | ||
144 | di.comment = s; | ||
145 | ++fieldIndex; | ||
146 | break; | ||
147 | default: | ||
148 | /* Too many fields in a record. | ||
149 | * We simply throw it away. | ||
150 | */ | ||
151 | break; | ||
152 | } | ||
153 | break; | ||
154 | case 1: | ||
155 | // record complete. | ||
156 | if (fieldIndex == 6) | ||
157 | di.comment = s; | ||
158 | inRecord = false; | ||
159 | fieldIndex = 0; | ||
160 | doc->addEntry(curCat, &di, true); | ||
161 | //US ENH: clear di for the next row | ||
162 | di.clear(); | ||
163 | break; | ||
164 | case 2: | ||
165 | // data completely parsed. | ||
166 | doc->flagDirty(); | ||
167 | return true; | ||
168 | case -1: | ||
169 | // parse error | ||
170 | doc->flagDirty(); | ||
171 | return false; | ||
172 | } | ||
173 | } | ||
174 | BUG(); | ||
175 | return false; | ||
176 | } | ||
177 | |||
178 | int Csv::nextField(QCString *ret, | ||
179 | const QByteArray &in, | ||
180 | bool inRecord, | ||
181 | int *_refIndex) | ||
182 | { | ||
183 | int rv = -2; | ||
184 | char c; | ||
185 | bool inField = false; | ||
186 | bool isQuoted = false; | ||
187 | bool searchingTerminator = false; | ||
188 | int refIndex; | ||
189 | int inSize = static_cast<int>(in.size()); | ||
190 | ret->truncate(0); | ||
191 | |||
192 | for (refIndex = *_refIndex; refIndex < inSize; ++refIndex) { | ||
193 | c = in.at(refIndex); | ||
194 | if (!inField) { | ||
195 | // we have to search the field beginning, now. | ||
196 | switch (c) { | ||
197 | case ' ': // space | ||
198 | case '': // tab | ||
199 | // hm, still not the beginning. Go on.. | ||
200 | break; | ||
201 | case '\r': | ||
202 | case '\n': | ||
203 | if (inRecord) { | ||
204 | /* This is the end of the last field in | ||
205 | * the record. | ||
206 | */ | ||
207 | PWM_ASSERT(ret->isEmpty()); | ||
208 | rv = 1; // record end | ||
209 | goto out; | ||
210 | } else { | ||
211 | // hm, still not the beginning. Go on.. | ||
212 | break; | ||
213 | } | ||
214 | case ',': | ||
215 | // Oh, an empty field. How sad. | ||
216 | PWM_ASSERT(ret->isEmpty()); | ||
217 | rv = 0; // field end | ||
218 | goto out; | ||
219 | case '\"': | ||
220 | // this is the quoted beginning. | ||
221 | inField = true; | ||
222 | isQuoted = true; | ||
223 | if (refIndex + 1 >= inSize) | ||
224 | goto unexp_eof; | ||
225 | break; | ||
226 | default: | ||
227 | // this is the unquoted beginning. | ||
228 | inField = true; | ||
229 | isQuoted = false; | ||
230 | *ret += c; | ||
231 | break; | ||
232 | } | ||
233 | } else { | ||
234 | // we are in the field now. Search the end. | ||
235 | if (isQuoted) { | ||
236 | if (searchingTerminator) { | ||
237 | switch (c) { | ||
238 | case '\r': | ||
239 | case '\n': | ||
240 | rv = 1; // record end | ||
241 | goto out; | ||
242 | case ',': | ||
243 | // found it. | ||
244 | rv = 0; // field end | ||
245 | goto out; | ||
246 | default: | ||
247 | // go on. | ||
248 | continue; | ||
249 | } | ||
250 | } | ||
251 | switch (c) { | ||
252 | case '\"': | ||
253 | /* check if this is the end of the | ||
254 | * entry, or just an inline escaped quote. | ||
255 | */ | ||
256 | char next; | ||
257 | if (refIndex + 1 >= inSize) { | ||
258 | // This is the last char, so it's the end. | ||
259 | rv = 2; // data end | ||
260 | goto out; | ||
261 | } | ||
262 | next = in.at(refIndex + 1); | ||
263 | switch (next) { | ||
264 | case '\"': | ||
265 | // This is an escaped double quote. | ||
266 | // So skip next iteration. | ||
267 | refIndex += 1; | ||
268 | *ret += c; | ||
269 | break; | ||
270 | default: | ||
271 | /* end of field. | ||
272 | * We have to search the comma (or newline...), | ||
273 | * which officially terminates the entry. | ||
274 | */ | ||
275 | searchingTerminator = true; | ||
276 | break; | ||
277 | } | ||
278 | break; | ||
279 | default: | ||
280 | // nothing special about the char. Go on! | ||
281 | *ret += c; | ||
282 | break; | ||
283 | } | ||
284 | } else { | ||
285 | switch (c) { | ||
286 | case '\"': | ||
287 | // This is not allowed here. | ||
288 | return -1; // parser error | ||
289 | case '\r': | ||
290 | case '\n': | ||
291 | rv = 1; // record end | ||
292 | goto out; | ||
293 | case ',': | ||
294 | rv = 0; // field end | ||
295 | goto out; | ||
296 | default: | ||
297 | // nothing special about the char. Go on! | ||
298 | *ret += c; | ||
299 | break; | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | // we are at the end of the stream, now! | ||
305 | if (searchingTerminator) { | ||
306 | /* Ok, there's no terminating comma (or newline...), | ||
307 | * because we are at the end. That's perfectly fine. | ||
308 | */ | ||
309 | PWM_ASSERT(inField); | ||
310 | rv = 2; // data end | ||
311 | goto out; | ||
312 | } | ||
313 | if (!isQuoted && inField) { | ||
314 | // That's the end of the last unquoted field. | ||
315 | rv = 2; // data end | ||
316 | goto out; | ||
317 | } | ||
318 | if (!inField) { | ||
319 | // This is expected EOF | ||
320 | rv = 2; // data end | ||
321 | goto out; | ||
322 | } | ||
323 | |||
324 | unexp_eof: | ||
325 | printDebug("unexpected EOF :("); | ||
326 | return -1; // parser error | ||
327 | |||
328 | out: | ||
329 | if (!isQuoted) | ||
330 | *ret = ret->stripWhiteSpace(); | ||
331 | *_refIndex = refIndex + 1; | ||
332 | return rv; | ||
333 | } | ||
334 | |||
335 | bool Csv::exportData(const QString &filepath, | ||
336 | PwMDoc *doc) | ||
337 | { | ||
338 | PWM_ASSERT(!doc->isDocEmpty()); | ||
339 | bool ret = true; | ||
340 | if (QFile::exists(filepath)) { | ||
341 | int ret; | ||
342 | ret = KMessageBox::questionYesNo(parent, | ||
343 | i18n("This file does already exist.\n" | ||
344 | "Do you want to overwrite it?"), | ||
345 | i18n("Overwrite file?")); | ||
346 | if (ret == KMessageBox::No) | ||
347 | return false; | ||
348 | if (!QFile::remove(filepath)) { | ||
349 | KMessageBox::error(parent, | ||
350 | i18n("Could not delete the old file."), | ||
351 | i18n("Delete error.")); | ||
352 | return false; | ||
353 | } | ||
354 | } | ||
355 | QFile f(filepath); | ||
356 | if (!f.open(IO_ReadWrite)) { | ||
357 | KMessageBox::error(parent, | ||
358 | i18n("Could not open file for writing."), | ||
359 | i18n("Open error.")); | ||
360 | ret = false; | ||
361 | goto out; | ||
362 | } | ||
363 | doc->unlockAll_tempoary(); | ||
364 | if (!doExport(f, doc)) | ||
365 | ret = false; | ||
366 | doc->unlockAll_tempoary(true); | ||
367 | f.close(); | ||
368 | out: | ||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | bool Csv::doExport(QFile &f, | ||
373 | PwMDoc *doc) | ||
374 | { | ||
375 | unsigned int numCat = doc->numCategories(); | ||
376 | unsigned int numEntr; | ||
377 | unsigned int i, j; | ||
378 | PwMDataItem d; | ||
379 | QCString s, catName; | ||
380 | QByteArray b; | ||
381 | |||
382 | for (i = 0; i < numCat; ++i) { | ||
383 | numEntr = doc->numEntries(i); | ||
384 | catName = newField(doc->getCategory(i)->c_str()); | ||
385 | for (j = 0; j < numEntr; ++j) { | ||
386 | doc->getEntry(i, j, &d); | ||
387 | s = catName; | ||
388 | s += ",,"; | ||
389 | s += newField(d.desc.c_str()); | ||
390 | s += ","; | ||
391 | s += newField(d.name.c_str()); | ||
392 | s += ","; | ||
393 | s += newField(d.pw.c_str()); | ||
394 | s += ","; | ||
395 | s += newField(d.url.c_str()); | ||
396 | s += ","; | ||
397 | s += newField(d.launcher.c_str()); | ||
398 | s += ","; | ||
399 | s += newField(d.comment.c_str()); | ||
400 | s += "\r\n"; | ||
401 | b = s; | ||
402 | // remove \0 termination | ||
403 | #ifndef PWM_EMBEDDED | ||
404 | b.resize(b.size() - 1, QGArray::SpeedOptim); | ||
405 | #else | ||
406 | b.resize(b.size() - 1); | ||
407 | #endif | ||
408 | if (!f.writeBlock(b)) | ||
409 | return false; | ||
410 | } | ||
411 | } | ||
412 | return true; | ||
413 | } | ||
414 | |||
415 | QCString Csv::newField(QCString s) | ||
416 | { | ||
417 | if (s.isEmpty()) | ||
418 | return QCString(); | ||
419 | QCString ret("\""); | ||
420 | #ifndef PWM_EMBEDDED | ||
421 | s.replace('\"', "\"\""); | ||
422 | #else | ||
423 | s.replace(QRegExp("\""), "\"\""); | ||
424 | #endif | ||
425 | ret += s; | ||
426 | ret += "\""; | ||
427 | return ret; | ||
428 | } | ||
diff --git a/pwmanager/pwmanager/csv.h b/pwmanager/pwmanager/csv.h new file mode 100644 index 0000000..6f3c1e1 --- a/dev/null +++ b/pwmanager/pwmanager/csv.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /*************************************************************************** | ||
2 | * * | ||
3 | * copyright (C) 2004 by Michael Buesch * | ||
4 | * email: mbuesch@freenet.de * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License version 2 * | ||
8 | * as published by the Free Software Foundation. * | ||
9 | * * | ||
10 | ***************************************************************************/ | ||
11 | |||
12 | /*************************************************************************** | ||
13 | * copyright (C) 2004 by Ulf Schenk | ||
14 | * This file is originaly based on version 1.1 of pwmanager | ||
15 | * and was modified to run on embedded devices that run microkde | ||
16 | * The original file version was 1.2 | ||
17 | * $Id$ | ||
18 | **************************************************************************/ | ||
19 | |||
20 | |||
21 | #ifndef __PWMANAGER_CSV_H | ||
22 | #define __PWMANAGER_CSV_H | ||
23 | |||
24 | #include <qcstring.h> | ||
25 | #include <qfile.h> | ||
26 | |||
27 | |||
28 | class PwMDoc; | ||
29 | class QString; | ||
30 | class QWidget; | ||
31 | |||
32 | /** class for CSV (Comma Separated Value) export and import. | ||
33 | * | ||
34 | * http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm | ||
35 | * http://en.wikipedia.org/wiki/Comma-separated_values | ||
36 | * | ||
37 | * There are two types of CSV output we can produce. | ||
38 | * One with Category support (recommended): | ||
39 | * "Category 1",, "Desc 1", "Username 1", "Password 1", "URL 1", "Launcher 1", "Comment 1" | ||
40 | * "Category 1",, "Desc 2", "Username 2", "Password 2", "URL 2", "Launcher 2", "Comment 2" | ||
41 | * ... | ||
42 | * The empty "" is neccessary, because in future versions we will | ||
43 | * support nested Categories. We want to be future compatible, now. | ||
44 | * | ||
45 | * And one without Category support: | ||
46 | *FIXME: it's not implemented, yet. ;) | ||
47 | * "Desc 1", "Username 1", "Password 1", "URL 1", "Launcher 1", "Comment 1" | ||
48 | * "Desc 2", "Username 2", "Password 2", "URL 2", "Launcher 2", "Comment 2" | ||
49 | * ... | ||
50 | * | ||
51 | */ | ||
52 | class Csv | ||
53 | { | ||
54 | public: | ||
55 | Csv(QWidget *_parent); | ||
56 | ~Csv(); | ||
57 | |||
58 | /** import data from "filepath" into "doc" */ | ||
59 | bool importData(const QString &filepath, | ||
60 | PwMDoc *doc); | ||
61 | /** export data from "doc" to "filepath" */ | ||
62 | bool exportData(const QString &filepath, | ||
63 | PwMDoc *doc); | ||
64 | |||
65 | protected: | ||
66 | /** do the import process. */ | ||
67 | bool doImport(const QByteArray &d, | ||
68 | PwMDoc *doc); | ||
69 | /** parse for the next field. | ||
70 | * @return Return values are: | ||
71 | * 0 -> successfully got the next field. | ||
72 | * 1 -> record end. | ||
73 | * 2 -> data end. | ||
74 | * -1 -> parser error. | ||
75 | */ | ||
76 | int nextField(QCString *ret, | ||
77 | const QByteArray &in, | ||
78 | bool inRecord, | ||
79 | int *_refIndex); | ||
80 | /** do the export process. */ | ||
81 | bool doExport(QFile &f, | ||
82 | PwMDoc *doc); | ||
83 | /** generate a new data field string. */ | ||
84 | QCString newField(QCString s); | ||
85 | |||
86 | protected: | ||
87 | /** current parent widget. */ | ||
88 | QWidget *parent; | ||
89 | }; | ||
90 | |||
91 | #endif // __PWMANAGER_CSV_H | ||
diff --git a/pwmanager/pwmanager/pwm.cpp b/pwmanager/pwmanager/pwm.cpp index 66d26d6..ac0c978 100644 --- a/pwmanager/pwmanager/pwm.cpp +++ b/pwmanager/pwmanager/pwm.cpp | |||
@@ -56,6 +56,7 @@ | |||
56 | #include "addentrywndimpl.h" | 56 | #include "addentrywndimpl.h" |
57 | #include "globalstuff.h" | 57 | #include "globalstuff.h" |
58 | #include "findwndimpl.h" | 58 | #include "findwndimpl.h" |
59 | #include "csv.h" | ||
59 | 60 | ||
60 | #ifdef CONFIG_KWALLETIF | 61 | #ifdef CONFIG_KWALLETIF |
61 | # include "kwalletif.h" | 62 | # include "kwalletif.h" |
@@ -113,7 +114,8 @@ enum { | |||
113 | // Button IDs for "export" popup menu (in "file" popup menu) | 114 | // Button IDs for "export" popup menu (in "file" popup menu) |
114 | enum { | 115 | enum { |
115 | BUTTON_POPUP_EXPORT_TEXT = 0, | 116 | BUTTON_POPUP_EXPORT_TEXT = 0, |
116 | BUTTON_POPUP_EXPORT_GPASMAN | 117 | BUTTON_POPUP_EXPORT_GPASMAN, |
118 | BUTTON_POPUP_EXPORT_CSV | ||
117 | #ifdef CONFIG_KWALLETIF | 119 | #ifdef CONFIG_KWALLETIF |
118 | ,BUTTON_POPUP_EXPORT_KWALLET | 120 | ,BUTTON_POPUP_EXPORT_KWALLET |
119 | #endif | 121 | #endif |
@@ -121,7 +123,8 @@ enum { | |||
121 | // Button IDs for "import" popup menu (in "file" popup menu) | 123 | // Button IDs for "import" popup menu (in "file" popup menu) |
122 | enum { | 124 | enum { |
123 | BUTTON_POPUP_IMPORT_TEXT = 0, | 125 | BUTTON_POPUP_IMPORT_TEXT = 0, |
124 | BUTTON_POPUP_IMPORT_GPASMAN | 126 | BUTTON_POPUP_IMPORT_GPASMAN, |
127 | BUTTON_POPUP_IMPORT_CSV | ||
125 | #ifdef CONFIG_KWALLETIF | 128 | #ifdef CONFIG_KWALLETIF |
126 | ,BUTTON_POPUP_IMPORT_KWALLET | 129 | ,BUTTON_POPUP_IMPORT_KWALLET |
127 | #endif | 130 | #endif |
@@ -181,10 +184,12 @@ PwM::PwM(PwMInit *_init, PwMDoc *doc, | |||
181 | 184 | ||
182 | PwM::~PwM() | 185 | PwM::~PwM() |
183 | { | 186 | { |
187 | //qDebug("PwM::~PwM()"); | ||
184 | disconnect(curDoc(), SIGNAL(docClosed(PwMDoc *)), | 188 | disconnect(curDoc(), SIGNAL(docClosed(PwMDoc *)), |
185 | this, SLOT(docClosed(PwMDoc *))); | 189 | this, SLOT(docClosed(PwMDoc *))); |
186 | conf()->confWndMainWndSize(size()); | 190 | conf()->confWndMainWndSize(size()); |
187 | emit closed(this); | 191 | emit closed(this); |
192 | //qDebug("PwM::~PwM() emited closed(this)"); | ||
188 | delete view; | 193 | delete view; |
189 | } | 194 | } |
190 | 195 | ||
@@ -241,6 +246,8 @@ void PwM::initMenubar() | |||
241 | SLOT(exportToText()), 0, BUTTON_POPUP_EXPORT_TEXT); | 246 | SLOT(exportToText()), 0, BUTTON_POPUP_EXPORT_TEXT); |
242 | exportPopup->insertItem(i18n("&Gpasman / Kpasman ..."), this, | 247 | exportPopup->insertItem(i18n("&Gpasman / Kpasman ..."), this, |
243 | SLOT(exportToGpasman()), 0, BUTTON_POPUP_EXPORT_GPASMAN); | 248 | SLOT(exportToGpasman()), 0, BUTTON_POPUP_EXPORT_GPASMAN); |
249 | exportPopup->insertItem(i18n("&CSV (Comma Separated Value) ..."), this, | ||
250 | SLOT(exportToCsv()), 0, BUTTON_POPUP_EXPORT_CSV); | ||
244 | #ifdef CONFIG_KWALLETIF | 251 | #ifdef CONFIG_KWALLETIF |
245 | exportPopup->insertItem(i18n("&KWallet..."), this, | 252 | exportPopup->insertItem(i18n("&KWallet..."), this, |
246 | SLOT(exportToKWallet()), 0, BUTTON_POPUP_EXPORT_KWALLET); | 253 | SLOT(exportToKWallet()), 0, BUTTON_POPUP_EXPORT_KWALLET); |
@@ -253,6 +260,8 @@ void PwM::initMenubar() | |||
253 | SLOT(importFromText()), 0, BUTTON_POPUP_IMPORT_TEXT); | 260 | SLOT(importFromText()), 0, BUTTON_POPUP_IMPORT_TEXT); |
254 | importPopup->insertItem(i18n("&Gpasman / Kpasman ..."), this, | 261 | importPopup->insertItem(i18n("&Gpasman / Kpasman ..."), this, |
255 | SLOT(importFromGpasman()), 0, BUTTON_POPUP_IMPORT_GPASMAN); | 262 | SLOT(importFromGpasman()), 0, BUTTON_POPUP_IMPORT_GPASMAN); |
263 | importPopup->insertItem(i18n("&CSV (Comma Separated Value) ..."), this, | ||
264 | SLOT(importCsv()), 0, BUTTON_POPUP_IMPORT_CSV); | ||
256 | #ifdef CONFIG_KWALLETIF | 265 | #ifdef CONFIG_KWALLETIF |
257 | importPopup->insertItem(i18n("&KWallet..."), this, | 266 | importPopup->insertItem(i18n("&KWallet..."), this, |
258 | SLOT(importKWallet()), 0, BUTTON_POPUP_IMPORT_KWALLET); | 267 | SLOT(importKWallet()), 0, BUTTON_POPUP_IMPORT_KWALLET); |
@@ -1016,6 +1025,78 @@ void PwM::exportToGpasman() | |||
1016 | curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); | 1025 | curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); |
1017 | } | 1026 | } |
1018 | 1027 | ||
1028 | |||
1029 | |||
1030 | void PwM::exportToCsv() | ||
1031 | { | ||
1032 | PWM_ASSERT(curDoc()); | ||
1033 | if (curDoc()->isDocEmpty()) { | ||
1034 | KMessageBox::information(this, | ||
1035 | i18n | ||
1036 | ("Sorry, there is nothing to export;\n" | ||
1037 | "please add some passwords first."), | ||
1038 | i18n("Nothing to Do")); | ||
1039 | return; | ||
1040 | } | ||
1041 | |||
1042 | curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); | ||
1043 | QString fn(KFileDialog::getSaveFileName("*.csv", i18n("*|CSV Text File"), this)); | ||
1044 | if (fn.isEmpty()) { | ||
1045 | curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); | ||
1046 | return; | ||
1047 | } | ||
1048 | |||
1049 | Csv csv(this); | ||
1050 | if (!csv.exportData(fn, curDoc())) { | ||
1051 | curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); | ||
1052 | showStatMsg(i18n("CSV file export failed.")); | ||
1053 | return; | ||
1054 | } | ||
1055 | showStatMsg(i18n("Successfully exported data.")); | ||
1056 | curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); | ||
1057 | } | ||
1058 | |||
1059 | bool PwM::importCsv() | ||
1060 | { | ||
1061 | Csv csv(this); | ||
1062 | if (!isVirgin()) { | ||
1063 | if (KMessageBox::questionYesNo(this, | ||
1064 | i18n("Do you want to import the data\n" | ||
1065 | "into the current document? (If you\n" | ||
1066 | "select \"no\", a new document will be\n" | ||
1067 | "opened.)"), | ||
1068 | i18n("Import into This Document?")) | ||
1069 | == KMessageBox::No) { | ||
1070 | // import the data to a new window. | ||
1071 | PwM *newInstance = init->createMainWnd(); | ||
1072 | bool ok = newInstance->importCsv(); | ||
1073 | if (!ok) { | ||
1074 | newInstance->setForceQuit(true); | ||
1075 | delete_and_null(newInstance); | ||
1076 | } | ||
1077 | return ok; | ||
1078 | } | ||
1079 | } | ||
1080 | |||
1081 | QString filename = KFileDialog::getOpenFileName("*.csv", i18n("*|CSV Text File"), this); | ||
1082 | if (filename.isEmpty()) | ||
1083 | return false; | ||
1084 | curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); | ||
1085 | if (!csv.importData(filename, curDoc())) { | ||
1086 | curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); | ||
1087 | showStatMsg(i18n("CSV file import failed.")); | ||
1088 | return false; | ||
1089 | } | ||
1090 | curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); | ||
1091 | KMessageBox::information(this, | ||
1092 | i18n("Successfully imported the CSV data\n" | ||
1093 | "into the current document."), i18n("Successfully Imported")); | ||
1094 | showStatMsg(i18n("Successfully imported")); | ||
1095 | setVirgin(false); | ||
1096 | return true; | ||
1097 | } | ||
1098 | |||
1099 | |||
1019 | void PwM::exportToKWallet() | 1100 | void PwM::exportToKWallet() |
1020 | { | 1101 | { |
1021 | #ifdef CONFIG_KWALLETIF | 1102 | #ifdef CONFIG_KWALLETIF |
diff --git a/pwmanager/pwmanager/pwm.h b/pwmanager/pwmanager/pwm.h index 6ab9d6b..5822d59 100644 --- a/pwmanager/pwmanager/pwm.h +++ b/pwmanager/pwmanager/pwm.h | |||
@@ -124,12 +124,16 @@ public slots: | |||
124 | void exportToGpasman(); | 124 | void exportToGpasman(); |
125 | /** file/export/kwallet triggered */ | 125 | /** file/export/kwallet triggered */ |
126 | void exportToKWallet(); | 126 | void exportToKWallet(); |
127 | /** file/export/csv triggered */ | ||
128 | void exportToCsv(); | ||
127 | /** file/import/text triggered */ | 129 | /** file/import/text triggered */ |
128 | bool importFromText(); | 130 | bool importFromText(); |
129 | /** file/import/gpasman triggered */ | 131 | /** file/import/gpasman triggered */ |
130 | bool importFromGpasman(); | 132 | bool importFromGpasman(); |
131 | /** file/import/kwallet triggered */ | 133 | /** file/import/kwallet triggered */ |
132 | bool importKWallet(); | 134 | bool importKWallet(); |
135 | /** file/import/csv triggered */ | ||
136 | bool importCsv(); | ||
133 | /** file/print triggered */ | 137 | /** file/print triggered */ |
134 | void print_slot(); | 138 | void print_slot(); |
135 | /** manage/add triggered */ | 139 | /** manage/add triggered */ |
diff --git a/pwmanager/pwmanager/pwmanagerE.pro b/pwmanager/pwmanager/pwmanagerE.pro index 1445bcf..c46e937 100644 --- a/pwmanager/pwmanager/pwmanagerE.pro +++ b/pwmanager/pwmanager/pwmanagerE.pro | |||
@@ -62,6 +62,7 @@ blowfish.h \ | |||
62 | commentbox.h \ | 62 | commentbox.h \ |
63 | compiler.h \ | 63 | compiler.h \ |
64 | compressgzip.h \ | 64 | compressgzip.h \ |
65 | csv.h \ | ||
65 | findwnd_emb.h \ | 66 | findwnd_emb.h \ |
66 | findwndimpl.h \ | 67 | findwndimpl.h \ |
67 | genpasswd.h \ | 68 | genpasswd.h \ |
@@ -127,6 +128,7 @@ binentrygen.cpp \ | |||
127 | blowfish.cpp \ | 128 | blowfish.cpp \ |
128 | commentbox.cpp \ | 129 | commentbox.cpp \ |
129 | compressgzip.cpp \ | 130 | compressgzip.cpp \ |
131 | csv.cpp \ | ||
130 | findwnd_emb.cpp \ | 132 | findwnd_emb.cpp \ |
131 | findwndimpl.cpp \ | 133 | findwndimpl.cpp \ |
132 | genpasswd.cpp \ | 134 | genpasswd.cpp \ |