Syndication

rdf/document.cpp
1/*
2 This file is part of the syndication library
3 SPDX-FileCopyrightText: 2006 Frank Osterfeld <osterfeld@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "document.h"
9#include "dublincore.h"
10#include "image.h"
11#include "item.h"
12#include "model.h"
13#include "model_p.h"
14#include "resource.h"
15#include "rssvocab.h"
16#include "sequence.h"
17#include "statement.h"
18#include "syndicationinfo.h"
19#include "textinput.h"
20
21#include <documentvisitor.h>
22#include <tools.h>
23
24#include <QList>
25#include <QString>
26#include <QStringList>
27#include <QVector>
28
29#include <algorithm>
30
31namespace Syndication
32{
33namespace RDF
34{
35class SYNDICATION_NO_EXPORT Document::Private
36{
37public:
38 Private()
39 : itemTitleContainsMarkup(false)
40 , itemTitlesGuessed(false)
41 , itemDescriptionContainsMarkup(false)
42 , itemDescGuessed(false)
43 {
44 }
45 mutable bool itemTitleContainsMarkup;
46 mutable bool itemTitlesGuessed;
47 mutable bool itemDescriptionContainsMarkup;
48 mutable bool itemDescGuessed;
50};
51
55 , d(new Private)
56{
57 d->modelPrivate = resource()->model().d;
58}
59
62 , ResourceWrapper(resource)
63 , d(new Private)
64{
65 d->modelPrivate = resource->model().d;
66}
67
69 : SpecificDocument(other)
70 , ResourceWrapper(other)
71 , d(new Private)
72{
73 *d = *(other.d);
74}
75
76Document::~Document() = default;
77
78bool Document::operator==(const Document &other) const
79{
80 return ResourceWrapper::operator==(other);
81}
82
84{
86 *d = *(other.d);
87
88 return *this;
89}
90
92{
93 return visitor->visitRDFDocument(this);
94}
95
97{
98 return !isNull();
99}
100
102{
103 const QString str = resource()->property(RSSVocab::self()->title())->asString();
104 return normalize(str);
105}
106
108{
109 const QString str = resource()->property(RSSVocab::self()->description())->asString();
110 return normalize(str);
111}
112
114{
115 return resource()->property(RSSVocab::self()->link())->asString();
116}
117
119{
120 return DublinCore(resource());
121}
122
124{
125 return SyndicationInfo(resource());
126}
127
128struct SortItem {
129 Item item;
130 int index;
131};
132
133struct LessThanByIndex {
134 bool operator()(const SortItem &lhs, const SortItem &rhs) const
135 {
136 return lhs.index < rhs.index;
137 }
138};
139
140static QList<Item> sortListToMatchSequence(QList<Item> items, const QStringList &uriSequence)
141{
142 QVector<SortItem> toSort;
143 toSort.reserve(items.size());
144 for (const Item &i : items) {
145 SortItem item;
146 item.item = i;
147 item.index = uriSequence.indexOf(i.resource()->uri());
148 toSort.append(item);
149 }
150 std::sort(toSort.begin(), toSort.end(), LessThanByIndex());
151
152 int i = 0;
153 for (const SortItem &sortItem : std::as_const(toSort)) {
154 items[i] = sortItem.item;
155 i++;
156 }
157
158 return items;
159}
160
161struct UriLessThan {
162 bool operator()(const RDF::ResourcePtr &lhs, const RDF::ResourcePtr &rhs) const
163 {
164 return lhs->uri() < rhs->uri();
165 }
166};
167
169{
170 QList<ResourcePtr> items = resource()->model().resourcesWithType(RSSVocab::self()->item());
171 // if there is no sequence, ensure sorting by URI to have a defined and deterministic order
172 // important for unit tests
173 std::sort(items.begin(), items.end(), UriLessThan());
174
175 DocumentPtr doccpy(new Document(*this));
176
177 QList<Item> list;
178 list.reserve(items.count());
179
180 for (const ResourcePtr &i : std::as_const(items)) {
181 list.append(Item(i, doccpy));
182 }
183
184 if (resource()->hasProperty(RSSVocab::self()->items())) {
185 NodePtr n = resource()->property(RSSVocab::self()->items())->object();
186 if (n->isSequence()) {
187 const SequencePtr seq = n.staticCast<Sequence>();
188
189 const QList<NodePtr> seqItems = seq->items();
190
191 QStringList uriSequence;
192 uriSequence.reserve(seqItems.size());
193
194 for (const NodePtr &i : seqItems) {
195 if (i->isResource()) {
196 uriSequence.append(i.staticCast<Resource>()->uri());
197 }
198 }
199 list = sortListToMatchSequence(list, uriSequence);
200 }
201 }
202
203 return list;
204}
205
207{
208 ResourcePtr img = resource()->property(RSSVocab::self()->image())->asResource();
209
210 return img ? Image(img) : Image();
211}
212
214{
215 ResourcePtr ti = resource()->property(RSSVocab::self()->textinput())->asResource();
216
217 return ti ? TextInput(ti) : TextInput();
218}
219
220void Document::getItemTitleFormatInfo(bool *containsMarkup) const
221{
222 if (!d->itemTitlesGuessed) {
223 QString titles;
224 QList<Item> litems = items();
225
226 if (litems.isEmpty()) {
227 d->itemTitlesGuessed = true;
228 return;
229 }
230
231 const int nmax = std::min<int>(litems.size(), 10); // we check a maximum of 10 items
232 int i = 0;
233
234 for (const auto &item : litems) {
235 if (i++ >= nmax) {
236 break;
237 }
238 titles += item.originalTitle();
239 }
240
241 d->itemTitleContainsMarkup = stringContainsMarkup(titles);
242 d->itemTitlesGuessed = true;
243 }
244 if (containsMarkup != nullptr) {
245 *containsMarkup = d->itemTitleContainsMarkup;
246 }
247}
248
249void Document::getItemDescriptionFormatInfo(bool *containsMarkup) const
250{
251 if (!d->itemDescGuessed) {
252 QString desc;
253 QList<Item> litems = items();
254
255 if (litems.isEmpty()) {
256 d->itemDescGuessed = true;
257 return;
258 }
259
260 const int nmax = std::min<int>(litems.size(), 10); // we check a maximum of 10 items
261 int i = 0;
262
263 for (const auto &item : litems) {
264 if (i++ >= nmax) {
265 break;
266 }
267 desc += item.originalDescription();
268 }
269
270 d->itemDescriptionContainsMarkup = stringContainsMarkup(desc);
271 d->itemDescGuessed = true;
272 }
273
274 if (containsMarkup != nullptr) {
275 *containsMarkup = d->itemDescriptionContainsMarkup;
276 }
277}
278
280{
281 QString info;
282 info += QLatin1String("### Document: ###################\n");
283 info += QLatin1String("title: #") + title() + QLatin1String("#\n");
284 info += QLatin1String("link: #") + link() + QLatin1String("#\n");
285 info += QLatin1String("description: #") + description() + QLatin1String("#\n");
286 info += dc().debugInfo();
287 info += syn().debugInfo();
288 Image img = image();
289 if (!img.resource() == 0L) {
290 info += img.debugInfo();
291 }
292 TextInput input = textInput();
293 if (!input.isNull()) {
294 info += input.debugInfo();
295 }
296
297 const QList<Item> itlist = items();
298 for (const auto &item : itlist) {
299 info += item.debugInfo();
300 }
301
302 info += QLatin1String("### Document end ################\n");
303 return info;
304}
305
306} // namespace RDF
307} // namespace Syndication
Visitor interface, following the Visitor design pattern.
virtual bool visitRDFDocument(Syndication::RDF::Document *document)
reimplement this method to handle RDF (i.e.
Document implementation for RDF, representing an RSS 1.0 feed.
QList< Item > items() const
list of items contained in this feed
QString debugInfo() const override
PRIVATE.
QString link() const
The URL to which an HTML rendering of the channel title will link, commonly the parent site's home or...
bool accept(DocumentVisitor *visitor) override
Used by visitors for double dispatch.
bool operator==(const Document &other) const
compares two documents.
Image image() const
An image to be associated with an HTML rendering of the channel.
TextInput textInput() const
An optional text input element associated with the channel.
QString description() const
A brief description of the channel's content, function, source, etc.
bool isValid() const override
returns whether this document is valid or not.
Document & operator=(const Document &other)
assigns another document
~Document() override
destructor
DublinCore dc() const
returns a dublin core description of the document.
Document()
creates a wrapper wrapping a null resource
SyndicationInfo syn() const
returns syndication information describing how often this feed is updated.
QString title() const
title of the feed (required)
A resource wrapper providing convenient access to Dublin Core metadata.
Definition dublincore.h:36
QString debugInfo() const
returns a debug string describing the available DC metadata for debugging purposes
An image to be associated with an HTML rendering of the channel.
Definition rdf/image.h:27
QString debugInfo() const
Returns a description of the image for debugging purposes.
Definition rdf/image.cpp:45
An RSS 1.0 item.
Definition rdf/item.h:37
static RSSVocab * self()
returns the singleton instance
Definition rssvocab.cpp:63
A wrapper for RDF resources.
ResourceWrapper & operator=(const ResourceWrapper &other)
Assignment oeprator Due to the shared d pointer, this is a cheap operation.
bool isNull() const
returns whether the wrapped resource is a null resource
bool operator==(const ResourceWrapper &other) const
compares two resource wrapper instances.
ResourcePtr resource() const
returns the wrapped resource.
Resources are the entities in the RDF graph.
Definition resource.h:37
virtual QString uri() const
returns the URI of the resource
Definition resource.cpp:207
Sequence container, a sequence contains an ordered list of RDF nodes.
Definition sequence.h:32
Wrapper to access syndication information for a feed.
QString debugInfo() const
description of the syndication information for debugging purposes
"The textinput element affords a method for submitting form data to an arbitrary URL - usually locate...
QString debugInfo() const
Returns a description of the text input for debugging purposes.
Document interface for format-specific feed documents as parsed from a document source (see DocumentS...
void append(QList< T > &&value)
iterator begin()
iterator end()
bool isEmpty() const const
void reserve(qsizetype size)
qsizetype size() const const
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:09:18 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.