/*************************************************************************** * Copyright (C) 2003 by Sébastien Laoût * * slaout@linux62.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "softwareimporters.h" #include "basket.h" #include "basketfactory.h" #include "notefactory.h" #include "global.h" #include "bnpview.h" #include "xmlwork.h" #include "tools.h" /** class TreeImportDialog: */ TreeImportDialog::TreeImportDialog(TQWidget *tqparent) : KDialogBase(KDialogBase::Swallow, i18n("Import Hierarchy"), KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, tqparent, /*name=*/"ImportHierarchy", /*modal=*/true, /*separator=*/false) { TQWidget *page = new TQWidget(this); TQVBoxLayout *topLayout = new TQVBoxLayout(page, /*margin=*/0, spacingHint()); m_choices = new TQVButtonGroup(i18n("How to Import the Notes?"), page); new TQRadioButton(i18n("&Keep original hierarchy (all notes in separate baskets)"), m_choices); new TQRadioButton(i18n("&First level notes in separate baskets"), m_choices); new TQRadioButton(i18n("&All notes in one basket"), m_choices); m_choices->setButton(0); topLayout->addWidget(m_choices); topLayout->addStretch(10); setMainWidget(page); } TreeImportDialog::~TreeImportDialog() { } int TreeImportDialog::choice() { return m_choices->selectedId(); } /** class TextFileImportDialog: */ TextFileImportDialog::TextFileImportDialog(TQWidget *tqparent) : KDialogBase(KDialogBase::Swallow, i18n("Import Text File"), KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, tqparent, /*name=*/"ImportTextFile", /*modal=*/true, /*separator=*/false) { TQWidget *page = new TQWidget(this); TQVBoxLayout *topLayout = new TQVBoxLayout(page, /*margin=*/0, spacingHint()); m_choices = new TQVButtonGroup(i18n("Format of the Text File"), page); new TQRadioButton(i18n("Notes separated by an &empty line"), m_choices); new TQRadioButton(i18n("One ¬e per line"), m_choices); new TQRadioButton(i18n("Notes begin with a &dash (-)"), m_choices); new TQRadioButton(i18n("Notes begin with a &star (*)"), m_choices); m_anotherSeparator = new TQRadioButton(i18n("&Use another separator:"), m_choices); TQWidget *indentedTextEdit = new TQWidget(m_choices); TQHBoxLayout *hLayout = new TQHBoxLayout(indentedTextEdit, /*margin=*/0, spacingHint()); hLayout->addSpacing(20); m_customSeparator = new TQTextEdit(indentedTextEdit); m_customSeparator->setTextFormat(TQt::PlainText); hLayout->addWidget(m_customSeparator); m_choices->insertChild(TQT_TQOBJECT(indentedTextEdit)); new TQRadioButton(i18n("&All in one note"), m_choices); m_choices->setButton(0); topLayout->addWidget(m_choices); connect( m_customSeparator, TQT_SIGNAL(textChanged()), this, TQT_SLOT(customSeparatorChanged()) ); setMainWidget(page); } TextFileImportDialog::~TextFileImportDialog() { } TQString TextFileImportDialog::separator() { switch (m_choices->selectedId()) { default: case 0: return "\n\n"; case 1: return "\n"; case 2: return "\n-"; case 3: return "\n*"; case 4: return m_customSeparator->text(); case 5: return ""; } } void TextFileImportDialog::customSeparatorChanged() { if (!m_anotherSeparator->isOn()) m_anotherSeparator->toggle(); } /** namespace SoftwareImporters: */ TQString SoftwareImporters::fromICS(const TQString &ics) { TQString result = ics; // Remove escaped '\' characters and append the text to the body int pos = 0; while ( (pos = result.tqfind('\\', pos)) != -1 ) { if ((uint)pos == result.length() - 1) // End of string break; if (result[pos+1] == 'n') { result.tqreplace(pos, 2, '\n'); } else if (result[pos+1] == 'r') { result.tqreplace(pos, 2, '\r'); } else if (result[pos+1] == 't') { result.tqreplace(pos, 2, '\t'); } else if (result[pos] == '\\') { result.remove(pos, 1); // Take care of "\\", "\,", "\;" and other escaped characters I haven't noticed ++pos; } } return result; } TQString SoftwareImporters::fromTomboy(TQString tomboy) { // 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...): tomboy = tomboy.mid(tomboy.tqfind("\n")).stripWhiteSpace(); // Font styles and decorations: tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); // Highlight not supported by TQTextEdit: tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); // Font sizes: tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); // Internal links to other notes aren't supported yet by BasKet Note Pads: tomboy.tqreplace("", ""); tomboy.tqreplace("", ""); // In the Tomboy file, new lines are "\n" and not "
": tomboy.tqreplace("\n", "
\n"); // Preserve consecutive spaces: return "" + tomboy + ""; } Note* SoftwareImporters::insertTitledNote(Basket *tqparent, const TQString &title, const TQString &content, TQt::TextFormat format/* = TQt::PlainText*/, Note *tqparentNote/* = 0*/) { Note *nGroup = new Note(tqparent); Note *nTitle = NoteFactory::createNoteText(title, tqparent); nTitle->addState(Tag::stateForId("title")); Note *nContent; if (format == TQt::PlainText) nContent = NoteFactory::createNoteText(content, tqparent); else nContent = NoteFactory::createNoteHtml(content, tqparent); if (tqparentNote == 0) tqparentNote = tqparent->firstNote(); // In the first column! tqparent->insertNote(nGroup, tqparentNote, Note::BottomColumn, TQPoint(), /*animate=*/false); tqparent->insertNote(nTitle, nGroup, Note::BottomColumn, TQPoint(), /*animate=*/false); tqparent->insertNote(nContent, nTitle, Note::BottomInsert, TQPoint(), /*animate=*/false); return nGroup; } void SoftwareImporters::finishImport(Basket *basket) { // Unselect the last inserted group: basket->unselectAll(); // Focus the FIRST note (the last inserted note is currently focused!): basket->setFocusedNote(basket->firstNoteShownInStack()); // Retqlayout every notes at theire new place and simulate a load animation (because already loaded just after the creation). // Without a retqlayouting, notes on the bottom would comes from the top (because they were inserted on top) and clutter the animation load: basket->retqlayoutNotes(/*animate=*/false); basket->animateLoad(); basket->save(); } void SoftwareImporters::importKJots() { TQString dirPath = locateLocal("appdata","") + "/../kjots/"; // I think the assumption is good TQDir dir(dirPath, TQString(), TQDir::Name | TQDir::IgnoreCase, TQDir::Files | TQDir::NoSymLinks); TQStringList list = dir.entryList(); if (list.isEmpty()) return; BasketFactory::newBasket(/*icon=*/"kjots", /*name=*/i18n("From KJots"), /*backgroundImage=*/"", /*backgroundColor=*/TQColor(), /*textColor=*/TQColor(), /*templateName=*/"1column", /*createIn=*/0); Basket *kjotsBasket = Global::bnpView->currentBasket(); for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) { // For each file TQFile file(dirPath + *it); if (file.open(IO_ReadOnly)) { TQTextStream stream(&file); stream.setEncoding(TQTextStream::Locale); TQString buf = stream.readLine(); // IT IS A NOTEBOOK FILE, AT THE VERION 0.6.x and older: if ( !buf.isNull() && buf.left(9) == "\\NewEntry") { // First create a basket for it: BasketFactory::newBasket(/*icon=*/"kjots", /*name=*/KURL(file.name()).fileName(), /*backgroundImage=*/"", /*backgroundColor=*/TQColor(), /*textColor=*/TQColor(), /*templateName=*/"1column", /*createIn=*/kjotsBasket); Basket *basket = Global::bnpView->currentBasket(); basket->load(); TQString title, body; bool haveAnEntry = false; while (1) { if (buf.left(9) == "\\NewEntry") { if (haveAnEntry) // Do not add note the first time insertTitledNote(basket, title, Tools::stripEndWhiteSpaces(body)); title = buf.mid(10, buf.length()); // Problem : basket will be saved body = ""; // New note will then be created // EACH time a note is imported haveAnEntry = true; } else if (buf.left(3) != "\\ID") { // Don't care of the ID // Remove escaped '\' characters and append the text to the body int pos = 0; while ( (pos = buf.tqfind('\\', pos)) != -1 ) if (buf[++pos] == '\\') buf.remove(pos, 1); body.append(buf + "\n"); } buf = stream.readLine(); if (buf.isNull()) // OEF break; } // Add the ending note (there isn't any other "\\NewEntry" to do it): if (haveAnEntry) insertTitledNote(basket, title, Tools::stripEndWhiteSpaces(body)); finishImport(basket); // IT IS A NOTEBOOK XML FILE, AT THE VERION 0.7.0 and later: } else if ( (*it).endsWith(".book") /*&& !buf.isNull() && (buf.left(2) == "documentElement(), "KJotsBook/Title"); // First create a basket for it: BasketFactory::newBasket(/*icon=*/"kjots", /*name=*/bookTitle, /*backgroundImage=*/"", /*backgroundColor=*/TQColor(), /*textColor=*/TQColor(), /*templateName=*/"1column", /*createIn=*/kjotsBasket); Basket *basket = Global::bnpView->currentBasket(); basket->load(); TQDomElement docElem = XMLWork::getElement(doc->documentElement(), "KJotsBook"); for ( TQDomNode n = docElem.firstChild(); !n.isNull(); n = n.nextSibling() ) { TQDomElement e = n.toElement(); if ( (!e.isNull()) && e.tagName() == "KJotsPage" ) insertTitledNote(basket, XMLWork::getElementText(e, "Title"), XMLWork::getElementText(e, "Text")); } finishImport(basket); } file.close(); } } } void SoftwareImporters::importKNotes() { TQString dirPath = locateLocal("appdata","") + "/../knotes/"; // I thing the assumption is good TQDir dir(dirPath, TQString(), TQDir::Name | TQDir::IgnoreCase, TQDir::Files | TQDir::NoSymLinks); TQStringList list = dir.entryList(); for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) { // For each file if ( ! (*it).endsWith(".ics") ) // Don't process *.ics~ and otehr files continue; TQFile file(dirPath + *it); if (file.open(IO_ReadOnly)) { TQTextStream stream(&file); stream.setEncoding(TQTextStream::UnicodeUTF8); // First create a basket for it: BasketFactory::newBasket(/*icon=*/"knotes", /*name=*/i18n("From KNotes"), /*backgroundImage=*/"", /*backgroundColor=*/TQColor(), /*textColor=*/TQColor(), /*templateName=*/"1column", /*createIn=*/0); Basket *basket = Global::bnpView->currentBasket(); basket->load(); bool inVJournal = false; bool inDescription = false; bool isRichText = false; TQString title, body; TQString buf; while (1) { buf = stream.readLine(); if (buf.isNull()) // OEF break; if ( !buf.isNull() && buf == "BEGIN:VJOURNAL") { inVJournal = true; } else if (inVJournal && buf.startsWith("SUMMARY:")) { title = buf.mid(8, buf.length()); } else if (inVJournal && buf.startsWith("DESCRIPTION:")) { body = buf.mid(12, buf.length()); inDescription = true; } else if (inDescription && buf.startsWith(" ")) { body += buf.mid(1, buf.length()); } else if (buf.startsWith("X-KDE-KNotes-RichText:")) { isRichText = XMLWork::trueOrFalse(buf.mid(22, buf.length() - 22).stripWhiteSpace(), "false"); } else if (buf == "END:VJOURNAL") { insertTitledNote(basket, fromICS(title), fromICS(body), (isRichText ? TQt::RichText : TQt::PlainText)); inVJournal = false; inDescription = false; isRichText = false; title = ""; body = ""; } else inDescription = false; } // Bouh : duplicate code // In case of unvalide ICAL file! if ( ! body.isEmpty() ) // Add the ending note insertTitledNote(basket, fromICS(title), fromICS(body), (isRichText ? TQt::RichText : TQt::PlainText)); file.close(); finishImport(basket); } } } void SoftwareImporters::importStickyNotes() { // Sticky Notes file is usually located in ~/.gnome2/stickynotes_applet // We will search all directories in "~/" that contain "gnome" in the name, // and will search for "stickynotes_applet" file (that should be XML file with root. TQDir dir(TQDir::home().absPath(), TQString(), TQDir::Name | TQDir::IgnoreCase, TQDir::Dirs | TQDir::NoSymLinks | TQDir::Hidden); TQStringList founds; TQStringList list = dir.entryList(); for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) { // For each folder if ( (*it).tqcontains("gnome", false) ) { TQString fullPath = TQDir::home().absPath() + "/" + (*it) + "/stickynotes_applet"; if (dir.exists(fullPath)) founds += fullPath; } } for ( TQStringList::Iterator it = founds.begin(); it != founds.end(); ++it ) { // For each file TQFile file(*it); TQDomDocument *doc = XMLWork::openFile("stickynotes", *it); if (doc == 0) continue; // First create a basket for it: BasketFactory::newBasket(/*icon=*/"gnome", /*name=*/i18n("From Sticky Notes"), /*backgroundImage=*/"", /*backgroundColor=*/TQColor(), /*textColor=*/TQColor(), /*templateName=*/"1column", /*createIn=*/0); Basket *basket = Global::bnpView->currentBasket(); basket->load(); TQDomElement docElem = doc->documentElement(); for ( TQDomNode n = docElem.firstChild(); !n.isNull(); n = n.nextSibling() ) { TQDomElement e = n.toElement(); if ( (!e.isNull()) && e.tagName() == "note" ) insertTitledNote(basket, e.attribute("title"), e.text()); } finishImport(basket); } } // TODO: FIXME: Code duplicated from notecontent.cpp but with UTF-8 encoding. // TODO: FIXME: Later, merge! TQString loadUtf8FileToString(const TQString &fileName) { TQFile file(fileName); if (file.open(IO_ReadOnly)) { TQTextStream stream(&file); stream.setEncoding(TQTextStream::UnicodeUTF8); TQString text; text = stream.read(); file.close(); return text; } else return ""; } void SoftwareImporters::importTomboy() { TQString dirPath = TQDir::home().absPath() + "/.tomboy/"; // I thing the assumption is good TQDir dir(dirPath, TQString(), TQDir::Name | TQDir::IgnoreCase, TQDir::Files | TQDir::NoSymLinks); Basket *basket = 0; // Create the basket ONLY if we found at least one note to add! TQStringList list = dir.entryList(); for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) { // For each file if ( ! (*it).endsWith(".note") ) continue; TQDomDocument *doc = XMLWork::openFile("note", dirPath + *it); if (doc == 0) continue; if (basket == 0) { // First create a basket for it: BasketFactory::newBasket(/*icon=*/"tomboy", /*name=*/i18n("From Tomboy"), /*backgroundImage=*/"", /*backgroundColor=*/TQColor(), /*textColor=*/TQColor(), /*templateName=*/"1column", /*createIn=*/0); basket = Global::bnpView->currentBasket(); basket->load(); } TQDomElement docElem = doc->documentElement(); TQString title = XMLWork::getElementText(docElem, "title"); // DOES NOT REALLY WORKS: //TQDomElement contentElement = XMLWork::getElement(docElem, "text/note-content"); //TQString content = XMLWork::innerXml(contentElement); // Isolate "CONTENT"! TQString xml = loadUtf8FileToString(dirPath + *it); xml = xml.mid(xml.tqfind("") + 1); xml = xml.mid(0, xml.tqfind("")); if (!title.isEmpty() && !/*content*/xml.isEmpty()) insertTitledNote(basket, title, fromTomboy(xml/*content*/), TQt::RichText); } if (basket) finishImport(basket); } void SoftwareImporters::importTextFile() { TQString fileName = KFileDialog::getOpenFileName(":ImportTextFile", "*|All files"); if (fileName.isEmpty()) return; TextFileImportDialog dialog; if (dialog.exec() == TQDialog::Rejected) return; TQString separator = dialog.separator(); TQFile file(fileName); if (file.open(IO_ReadOnly)) { TQTextStream stream(&file); stream.setEncoding(TQTextStream::Locale); TQString content = stream.read(); TQStringList list = (separator.isEmpty() ? TQStringList(content) : TQStringList::split(separator, content, /*allowEmptyEntries=*/false) ); // First create a basket for it: TQString title = i18n("From TextFile.txt", "From %1").tqarg(KURL(fileName).fileName()); BasketFactory::newBasket(/*icon=*/"txt", title, /*backgroundImage=*/"", /*backgroundColor=*/TQColor(), /*textColor=*/TQColor(), /*templateName=*/"1column", /*createIn=*/0); Basket *basket = Global::bnpView->currentBasket(); basket->load(); // Import every notes: for (TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) { Note *note = NoteFactory::createNoteFromText((*it).stripWhiteSpace(), basket); basket->insertNote(note, basket->firstNote(), Note::BottomColumn, TQPoint(), /*animate=*/false); } // Finish the export: finishImport(basket); } } /** @author Petri Damsten */ void SoftwareImporters::importKnowIt() { KURL url = KFileDialog::getOpenURL(":ImportKnowIt", "*.kno|KnowIt files\n*|All files"); if (!url.isEmpty()) { TQFile file(url.path()); TQFileInfo info(url.path()); Basket* basket = 0; TQPtrStack baskets; TQString text; int hierarchy = 0; TreeImportDialog dialog; if (dialog.exec() == TQDialog::Rejected) return; hierarchy = dialog.choice(); BasketFactory::newBasket(/*icon=*/"knowit", /*name=*/info.baseName(), /*backgroundImage=*/"", /*backgroundColor=*/TQColor(), /*textColor=*/TQColor(), /*templateName=*/"1column", /*createIn=*/0); basket = Global::bnpView->currentBasket(); basket->load(); baskets.push(basket); if(file.open(IO_ReadOnly)) { TQTextStream stream(&file); uint level = 0; TQString name; TQString line; TQStringList links; TQStringList descriptions; stream.setEncoding(TQTextStream::UnicodeUTF8); while(1) { line = stream.readLine(); if(line.startsWith("\\NewEntry") || line.startsWith("\\CurrentEntry") || stream.atEnd()) { while(level + 1 < baskets.count()) baskets.pop(); if(level + 1 > baskets.count()) baskets.push(basket); if(!name.isEmpty()) { if((level == 0 && hierarchy == 1) || (hierarchy == 0)) { BasketFactory::newBasket(/*icon=*/"knowit", /*name=*/name, /*backgroundImage=*/"", /*backgroundColor=*/TQColor(), /*textColor=*/TQColor(), /*templateName=*/"1column", /*createIn=*/baskets.top()); basket = Global::bnpView->currentBasket(); basket->load(); } if(!text.stripWhiteSpace().isEmpty() || hierarchy == 2 || (hierarchy == 1 && level > 0)) { insertTitledNote(basket, name, text, TQt::RichText); } for(uint j = 0; j < links.count(); ++j) { Note* link; if(descriptions.count() < j+1 || descriptions[j].isEmpty()) link = NoteFactory::createNoteLink(links[j], basket); else link = NoteFactory::createNoteLink(links[j], descriptions[j], basket); basket->insertCreatedNote(link); } finishImport(basket); } if(stream.atEnd()) break; int i = line.tqfind("Entry") + 6; int n = line.tqfind(' ', i); level = line.mid(i, n - i).toInt(); name = line.mid(n+1); text = ""; links.clear(); descriptions.clear(); } else if(line.startsWith("\\Link")) { links.append(line.mid(6)); } else if(line.startsWith("\\Descr")) { while(descriptions.count() < links.count() - 1) descriptions.append(""); descriptions.append(line.mid(7)); } else { text += line + "\n"; } } file.close(); } } } void SoftwareImporters::importTuxCards() { TQString fileName = KFileDialog::getOpenFileName(":ImportTuxCards", "*|All files"); if (fileName.isEmpty()) return; TreeImportDialog dialog; if (dialog.exec() == TQDialog::Rejected) return; int hierarchy = dialog.choice(); TQDomDocument *document = XMLWork::openFile("tuxcards_data_file"/*"InformationCollection"*/, fileName); if (document == 0) { KMessageBox::error(0, i18n("Can not import that file. It is either corrupted or not a TuxCards file."), i18n("Bad File Format")); return; } TQDomElement collection = document->documentElement(); int remainingHierarchy = (hierarchy == 0 ? 65000 : 3 - hierarchy); importTuxCardsNode(collection, /*tqparentBasket=*/0, /*tqparentNote=*/0, remainingHierarchy); } // TODO: Encrypted note.
The importer do not support encrypted notes yet. Please remove the encryption with TuxCards and re-import the file."); } if (remainingHierarchy > 0) { BasketFactory::newBasket(icon, name, /*backgroundImage=*/"", /*backgroundColor=*/TQColor(), /*textColor=*/TQColor(), /*templateName=*/"1column", tqparentBasket); Basket *basket = Global::bnpView->currentBasket(); basket->load(); if (isRichText) nContent = NoteFactory::createNoteHtml(content, basket); else nContent = NoteFactory::createNoteText(content, basket); basket->insertNote(nContent, basket->firstNote(), Note::BottomColumn, TQPoint(), /*animate=*/false); importTuxCardsNode(e, basket, 0, remainingHierarchy - 1); finishImport(basket); } else { Note *nGroup = insertTitledNote(tqparentBasket, name, content, (isRichText ? TQt::RichText : TQt::PlainText), tqparentNote); importTuxCardsNode(e, tqparentBasket, nGroup, remainingHierarchy - 1); } } } #include "softwareimporters.moc"