1 /***************************************************************************
2 * Copyright (C) 2003 by Sébastien Laoût *
3 * slaout@linux62.org *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #include "softwareimporters.h"
22
23 #include <QtCore/QString>
24 #include <QtCore/QDir>
25 #include <QtCore/QTextStream>
26 #include <QtCore/QStack>
27 #include <QGroupBox>
28 #include <QHBoxLayout>
29 #include <QVBoxLayout>
30 #include <QRadioButton>
31 #include <QtXml/QDomDocument>
32 #include <QRegExp>
33 #include <QLocale>
34 #include <QDialogButtonBox>
35 #include <QPushButton>
36 #include <QVBoxLayout>
37 #include <QStandardPaths>
38 #include <QFileDialog>
39
40 #include <KMessageBox>
41 #include <KTextEdit>
42 #include <KConfigGroup>
43 #include <KLocalizedString>
44
45 #include "basketscene.h"
46 #include "basketfactory.h"
47 #include "notefactory.h"
48 #include "global.h"
49 #include "bnpview.h"
50 #include "xmlwork.h"
51 #include "tools.h"
52 #include "icon_names.h"
53 #include "debugwindow.h"
54
55 /** class TreeImportDialog: */
56
TreeImportDialog(QWidget * parent)57 TreeImportDialog::TreeImportDialog(QWidget *parent)
58 : QDialog(parent)
59 {
60 QWidget *page = new QWidget(this);
61 QVBoxLayout *topLayout = new QVBoxLayout(page);
62
63 // QDialog options
64 setWindowTitle(i18n("Import Hierarchy"));
65
66 QWidget *mainWidget = new QWidget(this);
67 QVBoxLayout *mainLayout = new QVBoxLayout;
68 setLayout(mainLayout);
69 mainLayout->addWidget(mainWidget);
70
71 setObjectName("ImportHeirachy");
72 setModal(true);
73
74 m_choices = new QGroupBox(i18n("How to Import the Notes?"), page);
75 m_choiceLayout = new QVBoxLayout();
76 m_choices->setLayout(m_choiceLayout);
77
78 m_hierarchy_choice = new QRadioButton(i18n("&Keep original hierarchy (all notes in separate baskets)"), m_choices);
79 m_separate_baskets_choice = new QRadioButton(i18n("&First level notes in separate baskets"), m_choices);
80 m_one_basket_choice = new QRadioButton(i18n("&All notes in one basket"), m_choices);
81
82 m_hierarchy_choice->setChecked(true);
83 m_choiceLayout->addWidget(m_hierarchy_choice);
84 m_choiceLayout->addWidget(m_separate_baskets_choice);
85 m_choiceLayout->addWidget(m_one_basket_choice);
86
87 topLayout->addWidget(m_choices);
88 topLayout->addStretch(10);
89
90 mainLayout->addWidget(page);
91
92 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, this);
93 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
94 okButton->setDefault(true);
95 okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
96 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
97 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
98 mainLayout->addWidget(buttonBox);
99 }
100
~TreeImportDialog()101 TreeImportDialog::~TreeImportDialog()
102 {
103 }
104
choice()105 int TreeImportDialog::choice()
106 {
107 if (m_hierarchy_choice->isChecked())
108 return 1;
109 else if (m_separate_baskets_choice->isChecked())
110 return 2;
111 else
112 return 3;
113 }
114
115 /** class TextFileImportDialog: */
116
TextFileImportDialog(QWidget * parent)117 TextFileImportDialog::TextFileImportDialog(QWidget *parent)
118 : QDialog(parent)
119 {
120 QWidget *page = new QWidget(this);
121 QVBoxLayout *topLayout = new QVBoxLayout(page);
122 QVBoxLayout *mainLayout = new QVBoxLayout;
123 setLayout(mainLayout);
124
125 // QDialog options
126 setWindowTitle(i18n("Import Text File"));
127 setObjectName("ImportTextFile");
128 setModal(true);
129
130
131 m_choices = new QGroupBox(i18n("Format of the Text File"), page);
132 mainLayout->addWidget(m_choices);
133 m_choiceLayout = new QVBoxLayout;
134 m_choices->setLayout(m_choiceLayout);
135
136 m_emptyline_choice = new QRadioButton(i18n("Notes separated by an &empty line"), m_choices);
137 m_newline_choice = new QRadioButton(i18n("One ¬e per line"), m_choices);
138 m_dash_choice = new QRadioButton(i18n("Notes begin with a &dash (-)"), m_choices);
139 m_star_choice = new QRadioButton(i18n("Notes begin with a &star (*)"), m_choices);
140 m_anotherSeparator = new QRadioButton(i18n("&Use another separator:"), m_choices);
141
142 m_choiceLayout->addWidget(m_emptyline_choice);
143 m_choiceLayout->addWidget(m_newline_choice);
144 m_choiceLayout->addWidget(m_dash_choice);
145 m_choiceLayout->addWidget(m_star_choice);
146 m_choiceLayout->addWidget(m_anotherSeparator);
147
148 QWidget *indentedTextEdit = new QWidget(m_choices);
149 m_choiceLayout->addWidget(indentedTextEdit);
150
151 QHBoxLayout *hLayout = new QHBoxLayout(indentedTextEdit);
152 hLayout->addSpacing(20);
153 m_customSeparator = new KTextEdit(indentedTextEdit);
154 hLayout->addWidget(m_customSeparator);
155
156 m_all_in_one_choice = new QRadioButton(i18n("&All in one note"), m_choices);
157 m_choiceLayout->addWidget(m_all_in_one_choice);
158
159 m_emptyline_choice->setChecked(true);
160 topLayout->addWidget(m_choices);
161
162 connect(m_customSeparator, SIGNAL(textChanged()), this, SLOT(customSeparatorChanged()));
163
164 mainLayout->addWidget(page);
165
166 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, this);
167 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
168 okButton->setDefault(true);
169 okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
170 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
171 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
172 mainLayout->addWidget(buttonBox);
173 }
174
~TextFileImportDialog()175 TextFileImportDialog::~TextFileImportDialog()
176 {
177 }
178
separator()179 QString TextFileImportDialog::separator()
180 {
181 if (m_emptyline_choice->isChecked())
182 return "\n\n";
183 else if (m_newline_choice->isChecked())
184 return "\n";
185 else if (m_dash_choice->isChecked())
186 return "\n-";
187 else if (m_star_choice->isChecked())
188 return "\n*";
189 else if (m_anotherSeparator->isChecked())
190 return m_customSeparator->toPlainText();
191 else if (m_all_in_one_choice->isChecked())
192 return "";
193 else
194 return "\n\n";
195 }
196
customSeparatorChanged()197 void TextFileImportDialog::customSeparatorChanged()
198 {
199 if (!m_anotherSeparator->isChecked())
200 m_anotherSeparator->toggle();
201 }
202
203 /** namespace SoftwareImporters: */
204
fromICS(const QString & ics)205 QString SoftwareImporters::fromICS(const QString &ics)
206 {
207 QString result = ics;
208
209 // Remove escaped '\' characters and append the text to the body
210 int pos = 0;
211 while ((pos = result.indexOf('\\', pos)) != -1) {
212 if (pos == result.length() - 1) // End of string
213 break;
214 if (result[pos+1] == 'n') {
215 result.replace(pos, 2, '\n');
216 } else if (result[pos+1] == 'r') {
217 result.replace(pos, 2, '\r');
218 } else if (result[pos+1] == 't') {
219 result.replace(pos, 2, '\t');
220 } else if (result[pos] == '\\') {
221 result.remove(pos, 1); // Take care of "\\", "\,", "\;" and other escaped characters I haven't noticed
222 ++pos;
223 }
224 }
225
226 return result;
227 }
228
fromTomboy(QString tomboy)229 QString SoftwareImporters::fromTomboy(QString tomboy)
230 {
231 // The first line is the note title, and we already have it, so we remove it (yes, that's pretty stupid to duplicate it in the content...):
232 tomboy = tomboy.mid(tomboy.indexOf("\n")).trimmed();
233
234 // Font styles and decorations:
235 tomboy.replace("<bold>", "<b>");
236 tomboy.replace("</bold>", "</b>");
237 tomboy.replace("<italic>", "<i>");
238 tomboy.replace("</italic>", "</i>");
239 tomboy.replace("<strikethrough>", "<span style='text-decoration: line-through'>");
240 tomboy.replace("</strikethrough>", "</span>");
241
242 // Highlight not supported by KTextEdit:
243 //TODO: implement this marker-style yellow highlight?
244 tomboy.replace("<highlight>", "<span style='color:#ff0080'>");
245 tomboy.replace("</highlight>", "</span>");
246
247 // Font sizes:
248 tomboy.replace("<size:small>", "<span style='font-size: 7pt'>");
249 tomboy.replace("</size:small>", "</span>");
250 tomboy.replace("<size:large>", "<span style='font-size: 16pt'>");
251 tomboy.replace("</size:large>", "</span>");
252 tomboy.replace("<size:huge>", "<span style='font-size: 20pt'>");
253 tomboy.replace("</size:huge>", "</span>");
254
255 // Internal links to other notes aren't supported yet by BasKet Note Pads:
256 tomboy.replace("<link:internal>", "");
257 tomboy.replace("</link:internal>", "");
258
259 // Bullets
260 tomboy.replace("<list>", "<ul>");
261 tomboy.replace("</list>", "</ul>");
262
263 QRegExp tagRegex("<list-item.*>");
264 tagRegex.setMinimal(true); // non-greedy
265 tomboy.replace(QRegExp(tagRegex), "<li>");
266 tomboy.replace("</list-item>", "</li>");
267
268 // In the Tomboy file, new lines are "\n" and not "<br>":
269 tomboy.replace("\n", "<br>\n");
270
271 // Preserve consecutive spaces:
272 return "<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"><meta name=\"qrichtext\" content=\"1\" /></head><body>" + tomboy + "</body></html>";
273 }
274
getFirstTomboyTag(const QDomElement & docElem)275 QString SoftwareImporters::getFirstTomboyTag(const QDomElement& docElem)
276 {
277 // Would be better to take the last tag (latest user choice), but that requires more DOM code
278
279 QString tag = XMLWork::getElementText(docElem, "tags/tag");
280 if (tag.length() > 0) {
281
282 // Carefully peel the markup
283 const QString SYSTEM_PREFIX = "system:";
284 const QString NOTEBOOK_PREFIX = "notebook:";
285
286 if (tag.startsWith(SYSTEM_PREFIX))
287 tag.remove(0, SYSTEM_PREFIX.length());
288
289 if (tag.startsWith(NOTEBOOK_PREFIX))
290 tag.remove(0, NOTEBOOK_PREFIX.length());
291 }
292
293 return tag;
294 }
295
insertTitledNote(BasketScene * parent,const QString & title,const QString & content,Qt::TextFormat format,Note * parentNote)296 Note* SoftwareImporters::insertTitledNote(BasketScene *parent, const QString &title, const QString &content, Qt::TextFormat format/* = Qt::PlainText*/, Note *parentNote/* = 0*/)
297 {
298 Note *nGroup = new Note(parent);
299
300 Note *nTitle = NoteFactory::createNoteText(title, parent);
301 nTitle->addState(Tag::stateForId("title"));
302
303 Note *nContent;
304 if (format == Qt::PlainText)
305 nContent = NoteFactory::createNoteText(content, parent);
306 else
307 nContent = NoteFactory::createNoteHtml(content, parent);
308
309 if (parentNote == 0)
310 parentNote = parent->firstNote(); // In the first column!
311 parent->insertNote(nGroup, parentNote, Note::BottomColumn, QPoint(), /*animate=*/false);
312 parent->insertNote(nTitle, nGroup, Note::BottomColumn, QPoint(), /*animate=*/false);
313 parent->insertNote(nContent, nTitle, Note::BottomInsert, QPoint(), /*animate=*/false);
314
315 return nGroup;
316 }
317
finishImport(BasketScene * basket)318 void SoftwareImporters::finishImport(BasketScene *basket)
319 {
320 // Unselect the last inserted group:
321 basket->unselectAll();
322
323 // Focus the FIRST note (the last inserted note is currently focused!):
324 basket->setFocusedNote(basket->firstNoteShownInStack());
325
326 // Relayout every notes at theire new place and simulate a load animation (because already loaded just after the creation).
327 // Without a relayouting, notes on the bottom would comes from the top (because they were inserted on top) and clutter the animation load:
328 basket->relayoutNotes(/*animate=*/false);
329 basket->animateLoad();
330 basket->save();
331 }
332
333
334
importKJots()335 void SoftwareImporters::importKJots()
336 {
337 //This code is out-of-date. KJots (KDE4) and KNotes (KDE4, 5) now store data in Akonadi and MIME files in .local/share/notes
338 QString dirPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/../kjots/"; // I think the assumption is good
339 QDir dir(dirPath, QString::null, QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::NoSymLinks);
340
341 QStringList list = dir.entryList();
342 if (list.isEmpty())
343 return;
344
345 BasketFactory::newBasket(/*icon=*/"kjots", /*name=*/i18n("From KJots"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
346 BasketScene *kjotsBasket = Global::bnpView->currentBasket();
347
348 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) { // For each file
349 QFile file(dirPath + *it);
350 if (file.open(QIODevice::ReadOnly)) {
351 QTextStream stream(&file);
352 QString buf = stream.readLine();
353
354 // IT IS A NOTEBOOK FILE, AT THE VERION 0.6.x and older:
355 if (!buf.isNull() && buf.left(9) == "\\NewEntry") {
356
357 // First create a basket for it:
358 BasketFactory::newBasket(/*icon=*/"kjots", /*name=*/QUrl::fromLocalFile(file.fileName()).fileName(), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/kjotsBasket);
359 BasketScene *basket = Global::bnpView->currentBasket();
360 basket->load();
361
362 QString title, body;
363 bool haveAnEntry = false;
364 while (1) {
365 if (buf.left(9) == "\\NewEntry") {
366 if (haveAnEntry) // Do not add note the first time
367 insertTitledNote(basket, title, Tools::stripEndWhiteSpaces(body));
368 title = buf.mid(10, buf.length()); // Problem : basket will be saved
369 body = ""; // New note will then be created // EACH time a note is imported
370 haveAnEntry = true;
371 } else if (buf.left(3) != "\\ID") { // Don't care of the ID
372 // Remove escaped '\' characters and append the text to the body
373 int pos = 0;
374 while ((pos = buf.indexOf('\\', pos)) != -1)
375 if (buf[++pos] == '\\')
376 buf.remove(pos, 1);
377 body.append(buf + "\n");
378 }
379 buf = stream.readLine();
380 if (buf.isNull()) // OEF
381 break;
382 }
383 // Add the ending note (there isn't any other "\\NewEntry" to do it):
384 if (haveAnEntry)
385 insertTitledNote(basket, title, Tools::stripEndWhiteSpaces(body));
386 finishImport(basket);
387
388 // IT IS A NOTEBOOK XML FILE, AT THE VERION 0.7.0 and later:
389 } else if ((*it).endsWith(QLatin1String(".book")) /*&& !buf.isNull() && (buf.left(2) == "<!" / *<!DOCTYPE...* / || buf.left(2) == "<?" / *<?xml...* /)*/) {
390
391 QDomDocument *doc = XMLWork::openFile("KJots", dirPath + *it);
392 if (doc == 0)
393 continue;
394
395 QString bookTitle = XMLWork::getElementText(doc->documentElement(), "KJotsBook/Title");
396
397 // First create a basket for it:
398 BasketFactory::newBasket(/*icon=*/"kjots", /*name=*/bookTitle, /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/kjotsBasket);
399 BasketScene *basket = Global::bnpView->currentBasket();
400 basket->load();
401
402 QDomElement docElem = XMLWork::getElement(doc->documentElement(), "KJotsBook");
403 for (QDomNode n = docElem.firstChild(); !n.isNull(); n = n.nextSibling()) {
404 QDomElement e = n.toElement();
405 if ((!e.isNull()) && e.tagName() == "KJotsPage")
406 insertTitledNote(basket, XMLWork::getElementText(e, "Title"), XMLWork::getElementText(e, "Text"));
407 }
408 finishImport(basket);
409
410 }
411
412 file.close();
413 }
414 }
415 }
416
importKNotes()417 void SoftwareImporters::importKNotes()
418 {
419 QString dirPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/../knotes/"; // I think the assumption is good
420 QDir dir(dirPath, QString::null, QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::NoSymLinks);
421
422 QStringList list = dir.entryList();
423 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) { // For each file
424 if (!(*it).endsWith(QLatin1String(".ics"))) // Don't process *.ics~ and other files
425 continue;
426 QFile file(dirPath + *it);
427 if (file.open(QIODevice::ReadOnly)) {
428 QTextStream stream(&file);
429 stream.setCodec("UTF-8");
430
431 // First create a basket for it:
432 BasketFactory::newBasket(/*icon=*/"knotes", /*name=*/i18n("From KNotes"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
433 BasketScene *basket = Global::bnpView->currentBasket();
434 basket->load();
435
436 bool inVJournal = false;
437 bool inDescription = false;
438 bool isRichText = false;
439 QString title, body;
440 QString buf;
441 while (1) {
442 buf = stream.readLine();
443 if (buf.isNull()) // OEF
444 break;
445
446 if (!buf.isNull() && buf == "BEGIN:VJOURNAL") {
447 inVJournal = true;
448 } else if (inVJournal && buf.startsWith(QLatin1String("SUMMARY:"))) {
449 title = buf.mid(8, buf.length());
450 } else if (inVJournal && buf.startsWith(QLatin1String("DESCRIPTION:"))) {
451 body = buf.mid(12, buf.length());
452 inDescription = true;
453 } else if (inDescription && buf.startsWith(QLatin1String(" "))) {
454 body += buf.mid(1, buf.length());
455 } else if (buf.startsWith(QLatin1String("X-KDE-KNotes-RichText:"))) {
456 isRichText = XMLWork::trueOrFalse(buf.mid(22, buf.length() - 22).trimmed(), "false");
457 } else if (buf == "END:VJOURNAL") {
458 insertTitledNote(basket, fromICS(title), fromICS(body), (isRichText ? Qt::RichText : Qt::PlainText));
459 inVJournal = false;
460 inDescription = false;
461 isRichText = false;
462 title = "";
463 body = "";
464 } else
465 inDescription = false;
466 }
467
468 // Bouh : duplicate code
469 // In case of unvalide ICAL file!
470 if (! body.isEmpty()) // Add the ending note
471 insertTitledNote(basket, fromICS(title), fromICS(body), (isRichText ? Qt::RichText : Qt::PlainText));
472 file.close();
473 finishImport(basket);
474 }
475 }
476 }
477
importStickyNotes()478 void SoftwareImporters::importStickyNotes()
479 {
480 // Sticky Notes file is usually located in ~/.gnome2/stickynotes_applet
481 // We will search all directories in "~/" that contain "gnome" in the name,
482 // and will search for "stickynotes_applet" file (that should be XML file with <stickynotes> root.
483 QDir dir(QDir::home().absolutePath(), QString::null, QDir::Name | QDir::IgnoreCase,
484 QDir::Dirs | QDir::NoSymLinks | QDir::Hidden);
485 QStringList founds;
486
487 QStringList list = dir.entryList();
488 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) { // For each folder
489 if ((*it).contains("gnome", Qt::CaseInsensitive)) {
490 QString fullPath = QDir::home().absolutePath() + "/" + (*it) + "/stickynotes_applet";
491 if (dir.exists(fullPath))
492 founds += fullPath;
493 }
494 }
495
496 for (QStringList::Iterator it = founds.begin(); it != founds.end(); ++it) { // For each file
497 QFile file(*it);
498 QDomDocument *doc = XMLWork::openFile("stickynotes", *it);
499 if (doc == 0)
500 continue;
501
502 // First create a basket for it:
503 BasketFactory::newBasket(/*icon=*/"gnome", /*name=*/i18n("From Sticky Notes"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
504 BasketScene *basket = Global::bnpView->currentBasket();
505 basket->load();
506
507 QDomElement docElem = doc->documentElement();
508 for (QDomNode n = docElem.firstChild(); !n.isNull(); n = n.nextSibling()) {
509 QDomElement e = n.toElement();
510 if ((!e.isNull()) && e.tagName() == "note")
511 insertTitledNote(basket, e.attribute("title"), e.text());
512 }
513 finishImport(basket);
514 }
515 }
516
517
518
519 // TODO: FIXME: Code duplicated from notecontent.cpp but with UTF-8 encoding.
520 // TODO: FIXME: Later, merge!
loadUtf8FileToString(const QString & fileName)521 QString loadUtf8FileToString(const QString &fileName)
522 {
523 QFile file(fileName);
524 if (file.open(QIODevice::ReadOnly)) {
525 QTextStream stream(&file);
526 stream.setCodec("UTF-8");
527 QString text;
528 text = stream.readAll();
529 file.close();
530 return text;
531 } else
532 return "";
533 }
534
535
importTomboy()536 void SoftwareImporters::importTomboy()
537 {
538 /* A notebook becomes a basket.
539 What can be improved: separate big text into notes by "\n\n";
540 remove "\n" from lists - we don't need <br> between two <li>s */
541
542 BasketScene *basketFromTomboy = 0; // Create the basket ONLY if we found at least one note to add!
543 BasketScene *subBasket; // Where are we adding current note? (can equal basketFromTomboy if the note is in generic notebook)
544 QMap<QString, BasketScene*> subBuskets; // "notebook name - basket" correspondence
545
546 QString possibleLocations[2] = { "/.tomboy/", "/.local/share/tomboy/" };
547 for (int L=0; L<2; L++) {
548
549 QString dirPath = QDir::home().absolutePath() + possibleLocations[L];
550 QDir dir(dirPath, QString::null, QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::NoSymLinks);
551 DEBUG_WIN << "Tomboy import: Checking " + dirPath;
552
553 QStringList list = dir.entryList();
554 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) { // For each file
555 if (!(*it).endsWith(QLatin1String(".note")))
556 continue;
557 QDomDocument *doc = XMLWork::openFile("note", dirPath + *it);
558 if (doc == 0)
559 continue;
560
561 if (basketFromTomboy == 0) {
562 // First create a basket for it:
563 BasketFactory::newBasket(/*icon=*/IconNames::TOMBOY, /*name=*/i18n("From Tomboy"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
564 basketFromTomboy = Global::bnpView->currentBasket();
565 basketFromTomboy->load();
566 }
567
568 QDomElement docElem = doc->documentElement();
569 QString title = XMLWork::getElementText(docElem, "title");
570 QString notebook = getFirstTomboyTag(docElem); //!< Tomboy notebook name
571
572 // Find subbasket or create a new one
573 if (notebook.length() > 0) {
574 if (subBuskets.contains(notebook))
575 subBasket = subBuskets[notebook]; else
576 {
577 BasketFactory::newBasket(IconNames::TOMBOY, notebook, "", QColor(), QColor(), "1column", /*createIn=*/basketFromTomboy);
578 subBasket = Global::bnpView->currentBasket(); //TODO: ? change newBasket() so that it returns pointer and we don't have to load it
579 subBasket->load();
580
581 subBuskets.insert(notebook, subBasket);
582 }
583 } else
584 subBasket = basketFromTomboy; // will insert to the root basket
585
586
587 // DOES NOT REALLY WORKS:
588 //QDomElement contentElement = XMLWork::getElement(docElem, "text/note-content");
589 //QString content = XMLWork::innerXml(contentElement);
590
591 // Isolate "<note-content version="0.1">CONTENT</note-content>"!
592 QString xml = loadUtf8FileToString(dirPath + *it);
593 xml = xml.mid(xml.indexOf("<note-content"));
594 xml = xml.mid(xml.indexOf(">") + 1);
595 xml = xml.mid(0, xml.indexOf("</note-content>"));
596
597 if (!title.isEmpty() && !/*content*/xml.isEmpty()) {
598 insertTitledNote(subBasket, title, fromTomboy(xml/*content*/), Qt::RichText);
599 DEBUG_WIN << QString("Tomboy import: Inserting note '%1' into '%2'").arg(title, notebook);
600 }
601 }
602
603 }
604
605 if (basketFromTomboy)
606 finishImport(basketFromTomboy);
607 }
608
importJreepadFile()609 void SoftwareImporters::importJreepadFile(){
610 typedef QPair<BasketScene *, QDomElement> basketAndElementPair;
611
612 QString fileName = QFileDialog::getOpenFileName(0, QString(), "kfiledialog:///:ImportJreepadFile",
613 "*.xml|XML files");
614 if (fileName.isEmpty()) {
615 return;
616 }
617
618 basketAndElementPair newElement;
619 basketAndElementPair currentElement;
620 QList<basketAndElementPair> elements;
621 QList<BasketScene*> basketList;
622
623 QDomDocument *doc = XMLWork::openFile("node", fileName);
624 newElement.second = doc->documentElement();
625
626 BasketScene *basket = 0;
627 BasketFactory::newBasket(/*icon=*/"xml", /*name=*/doc->documentElement().attribute("title"),
628 /*backgroundImage=*/"", /*backgroundColor=*/QColor(),
629 /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
630 basket = Global::bnpView->currentBasket();
631 basket->load();
632 basketList << basket;
633 newElement.first = basket;
634
635 elements << newElement;
636
637 while ( !elements.isEmpty() ) {
638 currentElement = elements.takeFirst();
639 for (QDomNode n = currentElement.second.firstChild(); !n.isNull(); n = n.nextSibling()) {
640 if ( n.isText() ) {
641 basket = currentElement.first;
642 Note *note = NoteFactory::createNoteFromText(n.toText().data(), basket);
643 basket->insertNote(note, basket->firstNote(),
644 Note::BottomColumn, QPoint(), /*animate=*/false);
645 } else if ( n.isElement() ) {
646 BasketFactory::newBasket(/*icon=*/"xml", /*name=*/n.toElement().attribute("title"),
647 /*backgroundImage=*/"", /*backgroundColor=*/QColor(),
648 /*textColor=*/QColor(), /*templateName=*/"1column",
649 /*createIn=*/currentElement.first);
650 basket = Global::bnpView->currentBasket();
651 basket->load();
652 basketList << basket;
653 newElement.first = basket;
654 newElement.second = n.toElement();
655 elements << newElement;
656 }
657 }
658 }
659
660 foreach (basket, basketList) {
661 finishImport(basket);
662 }
663 }
664
importTextFile()665 void SoftwareImporters::importTextFile()
666 {
667 QString fileName = QFileDialog::getOpenFileName(0, QString(), "kfiledialog:///:ImportTextFile", "*|All files");
668 if (fileName.isEmpty())
669 return;
670
671 TextFileImportDialog dialog;
672 if (dialog.exec() == QDialog::Rejected)
673 return;
674 QString separator = dialog.separator();
675
676
677 QFile file(fileName);
678 if (file.open(QIODevice::ReadOnly)) {
679 QTextStream stream(&file);
680 QString content = stream.readAll();
681 QStringList list = (separator.isEmpty()
682 ? QStringList(content)
683 : content.split(separator)
684 );
685
686 // First create a basket for it:
687 QString title = i18nc("From TextFile.txt", "From %1", QUrl::fromLocalFile(fileName).fileName());
688 BasketFactory::newBasket(/*icon=*/"txt", title, /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
689 BasketScene *basket = Global::bnpView->currentBasket();
690 basket->load();
691
692 // Import every notes:
693 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
694 Note *note = NoteFactory::createNoteFromText((*it).trimmed(), basket);
695 basket->insertNote(note, basket->firstNote(), Note::BottomColumn, QPoint(), /*animate=*/false);
696 }
697
698 // Finish the export:
699 finishImport(basket);
700 }
701 }
702
703 /** @author Petri Damsten <petri.damsten@iki.fi>
704 */
importKnowIt()705 void SoftwareImporters::importKnowIt()
706 {
707 QUrl url = QFileDialog::getOpenFileUrl(NULL, "", QUrl("kfiledialog:///:ImportKnowIt"),
708 "*.kno|KnowIt files\n*|All files");
709 if (!url.isEmpty()) {
710 QFile file(url.path());
711 QFileInfo info(url.path());
712 BasketScene* basket = 0;
713 QStack<BasketScene*> baskets;
714 QString text;
715 int hierarchy = 0;
716
717 TreeImportDialog dialog;
718 if (dialog.exec() == QDialog::Rejected)
719 return;
720
721 hierarchy = dialog.choice();
722
723 BasketFactory::newBasket(/*icon=*/"knowit",
724 /*name=*/info.baseName(),
725 /*backgroundImage=*/"",
726 /*backgroundColor=*/QColor(),
727 /*textColor=*/QColor(),
728 /*templateName=*/"1column",
729 /*createIn=*/0);
730 basket = Global::bnpView->currentBasket();
731 basket->load();
732 baskets.push(basket);
733
734 if (file.open(QIODevice::ReadOnly)) {
735 QTextStream stream(&file);
736 int level = 0;
737 QString name;
738 QString line;
739 QStringList links;
740 QStringList descriptions;
741
742 stream.setCodec("UTF-8");
743 while (1) {
744 line = stream.readLine();
745
746 if (line.startsWith(QLatin1String("\\NewEntry")) ||
747 line.startsWith(QLatin1String("\\CurrentEntry")) || stream.atEnd()) {
748 while (level + 1 < baskets.size() - baskets.count(0))
749 baskets.pop();
750 if (level + 1 > baskets.size() - baskets.count(0))
751 baskets.push(basket);
752
753 if (!name.isEmpty()) {
754 if ((level == 0 && hierarchy == 1) ||
755 (hierarchy == 0)) {
756 BasketFactory::newBasket(/*icon=*/"knowit",
757 /*name=*/name,
758 /*backgroundImage=*/"",
759 /*backgroundColor=*/QColor(),
760 /*textColor=*/QColor(),
761 /*templateName=*/"1column",
762 /*createIn=*/baskets.top());
763 basket = Global::bnpView->currentBasket();
764 basket->load();
765 }
766
767 if (!text.trimmed().isEmpty() ||
768 hierarchy == 2 ||
769 (hierarchy == 1 && level > 0)) {
770 insertTitledNote(basket, name, text, Qt::RichText);
771 }
772 for (int j = 0; j < links.count(); ++j) {
773 Note* link;
774 if (descriptions.count() < j + 1 || descriptions[j].isEmpty())
775 link = NoteFactory::createNoteLink(links[j], basket);
776 else
777 link = NoteFactory::createNoteLink(links[j],
778 descriptions[j], basket);
779 basket->insertCreatedNote(link);
780 }
781 finishImport(basket);
782 }
783 if (stream.atEnd())
784 break;
785
786 int i = line.indexOf("Entry") + 6;
787 int n = line.indexOf(' ', i);
788 level = line.mid(i, n - i).toInt();
789 name = line.mid(n + 1);
790 text = "";
791 links.clear();
792 descriptions.clear();
793 } else if (line.startsWith(QLatin1String("\\Link"))) {
794 links.append(line.mid(6));
795 } else if (line.startsWith(QLatin1String("\\Descr"))) {
796 while (descriptions.count() < links.count() - 1)
797 descriptions.append("");
798 descriptions.append(line.mid(7));
799 } else {
800 text += line + "\n";
801 }
802 }
803 file.close();
804 }
805 }
806 }
807
importTuxCards()808 void SoftwareImporters::importTuxCards()
809 {
810 QString fileName = QFileDialog::getOpenFileName(0, QString(), "kfiledialog:///:ImportTuxCards", "*|All files");
811 if (fileName.isEmpty())
812 return;
813
814 TreeImportDialog dialog;
815 if (dialog.exec() == QDialog::Rejected)
816 return;
817
818 int hierarchy = dialog.choice();
819
820 QDomDocument *document = XMLWork::openFile("tuxcards_data_file"/*"InformationCollection"*/, fileName);
821 if (document == 0) {
822 KMessageBox::error(0, i18n("Can not import that file. It is either corrupted or not a TuxCards file."), i18n("Bad File Format"));
823 return;
824 }
825
826 QDomElement collection = document->documentElement();
827 int remainingHierarchy = (hierarchy == 0 ? 65000 : 3 - hierarchy);
828 importTuxCardsNode(collection, /*parentBasket=*/0, /*parentNote=*/0, remainingHierarchy);
829 }
830
831 // TODO: <InformationElement isOpen="true" isEncripted="false"
832
importTuxCardsNode(const QDomElement & element,BasketScene * parentBasket,Note * parentNote,int remainingHierarchy)833 void SoftwareImporters::importTuxCardsNode(const QDomElement &element, BasketScene *parentBasket, Note *parentNote, int remainingHierarchy)
834 {
835 for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) {
836 QDomElement e = n.toElement();
837 if (e.isNull() || e.tagName() != "InformationElement") // Cannot handle that!
838 continue;
839
840 QString icon = e.attribute("iconFileName");
841 QString name = XMLWork::getElementText(e, "Description");
842 QString content = XMLWork::getElementText(e, "Information");
843 bool isRichText = (e.attribute("informationFormat") == "RTF");
844 bool isEncrypted = (e.attribute("isEncripted") == "true");
845 if (icon.isEmpty() || icon == "none")
846 icon = "tuxcards";
847 Note *nContent;
848
849 if (isEncrypted) {
850 KMessageBox::information(0, i18n("A note is encrypted. The importer does not yet support encrypted notes. Please remove the encryption with TuxCards and re-import the file."), i18n("Encrypted Notes not Supported Yet"));
851 isRichText = true;
852 content = i18n("<font color='red'><b>Encrypted note.</b><br>The importer do not support encrypted notes yet. Please remove the encryption with TuxCards and re-import the file.</font>");
853 }
854
855 if (remainingHierarchy > 0) {
856 BasketFactory::newBasket(icon, name, /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", parentBasket);
857 BasketScene *basket = Global::bnpView->currentBasket();
858 basket->load();
859
860 if (isRichText)
861 nContent = NoteFactory::createNoteHtml(content, basket);
862 else
863 nContent = NoteFactory::createNoteText(content, basket);
864 basket->insertNote(nContent, basket->firstNote(), Note::BottomColumn, QPoint(), /*animate=*/false);
865
866 importTuxCardsNode(e, basket, 0, remainingHierarchy - 1);
867 finishImport(basket);
868 } else {
869 Note *nGroup = insertTitledNote(parentBasket, name, content, (isRichText ? Qt::RichText : Qt::PlainText), parentNote);
870 importTuxCardsNode(e, parentBasket, nGroup, remainingHierarchy - 1);
871 }
872 }
873 }
874
875