diff options
author | Slávek Banko <slavek.banko@axis.cz> | 2014-03-03 13:46:44 +0100 |
---|---|---|
committer | Slávek Banko <slavek.banko@axis.cz> | 2014-03-03 13:46:44 +0100 |
commit | 2e02da046d3e56cdf4744f644af35ad07424f48b (patch) | |
tree | f2dcf353aa2338eae1c2ff2c41af971c580c2762 /src/translators/xmlstatehandler.cpp | |
parent | 3c13229d98167ae4ae0710d5eeef23fef5005bf0 (diff) | |
download | tellico-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.cpp | 772 |
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; +} + |