summaryrefslogtreecommitdiffstats
path: root/src/translators/xmlstatehandler.cpp
diff options
context:
space:
mode:
authorSlávek Banko <slavek.banko@axis.cz>2014-03-03 13:46:44 +0100
committerSlávek Banko <slavek.banko@axis.cz>2014-03-03 13:46:44 +0100
commit2e02da046d3e56cdf4744f644af35ad07424f48b (patch)
treef2dcf353aa2338eae1c2ff2c41af971c580c2762 /src/translators/xmlstatehandler.cpp
parent3c13229d98167ae4ae0710d5eeef23fef5005bf0 (diff)
downloadtellico-2e02da046d3e56cdf4744f644af35ad07424f48b.tar.gz
tellico-2e02da046d3e56cdf4744f644af35ad07424f48b.zip
Update to upstream version 1.3.6
Diffstat (limited to 'src/translators/xmlstatehandler.cpp')
-rw-r--r--src/translators/xmlstatehandler.cpp772
1 files changed, 772 insertions, 0 deletions
diff --git a/src/translators/xmlstatehandler.cpp b/src/translators/xmlstatehandler.cpp
new file mode 100644
index 0000000..48d52d6
--- /dev/null
+++ b/src/translators/xmlstatehandler.cpp
@@ -0,0 +1,772 @@
+/***************************************************************************
+ copyright : (C) 2008 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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 "xmlstatehandler.h"
+#include "tellico_xml.h"
+#include "../latin1literal.h"
+#include "../collection.h"
+#include "../collectionfactory.h"
+#include "../collections/bibtexcollection.h"
+#include "../image.h"
+#include "../imagefactory.h"
+#include "../isbnvalidator.h"
+#include "../tellico_utils.h"
+#include "../tellico_debug.h"
+
+#include <tdelocale.h>
+#include <kmdcodec.h>
+
+namespace {
+
+inline
+TQString attValue(const TQXmlAttributes& atts, const char* name, const TQString& defaultValue=TQString()) {
+ int idx = atts.index(TQString::fromLatin1(name));
+ return idx < 0 ? defaultValue : atts.value(idx);
+}
+
+inline
+TQString attValue(const TQXmlAttributes& atts, const char* name, const char* defaultValue) {
+ Q_ASSERT(defaultValue);
+ return attValue(atts, name, TQString::fromLatin1(defaultValue));
+}
+
+}
+
+using Tellico::Import::SAX::StateHandler;
+using Tellico::Import::SAX::NullHandler;
+using Tellico::Import::SAX::RootHandler;
+using Tellico::Import::SAX::DocumentHandler;
+using Tellico::Import::SAX::CollectionHandler;
+using Tellico::Import::SAX::FieldsHandler;
+using Tellico::Import::SAX::FieldHandler;
+using Tellico::Import::SAX::FieldPropertyHandler;
+using Tellico::Import::SAX::BibtexPreambleHandler;
+using Tellico::Import::SAX::BibtexMacrosHandler;
+using Tellico::Import::SAX::BibtexMacroHandler;
+using Tellico::Import::SAX::EntryHandler;
+using Tellico::Import::SAX::FieldValueContainerHandler;
+using Tellico::Import::SAX::FieldValueHandler;
+using Tellico::Import::SAX::DateValueHandler;
+using Tellico::Import::SAX::TableColumnHandler;
+using Tellico::Import::SAX::ImagesHandler;
+using Tellico::Import::SAX::ImageHandler;
+using Tellico::Import::SAX::FiltersHandler;
+using Tellico::Import::SAX::FilterHandler;
+using Tellico::Import::SAX::FilterRuleHandler;
+using Tellico::Import::SAX::BorrowersHandler;
+using Tellico::Import::SAX::BorrowerHandler;
+using Tellico::Import::SAX::LoanHandler;
+
+StateHandler* StateHandler::nextHandler(const TQString& ns_, const TQString& localName_, const TQString& qName_) {
+ StateHandler* handler = nextHandlerImpl(ns_, localName_, qName_);
+ if(!handler) {
+ myWarning() << "StateHandler::nextHandler() - no handler for " << localName_ << endl;
+ }
+ return handler ? handler : new NullHandler(d);
+}
+
+StateHandler* RootHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(localName_ == Latin1Literal("tellico") || localName_ == Latin1Literal("bookcase")) {
+ return new DocumentHandler(d);
+ }
+ return new RootHandler(d);
+}
+
+StateHandler* DocumentHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(localName_ == Latin1Literal("collection")) {
+ return new CollectionHandler(d);
+ } else if(localName_ == Latin1Literal("filters")) {
+ return new FiltersHandler(d);
+ } else if(localName_ == Latin1Literal("borrowers")) {
+ return new BorrowersHandler(d);
+ }
+ return 0;
+}
+
+bool DocumentHandler::start(const TQString&, const TQString& localName_, const TQString&, const TQXmlAttributes& atts_) {
+ // the syntax version field name changed from "version" to "syntaxVersion" in version 3
+ int idx = atts_.index(TQString::fromLatin1("syntaxVersion"));
+ if(idx < 0) {
+ idx = atts_.index(TQString::fromLatin1("version"));
+ }
+ if(idx < 0) {
+ myWarning() << "RootHandler::start() - no syntax version" << endl;
+ return false;
+ }
+ d->syntaxVersion = atts_.value(idx).toUInt();
+ if(d->syntaxVersion > Tellico::XML::syntaxVersion) {
+ d->error = i18n("It is from a future version of Tellico.");
+ return false;
+ } else if(Tellico::XML::versionConversion(d->syntaxVersion, Tellico::XML::syntaxVersion)) {
+ // going from version 9 to 10, there's no conversion needed
+ TQString str = i18n("Tellico is converting the file to a more recent document format. "
+ "Information loss may occur if an older version of Tellico is used "
+ "to read this file in the future.");
+ myDebug() << str << endl;
+ }
+ if((d->syntaxVersion > 6 && localName_ != Latin1Literal("tellico")) ||
+ (d->syntaxVersion < 7 && localName_ != Latin1Literal("bookcase"))) {
+ // no error message
+ myWarning() << "RootHandler::start() - bad root element name" << endl;
+ return false;
+ }
+ d->ns = d->syntaxVersion > 6 ? Tellico::XML::nsTellico : Tellico::XML::nsBookcase;
+ return true;
+}
+
+bool DocumentHandler::end(const TQString&, const TQString&, const TQString&) {
+ return true;
+}
+
+StateHandler* CollectionHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if((d->syntaxVersion > 3 && localName_ == Latin1Literal("fields")) ||
+ (d->syntaxVersion < 4 && localName_ == Latin1Literal("attributes"))) {
+ return new FieldsHandler(d);
+ } else if(localName_ == Latin1Literal("bibtex-preamble")) {
+ return new BibtexPreambleHandler(d);
+ } else if(localName_ == Latin1Literal("macros")) {
+ return new BibtexMacrosHandler(d);
+ } else if(localName_ == d->entryName) {
+ return new EntryHandler(d);
+ } else if(localName_ == Latin1Literal("images")) {
+ return new ImagesHandler(d);
+ }
+ return 0;
+}
+
+bool CollectionHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes& atts_) {
+ d->collTitle = attValue(atts_, "title");
+ d->collType = attValue(atts_, "type").toInt();
+ d->entryName = attValue(atts_, "unit");
+
+ Q_ASSERT(d->collType);
+ return true;
+}
+
+bool CollectionHandler::end(const TQString&, const TQString&, const TQString&) {
+ d->coll->addEntries(d->entries);
+ // a little hidden capability was to just have a local path as an image file name
+ // and on reading the xml file, Tellico would load the image file, too
+ // here, we need to scan all the image values in all the entries and check
+ // maybe this is too costly, especially since the capability wasn't advertised?
+ Data::FieldVec fields = d->coll->imageFields();
+ for(Data::EntryVecIt entry = d->entries.begin(); entry != d->entries.end(); ++entry) {
+ for(Data::FieldVecIt field = fields.begin(); field != fields.end(); ++field) {
+ TQString value = entry->field(field, false);
+ // image info should have already been loaded
+ const Data::ImageInfo& info = ImageFactory::imageInfo(value);
+ // possible that value needs to be cleaned first in which case info is null
+ if(info.isNull() || !info.linkOnly) {
+ // for local files only, allow paths here
+ KURL u = KURL::fromPathOrURL(value);
+ if(u.isValid() && u.isLocalFile()) {
+ TQString result = ImageFactory::addImage(u, false /* quiet */);
+ if(!result.isEmpty()) {
+ value = result;
+ }
+ }
+ value = Data::Image::idClean(value);
+ entry->setField(field->name(), value);
+ }
+ }
+ }
+ return true;
+}
+
+StateHandler* FieldsHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if((d->syntaxVersion > 3 && localName_ == Latin1Literal("field")) ||
+ (d->syntaxVersion < 4 && localName_ == Latin1Literal("attribute"))) {
+ return new FieldHandler(d);
+ }
+ return 0;
+}
+
+bool FieldsHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes&) {
+ d->defaultFields = false;
+ return true;
+}
+
+bool FieldsHandler::end(const TQString&, const TQString&, const TQString&) {
+ // add default fields if there was a default field name, or no names at all
+ const bool addFields = d->defaultFields || d->fields.isEmpty();
+ // in syntax 4, the element name was changed to "entry", always, rather than depending on
+ // on the entryName of the collection.
+ if(d->syntaxVersion > 3) {
+ d->entryName = TQString::fromLatin1("entry");
+ Data::Collection::Type type = static_cast<Data::Collection::Type>(d->collType);
+ d->coll = CollectionFactory::collection(type, addFields);
+ } else {
+ d->coll = CollectionFactory::collection(d->entryName, addFields);
+ }
+
+ if(!d->collTitle.isEmpty()) {
+ d->coll->setTitle(d->collTitle);
+ }
+
+ d->coll->addFields(d->fields);
+
+// as a special case, for old book collections with a bibtex-id field, convert to Bibtex
+ if(d->syntaxVersion < 4 && d->collType == Data::Collection::Book
+ && d->coll->hasField(TQString::fromLatin1("bibtex-id"))) {
+ d->coll = Data::BibtexCollection::convertBookCollection(d->coll);
+ }
+
+ return true;
+}
+
+StateHandler* FieldHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(localName_ == Latin1Literal("prop")) {
+ return new FieldPropertyHandler(d);
+ }
+ return 0;
+}
+
+bool FieldHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes& atts_) {
+ // special case: if the i18n attribute equals true, then translate the title, description, and category
+ const bool isI18n = attValue(atts_, "i18n") == Latin1Literal("true");
+
+ TQString name = attValue(atts_, "name", "unknown");
+ if(name == Latin1Literal("_default")) {
+ d->defaultFields = true;
+ return true;
+ }
+
+ TQString title = attValue(atts_, "title", i18n("Unknown"));
+ if(isI18n) {
+ title = i18n(title.utf8());
+ }
+
+ TQString typeStr = attValue(atts_, "type", TQString::number(Data::Field::Line));
+ Data::Field::Type type = static_cast<Data::Field::Type>(typeStr.toInt());
+
+ Data::FieldPtr field;
+ if(type == Data::Field::Choice) {
+ TQStringList allowed = TQStringList::split(TQRegExp(TQString::fromLatin1("\\s*;\\s*")),
+ attValue(atts_, "allowed"));
+ if(isI18n) {
+ for(TQStringList::Iterator word = allowed.begin(); word != allowed.end(); ++word) {
+ (*word) = i18n((*word).utf8());
+ }
+ }
+ field = new Data::Field(name, title, allowed);
+ } else {
+ field = new Data::Field(name, title, type);
+ }
+
+ int idx = atts_.index(TQString::fromLatin1("category"));
+ if(idx > -1) {
+ // at one point, the categories had keyboard accels
+ TQString cat = atts_.value(idx);
+ if(d->syntaxVersion < 9 && cat.find('&') > -1) {
+ cat.remove('&');
+ }
+ if(isI18n) {
+ cat = i18n(cat.utf8());
+ }
+ field->setCategory(cat);
+ }
+
+ idx = atts_.index(TQString::fromLatin1("flags"));
+ if(idx > -1) {
+ int flags = atts_.value(idx).toInt();
+ // I also changed the enum values for syntax 3, but the only custom field
+ // would have been bibtex-id
+ if(d->syntaxVersion < 3 && name == Latin1Literal("bibtex-id")) {
+ flags = 0;
+ }
+
+ // in syntax version 4, added a flag to disallow deleting attributes
+ // if it's a version before that and is the title, then add the flag
+ if(d->syntaxVersion < 4 && name == Latin1Literal("title")) {
+ flags |= Data::Field::NoDelete;
+ }
+ field->setFlags(flags);
+ }
+
+ TQString formatStr = attValue(atts_, "format", TQString::number(Data::Field::FormatNone));
+ Data::Field::FormatFlag format = static_cast<Data::Field::FormatFlag>(formatStr.toInt());
+ field->setFormatFlag(format);
+
+ idx = atts_.index(TQString::fromLatin1("description"));
+ if(idx > -1) {
+ TQString desc = atts_.value(idx);
+ if(isI18n) {
+ desc = i18n(desc.utf8());
+ }
+ field->setDescription(desc);
+ }
+
+ if(d->syntaxVersion < 5 && atts_.index(TQString::fromLatin1("bibtex-field")) > -1) {
+ field->setProperty(TQString::fromLatin1("bibtex"), attValue(atts_, "bibtex-field"));
+ }
+
+ // Table2 is deprecated
+ if(type == Data::Field::Table2) {
+ field->setType(Data::Field::Table);
+ field->setProperty(TQString::fromLatin1("columns"), TQChar('2'));
+ }
+
+ // for syntax 8, rating fields got their own type
+ if(d->syntaxVersion < 8) {
+ Data::Field::convertOldRating(field); // does all its own checking
+ }
+ d->fields.append(field);
+
+ return true;
+}
+
+bool FieldHandler::end(const TQString&, const TQString&, const TQString&) {
+ return true;
+}
+
+bool FieldPropertyHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes& atts_) {
+ // there should be at least one field already so we can add properties to it
+ Q_ASSERT(!d->fields.isEmpty());
+ Data::FieldPtr field = d->fields.back();
+
+ m_propertyName = attValue(atts_, "name");
+
+ // all track fields in music collections prior to version 9 get converted to three columns
+ if(d->syntaxVersion < 9) {
+ if(d->collType == Data::Collection::Album && field->name() == Latin1Literal("track")) {
+ field->setProperty(TQString::fromLatin1("columns"), TQChar('3'));
+ field->setProperty(TQString::fromLatin1("column1"), i18n("Title"));
+ field->setProperty(TQString::fromLatin1("column2"), i18n("Artist"));
+ field->setProperty(TQString::fromLatin1("column3"), i18n("Length"));
+ } else if(d->collType == Data::Collection::Video && field->name() == Latin1Literal("cast")) {
+ field->setProperty(TQString::fromLatin1("column1"), i18n("Actor/Actress"));
+ field->setProperty(TQString::fromLatin1("column2"), i18n("Role"));
+ }
+ }
+
+ return true;
+}
+
+bool FieldPropertyHandler::end(const TQString&, const TQString&, const TQString&) {
+ Q_ASSERT(!m_propertyName.isEmpty());
+ // add the previous property
+ Data::FieldPtr field = d->fields.back();
+ field->setProperty(m_propertyName, d->text);
+ return true;
+}
+
+bool BibtexPreambleHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes&) {
+ return true;
+}
+
+bool BibtexPreambleHandler::end(const TQString&, const TQString&, const TQString&) {
+ Q_ASSERT(d->coll);
+ if(d->coll && d->collType == Data::Collection::Bibtex && !d->text.isEmpty()) {
+ Data::BibtexCollection* c = static_cast<Data::BibtexCollection*>(d->coll.data());
+ c->setPreamble(d->text);
+ }
+ return true;
+}
+
+StateHandler* BibtexMacrosHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(localName_ == Latin1Literal("macro")) {
+ return new BibtexMacroHandler(d);
+ }
+ return 0;
+}
+
+bool BibtexMacrosHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes&) {
+ return true;
+}
+
+bool BibtexMacrosHandler::end(const TQString&, const TQString&, const TQString&) {
+ return true;
+}
+
+bool BibtexMacroHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes& atts_) {
+ m_macroName = attValue(atts_, "name");
+ return true;
+}
+
+bool BibtexMacroHandler::end(const TQString&, const TQString&, const TQString&) {
+ if(d->coll && d->collType == Data::Collection::Bibtex && !m_macroName.isEmpty() && !d->text.isEmpty()) {
+ Data::BibtexCollection* c = static_cast<Data::BibtexCollection*>(d->coll.data());
+ c->addMacro(m_macroName, d->text);
+ }
+ return true;
+}
+
+StateHandler* EntryHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(d->coll->hasField(localName_)) {
+ return new FieldValueHandler(d);
+ }
+ return new FieldValueContainerHandler(d);
+}
+
+bool EntryHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes& atts_) {
+ // the entries must come after the fields
+ if(!d->coll || d->coll->fields().isEmpty()) {
+ myWarning() << "EntryHandler::start() - entries must come after fields are defined" << endl;
+ // TODO: i18n
+ d->error = TQString::fromLatin1("File format error: entries must come after fields are defined");
+ return false;
+ }
+ int id = attValue(atts_, "id").toInt();
+ Data::EntryPtr entry;
+ if(id > 0) {
+ entry = new Data::Entry(d->coll, id);
+ } else {
+ entry = new Data::Entry(d->coll);
+ }
+ d->entries.append(entry);
+ return true;
+}
+
+bool EntryHandler::end(const TQString&, const TQString&, const TQString&) {
+ return true;
+}
+
+StateHandler* FieldValueContainerHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(d->coll->hasField(localName_)) {
+ return new FieldValueHandler(d);
+ }
+ return new FieldValueContainerHandler(d);
+}
+
+bool FieldValueContainerHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes&) {
+ return true;
+}
+
+bool FieldValueContainerHandler::end(const TQString&, const TQString&, const TQString&) {
+ return true;
+}
+
+StateHandler* FieldValueHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(localName_ == Latin1Literal("year") ||
+ localName_ == Latin1Literal("month") ||
+ localName_ == Latin1Literal("day")) {
+ return new DateValueHandler(d);
+ } else if(localName_ == Latin1Literal("column")) {
+ return new TableColumnHandler(d);
+ }
+ return 0;
+}
+
+bool FieldValueHandler::start(const TQString&, const TQString&, const TQString& localName_, const TQXmlAttributes& atts_) {
+ d->currentField = d->coll->fieldByName(localName_);
+ m_i18n = attValue(atts_, "i18n") == Latin1Literal("true");
+ m_validateISBN = attValue(atts_, "validate") != Latin1Literal("no");
+ return true;
+}
+
+bool FieldValueHandler::end(const TQString&, const TQString& localName_, const TQString&) {
+ Data::FieldPtr f = d->coll->fieldByName(localName_);
+ if(!f) {
+ myWarning() << "FieldValueHandler::end() - no field named " << localName_ << endl;
+ return true;
+ }
+ // if it's a derived value, no field value is added
+ if(f->type() == Data::Field::Dependent) {
+ return true;
+ }
+
+ Data::EntryPtr entry = d->entries.back();
+ Q_ASSERT(entry);
+ TQString fieldName = localName_;
+ TQString fieldValue = d->text;
+
+ if(d->syntaxVersion < 2 && fieldName == Latin1Literal("keywords")) {
+ // in version 2, "keywords" changed to "keyword"
+ fieldName = TQString::fromLatin1("keyword");
+ } else if(d->syntaxVersion < 4 && f->type() == Data::Field::Bool) {
+ // in version 3 and prior, checkbox attributes had no text(), set it to "true"
+ fieldValue = TQString::fromLatin1("true");
+ } else if(d->syntaxVersion < 8 && f->type() == Data::Field::Rating) {
+ // in version 8, old rating fields get changed
+ bool ok;
+ uint i = Tellico::toUInt(fieldValue, &ok);
+ if(ok) {
+ fieldValue = TQString::number(i);
+ }
+ } else if(!d->textBuffer.isEmpty()) {
+ // for dates and tables, the value is built up from child elements
+#ifndef NDEBUG
+ if(!d->text.isEmpty()) {
+ myWarning() << "FieldValueHandler::end() - ignoring value for field " << localName_ << ": " << d->text << endl;
+ }
+#endif
+ fieldValue = d->textBuffer;
+ d->textBuffer = TQString();
+ }
+ // this is not an else branch, the data may be in the textBuffer
+ if(d->syntaxVersion < 9 && d->coll->type() == Data::Collection::Album && fieldName == Latin1Literal("track")) {
+ // yes, this assumes the artist has already been set
+ fieldValue += TQString::fromLatin1("::");
+ fieldValue += entry->field(TQString::fromLatin1("artist"));
+ }
+ // special case: if the i18n attribute equals true, then translate the title, description, and category
+ if(m_i18n) {
+ fieldValue = i18n(fieldValue.utf8());
+ }
+ // special case for isbn fields, go ahead and validate
+ if(m_validateISBN && fieldName == Latin1Literal("isbn")) {
+ ISBNValidator val(0);
+ val.fixup(fieldValue);
+ }
+ if(fieldValue.isEmpty()) {
+ return true;
+ }
+ // for fields with multiple values, we need to add on the new value
+ TQString oldValue = entry->field(fieldName);
+ if(!oldValue.isEmpty()) {
+ fieldValue = oldValue + TQString::fromLatin1("; ") + fieldValue;
+ }
+ entry->setField(fieldName, fieldValue);
+ return true;
+}
+
+bool DateValueHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes&) {
+ return true;
+}
+
+bool DateValueHandler::end(const TQString&, const TQString& localName_, const TQString&) {
+ // the data value is y-m-d even if there are no date values
+ if(d->textBuffer.isEmpty()) {
+ d->textBuffer = TQString::fromLatin1("--");
+ }
+ TQStringList tokens = TQStringList::split('-', d->textBuffer, true /* allow empty */);
+ Q_ASSERT(tokens.size() == 3);
+ if(localName_ == Latin1Literal("year")) {
+ tokens[0] = d->text;
+ } else if(localName_ == Latin1Literal("month")) {
+ tokens[1] = d->text;
+ } else if(localName_ == Latin1Literal("day")) {
+ tokens[2] = d->text;
+ }
+ d->textBuffer = tokens.join(TQChar('-'));
+ return true;
+}
+
+bool TableColumnHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes&) {
+ return true;
+}
+
+bool TableColumnHandler::end(const TQString&, const TQString&, const TQString&) {
+ // for old collections, if the second column holds the track length, bump it to next column
+ if(d->syntaxVersion < 9 &&
+ d->coll->type() == Data::Collection::Album &&
+ d->currentField->name() == Latin1Literal("track") &&
+ !d->textBuffer.isEmpty() &&
+ d->textBuffer.contains(TQString::fromLatin1("::")) == 0) {
+ TQRegExp rx(TQString::fromLatin1("\\d+:\\d\\d"));
+ if(rx.exactMatch(d->text)) {
+ d->text += TQString::fromLatin1("::");
+ d->text += d->entries.back()->field(TQString::fromLatin1("artist"));
+ }
+ }
+
+ if(!d->textBuffer.isEmpty()) {
+ d->textBuffer += TQString::fromLatin1("::");
+ }
+ d->textBuffer += d->text;
+ return true;
+}
+
+StateHandler* ImagesHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(localName_ == Latin1Literal("image")) {
+ return new ImageHandler(d);
+ }
+ return 0;
+}
+
+bool ImagesHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes&) {
+ // reset variable that gets updated in the image handler
+ d->hasImages = false;
+ return true;
+}
+
+bool ImagesHandler::end(const TQString&, const TQString&, const TQString&) {
+ return true;
+}
+
+bool ImageHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes& atts_) {
+ m_format = attValue(atts_, "format");
+ m_link = attValue(atts_, "link") == Latin1Literal("true");
+ // idClean() already calls shareString()
+ m_imageId = m_link ? shareString(attValue(atts_, "id"))
+ : Data::Image::idClean(attValue(atts_, "id"));
+ m_width = attValue(atts_, "width").toInt();
+ m_height = attValue(atts_, "height").toInt();
+ return true;
+}
+
+bool ImageHandler::end(const TQString&, const TQString&, const TQString&) {
+ bool readInfo = true;
+ if(d->loadImages) {
+ TQByteArray ba;
+ KCodecs::base64Decode(TQCString(d->text.latin1()), ba);
+ if(!ba.isEmpty()) {
+ TQString result = ImageFactory::addImage(ba, m_format, m_imageId);
+ if(result.isEmpty()) {
+ myDebug() << "TellicoImporter::readImage(XML) - null image for " << m_imageId << endl;
+ }
+ d->hasImages = true;
+ readInfo = false;
+ }
+ }
+ if(readInfo) {
+ // a width or height of 0 is ok here
+ Data::ImageInfo info(m_imageId, m_format.latin1(), m_width, m_height, m_link);
+ ImageFactory::cacheImageInfo(info);
+ }
+ return true;
+}
+
+StateHandler* FiltersHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(localName_ == Latin1Literal("filter")) {
+ return new FilterHandler(d);
+ }
+ return 0;
+}
+
+bool FiltersHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes&) {
+ return true;
+}
+
+bool FiltersHandler::end(const TQString&, const TQString&, const TQString&) {
+ return true;
+}
+
+StateHandler* FilterHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(localName_ == Latin1Literal("rule")) {
+ return new FilterRuleHandler(d);
+ }
+ return 0;
+}
+
+bool FilterHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes& atts_) {
+ d->filter = new Filter(Filter::MatchAny);
+ d->filter->setName(attValue(atts_, "name"));
+
+ if(attValue(atts_, "match") == Latin1Literal("all")) {
+ d->filter->setMatch(Filter::MatchAll);
+ }
+ return true;
+}
+
+bool FilterHandler::end(const TQString&, const TQString&, const TQString&) {
+ if(d->coll && !d->filter->isEmpty()) {
+ d->coll->addFilter(d->filter);
+ }
+ d->filter = FilterPtr();
+ return true;
+}
+
+bool FilterRuleHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes& atts_) {
+ TQString field = attValue(atts_, "field");
+ // empty field means match any of them
+ TQString pattern = attValue(atts_, "pattern");
+ // empty pattern is bad
+ if(pattern.isEmpty()) {
+ myWarning() << "FilterRuleHandler::start() - empty rule!" << endl;
+ return true;
+ }
+ TQString function = attValue(atts_, "function").lower();
+ FilterRule::Function func;
+ if(function == Latin1Literal("contains")) {
+ func = FilterRule::FuncContains;
+ } else if(function == Latin1Literal("notcontains")) {
+ func = FilterRule::FuncNotContains;
+ } else if(function == Latin1Literal("equals")) {
+ func = FilterRule::FuncEquals;
+ } else if(function == Latin1Literal("notequals")) {
+ func = FilterRule::FuncNotEquals;
+ } else if(function == Latin1Literal("regexp")) {
+ func = FilterRule::FuncRegExp;
+ } else if(function == Latin1Literal("notregexp")) {
+ func = FilterRule::FuncNotRegExp;
+ } else {
+ myWarning() << "FilterRuleHandler::start() - invalid rule function: " << function << endl;
+ return true;
+ }
+ d->filter->append(new FilterRule(field, pattern, func));
+ return true;
+}
+
+bool FilterRuleHandler::end(const TQString&, const TQString&, const TQString&) {
+ return true;
+}
+
+StateHandler* BorrowersHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(localName_ == Latin1Literal("borrower")) {
+ return new BorrowerHandler(d);
+ }
+ return 0;
+}
+
+bool BorrowersHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes&) {
+ return true;
+}
+
+bool BorrowersHandler::end(const TQString&, const TQString&, const TQString&) {
+ return true;
+}
+
+StateHandler* BorrowerHandler::nextHandlerImpl(const TQString&, const TQString& localName_, const TQString&) {
+ if(localName_ == Latin1Literal("loan")) {
+ return new LoanHandler(d);
+ }
+ return 0;
+}
+
+bool BorrowerHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes& atts_) {
+ TQString name = attValue(atts_, "name");
+ TQString uid = attValue(atts_, "uid");
+ d->borrower = new Data::Borrower(name, uid);
+
+ return true;
+}
+
+bool BorrowerHandler::end(const TQString&, const TQString&, const TQString&) {
+ if(d->coll && !d->borrower->isEmpty()) {
+ d->coll->addBorrower(d->borrower);
+ }
+ d->borrower = Data::BorrowerPtr();
+ return true;
+}
+
+bool LoanHandler::start(const TQString&, const TQString&, const TQString&, const TQXmlAttributes& atts_) {
+ m_id = attValue(atts_, "entryRef").toInt();
+ m_uid = attValue(atts_, "uid");
+ m_loanDate = attValue(atts_, "loanDate");
+ m_dueDate = attValue(atts_, "dueDate");
+ m_inCalendar = attValue(atts_, "calendar") == Latin1Literal("true");
+ return true;
+}
+
+bool LoanHandler::end(const TQString&, const TQString&, const TQString&) {
+ Data::EntryPtr entry = d->coll->entryById(m_id);
+ if(!entry) {
+ myWarning() << "LoanHandler::end() - no entry with id = " << m_id << endl;
+ return true;
+ }
+ TQDate loanDate, dueDate;
+ if(!m_loanDate.isEmpty()) {
+ loanDate = TQDate::fromString(m_loanDate, TQt::ISODate);
+ }
+ if(!m_dueDate.isEmpty()) {
+ dueDate = TQDate::fromString(m_dueDate, TQt::ISODate);
+ }
+
+ Data::LoanPtr loan = new Data::Loan(entry, loanDate, dueDate, d->text);
+ loan->setUID(m_uid);
+ loan->setInCalendar(m_inCalendar);
+ d->borrower->addLoan(loan);
+ return true;
+}
+