diff options
Diffstat (limited to 'src/translators/alexandriaimporter.cpp')
-rw-r--r-- | src/translators/alexandriaimporter.cpp | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/src/translators/alexandriaimporter.cpp b/src/translators/alexandriaimporter.cpp new file mode 100644 index 0000000..5e49e86 --- /dev/null +++ b/src/translators/alexandriaimporter.cpp @@ -0,0 +1,255 @@ +/*************************************************************************** + copyright : (C) 2003-2006 by Robby Stephenson + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of version 2 of the GNU General Public License as * + * published by the Free Software Foundation; * + * * + ***************************************************************************/ + +#include "alexandriaimporter.h" +#include "../collections/bookcollection.h" +#include "../entry.h" +#include "../field.h" +#include "../latin1literal.h" +#include "../isbnvalidator.h" +#include "../imagefactory.h" +#include "../progressmanager.h" +#include "../tellico_debug.h" + +#include <kcombobox.h> +#include <kapplication.h> +#include <kstringhandler.h> + +#include <qlayout.h> +#include <qlabel.h> +#include <qgroupbox.h> + +using Tellico::Import::AlexandriaImporter; + +bool AlexandriaImporter::canImport(int type) const { + return type == Data::Collection::Book; +} + +Tellico::Data::CollPtr AlexandriaImporter::collection() { + if(!m_widget || m_library->count() == 0) { + return 0; + } + + m_coll = new Data::BookCollection(true); + + QDir dataDir = m_libraryDir; + dataDir.cd(m_library->currentText()); + dataDir.setFilter(QDir::Files | QDir::Readable | QDir::NoSymLinks); + + const QString title = QString::fromLatin1("title"); + const QString author = QString::fromLatin1("author"); + const QString year = QString::fromLatin1("pub_year"); + const QString binding = QString::fromLatin1("binding"); + const QString isbn = QString::fromLatin1("isbn"); + const QString pub = QString::fromLatin1("publisher"); + const QString rating = QString::fromLatin1("rating"); + const QString cover = QString::fromLatin1("cover"); + const QString comments = QString::fromLatin1("comments"); + + // start with yaml files + dataDir.setNameFilter(QString::fromLatin1("*.yaml")); + const QStringList files = dataDir.entryList(); + const uint numFiles = files.count(); + const uint stepSize = QMAX(s_stepSize, numFiles/100); + const bool showProgress = options() & ImportProgress; + + ProgressItem& item = ProgressManager::self()->newProgressItem(this, progressLabel(), true); + item.setTotalSteps(numFiles); + connect(&item, SIGNAL(signalCancelled(ProgressItem*)), SLOT(slotCancel())); + ProgressItem::Done done(this); + + QStringList covers; + covers << QString::fromLatin1(".cover") + << QString::fromLatin1("_medium.jpg") + << QString::fromLatin1("_small.jpg"); + + QTextStream ts; + ts.setEncoding(QTextStream::UnicodeUTF8); // YAML is always utf8? + uint j = 0; + for(QStringList::ConstIterator it = files.begin(); !m_cancelled && it != files.end(); ++it, ++j) { + QFile file(dataDir.absFilePath(*it)); + if(!file.open(IO_ReadOnly)) { + continue; + } + + Data::EntryPtr entry = new Data::Entry(m_coll); + + bool readNextLine = true; + ts.unsetDevice(); + ts.setDevice(&file); + QString line; + while(!ts.atEnd()) { + if(readNextLine) { + line = ts.readLine(); + } else { + readNextLine = true; + } + // skip the line that starts with --- + if(line.isEmpty() || line.startsWith(QString::fromLatin1("---"))) { + continue; + } + if(line.endsWith(QChar('\\'))) { + line.truncate(line.length()-1); // remove last character + line += ts.readLine(); + } + + cleanLine(line); + QString alexField = line.section(':', 0, 0); + QString alexValue = line.section(':', 1).stripWhiteSpace(); + clean(alexValue); + + // Alexandria uses "n/a for empty values, and it is translated + // only thing we can do is check for english value and continue + if(alexValue == Latin1Literal("n/a")) { + continue; + } + + if(alexField == Latin1Literal("authors")) { + QStringList authors; + line = ts.readLine(); + QRegExp begin(QString::fromLatin1("^\\s*-\\s+")); + while(!line.isNull() && line.find(begin) > -1) { + line.remove(begin); + authors += clean(line); + line = ts.readLine(); + } + entry->setField(author, authors.join(QString::fromLatin1("; "))); + // the next line has already been read + readNextLine = false; + + // Alexandria calls the edition the binding + } else if(alexField == Latin1Literal("edition")) { + // special case if it's "Hardcover" + if(alexValue.lower() == Latin1Literal("hardcover")) { + alexValue = i18n("Hardback"); + } + entry->setField(binding, alexValue); + + } else if(alexField == Latin1Literal("publishing_year")) { + entry->setField(year, alexValue); + + } else if(alexField == Latin1Literal("isbn")) { + const ISBNValidator val(0); + val.fixup(alexValue); + entry->setField(isbn, alexValue); + + // now find cover image + KURL u; + alexValue.remove('-'); + for(QStringList::Iterator ext = covers.begin(); ext != covers.end(); ++ext) { + u.setPath(dataDir.absFilePath(alexValue + *ext)); + if(!QFile::exists(u.path())) { + continue; + } + QString id = ImageFactory::addImage(u, true); + if(!id.isEmpty()) { + entry->setField(cover, id); + break; + } + } + } else if(alexField == Latin1Literal("notes")) { + entry->setField(comments, alexValue); + + // now try by name then title + } else if(m_coll->fieldByName(alexField)) { + entry->setField(alexField, alexValue); + + } else if(m_coll->fieldByTitle(alexField)) { + entry->setField(m_coll->fieldByTitle(alexField), alexValue); + } + } + m_coll->addEntries(entry); + + if(showProgress && j%stepSize == 0) { + ProgressManager::self()->setProgress(this, j); + kapp->processEvents(); + } + } + + return m_coll; +} + +QWidget* AlexandriaImporter::widget(QWidget* parent_, const char* name_/*=0*/) { + if(m_widget) { + return m_widget; + } + + m_libraryDir = QDir::home(); + m_libraryDir.setFilter(QDir::Dirs | QDir::Readable | QDir::NoSymLinks); + + m_widget = new QWidget(parent_, name_); + QVBoxLayout* l = new QVBoxLayout(m_widget); + + QGroupBox* box = new QGroupBox(2, Qt::Horizontal, i18n("Alexandria Options"), m_widget); + QLabel* label = new QLabel(i18n("&Library:"), box); + m_library = new KComboBox(box); + label->setBuddy(m_library); + + // .alexandria might not exist + if(m_libraryDir.cd(QString::fromLatin1(".alexandria"))) { + QStringList dirs = m_libraryDir.entryList(); + dirs.remove(QString::fromLatin1(".")); // why can't I tell QDir not to include these? QDir::Hidden doesn't work + dirs.remove(QString::fromLatin1("..")); + m_library->insertStringList(dirs); + } + + l->addWidget(box); + l->addStretch(1); + return m_widget; +} + +QString& AlexandriaImporter::cleanLine(QString& str_) { + static QRegExp escRx(QString::fromLatin1("\\\\x(\\w\\w)"), false); + str_.remove(QString::fromLatin1("\\r")); + str_.replace(QString::fromLatin1("\\n"), QString::fromLatin1("\n")); + str_.replace(QString::fromLatin1("\\t"), QString::fromLatin1("\t")); + + // YAML uses escape sequences like \xC3 + int pos = escRx.search(str_); + int origPos = pos; + QCString bytes; + while(pos > -1) { + bool ok; + char c = escRx.cap(1).toInt(&ok, 16); + if(ok) { + bytes += c; + } else { + bytes = QCString(); + break; + } + pos = escRx.search(str_, pos+1); + } + if(!bytes.isEmpty()) { + str_.replace(origPos, bytes.length()*4, QString::fromUtf8(bytes.data())); + } + return str_; +} + +QString& AlexandriaImporter::clean(QString& str_) { + const QRegExp quote(QString::fromLatin1("\\\\\"")); // equals \" + if(str_.startsWith(QChar('\'')) || str_.startsWith(QChar('"'))) { + str_.remove(0, 1); + } + if(str_.endsWith(QChar('\'')) || str_.endsWith(QChar('"'))) { + str_.truncate(str_.length()-1); + } + // we ignore YAML tags, this is not actually a good parser, but will do for now + str_.remove(QRegExp(QString::fromLatin1("^![^\\s]*\\s+"))); + return str_.replace(quote, QChar('"')); +} + +void AlexandriaImporter::slotCancel() { + m_cancelled = true; +} + +#include "alexandriaimporter.moc" |