You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tellico/src/translators/xmlstatehandler.cpp

773 lines
27 KiB

/***************************************************************************
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;
}