1 | /* |
2 | This file is part of KNewStuff2. |
3 | SPDX-FileCopyrightText: 2002 Cornelius Schumacher <schumacher@kde.org> |
4 | SPDX-FileCopyrightText: 2003-2007 Josef Spillner <spillner@kde.org> |
5 | SPDX-FileCopyrightText: 2009 Frederik Gladhorn <gladhorn@kde.org> |
6 | |
7 | SPDX-License-Identifier: LGPL-2.1-or-later |
8 | */ |
9 | |
10 | #include "entry.h" |
11 | #include "entry_p.h" |
12 | |
13 | #include <QDomElement> |
14 | #include <QMetaEnum> |
15 | #include <QStringList> |
16 | #include <QXmlStreamReader> |
17 | #include <knewstuffcore_debug.h> |
18 | |
19 | #include "xmlloader_p.h" |
20 | |
21 | using namespace KNSCore; |
22 | |
23 | Entry::Entry() |
24 | : d(new EntryPrivate()) |
25 | { |
26 | } |
27 | |
28 | Entry::Entry(const Entry &other) |
29 | : d(other.d) |
30 | { |
31 | } |
32 | |
33 | Entry &Entry::operator=(const Entry &other) |
34 | { |
35 | d = other.d; |
36 | return *this; |
37 | } |
38 | |
39 | bool Entry::operator<(const KNSCore::Entry &other) const |
40 | { |
41 | return d->mUniqueId < other.d->mUniqueId; |
42 | } |
43 | |
44 | bool Entry::operator==(const KNSCore::Entry &other) const |
45 | { |
46 | return d->mUniqueId == other.d->mUniqueId && d->mProviderId == other.d->mProviderId; |
47 | } |
48 | |
49 | Entry::~Entry() = default; |
50 | |
51 | bool Entry::isValid() const |
52 | { |
53 | return !d->mUniqueId.isEmpty(); // This should not use the uniqueId getter due to the fallback! |
54 | } |
55 | |
56 | QString Entry::name() const |
57 | { |
58 | return d->mName; |
59 | } |
60 | |
61 | void Entry::setName(const QString &name) |
62 | { |
63 | d->mName = name; |
64 | } |
65 | |
66 | QString Entry::uniqueId() const |
67 | { |
68 | return d->mUniqueId.isEmpty() ? d->mRequestedUniqueId : d->mUniqueId; |
69 | } |
70 | |
71 | void Entry::setUniqueId(const QString &id) |
72 | { |
73 | d->mUniqueId = id; |
74 | } |
75 | |
76 | QString Entry::providerId() const |
77 | { |
78 | return d->mProviderId; |
79 | } |
80 | |
81 | void Entry::setProviderId(const QString &id) |
82 | { |
83 | d->mProviderId = id; |
84 | } |
85 | |
86 | QStringList KNSCore::Entry::tags() const |
87 | { |
88 | return d->mTags; |
89 | } |
90 | |
91 | void KNSCore::Entry::setTags(const QStringList &tags) |
92 | { |
93 | d->mTags = tags; |
94 | } |
95 | |
96 | QString Entry::category() const |
97 | { |
98 | return d->mCategory; |
99 | } |
100 | |
101 | void Entry::setCategory(const QString &category) |
102 | { |
103 | d->mCategory = category; |
104 | } |
105 | |
106 | QUrl Entry::homepage() const |
107 | { |
108 | return d->mHomepage; |
109 | } |
110 | |
111 | void Entry::setHomepage(const QUrl &page) |
112 | { |
113 | d->mHomepage = page; |
114 | } |
115 | |
116 | Author Entry::author() const |
117 | { |
118 | return d->mAuthor; |
119 | } |
120 | |
121 | void Entry::setAuthor(const KNSCore::Author &author) |
122 | { |
123 | d->mAuthor = author; |
124 | } |
125 | |
126 | QString Entry::license() const |
127 | { |
128 | return d->mLicense; |
129 | } |
130 | |
131 | void Entry::setLicense(const QString &license) |
132 | { |
133 | d->mLicense = license; |
134 | } |
135 | |
136 | QString Entry::summary() const |
137 | { |
138 | return d->mSummary; |
139 | } |
140 | |
141 | void Entry::setSummary(const QString &summary) |
142 | { |
143 | d->mSummary = summary; |
144 | } |
145 | |
146 | QString Entry::shortSummary() const |
147 | { |
148 | return d->mShortSummary; |
149 | } |
150 | |
151 | void Entry::setShortSummary(const QString &summary) |
152 | { |
153 | d->mShortSummary = summary; |
154 | } |
155 | |
156 | void Entry::setChangelog(const QString &changelog) |
157 | { |
158 | d->mChangelog = changelog; |
159 | } |
160 | |
161 | QString Entry::changelog() const |
162 | { |
163 | return d->mChangelog; |
164 | } |
165 | |
166 | QString Entry::version() const |
167 | { |
168 | return d->mVersion; |
169 | } |
170 | |
171 | void Entry::setVersion(const QString &version) |
172 | { |
173 | d->mVersion = version; |
174 | } |
175 | |
176 | QDate Entry::releaseDate() const |
177 | { |
178 | return d->mReleaseDate; |
179 | } |
180 | |
181 | void Entry::setReleaseDate(const QDate &releasedate) |
182 | { |
183 | d->mReleaseDate = releasedate; |
184 | } |
185 | |
186 | QString Entry::payload() const |
187 | { |
188 | return d->mPayload; |
189 | } |
190 | |
191 | void Entry::setPayload(const QString &url) |
192 | { |
193 | d->mPayload = url; |
194 | } |
195 | |
196 | QDate Entry::updateReleaseDate() const |
197 | { |
198 | return d->mUpdateReleaseDate; |
199 | } |
200 | |
201 | void Entry::setUpdateReleaseDate(const QDate &releasedate) |
202 | { |
203 | d->mUpdateReleaseDate = releasedate; |
204 | } |
205 | |
206 | QString Entry::updateVersion() const |
207 | { |
208 | return d->mUpdateVersion; |
209 | } |
210 | |
211 | void Entry::setUpdateVersion(const QString &version) |
212 | { |
213 | d->mUpdateVersion = version; |
214 | } |
215 | |
216 | QString Entry::previewUrl(PreviewType type) const |
217 | { |
218 | return d->mPreviewUrl[type]; |
219 | } |
220 | |
221 | void Entry::setPreviewUrl(const QString &url, PreviewType type) |
222 | { |
223 | d->mPreviewUrl[type] = url; |
224 | } |
225 | |
226 | QImage Entry::previewImage(PreviewType type) const |
227 | { |
228 | return d->mPreviewImage[type]; |
229 | } |
230 | |
231 | void Entry::setPreviewImage(const QImage &image, PreviewType type) |
232 | { |
233 | d->mPreviewImage[type] = image; |
234 | } |
235 | |
236 | int Entry::rating() const |
237 | { |
238 | return d->mRating; |
239 | } |
240 | |
241 | void Entry::setRating(int rating) |
242 | { |
243 | d->mRating = rating; |
244 | } |
245 | |
246 | int Entry::() const |
247 | { |
248 | return d->mNumberOfComments; |
249 | } |
250 | |
251 | void Entry::(int ) |
252 | { |
253 | d->mNumberOfComments = comments; |
254 | } |
255 | |
256 | int Entry::downloadCount() const |
257 | { |
258 | return d->mDownloadCount; |
259 | } |
260 | |
261 | void Entry::setDownloadCount(int downloads) |
262 | { |
263 | d->mDownloadCount = downloads; |
264 | } |
265 | |
266 | int Entry::numberFans() const |
267 | { |
268 | return d->mNumberFans; |
269 | } |
270 | |
271 | void Entry::setNumberFans(int fans) |
272 | { |
273 | d->mNumberFans = fans; |
274 | } |
275 | |
276 | QString Entry::donationLink() const |
277 | { |
278 | return d->mDonationLink; |
279 | } |
280 | |
281 | void Entry::setDonationLink(const QString &link) |
282 | { |
283 | d->mDonationLink = link; |
284 | } |
285 | |
286 | int Entry::numberKnowledgebaseEntries() const |
287 | { |
288 | return d->mNumberKnowledgebaseEntries; |
289 | } |
290 | void Entry::setNumberKnowledgebaseEntries(int num) |
291 | { |
292 | d->mNumberKnowledgebaseEntries = num; |
293 | } |
294 | |
295 | QString Entry::knowledgebaseLink() const |
296 | { |
297 | return d->mKnowledgebaseLink; |
298 | } |
299 | void Entry::setKnowledgebaseLink(const QString &link) |
300 | { |
301 | d->mKnowledgebaseLink = link; |
302 | } |
303 | |
304 | Entry::Source Entry::source() const |
305 | { |
306 | return d->mSource; |
307 | } |
308 | |
309 | void Entry::setEntryType(Entry::EntryType type) |
310 | { |
311 | d->mEntryType = type; |
312 | } |
313 | |
314 | Entry::EntryType Entry::entryType() const |
315 | { |
316 | return d->mEntryType; |
317 | } |
318 | |
319 | void Entry::setSource(Source source) |
320 | { |
321 | d->mSource = source; |
322 | } |
323 | |
324 | KNSCore::Entry::Status Entry::status() const |
325 | { |
326 | return d->mStatus; |
327 | } |
328 | |
329 | void Entry::setStatus(KNSCore::Entry::Status status) |
330 | { |
331 | d->mStatus = status; |
332 | } |
333 | |
334 | void KNSCore::Entry::setInstalledFiles(const QStringList &files) |
335 | { |
336 | d->mInstalledFiles = files; |
337 | } |
338 | |
339 | QStringList KNSCore::Entry::installedFiles() const |
340 | { |
341 | return d->mInstalledFiles; |
342 | } |
343 | |
344 | QStringList KNSCore::Entry::uninstalledFiles() const |
345 | { |
346 | return d->mUnInstalledFiles; |
347 | } |
348 | |
349 | int KNSCore::Entry::downloadLinkCount() const |
350 | { |
351 | return d->mDownloadLinkInformationList.size(); |
352 | } |
353 | |
354 | QList<KNSCore::Entry::DownloadLinkInformation> KNSCore::Entry::downloadLinkInformationList() const |
355 | { |
356 | const auto infos = d->mDownloadLinkInformationList; |
357 | QList<KNSCore::Entry::DownloadLinkInformation> ret; |
358 | ret.reserve(asize: infos.size()); |
359 | for (const auto &info : infos) { |
360 | ret.append(t: {.name = info.name, |
361 | .priceAmount = info.priceAmount, |
362 | .distributionType = info.distributionType, |
363 | .descriptionLink = info.descriptionLink, |
364 | .id = info.id, |
365 | .isDownloadtypeLink = info.isDownloadtypeLink, |
366 | .size = info.size, |
367 | .tags = info.tags}); |
368 | } |
369 | return ret; |
370 | } |
371 | |
372 | void KNSCore::Entry::appendDownloadLinkInformation(const KNSCore::Entry::DownloadLinkInformation &info) |
373 | { |
374 | d->mDownloadLinkInformationList.append(t: {.name = info.name, |
375 | .priceAmount = info.priceAmount, |
376 | .distributionType = info.distributionType, |
377 | .descriptionLink = info.descriptionLink, |
378 | .id = info.id, |
379 | .isDownloadtypeLink = info.isDownloadtypeLink, |
380 | .size = info.size, |
381 | .tags = info.tags, |
382 | .version = QString()}); |
383 | } |
384 | |
385 | void Entry::clearDownloadLinkInformation() |
386 | { |
387 | d->mDownloadLinkInformationList.clear(); |
388 | } |
389 | |
390 | static QXmlStreamReader::TokenType (QXmlStreamReader *xml) |
391 | { |
392 | do { |
393 | xml->readNext(); |
394 | } while (xml->tokenType() == QXmlStreamReader::Comment || (xml->tokenType() == QXmlStreamReader::Characters && xml->text().trimmed().isEmpty())); |
395 | return xml->tokenType(); |
396 | } |
397 | |
398 | static QString readText(QXmlStreamReader *xml) |
399 | { |
400 | Q_ASSERT(xml->tokenType() == QXmlStreamReader::StartElement); |
401 | QString ret; |
402 | const auto token = readNextSkipComments(xml); |
403 | if (token == QXmlStreamReader::Characters) { |
404 | ret = xml->text().toString(); |
405 | } |
406 | return ret; |
407 | } |
408 | |
409 | static QString readStringTrimmed(QXmlStreamReader *xml) |
410 | { |
411 | Q_ASSERT(xml->tokenType() == QXmlStreamReader::StartElement); |
412 | QString ret = readText(xml).trimmed(); |
413 | |
414 | if (xml->tokenType() == QXmlStreamReader::Characters) { |
415 | readNextSkipComments(xml); |
416 | } |
417 | Q_ASSERT(xml->tokenType() == QXmlStreamReader::EndElement); |
418 | return ret; |
419 | } |
420 | |
421 | static int readInt(QXmlStreamReader *xml) |
422 | { |
423 | Q_ASSERT(xml->tokenType() == QXmlStreamReader::StartElement); |
424 | int ret = readText(xml).toInt(); |
425 | |
426 | xml->readNext(); |
427 | Q_ASSERT(xml->tokenType() == QXmlStreamReader::EndElement); |
428 | return ret; |
429 | } |
430 | |
431 | bool KNSCore::Entry::setEntryXML(QXmlStreamReader &reader) |
432 | { |
433 | if (reader.name() != QLatin1String("stuff" )) { |
434 | qCWarning(KNEWSTUFFCORE) << "Parsing Entry from invalid XML. Reader tag name was expected to be \"stuff\", but was found as:" << reader.name(); |
435 | return false; |
436 | } |
437 | |
438 | d->mCategory = reader.attributes().value(QStringLiteral("category" )).toString(); |
439 | |
440 | while (!reader.atEnd()) { |
441 | const auto token = readNextSkipComments(xml: &reader); |
442 | if (token == QXmlStreamReader::EndElement) { |
443 | break; |
444 | } else if (token != QXmlStreamReader::StartElement) { |
445 | continue; |
446 | } |
447 | |
448 | if (reader.name() == QLatin1String("name" )) { |
449 | // TODO maybe do something with the language attribute? QString lang = e.attribute("lang"); |
450 | d->mName = reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements); |
451 | } else if (reader.name() == QLatin1String("author" )) { |
452 | // ### careful, the following variables are string views that become invalid when we |
453 | // proceed with reading from reader, such as the readStringTrimmed call below does! |
454 | const auto email = reader.attributes().value(QStringLiteral("email" )); |
455 | const auto jabber = reader.attributes().value(QStringLiteral("im" )); |
456 | const auto homepage = reader.attributes().value(QStringLiteral("homepage" )); |
457 | d->mAuthor.setEmail(email.toString()); |
458 | d->mAuthor.setJabber(jabber.toString()); |
459 | d->mAuthor.setHomepage(homepage.toString()); |
460 | d->mAuthor.setName(readStringTrimmed(xml: &reader)); |
461 | } else if (reader.name() == QLatin1String("providerid" )) { |
462 | d->mProviderId = reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements); |
463 | } else if (reader.name() == QLatin1String("homepage" )) { |
464 | d->mHomepage = QUrl(reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements)); |
465 | } else if (reader.name() == QLatin1String("licence" )) { // krazy:exclude=spelling |
466 | d->mLicense = readStringTrimmed(xml: &reader); |
467 | } else if (reader.name() == QLatin1String("summary" )) { |
468 | d->mSummary = reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements); |
469 | } else if (reader.name() == QLatin1String("changelog" )) { |
470 | d->mChangelog = reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements); |
471 | } else if (reader.name() == QLatin1String("version" )) { |
472 | d->mVersion = readStringTrimmed(xml: &reader); |
473 | } else if (reader.name() == QLatin1String("releasedate" )) { |
474 | d->mReleaseDate = QDate::fromString(string: readStringTrimmed(xml: &reader), format: Qt::ISODate); |
475 | } else if (reader.name() == QLatin1String("preview" )) { |
476 | // TODO support for all 6 image links |
477 | d->mPreviewUrl[PreviewSmall1] = readStringTrimmed(xml: &reader); |
478 | } else if (reader.name() == QLatin1String("previewBig" )) { |
479 | d->mPreviewUrl[PreviewBig1] = readStringTrimmed(xml: &reader); |
480 | } else if (reader.name() == QLatin1String("payload" )) { |
481 | d->mPayload = readStringTrimmed(xml: &reader); |
482 | } else if (reader.name() == QLatin1String("rating" )) { |
483 | d->mRating = readInt(xml: &reader); |
484 | } else if (reader.name() == QLatin1String("downloads" )) { |
485 | d->mDownloadCount = readInt(xml: &reader); |
486 | } else if (reader.name() == QLatin1String("category" )) { |
487 | d->mCategory = reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements); |
488 | } else if (reader.name() == QLatin1String("signature" )) { |
489 | d->mSignature = reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements); |
490 | } else if (reader.name() == QLatin1String("checksum" )) { |
491 | d->mChecksum = reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements); |
492 | } else if (reader.name() == QLatin1String("installedfile" )) { |
493 | d->mInstalledFiles.append(t: reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements)); |
494 | } else if (reader.name() == QLatin1String("id" )) { |
495 | d->mUniqueId = reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements); |
496 | } else if (reader.name() == QLatin1String("tags" )) { |
497 | d->mTags = reader.readElementText(behaviour: QXmlStreamReader::SkipChildElements).split(sep: QLatin1Char(',')); |
498 | } else if (reader.name() == QLatin1String("status" )) { |
499 | const auto statusText = readText(xml: &reader); |
500 | if (statusText == QLatin1String("installed" )) { |
501 | qCDebug(KNEWSTUFFCORE) << "Found an installed entry in registry" ; |
502 | d->mStatus = KNSCore::Entry::Installed; |
503 | } else if (statusText == QLatin1String("updateable" )) { |
504 | d->mStatus = KNSCore::Entry::Updateable; |
505 | } |
506 | if (reader.tokenType() == QXmlStreamReader::Characters) { |
507 | readNextSkipComments(xml: &reader); |
508 | } |
509 | } |
510 | Q_ASSERT_X(reader.tokenType() == QXmlStreamReader::EndElement, |
511 | Q_FUNC_INFO, |
512 | QStringLiteral("token name was %1 and the type was %2" ).arg(reader.name().toString(), reader.tokenString()).toLocal8Bit().data()); |
513 | } |
514 | |
515 | // Validation |
516 | if (d->mName.isEmpty()) { |
517 | qCWarning(KNEWSTUFFCORE) << "Entry: no name given" ; |
518 | return false; |
519 | } |
520 | |
521 | if (d->mUniqueId.isEmpty()) { |
522 | if (!d->mPayload.isEmpty()) { |
523 | d->mUniqueId = d->mPayload; |
524 | } else { |
525 | d->mUniqueId = d->mName; |
526 | } |
527 | } |
528 | |
529 | if (d->mPayload.isEmpty()) { |
530 | qCWarning(KNEWSTUFFCORE) << "Entry: no payload URL given for: " << d->mName << " - " << d->mUniqueId; |
531 | return false; |
532 | } |
533 | return true; |
534 | } |
535 | |
536 | bool KNSCore::Entry::setEntryXML(const QDomElement &xmldata) |
537 | { |
538 | if (xmldata.tagName() != QLatin1String("stuff" )) { |
539 | qCWarning(KNEWSTUFFCORE) << "Parsing Entry from invalid XML" ; |
540 | return false; |
541 | } |
542 | |
543 | d->mCategory = xmldata.attribute(QStringLiteral("category" )); |
544 | |
545 | QDomNode n; |
546 | for (n = xmldata.firstChild(); !n.isNull(); n = n.nextSibling()) { |
547 | QDomElement e = n.toElement(); |
548 | if (e.tagName() == QLatin1String("name" )) { |
549 | // TODO maybe do something with the language attribute? QString lang = e.attribute("lang"); |
550 | d->mName = e.text().trimmed(); |
551 | } else if (e.tagName() == QLatin1String("author" )) { |
552 | QString email = e.attribute(QStringLiteral("email" )); |
553 | QString jabber = e.attribute(QStringLiteral("im" )); |
554 | QString homepage = e.attribute(QStringLiteral("homepage" )); |
555 | d->mAuthor.setName(e.text().trimmed()); |
556 | d->mAuthor.setEmail(email); |
557 | d->mAuthor.setJabber(jabber); |
558 | d->mAuthor.setHomepage(homepage); |
559 | } else if (e.tagName() == QLatin1String("providerid" )) { |
560 | d->mProviderId = e.text(); |
561 | } else if (e.tagName() == QLatin1String("homepage" )) { |
562 | d->mHomepage = QUrl(e.text()); |
563 | } else if (e.tagName() == QLatin1String("licence" )) { // krazy:exclude=spelling |
564 | d->mLicense = e.text().trimmed(); |
565 | } else if (e.tagName() == QLatin1String("summary" )) { |
566 | d->mSummary = e.text(); |
567 | } else if (e.tagName() == QLatin1String("changelog" )) { |
568 | d->mChangelog = e.text(); |
569 | } else if (e.tagName() == QLatin1String("version" )) { |
570 | d->mVersion = e.text().trimmed(); |
571 | } else if (e.tagName() == QLatin1String("releasedate" )) { |
572 | d->mReleaseDate = QDate::fromString(string: e.text().trimmed(), format: Qt::ISODate); |
573 | } else if (e.tagName() == QLatin1String("preview" )) { |
574 | // TODO support for all 6 image links |
575 | d->mPreviewUrl[PreviewSmall1] = e.text().trimmed(); |
576 | } else if (e.tagName() == QLatin1String("previewBig" )) { |
577 | d->mPreviewUrl[PreviewBig1] = e.text().trimmed(); |
578 | } else if (e.tagName() == QLatin1String("payload" )) { |
579 | d->mPayload = e.text().trimmed(); |
580 | } else if (e.tagName() == QLatin1String("rating" )) { |
581 | d->mRating = e.text().toInt(); |
582 | } else if (e.tagName() == QLatin1String("downloads" )) { |
583 | d->mDownloadCount = e.text().toInt(); |
584 | } else if (e.tagName() == QLatin1String("category" )) { |
585 | d->mCategory = e.text(); |
586 | } else if (e.tagName() == QLatin1String("signature" )) { |
587 | d->mSignature = e.text(); |
588 | } else if (e.tagName() == QLatin1String("checksum" )) { |
589 | d->mChecksum = e.text(); |
590 | } else if (e.tagName() == QLatin1String("installedfile" )) { |
591 | // TODO KF6 Add a "installeddirectory" entry to avoid |
592 | // all the issues with the "/*" notation which is currently used as a workaround |
593 | d->mInstalledFiles.append(t: e.text()); |
594 | } else if (e.tagName() == QLatin1String("id" )) { |
595 | d->mUniqueId = e.text(); |
596 | } else if (e.tagName() == QLatin1String("tags" )) { |
597 | d->mTags = e.text().split(sep: QLatin1Char(',')); |
598 | } else if (e.tagName() == QLatin1String("status" )) { |
599 | QString statusText = e.text(); |
600 | if (statusText == QLatin1String("installed" )) { |
601 | qCDebug(KNEWSTUFFCORE) << "Found an installed entry in registry" ; |
602 | d->mStatus = KNSCore::Entry::Installed; |
603 | } else if (statusText == QLatin1String("updateable" )) { |
604 | d->mStatus = KNSCore::Entry::Updateable; |
605 | } |
606 | } |
607 | } |
608 | |
609 | // Validation |
610 | if (d->mName.isEmpty()) { |
611 | qCWarning(KNEWSTUFFCORE) << "Entry: no name given" ; |
612 | return false; |
613 | } |
614 | |
615 | if (d->mUniqueId.isEmpty()) { |
616 | if (!d->mPayload.isEmpty()) { |
617 | d->mUniqueId = d->mPayload; |
618 | } else { |
619 | d->mUniqueId = d->mName; |
620 | } |
621 | } |
622 | |
623 | if (d->mPayload.isEmpty()) { |
624 | qCWarning(KNEWSTUFFCORE) << "Entry: no payload URL given for: " << d->mName << " - " << d->mUniqueId; |
625 | return false; |
626 | } |
627 | return true; |
628 | } |
629 | |
630 | /** |
631 | * get the xml string for the entry |
632 | */ |
633 | QDomElement KNSCore::Entry::entryXML() const |
634 | { |
635 | Q_ASSERT(!d->mUniqueId.isEmpty()); |
636 | Q_ASSERT(!d->mProviderId.isEmpty()); |
637 | |
638 | QDomDocument doc; |
639 | |
640 | QDomElement el = doc.createElement(QStringLiteral("stuff" )); |
641 | el.setAttribute(QStringLiteral("category" ), value: d->mCategory); |
642 | |
643 | QString name = d->mName; |
644 | |
645 | QDomElement e; |
646 | e = addElement(doc, parent&: el, QStringLiteral("name" ), value: name); |
647 | // todo: add language attribute |
648 | (void)addElement(doc, parent&: el, QStringLiteral("providerid" ), value: d->mProviderId); |
649 | |
650 | QDomElement author = addElement(doc, parent&: el, QStringLiteral("author" ), value: d->mAuthor.name()); |
651 | if (!d->mAuthor.email().isEmpty()) { |
652 | author.setAttribute(QStringLiteral("email" ), value: d->mAuthor.email()); |
653 | } |
654 | if (!d->mAuthor.homepage().isEmpty()) { |
655 | author.setAttribute(QStringLiteral("homepage" ), value: d->mAuthor.homepage()); |
656 | } |
657 | if (!d->mAuthor.jabber().isEmpty()) { |
658 | author.setAttribute(QStringLiteral("im" ), value: d->mAuthor.jabber()); |
659 | } |
660 | // FIXME: 'jabber' or 'im'? consult with kopete guys... |
661 | addElement(doc, parent&: el, QStringLiteral("homepage" ), value: d->mHomepage.url()); |
662 | (void)addElement(doc, parent&: el, QStringLiteral("licence" ), value: d->mLicense); // krazy:exclude=spelling |
663 | (void)addElement(doc, parent&: el, QStringLiteral("version" ), value: d->mVersion); |
664 | if ((d->mRating > 0) || (d->mDownloadCount > 0)) { |
665 | (void)addElement(doc, parent&: el, QStringLiteral("rating" ), value: QString::number(d->mRating)); |
666 | (void)addElement(doc, parent&: el, QStringLiteral("downloads" ), value: QString::number(d->mDownloadCount)); |
667 | } |
668 | if (!d->mSignature.isEmpty()) { |
669 | (void)addElement(doc, parent&: el, QStringLiteral("signature" ), value: d->mSignature); |
670 | } |
671 | if (!d->mChecksum.isEmpty()) { |
672 | (void)addElement(doc, parent&: el, QStringLiteral("checksum" ), value: d->mChecksum); |
673 | } |
674 | for (const QString &file : std::as_const(t&: d->mInstalledFiles)) { |
675 | (void)addElement(doc, parent&: el, QStringLiteral("installedfile" ), value: file); |
676 | } |
677 | if (!d->mUniqueId.isEmpty()) { |
678 | addElement(doc, parent&: el, QStringLiteral("id" ), value: d->mUniqueId); |
679 | } |
680 | |
681 | (void)addElement(doc, parent&: el, QStringLiteral("releasedate" ), value: d->mReleaseDate.toString(format: Qt::ISODate)); |
682 | |
683 | e = addElement(doc, parent&: el, QStringLiteral("summary" ), value: d->mSummary); |
684 | e = addElement(doc, parent&: el, QStringLiteral("changelog" ), value: d->mChangelog); |
685 | e = addElement(doc, parent&: el, QStringLiteral("preview" ), value: d->mPreviewUrl[PreviewSmall1]); |
686 | e = addElement(doc, parent&: el, QStringLiteral("previewBig" ), value: d->mPreviewUrl[PreviewBig1]); |
687 | e = addElement(doc, parent&: el, QStringLiteral("payload" ), value: d->mPayload); |
688 | e = addElement(doc, parent&: el, QStringLiteral("tags" ), value: d->mTags.join(sep: QLatin1Char(','))); |
689 | |
690 | if (d->mStatus == KNSCore::Entry::Installed) { |
691 | (void)addElement(doc, parent&: el, QStringLiteral("status" ), QStringLiteral("installed" )); |
692 | } |
693 | if (d->mStatus == KNSCore::Entry::Updateable) { |
694 | (void)addElement(doc, parent&: el, QStringLiteral("status" ), QStringLiteral("updateable" )); |
695 | } |
696 | |
697 | return el; |
698 | } |
699 | |
700 | void KNSCore::Entry::setEntryDeleted() |
701 | { |
702 | setStatus(Entry::Deleted); |
703 | d->mUnInstalledFiles = installedFiles(); |
704 | setInstalledFiles(QStringList()); |
705 | } |
706 | |
707 | void KNSCore::Entry::setEntryRequestedId(const QString &id) |
708 | { |
709 | d->mRequestedUniqueId = id; |
710 | } |
711 | |
712 | QString KNSCore::replaceBBCode(const QString &unformattedText) |
713 | { |
714 | QString text(unformattedText); |
715 | text.replace(before: QLatin1String("[b]" ), after: QLatin1String("<b>" )); |
716 | text.replace(before: QLatin1String("[/b]" ), after: QLatin1String("</b>" )); |
717 | text.replace(before: QLatin1String("[i]" ), after: QLatin1String("<i>" )); |
718 | text.replace(before: QLatin1String("[/i]" ), after: QLatin1String("</i>" )); |
719 | text.replace(before: QLatin1String("[u]" ), after: QLatin1String("<i>" )); |
720 | text.replace(before: QLatin1String("[/u]" ), after: QLatin1String("</i>" )); |
721 | text.replace(before: QLatin1String("\\\"" ), after: QLatin1String("\"" )); |
722 | text.replace(before: QLatin1String("\\\'" ), after: QLatin1String("\'" )); |
723 | text.replace(before: QLatin1String("[li]" ), after: QLatin1String("* " )); // TODO: better replacement for list elements? |
724 | text.remove(QStringLiteral("[/li]" )); |
725 | text.remove(QStringLiteral("[url]" )); |
726 | text.remove(QStringLiteral("[/url]" )); |
727 | return text; |
728 | } |
729 | |
730 | QDebug KNSCore::operator<<(QDebug debug, const KNSCore::Entry &entry) |
731 | { |
732 | QDebugStateSaver saver(debug); |
733 | |
734 | const static QMetaEnum metaEnum = QMetaEnum::fromType<KNSCore::Entry::Status>(); |
735 | bool deleted = entry.status() == Entry::Status::Deleted; |
736 | |
737 | debug.nospace() << "KNSCore::Entry(uniqueId: " << entry.uniqueId() << ", name:" << entry.name() << ", status: " << metaEnum.valueToKey(value: entry.status()) |
738 | << ", " << (deleted ? "uninstalled" : "installed" ) << "Files: " // When the entry is installed, it can not have uninstalledFiles |
739 | << (deleted ? entry.uninstalledFiles() : entry.installedFiles()) << ')'; |
740 | return debug; |
741 | } |
742 | |
743 | #include "moc_entry.cpp" |
744 | |