diff --git a/syndication/rdf/document.cpp b/syndication/rdf/document.cpp index 2ae52cdee..42a48cc9a 100644 --- a/syndication/rdf/document.cpp +++ b/syndication/rdf/document.cpp @@ -1,278 +1,284 @@ /* * This file is part of the syndication library * * Copyright (C) 2006 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "document.h" #include "dublincore.h" #include "image.h" #include "item.h" #include "model.h" +#include "model_p.h" #include "resource.h" #include "rssvocab.h" #include "sequence.h" #include "statement.h" #include "syndicationinfo.h" #include "textinput.h" #include #include #include #include +using namespace boost; + namespace Syndication { namespace RDF { class Document::Private { public: Private() : itemTitleContainsMarkup(false), itemTitlesGuessed(false), itemDescriptionContainsMarkup(false), itemDescGuessed(false) {} mutable bool itemTitleContainsMarkup; mutable bool itemTitlesGuessed; mutable bool itemDescriptionContainsMarkup; mutable bool itemDescGuessed; + shared_ptr modelPrivate; }; -Document::Document() : Syndication::SpecificDocument(), +Document::Document() : Syndication::SpecificDocument(), ResourceWrapper(), d(new Private) { + d->modelPrivate = resource()->model().d; } Document::Document(ResourcePtr resource) : Syndication::SpecificDocument(), ResourceWrapper(resource), d(new Private) { + d->modelPrivate = resource->model().d; } Document::Document(const Document& other) : SpecificDocument(other), ResourceWrapper(other), d(new Private) { *d = *(other.d); } Document::~Document() { delete d; d = 0; } bool Document::operator==(const Document& other) const { return ResourceWrapper::operator==(other); } Document& Document::operator=(const Document& other) { ResourceWrapper::operator=(other); *d = *(other.d); - + return *this; } - + bool Document::accept(DocumentVisitor* visitor) { return visitor->visitRDFDocument(this); } bool Document::isValid() const { return !isNull(); } - + QString Document::title() const { QString str = resource()->property(RSSVocab::self()->title())->asString(); return normalize(str); } QString Document::description() const { QString str = resource()->property(RSSVocab::self()->description())->asString(); return normalize(str); } QString Document::link() const { return resource()->property(RSSVocab::self()->link())->asString(); } DublinCore Document::dc() const { return DublinCore(resource()); } SyndicationInfo Document::syn() const { return SyndicationInfo(resource()); } QList Document::items() const { QList list; if (!resource()->hasProperty(RSSVocab::self()->items())) return list; - + NodePtr n = resource()->property(RSSVocab::self()->items())->object(); if (n->isSequence()) { Sequence* seq = static_cast(n.get()); - + const QList items = seq->items(); QList::ConstIterator it = items.begin(); QList::ConstIterator end = items.end(); - + DocumentPtr doccpy(new Document(*this)); - + for ( ; it != end; ++it) { if ((*it)->isResource()) { // well, we need it as ResourcePtr // maybe this should go to the node // interface ResourcePtr asResource()? ResourcePtr ptr = resource()->model().createResource((static_cast((*it).get()))->uri()); - + list.append(Item(ptr, doccpy)); } } - + } return list; } Image Document::image() const { ResourcePtr img = resource()->property(RSSVocab::self()->image())->asResource(); - + return img ? Image(img) : Image(); } TextInput Document::textInput() const { ResourcePtr ti = resource()->property(RSSVocab::self()->textinput())->asResource(); - + return ti ? TextInput(ti) : TextInput(); } void Document::getItemTitleFormatInfo(bool* containsMarkup) const { if (!d->itemTitlesGuessed) { QString titles; QList litems = items(); - + if (litems.isEmpty()) { d->itemTitlesGuessed = true; return; } - + int nmax = litems.size() < 10 ? litems.size() : 10; // we check a maximum of 10 items int i = 0; - - QList::ConstIterator it = litems.constBegin(); - + + QList::ConstIterator it = litems.constBegin(); + while (i < nmax) { titles += (*it).originalTitle(); ++it; ++i; } - + d->itemTitleContainsMarkup = stringContainsMarkup(titles); d->itemTitlesGuessed = true; } if (containsMarkup != 0L) *containsMarkup = d->itemTitleContainsMarkup; } - + void Document::getItemDescriptionFormatInfo(bool* containsMarkup) const { if (!d->itemDescGuessed) { QString desc; QList litems = items(); - - + + if (litems.isEmpty()) { d->itemDescGuessed = true; return; } - + int nmax = litems.size() < 10 ? litems.size() : 10; // we check a maximum of 10 items int i = 0; - QList::ConstIterator it = litems.constBegin(); + QList::ConstIterator it = litems.constBegin(); while (i < nmax) { desc += (*it).originalDescription(); ++it; ++i; } d->itemDescriptionContainsMarkup = stringContainsMarkup(desc); d->itemDescGuessed = true; } - + if (containsMarkup != 0L) *containsMarkup = d->itemDescriptionContainsMarkup; } QString Document::debugInfo() const { QString info; info += "### Document: ###################\n"; info += "title: #" + title() + "#\n"; info += "link: #" + link() + "#\n"; info += "description: #" + description() + "#\n"; info += dc().debugInfo(); info += syn().debugInfo(); Image img = image(); if (!img.resource() == 0L) info += img.debugInfo(); TextInput input = textInput(); if (!input.isNull()) info += input.debugInfo(); QList itlist = items(); QList::ConstIterator it = itlist.constBegin(); QList::ConstIterator end = itlist.constEnd(); for ( ; it != end; ++it) info += (*it).debugInfo(); - - + + info += "### Document end ################\n"; return info; } } // namespace RDF } // namespace Syndication diff --git a/syndication/rdf/item.h b/syndication/rdf/item.h index 81d6cde92..cee7af2b9 100644 --- a/syndication/rdf/item.h +++ b/syndication/rdf/item.h @@ -1,175 +1,175 @@ /* * This file is part of the syndication library * * Copyright (C) 2006 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #ifndef SYNDICATION_RDF_ITEM_H #define SYNDICATION_RDF_ITEM_H #include #include #include class QString; namespace Syndication { class SpecificItemVisitor; namespace RDF { class DublinCore; class Item; /** * An RSS 1.0 item. * (It is a convenience wrapper for the * underlying RDF resource, which can be accessed via resource()). * * @author Frank Osterfeld */ class SYNDICATION_EXPORT Item : public ResourceWrapper, public SpecificItem { public: /** * creates an item object wrapping a null resource, isNull() is * @c true. */ Item(); /** * Creates an item wrapping the given resource * @param resource resource to wrap, should be of type * of rss1:item, otherwise the wrapper will not return useful * information. * @param doc the document this item is part of. Used by Document */ explicit Item(ResourcePtr resource, DocumentPtr doc=DocumentPtr()); /** * copies an item - * + * * @param other item to copy */ Item(const Item& other); - + /** * virtual destructor */ virtual ~Item(); /** * assigns another item - * + * * @param other the item to assign */ Item& operator=(const Item& other); - + /** * compares two item instances. Two instances are equal, * if the wrapped resources are equal. See ResourceWrapper::operator==() * for details. - * + * * @param other the item to compare this item to */ bool operator==(const Item& other) const; - + /** * interface for item visitors. See SpecificItemVisitor for * more information. * * @param visitor a visitor visiting this object */ bool accept(SpecificItemVisitor* visitor); /** * The item's title (required). * * @return The item's title as HTML, or a null string if not specified */ QString title() const; /** * A brief description/abstract of the item. * if encodedContent() is not provided, this can also contain the full * content. * * @return description as HTML, or a null string if not specified */ QString description() const; /** * The item's URL, usually pointing to a website containing the * full content (news article, blog entry etc.). * * @return the link */ QString link() const; /** * returns a dublin core description of this * item (including metadata such as item author * or subject) */ DublinCore dc() const; /** * returns content (@c content:encoded) as HTML. * * @return content as HTML, or a null string if not specified */ QString encodedContent() const; //@cond PRIVATE /** * @internal * returns the title unmodified * used by Document */ QString originalTitle() const; - + /** * @internal * returns the description unmodified * used by Document */ QString originalDescription() const; - + //@endcond - + /** * Returns a description of the item for debugging purposes. * * @return debug string */ QString debugInfo() const; - + private: - + class Private; Private* d; }; } // namespace RDF } // namespace Syndication #endif // SYNDICATION_RDF_ITEM_H diff --git a/syndication/rdf/model.cpp b/syndication/rdf/model.cpp index 7c82a4d81..dde848653 100644 --- a/syndication/rdf/model.cpp +++ b/syndication/rdf/model.cpp @@ -1,489 +1,399 @@ /* * This file is part of the syndication library * * Copyright (C) 2006 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "model.h" -#include "literal.h" -#include "nodevisitor.h" -#include "property.h" -#include "rdfvocab.h" -#include "resource.h" -#include "sequence.h" -#include "statement.h" - -#include -#include -#include +#include "model_p.h" namespace Syndication { namespace RDF { -class Model::ModelPrivate -{ - public: - - long id; - static long idCounter; - LiteralPtr nullLiteral; - PropertyPtr nullProperty; - ResourcePtr nullResource; - StatementPtr nullStatement; - QHash statements; - QHash > stmtsBySubject; - - QHash nodes; - QHash resources; - QHash properties; - QHash sequences; - Model* model; - - class AddToHashesVisitor; - - ModelPrivate(Model* m) - { - model = m; - id = idCounter++; - addToHashesVisitor = new AddToHashesVisitor(this); - initialized = false; - } - - ~ModelPrivate() - { - delete addToHashesVisitor; - } - - bool operator==(const ModelPrivate& other) const - { - return id == other.id; - } - - class AddToHashesVisitor : public NodeVisitor - { - public: - - AddToHashesVisitor(ModelPrivate* parent) : p(parent) - {} - - bool visitResource(ResourcePtr res) - { - visitNode(res); - p->resources[res->uri()] = res; - return true; - } - - bool visitSequence(SequencePtr seq) - { - visitResource(seq); - p->sequences[seq->uri()] = seq; - return true; - } - - bool visitProperty(PropertyPtr prop) - { - visitResource(prop); - p->properties[prop->uri()] = prop; - return true; - } - - bool visitNode(NodePtr node) - { - p->nodes[node->id()] = node; - return true; - } - - ModelPrivate* p; - }; - - AddToHashesVisitor* addToHashesVisitor; - - void addToHashes(NodePtr node) - { - addToHashesVisitor->visit(node); - } - - void addToHashes(StatementPtr stmt, const QString& key) - { - statements[key] = stmt; - stmtsBySubject[stmt->subject()->uri()].append(stmt); - } - - void removeFromHashes(const QString& key) - { - StatementPtr stmt = statements[key]; - if (stmt) - stmtsBySubject[stmt->subject()->uri()].removeAll(stmt); - statements.remove(key); - - } - - bool initialized; - - void init() - { - if (!initialized) - { - nullLiteral = LiteralPtr( new Literal() ); - nullLiteral->setModel(*model); - nullProperty = PropertyPtr( new Property() ); - nullProperty->setModel(*model); - nullResource = ResourcePtr( new Resource() ); - nullResource->setModel(*model); - nullStatement = StatementPtr( new Statement() ); - initialized = true; - } - } -}; - long Model::ModelPrivate::idCounter = 0; -Model::Model() : d(new ModelPrivate(this)) +Model::Model() : d(new ModelPrivate) { } Model::Model(const Model& other) { *this = other; } Model::~Model() { } Model& Model::operator=(const Model& other) { d = other.d; return *this; } bool Model::operator==(const Model& other) const { return *d == *(other.d); } PropertyPtr Model::createProperty(const QString& uri) { PropertyPtr prop; - + if (d->properties.contains(uri)) { prop = d->properties[uri]; } else { prop = PropertyPtr( new Property(uri) ); prop->setModel(*this); // if there is a resource object with the same uri, replace // the resource object by the new property object and reuse the id if (d->resources.contains(uri)) { prop->setId(d->resources[uri]->id()); } d->addToHashes(prop); } return prop; } ResourcePtr Model::createResource(const QString& uri) { ResourcePtr res; - + if (d->resources.contains(uri)) { res = d->resources[uri]; } else { res = ResourcePtr( new Resource(uri) ); res->setModel(*this); d->addToHashes(res); } return res; } SequencePtr Model::createSequence(const QString& uri) { SequencePtr seq; - + if (d->sequences.contains(uri)) { seq = d->sequences[uri]; } else { seq = SequencePtr( new Sequence(uri) ); seq->setModel(*this); // if there is a resource object with the same uri, replace // the resource object by the new sequence object and reuse the id if (d->resources.contains(uri)) { seq->setId(d->resources[uri]->id()); } d->addToHashes(seq); } return seq; } LiteralPtr Model::createLiteral(const QString& text) { LiteralPtr lit(new Literal(text)); - + d->addToHashes(lit); return lit; } void Model::removeStatement(StatementPtr statement) { removeStatement(statement->subject(), statement->predicate(), statement->object()); } - + void Model::removeStatement(ResourcePtr subject, PropertyPtr predicate, NodePtr object) { QString key = QString("%1-%2-%3") .arg(QString::number(subject->id())) .arg(QString::number(predicate->id())) .arg(QString::number(object->id())); d->removeFromHashes(key); } StatementPtr Model::addStatement(ResourcePtr subject, PropertyPtr predicate, NodePtr object) { d->init(); ResourcePtr subjInternal = subject; - + if (!d->nodes.contains(subjInternal->id())) { subjInternal = ResourcePtr( subject->clone() ); subjInternal->setModel(*this); d->addToHashes(subjInternal); } - + PropertyPtr predInternal = predicate; - + if (!d->nodes.contains(predInternal->id())) { predInternal = PropertyPtr( predicate->clone() ); predInternal->setModel(*this); d->addToHashes(predInternal); } - + NodePtr objInternal = object; - + if (!d->nodes.contains(objInternal->id())) { objInternal = NodePtr( object->clone() ); objInternal->setModel(*this); d->addToHashes(objInternal); } - + // TODO: avoid duplicated stmts with literal objects! - + QString key = QString("%1-%2-%3") .arg(QString::number(subjInternal->id())) .arg(QString::number(predInternal->id())) .arg(QString::number(objInternal->id())); - + StatementPtr stmt; - + if (!d->statements.contains(key)) { stmt = StatementPtr( new Statement(subjInternal, predInternal, objInternal) ); d->addToHashes(stmt, key); } else { stmt = d->statements[key]; } - + return stmt; } bool Model::isEmpty() const { return d->statements.isEmpty(); } bool Model::resourceHasProperty(const Resource* resource, PropertyPtr property) const +{ + return d->resourceHasProperty( resource, property ); +} + +bool Model::ModelPrivate::resourceHasProperty(const Resource* resource, PropertyPtr property) const { // resource unknown - if (!d->resources.contains(resource->uri())) + if (!resources.contains(resource->uri())) return false; - - QList stmts = d->stmtsBySubject[resource->uri()]; + + QList stmts = stmtsBySubject[resource->uri()]; QList::ConstIterator it = stmts.constBegin(); QList::ConstIterator end = stmts.constEnd(); for ( ; it != end; ++it) { if (*((*it)->predicate()) == *property) return true; } return false; } StatementPtr Model::resourceProperty(const Resource* resource, PropertyPtr property) const { - QList stmts = d->stmtsBySubject[resource->uri()]; + return d->resourceProperty(resource, property); +} + +StatementPtr Model::ModelPrivate::resourceProperty(const Resource* resource, PropertyPtr property) const +{ + QList stmts = stmtsBySubject[resource->uri()]; QList::ConstIterator it = stmts.constBegin(); QList::ConstIterator end = stmts.constEnd(); for ( ; it != end; ++it) { if (*((*it)->predicate()) == *property) return *it; } - return d->nullStatement; + return nullStatement; } QList Model::resourceProperties(const Resource* resource, PropertyPtr property) const +{ + return d->resourceProperties( resource, property ); +} + +QList Model::ModelPrivate::resourceProperties(const Resource* resource, PropertyPtr property) const { QList res; - QList stmts = d->stmtsBySubject[resource->uri()]; + QList stmts = stmtsBySubject[resource->uri()]; QList::ConstIterator it = stmts.constBegin(); QList::ConstIterator end = stmts.constEnd(); for ( ; it != end; ++it) { if (*((*it)->predicate()) == *property) res.append(*it); } - + return res; } QList Model::statements() const { return d->statements.values(); } QString Model::debugInfo() const { QString info; - + QList stmts = d->statements.values(); QList::ConstIterator it = stmts.constBegin(); QList::ConstIterator end = stmts.constEnd(); - + for ( ; it != end; ++it) { info += QString("<%1> <%2> ").arg((*it)->subject()->uri()).arg((*it)->predicate()->uri()); - + if ((*it)->object()->isLiteral()) { info += QString("\"%1\"\n").arg((*it)->asString()); } else { info += QString("<%1>\n").arg((*it)->asResource()->uri()); } - + } - + return info; } QList Model::resourcesWithType(ResourcePtr type) const { QList list; - + QList stmts = d->statements.values(); QList::ConstIterator it = stmts.constBegin(); QList::ConstIterator end = stmts.constEnd(); for ( ; it != end; ++it) { if (*((*it)->predicate()) == *(RDFVocab::self()->type()) && *((*it)->object()) == *type ) list.append((*it)->subject()); } return list; } NodePtr Model::nodeByID(uint id) const { - if (!d->nodes.contains(id)) + return d->nodeByID(id); +} + +NodePtr Model::ModelPrivate::nodeByID(uint id) const +{ + if (!nodes.contains(id)) { - return d->nullLiteral; + return nullLiteral; } else { - return d->nodes[id]; + return nodes.value(id); } } - + ResourcePtr Model::resourceByID(uint id) const { - if (!d->nodes.contains(id)) + return d->resourceByID(id); +} + +ResourcePtr Model::ModelPrivate::resourceByID(uint id) const +{ + if (!nodes.contains(id)) { - return d->nullResource; + return nullResource; } else { - NodePtr node = d->nodes[id]; + NodePtr node = nodes.value(id); if (node->isResource()) return boost::static_pointer_cast(node); else - return d->nullResource; + return nullResource; } } PropertyPtr Model::propertyByID(uint id) const { - if (!d->nodes.contains(id)) + return d->propertyByID(id); +} + +PropertyPtr Model::ModelPrivate::propertyByID(uint id) const +{ + if (!nodes.contains(id)) { - return d->nullProperty; + return nullProperty; } else { - NodePtr node = d->nodes[id]; + NodePtr node = nodes.value(id); if (node->isProperty()) return boost::static_pointer_cast(node); else - return d->nullProperty; + return nullProperty; } } LiteralPtr Model::literalByID(uint id) const { - if (!d->nodes.contains(id)) + return d->literalByID(id); +} + + +LiteralPtr Model::ModelPrivate::literalByID(uint id) const +{ + if (!nodes.contains(id)) { - return d->nullLiteral; + return nullLiteral; } else { - NodePtr node = d->nodes[id]; + NodePtr node = nodes.value(id); if (node->isLiteral()) return boost::static_pointer_cast(node); else - return d->nullLiteral; + return nullLiteral; } } } // namespace RDF } // namespace Syndication diff --git a/syndication/rdf/model.h b/syndication/rdf/model.h index 7114c410a..62ceb15ff 100644 --- a/syndication/rdf/model.h +++ b/syndication/rdf/model.h @@ -1,257 +1,265 @@ /* * This file is part of the syndication library * * Copyright (C) 2006 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #ifndef SYNDICATION_RDF_MODEL_H #define SYNDICATION_RDF_MODEL_H #include #include #include #include #include #include #include #include template class QList; namespace Syndication { namespace RDF { +class Document; +class Resource; +class Statement; + /** * An RDF model, a set of RDF statements. * Model objects are implicitely shared. * * @author Frank Osterfeld */ class SYNDICATION_EXPORT Model { + friend class ::Syndication::RDF::Document; + friend class ::Syndication::RDF::Resource; + friend class ::Syndication::RDF::Statement; + public: /** * default constructor, creates an empty model * containing no statements */ Model(); /** * constructs a model from another. * Both models will share the same set of statements, * so adding/removing statements from one model also * modifies the other! * * @param other another model */ Model(const Model& other); /** * destructor */ virtual ~Model(); /** * assigns another model. Both models will share the same * set of statements, so adding/removing statements from * one model also modifies the other! * * @param other another model */ Model& operator=(const Model& other); /** * Returns whether two models objects represent the same model * (i.e. share the same underlying statement set). Currently this * method does _not_ compare the statement list. * Two indepently created models containing the same statements * are not equal! - * + * * @param other the model to compare to */ bool operator==(const Model& other) const; /** * creates a resource and associates it with this model. If the model * already contains a resource with the given URI, the existing instance * is returned. * * @param uri the URI of the resource. If a null string, a blank node * is created. * @return a shared pointer to the requested resource */ virtual ResourcePtr createResource(const QString& uri=QString()); /** * creates a property and associates it with this model. If the model * already contains a property with the given URI, the existing instance * is returned. * * @param uri the URI of the property. This must be non-empty, otherwise * null property is returned * @return a shared pointer to the requested property */ virtual PropertyPtr createProperty(const QString& uri); /** * creates a sequence and associates it with this model. If the model * already contains a sequence with the given URI, the existing * instance is returned. * * @param uri the URI of the sequence, or a null string for an * anonymous instance * @return a shared pointer to the requested sequence */ virtual SequencePtr createSequence(const QString& uri=QString()); /** * creates a literal and associates it with this model. * * @param text the literal text * @return a shared pointer to the requested literal */ virtual LiteralPtr createLiteral(const QString& text); /** * adds a statement to the model. * * @param subject * @param predicate * @param object * @return a shared pointer to a statement associated with this * model, with the given @c subject, @c predicate and @c object */ virtual StatementPtr addStatement(ResourcePtr subject, PropertyPtr predicate, NodePtr object); /** * removes a statement from the model. * * @param subject subject of the statement * @param predicate predicate of the statement * @param object object of the statement */ virtual void removeStatement(ResourcePtr subject, PropertyPtr predicate, NodePtr object); /** * removes a statement from the model. * * @param statement the statement to remove */ virtual void removeStatement(StatementPtr statement); /** * returns whether this model is empty, i.e. contains no statements. */ virtual bool isEmpty() const; /** * returns all resources of a given type. * subClassOf semantics are ignored. * * @param type a resource representing an RDFS class */ virtual QList resourcesWithType(ResourcePtr type) const; /** * returns a list of the statements in this model. * */ virtual QList statements() const; /** * searches the model for a node by ID. * * @param id the ID to search for * @return the node with the given ID, or a null node (which is of type * Literal) if the model doesn't contain the node with this ID */ virtual NodePtr nodeByID(uint id) const; /** * searches the model for a resource by ID. * * @param id the ID to search for * @return the resource with the given ID, or a null resource if the * model doesn't contain a resource with this ID */ virtual ResourcePtr resourceByID(uint id) const; /** * searches the model for a property by ID. * * @param id the ID to search for * @return the property with the given ID, or a null property if the * model doesn't contain a property with this ID */ virtual PropertyPtr propertyByID(uint id) const; /** * searches the model for a literal by ID. * * @param id the ID to search for * @return the literal with the given ID, or a null literal if the * model doesn't contain a literal with this ID */ virtual LiteralPtr literalByID(uint id) const; //@cond PRIVATE /** * @internal * used by Resource::hasProperty() */ virtual bool resourceHasProperty(const Resource* resource, PropertyPtr property) const; /** * @internal * used by Resource::property() */ virtual StatementPtr resourceProperty(const Resource* resource, PropertyPtr property) const; /** * @internal * used by Resource::properties() */ virtual QList resourceProperties(const Resource* resource, PropertyPtr property) const; //@endcond /** * a debug string listing the contained statements for * debugging purposes * * @return debug string */ virtual QString debugInfo() const; private: class ModelPrivate; boost::shared_ptr d; }; } // namespace RDF } // namespace Syndication #endif // SYNDICATION_RDF_MODEL_H diff --git a/syndication/rdf/model_p.h b/syndication/rdf/model_p.h new file mode 100644 index 000000000..cee7d4332 --- /dev/null +++ b/syndication/rdf/model_p.h @@ -0,0 +1,177 @@ +/* + * This file is part of the syndication library + * + * Copyright (C) 2006 Frank Osterfeld + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ +#ifndef SYNDICATION_RDF_MODEL_P_H +#define SYNDICATION_RDF_MODEL_P_H + +#include "model.h" +#include "literal.h" +#include "nodevisitor.h" +#include "property.h" +#include "rdfvocab.h" +#include "resource.h" +#include "sequence.h" +#include "statement.h" + +#include +#include +#include + +#include + +namespace Syndication { +namespace RDF { + +class Model::ModelPrivate : public boost::enable_shared_from_this +{ +public: + long id; + static long idCounter; + LiteralPtr nullLiteral; + PropertyPtr nullProperty; + ResourcePtr nullResource; + StatementPtr nullStatement; + QHash statements; + QHash > stmtsBySubject; + + QHash nodes; + QHash resources; + QHash properties; + QHash sequences; + bool initialized; + + class AddToHashesVisitor; + + + ModelPrivate() : id(idCounter++) + { + addToHashesVisitor = new AddToHashesVisitor(this); + initialized = false; + } + + ~ModelPrivate() + { + delete addToHashesVisitor; + } + + bool operator==(const ModelPrivate& other) const + { + return id == other.id; + } + + class AddToHashesVisitor : public NodeVisitor + { + public: + + AddToHashesVisitor(ModelPrivate* parent) : p(parent) + {} + + bool visitResource(ResourcePtr res) + { + visitNode(res); + p->resources[res->uri()] = res; + return true; + } + + bool visitSequence(SequencePtr seq) + { + visitResource(seq); + p->sequences[seq->uri()] = seq; + return true; + } + + bool visitProperty(PropertyPtr prop) + { + visitResource(prop); + p->properties[prop->uri()] = prop; + return true; + } + + bool visitNode(NodePtr node) + { + p->nodes[node->id()] = node; + return true; + } + + ModelPrivate* p; + }; + + AddToHashesVisitor* addToHashesVisitor; + + bool resourceHasProperty(const Resource* resource, + PropertyPtr property) const; + + StatementPtr resourceProperty(const Resource* resource, + PropertyPtr property) const; + + QList resourceProperties(const Resource* resource, + PropertyPtr property) const; + + NodePtr nodeByID(uint id) const; + + ResourcePtr resourceByID(uint id) const; + + PropertyPtr propertyByID(uint id) const; + + LiteralPtr literalByID(uint id) const; + + void addToHashes(NodePtr node) + { + addToHashesVisitor->visit(node); + } + + void addToHashes(StatementPtr stmt, const QString& key) + { + statements[key] = stmt; + stmtsBySubject[stmt->subject()->uri()].append(stmt); + } + + void removeFromHashes(const QString& key) + { + StatementPtr stmt = statements[key]; + if (stmt) + stmtsBySubject[stmt->subject()->uri()].removeAll(stmt); + statements.remove(key); + + } + + void init() + { + if (!initialized) + { + Model m; + m.d = shared_from_this(); + nullLiteral = LiteralPtr( new Literal() ); + nullLiteral->setModel(m); + nullProperty = PropertyPtr( new Property() ); + nullProperty->setModel(m); + nullResource = ResourcePtr( new Resource() ); + nullResource->setModel(m); + nullStatement = StatementPtr( new Statement() ); + initialized = true; + } + } +}; + +} // namespace RDF +} // namespace Syndication + +#endif // SYNDICATION_RDF_MODEL_P_H diff --git a/syndication/rdf/resource.cpp b/syndication/rdf/resource.cpp index d9403aca7..6bbb209ab 100644 --- a/syndication/rdf/resource.cpp +++ b/syndication/rdf/resource.cpp @@ -1,196 +1,223 @@ /* * This file is part of the syndication library * * Copyright (C) 2006 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "resource.h" #include "model.h" +#include "model_p.h" #include "nodevisitor.h" #include "property.h" #include "statement.h" #include #include #include +#include + +using namespace boost; + namespace Syndication { namespace RDF { class Resource::ResourcePrivate { public: - + QString uri; - Model model; + weak_ptr model; bool isAnon; unsigned int id; - + bool operator==(const ResourcePrivate& other) const { if (!isAnon && !other.isAnon) return uri == other.uri; else return id == other.id; } }; Resource::Resource(const Resource& other) : Node(other) { *this = other; } Resource::Resource() : d() { } Resource::Resource(const QString& uri) : d(new ResourcePrivate) { if (uri.isNull()) { d->uri = KRandom::randomString(10); // TODO: ensure uniqueness d->isAnon = true; } else { d->uri = uri; d->isAnon = false; } - + d->id = idCounter++; } Resource::~Resource() { } Resource& Resource::operator=(const Resource& other) { d = other.d; return *this; } bool Resource::operator==(const Node& other) const { const Resource* o2 = dynamic_cast(&other); if (!o2) return false; if (!d || !o2->d) return d == o2->d; return *d == *(o2->d); } bool Resource::hasProperty(PropertyPtr property) const { - return d ? d->model.resourceHasProperty(this, property) : false; + if (!d) + return false; + const shared_ptr m = d->model.lock(); + if (!m) + return false; + return m->resourceHasProperty(this, property); } StatementPtr Resource::property(PropertyPtr property) const { StatementPtr ptr(new Statement()); - if (d) - ptr = d->model.resourceProperty(this, property); - return ptr; + if (!d) + return ptr; + const shared_ptr m = d->model.lock(); + if (!m) + return ptr; + return m->resourceProperty(this, property); } QList Resource::properties(PropertyPtr property) const { - if (d) - return d->model.resourceProperties(this, property); - return QList(); + if (!d) + return QList(); + const shared_ptr m = d->model.lock(); + if (!m) + return QList(); + + return m->resourceProperties(this, property); } Resource* Resource::clone() const { return new Resource(*this); } void Resource::accept(NodeVisitor* visitor, NodePtr ptr) { ResourcePtr rptr = boost::static_pointer_cast(ptr); if (!visitor->visitResource(rptr)) Node::accept(visitor, ptr); } unsigned int Resource::id() const { return d ? d->id : 0; } bool Resource::isNull() const { return !d; } Model Resource::model() const { - return d ? d->model : Model(); + if (!d) + return Model(); + + const shared_ptr mp = d->model.lock(); + + Model m; + + if (mp) + m.d = mp; + + return m; } bool Resource::isResource() const { return true; } bool Resource::isProperty() const { return false; } bool Resource::isLiteral() const { return false; } bool Resource::isAnon() const { return d ? d->isAnon : false; } bool Resource::isSequence() const { return false; } void Resource::setModel(const Model& model) { if (d) - d->model = model; + d->model = model.d; } void Resource::setId(unsigned int id) { if (d) d->id = id; } - + QString Resource::text() const { return QString(); } QString Resource::uri() const { return d ? d->uri : QString(); } } // namespace RDF } // namespace Syndication diff --git a/syndication/rdf/resource.h b/syndication/rdf/resource.h index 5cd57ac21..78445c516 100644 --- a/syndication/rdf/resource.h +++ b/syndication/rdf/resource.h @@ -1,215 +1,215 @@ /* * This file is part of the syndication library * * Copyright (C) 2006 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #ifndef SYNDICATION_RDF_RESOURCE_H #define SYNDICATION_RDF_RESOURCE_H #include #include class QString; template class QList; namespace Syndication { namespace RDF { class Model; class Property; typedef boost::shared_ptr PropertyPtr; class Resource; class Statement; typedef boost::shared_ptr StatementPtr; typedef boost::shared_ptr ResourcePtr; /** - * Resources are the entities in the RDF graph. + * Resources are the entities in the RDF graph. * In RSS, e.g. the feed channel itself and the items are * resources. */ class SYNDICATION_EXPORT Resource : public Node { friend class Model; public: /** * creates a null resource */ Resource(); - + /** * copies a resource - * + * * @param other the resource to copy */ Resource(const Resource& other); - + /** * creates a resource with a given URI. * Do not use this directly, use Model::createResource() instead. - * + * * @param uri the URI of the new resource */ explicit Resource(const QString& uri); /** * destructor */ virtual ~Resource(); /** * assigns a resource - * + * * @param other the resource to assign */ Resource& operator=(const Resource& other); - + /** * checks two resources for equality. Currently both URI (or anonID) * _and_ id() must be equal! - * + * * @param other the node to compare this node to */ bool operator==(const Node& other) const; /** * Used by visitors for double dispatch. See NodeVisitor * for more information. * @param visitor the visitor calling the method * @param ptr a shared pointer object for this node */ virtual void accept(NodeVisitor* visitor, NodePtr ptr); - + /** * creates a copy of the resource object */ virtual Resource* clone() const; /** * the model this resource belongs to */ virtual Model model() const; /** * returns whether the resource has a property @p property in the * associated model. - * + * * @param property the property to check for */ virtual bool hasProperty(PropertyPtr property) const; - + /** * returns a statement from the associated model where this resource is * the subject and the given property the predicate. - * + * * @param property the property to check for - * + * * @return the first statement found that satisfies the conditions. * If there are multiple statements, an arbitrary one is returned. */ virtual StatementPtr property(PropertyPtr property) const; - + /** * returns the list of all statements from the associated model where * this resource is the subject and the given property the predicate. - * + * * @param property the property to check for - * + * * @return a list of the statements that satisfy the conditions. */ virtual QList properties(PropertyPtr property) const; /** * returns whether the resource is a null resource */ virtual bool isNull() const; /** * the identifier of this node. the ID is unique per model * and set by the associated model at creation time. */ virtual unsigned int id() const; - + /** * returns @p true */ virtual bool isResource() const; - + /** * returns @p false */ virtual bool isLiteral() const; - + /** * returns @p true if this resource is also a property, @p false * otherwise */ virtual bool isProperty() const; - + /** * returns whether this resource is an anonymous resource */ virtual bool isAnon() const; - + /** - * returns @p true if this resource is also a sequence, @p false + * returns @p true if this resource is also a sequence, @p false * otherwise. */ virtual bool isSequence() const; /** * returns a null string */ virtual QString text() const; - + /** * returns the URI of the resource */ virtual QString uri() const; - + /** * used in Model * @internal */ virtual void setModel(const Model& model); - + /** * used in Model * @internal */ virtual void setId(unsigned int id); private: class ResourcePrivate; typedef boost::shared_ptr ResourcePrivatePtr; ResourcePrivatePtr d; }; } // namespace RDF } // namespace Syndication #endif // SYNDICATION_RDF_RESOURCE_H diff --git a/syndication/rdf/resourcewrapper.cpp b/syndication/rdf/resourcewrapper.cpp index 4e885a2e5..452925b53 100644 --- a/syndication/rdf/resourcewrapper.cpp +++ b/syndication/rdf/resourcewrapper.cpp @@ -1,78 +1,81 @@ /* * This file is part of the syndication library * * Copyright (C) 2006 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "resourcewrapper.h" +#include "model.h" #include "resource.h" namespace Syndication { namespace RDF { class ResourceWrapper::ResourceWrapperPrivate { public: - + ResourcePtr resource; + Model model; }; ResourceWrapper::ResourceWrapper() : d(new ResourceWrapperPrivate) { d->resource = ResourcePtr( new Resource() ); } ResourceWrapper::ResourceWrapper(const ResourceWrapper& other) { *this = other; } ResourceWrapper::ResourceWrapper(ResourcePtr resource) : d(new ResourceWrapperPrivate) { // if a null pointer is passed, we create a null resource d->resource = !resource ? ResourcePtr( new Resource() ) : resource; + d->model = d->resource->model(); } ResourceWrapper::~ResourceWrapper() { } ResourceWrapper& ResourceWrapper::operator=(const ResourceWrapper& other) { d = other.d; return *this; } bool ResourceWrapper::operator==(const ResourceWrapper& other) const { return *(d->resource) == *(other.d->resource); } bool ResourceWrapper::isNull() const { return d->resource->isNull(); } ResourcePtr ResourceWrapper::resource() const { return d->resource; } } // namespace RDF } // namespace Syndication diff --git a/syndication/rdf/statement.cpp b/syndication/rdf/statement.cpp index 3bd286601..a88ee77de 100644 --- a/syndication/rdf/statement.cpp +++ b/syndication/rdf/statement.cpp @@ -1,128 +1,139 @@ /* * This file is part of the syndication library * * Copyright (C) 2006 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "statement.h" #include "literal.h" #include "model.h" +#include "model_p.h" #include "property.h" #include "resource.h" #include +#include + +using namespace boost; + namespace Syndication { namespace RDF { class Statement::StatementPrivate { public: - + uint subjectID; uint predicateID; uint objectID; - Model model; + weak_ptr model; bool operator==(const StatementPrivate& other) const { // FIXME: use better check that works also with multiple models return subjectID == other.subjectID && predicateID == other.predicateID && objectID == other.objectID; } }; Statement::Statement() : d(new StatementPrivate) { d->subjectID = 0; d->predicateID = 0; d->objectID = 0; } Statement::Statement(const Statement& other) { d = other.d; } -Statement::Statement(ResourcePtr subject, PropertyPtr predicate, +Statement::Statement(ResourcePtr subject, PropertyPtr predicate, NodePtr object) : d(new StatementPrivate) { - d->model = subject->model(); + d->model = subject->model().d; d->subjectID = subject->id(); d->predicateID = predicate->id(); d->objectID = object->id(); } Statement::~Statement() { } Statement& Statement::operator=(const Statement& other) { d = other.d; return *this; } bool Statement::operator==(const Statement& other) const { if (!d || !other.d) return d == other.d; return *d == *(other.d); } bool Statement::isNull() const { return d->subjectID == 0; } ResourcePtr Statement::subject() const { - return d->model.resourceByID(d->subjectID); + const shared_ptr m = d ? d->model.lock() : shared_ptr(); + return m ? m->resourceByID(d->subjectID) : ResourcePtr(new Resource); } PropertyPtr Statement::predicate() const { - return d->model.propertyByID(d->predicateID); + const shared_ptr m = d ? d->model.lock() : shared_ptr(); + return m ? m->propertyByID(d->predicateID) : PropertyPtr( new Property() ); } NodePtr Statement::object() const { - return d->model.nodeByID(d->objectID); + const shared_ptr m = d ? d->model.lock() : shared_ptr(); + return m ? m->nodeByID(d->objectID) : LiteralPtr( new Literal() ); } ResourcePtr Statement::asResource() const { - if (isNull() || !d->model.nodeByID(d->objectID)->isResource()) + const shared_ptr m = d ? d->model.lock() : shared_ptr(); + + if (isNull() || !m || !m->nodeByID(d->objectID)->isResource()) return ResourcePtr(new Resource); - return d->model.resourceByID(d->objectID); + return m->resourceByID(d->objectID); } QString Statement::asString() const { if (isNull()) return QString(); - return d->model.nodeByID(d->objectID)->text(); + const shared_ptr m = d ? d->model.lock() : shared_ptr(); + return m ? m->nodeByID(d->objectID)->text() : QString(); } } // namespace RDF } // namespace Syndication diff --git a/syndication/rss2/document.cpp b/syndication/rss2/document.cpp index acf00b6eb..dae4afcb5 100644 --- a/syndication/rss2/document.cpp +++ b/syndication/rss2/document.cpp @@ -1,472 +1,472 @@ /* * This file is part of the syndication library * * Copyright (C) 2005 Frank Osterfeld * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. 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 #include namespace Syndication { namespace RSS2 { class Document::DocumentPrivate { public: DocumentPrivate() : itemDescriptionIsCDATA(false), itemDescriptionContainsMarkup(false), itemDescGuessed(false), itemTitleIsCDATA(false), itemTitleContainsMarkup(false), itemTitlesGuessed(false) {} mutable bool itemDescriptionIsCDATA; mutable bool itemDescriptionContainsMarkup; mutable bool itemDescGuessed; mutable bool itemTitleIsCDATA; mutable bool itemTitleContainsMarkup; mutable bool itemTitlesGuessed; }; -Document::Document(const QDomElement& element) : SpecificDocument(), - ElementWrapper(element), +Document::Document(const QDomElement& element) : SpecificDocument(), + ElementWrapper(element), d(new DocumentPrivate) { } Document Document::fromXML(const QDomDocument& doc) { QDomNode channelNode = doc.namedItem(QString::fromUtf8("rss")).namedItem(QString::fromUtf8("channel")); return Document(channelNode.toElement()); } Document::Document() : SpecificDocument(), ElementWrapper(), d(new DocumentPrivate) { } Document::Document(const Document& other) : SpecificDocument(other), ElementWrapper(other) { d = other.d; } Document::~Document() { } Document& Document::operator=(const Document& other) { ElementWrapper::operator=(other); d = other.d; return *this; } bool Document::isValid() const { return !isNull(); } - + QString Document::title() const { return extractElementTextNS(QString(), QString::fromUtf8("title")); } QString Document::link() const { return extractElementTextNS(QString(), QString::fromUtf8("link") ); } QString Document::description() const { QString d = extractElementTextNS(QString(), QString::fromUtf8("description")); return normalize(d); } QString Document::language() const { QString lang = extractElementTextNS(QString(), QString::fromUtf8("language")); - + if (!lang.isNull()) { return lang; } else { return extractElementTextNS( - dublinCoreNamespace(), QString::fromUtf8("language")); + dublinCoreNamespace(), QString::fromUtf8("language")); } - + } QString Document::copyright() const { QString rights = extractElementTextNS(QString(), QString::fromUtf8("copyright")); if (!rights.isNull()) { return rights; } else { // if is not provided, use return extractElementTextNS(dublinCoreNamespace(), QString::fromUtf8("rights")); } } QString Document::managingEditor() const { return extractElementTextNS(QString(), QString::fromUtf8("managingEditor")); } QString Document::webMaster() const { return extractElementTextNS(QString(), QString::fromUtf8("webMaster")); } time_t Document::pubDate() const { QString str = extractElementTextNS(QString(), QString::fromUtf8("pubDate")); - + if (!str.isNull()) { return parseDate(str, RFCDate); } else { // if there is no pubDate, check for dc:date str = extractElementTextNS(dublinCoreNamespace(), QString::fromUtf8("date")); return parseDate(str, ISODate); } } time_t Document::lastBuildDate() const { QString str = extractElementTextNS(QString(), QString::fromUtf8("lastBuildDate")); - + return parseDate(str, RFCDate); } QList Document::categories() const { QList categories; QList catNodes = elementsByTagNameNS(QString(), QString::fromUtf8("category")); QList::ConstIterator it = catNodes.constBegin(); for ( ; it != catNodes.constEnd(); ++it) { categories.append(Category(*it)); } - + return categories; } QString Document::generator() const { return extractElementTextNS(QString(), QString::fromUtf8("generator")); } QString Document::docs() const { return extractElementTextNS(QString(), QString::fromUtf8("docs")); } Cloud Document::cloud() const { return Cloud(firstElementByTagNameNS(QString(), QString::fromUtf8("cloud"))); } int Document::ttl() const { bool ok; int c; QString text = extractElementTextNS(QString(), QString::fromUtf8("ttl")); c = text.toInt(&ok); return ok ? c : 0; } Image Document::image() const { return Image(firstElementByTagNameNS(QString(), QString::fromUtf8("image"))); } TextInput Document::textInput() const { TextInput ti = TextInput(firstElementByTagNameNS(QString(), QString::fromUtf8("textInput"))); - + if (!ti.isNull()) return ti; - + // Netscape's version of RSS 0.91 has textinput, not textInput return TextInput(firstElementByTagNameNS(QString(), QString::fromUtf8("textinput"))); } QSet Document::skipHours() const { QSet skipHours; QDomElement skipHoursNode = firstElementByTagNameNS(QString(), QString::fromUtf8("skipHours")); if (!skipHoursNode.isNull()) { ElementWrapper skipHoursWrapper(skipHoursNode); bool ok = false; - QList hours = + QList hours = skipHoursWrapper.elementsByTagNameNS(QString(), QString::fromUtf8("hour")); QList::ConstIterator it = hours.constBegin(); for ( ; it != hours.constEnd(); ++it) { int h = (*it).text().toInt(&ok); if (ok) skipHours.insert(h); } } return skipHours; } QSet Document::skipDays() const { QSet skipDays; QDomElement skipDaysNode = firstElementByTagNameNS(QString(), QString::fromUtf8("skipDays")); if (!skipDaysNode.isNull()) { ElementWrapper skipDaysWrapper(skipDaysNode); QHash weekDays; weekDays[QString::fromUtf8("Monday")] = Monday; weekDays[QString::fromUtf8("Tuesday")] = Tuesday; weekDays[QString::fromUtf8("Wednesday")] = Wednesday; weekDays[QString::fromUtf8("Thursday")] = Thursday; weekDays[QString::fromUtf8("Friday")] = Friday; weekDays[QString::fromUtf8("Saturday")] = Saturday; weekDays[QString::fromUtf8("Sunday")] = Sunday; QList days = skipDaysWrapper.elementsByTagNameNS(QString(), QString::fromUtf8("day")); for (QList::ConstIterator it = days.constBegin(); it != days.constEnd(); ++it) { if (weekDays.contains((*it).text())) skipDays.insert(weekDays[(*it).text()]); } } return skipDays; } QList Document::items() const { QList items; - + QList itemNodes = elementsByTagNameNS(QString(), QString::fromUtf8("item")); - + DocumentPtr doccpy(new Document(*this)); - + for (QList::ConstIterator it = itemNodes.constBegin(); it != itemNodes.constEnd(); ++it) { items.append(Item(*it, doccpy)); } - + return items; } QList Document::unhandledElements() const { // TODO: do not hardcode this list here QList handled; handled.append(QString::fromUtf8("title")); handled.append(QString::fromUtf8("link")); handled.append(QString::fromUtf8("description")); handled.append(QString::fromUtf8("language")); handled.append(QString::fromUtf8("copyright")); handled.append(QString::fromUtf8("managingEditor")); handled.append(QString::fromUtf8("webMaster")); handled.append(QString::fromUtf8("pubDate")); handled.append(QString::fromUtf8("lastBuildDate")); handled.append(QString::fromUtf8("skipDays")); handled.append(QString::fromUtf8("skipHours")); handled.append(QString::fromUtf8("item")); handled.append(QString::fromUtf8("textinput")); handled.append(QString::fromUtf8("textInput")); handled.append(QString::fromUtf8("image")); handled.append(QString::fromUtf8("ttl")); handled.append(QString::fromUtf8("generator")); handled.append(QString::fromUtf8("docs")); handled.append(QString::fromUtf8("cloud")); handled.append(ElementType(QString::fromUtf8("language"), dublinCoreNamespace())); handled.append(ElementType(QString::fromUtf8("rights"), dublinCoreNamespace())); handled.append(ElementType(QString::fromUtf8("date"), dublinCoreNamespace())); - + QList notHandled; - + QDomNodeList children = element().childNodes(); for (int i = 0; i < children.size(); ++i) { QDomElement el = children.at(i).toElement(); if (!el.isNull() && !handled.contains(ElementType(el.localName(), el.namespaceURI()))) { notHandled.append(el); } } - + return notHandled; } QString Document::debugInfo() const { QString info; info += "### Document: ###################\n"; if (!title().isNull()) info += "title: #" + title() + "#\n"; if (!description().isNull()) info += "description: #" + description() + "#\n"; if (!link().isNull()) info += "link: #" + link() + "#\n"; if (!language().isNull()) info += "language: #" + language() + "#\n"; if (!copyright().isNull()) info += "copyright: #" + copyright() + "#\n"; if (!managingEditor().isNull()) info += "managingEditor: #" + managingEditor() + "#\n"; if (!webMaster().isNull()) info += "webMaster: #" + webMaster() + "#\n"; - + QString dpubdate = dateTimeToString(pubDate()); if (!dpubdate.isNull()) info += "pubDate: #" + dpubdate + "#\n"; - + QString dlastbuilddate = dateTimeToString(lastBuildDate()); if (!dlastbuilddate.isNull()) info += "lastBuildDate: #" + dlastbuilddate + "#\n"; - + if (!textInput().isNull()) info += textInput().debugInfo(); if (!cloud().isNull()) info += cloud().debugInfo(); if (!image().isNull()) info += image().debugInfo(); - + QList cats = categories(); - + for (QList::ConstIterator it = cats.constBegin(); it != cats.constEnd(); ++it) info += (*it).debugInfo(); QList litems = items(); for (QList::ConstIterator it = litems.constBegin(); it != litems.constEnd(); ++it) info += (*it).debugInfo(); info += "### Document end ################\n"; return info; } void Document::getItemTitleFormatInfo(bool* isCDATA, bool* containsMarkup) const { if (!d->itemTitlesGuessed) { QString titles; QList litems = items(); - + if (litems.isEmpty()) { d->itemTitlesGuessed = true; return; } - + QDomElement titleEl = (*litems.begin()).firstElementByTagNameNS(QString(), QString::fromUtf8("title")); d->itemTitleIsCDATA = titleEl.firstChild().isCDATASection(); - + int nmax = litems.size() < 10 ? litems.size() : 10; // we check a maximum of 10 items int i = 0; - - QList::ConstIterator it = litems.constBegin(); - + + QList::ConstIterator it = litems.constBegin(); + while (i < nmax) { titles += (*it).originalTitle(); ++it; ++i; } - + d->itemTitleContainsMarkup = stringContainsMarkup(titles); d->itemTitlesGuessed = true; } - + if (isCDATA != 0L) *isCDATA = d->itemTitleIsCDATA; if (containsMarkup != 0L) *containsMarkup = d->itemTitleContainsMarkup; } - + void Document::getItemDescriptionFormatInfo(bool* isCDATA, bool* containsMarkup) const { if (!d->itemDescGuessed) { QString desc; QList litems = items(); - - + + if (litems.isEmpty()) { d->itemDescGuessed = true; return; } - + QDomElement descEl = (*litems.begin()).firstElementByTagNameNS(QString(), QString::fromUtf8("description")); d->itemDescriptionIsCDATA = descEl.firstChild().isCDATASection(); int nmax = litems.size() < 10 ? litems.size() : 10; // we check a maximum of 10 items int i = 0; - QList::ConstIterator it = litems.constBegin(); + QList::ConstIterator it = litems.constBegin(); while (i < nmax) { desc += (*it).originalDescription(); ++it; ++i; } d->itemDescriptionContainsMarkup = stringContainsMarkup(desc); d->itemDescGuessed = true; } - + if (isCDATA != 0L) *isCDATA = d->itemDescriptionIsCDATA; if (containsMarkup != 0L) *containsMarkup = d->itemDescriptionContainsMarkup; } - + bool Document::accept(DocumentVisitor* visitor) { return visitor->visitRSS2Document(this); } } // namespace RSS2 } // namespace Syndication