File indexing completed on 2024-04-28 03:56:26
0001 /* 0002 This file is part of KNewStuff2. 0003 SPDX-FileCopyrightText: 2002 Cornelius Schumacher <schumacher@kde.org> 0004 SPDX-FileCopyrightText: 2003-2007 Josef Spillner <spillner@kde.org> 0005 SPDX-FileCopyrightText: 2009 Frederik Gladhorn <gladhorn@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.1-or-later 0008 */ 0009 0010 #include "entry.h" 0011 0012 #include <QDomElement> 0013 #include <QMetaEnum> 0014 #include <QStringList> 0015 #include <QXmlStreamReader> 0016 #include <knewstuffcore_debug.h> 0017 0018 #include "xmlloader_p.h" 0019 0020 using namespace KNSCore; 0021 0022 class KNSCore::EntryPrivate : public QSharedData 0023 { 0024 public: 0025 EntryPrivate() 0026 { 0027 qRegisterMetaType<KNSCore::Entry::List>(); 0028 } 0029 0030 bool operator==(const EntryPrivate &other) const 0031 { 0032 return mUniqueId == other.mUniqueId && mProviderId == other.mProviderId; 0033 } 0034 0035 QString mUniqueId; 0036 QString mRequestedUniqueId; // We need to map the entry to the request in the ResultsStream, but invalid entries would have an empty ID 0037 QString mName; 0038 QUrl mHomepage; 0039 QString mCategory; 0040 QString mLicense; 0041 QString mVersion; 0042 QDate mReleaseDate = QDate::currentDate(); 0043 0044 // Version and date if a newer version is found (updateable) 0045 QString mUpdateVersion; 0046 QDate mUpdateReleaseDate; 0047 0048 Author mAuthor; 0049 int mRating = 0; 0050 int mNumberOfComments = 0; 0051 int mDownloadCount = 0; 0052 int mNumberFans = 0; 0053 int mNumberKnowledgebaseEntries = 0; 0054 QString mKnowledgebaseLink; 0055 QString mSummary; 0056 QString mShortSummary; 0057 QString mChangelog; 0058 QString mPayload; 0059 QStringList mInstalledFiles; 0060 QString mProviderId; 0061 QStringList mUnInstalledFiles; 0062 QString mDonationLink; 0063 QStringList mTags; 0064 0065 QString mChecksum; 0066 QString mSignature; 0067 KNSCore::Entry::Status mStatus = Entry::Invalid; 0068 Entry::Source mSource = Entry::Online; 0069 Entry::EntryType mEntryType = Entry::CatalogEntry; 0070 0071 QString mPreviewUrl[6]; 0072 QImage mPreviewImage[6]; 0073 0074 QList<Entry::DownloadLinkInformation> mDownloadLinkInformationList; 0075 }; 0076 0077 Entry::Entry() 0078 : d(new EntryPrivate()) 0079 { 0080 } 0081 0082 Entry::Entry(const Entry &other) 0083 : d(other.d) 0084 { 0085 } 0086 0087 Entry &Entry::operator=(const Entry &other) 0088 { 0089 d = other.d; 0090 return *this; 0091 } 0092 0093 bool Entry::operator<(const KNSCore::Entry &other) const 0094 { 0095 return d->mUniqueId < other.d->mUniqueId; 0096 } 0097 0098 bool Entry::operator==(const KNSCore::Entry &other) const 0099 { 0100 return d->mUniqueId == other.d->mUniqueId && d->mProviderId == other.d->mProviderId; 0101 } 0102 0103 Entry::~Entry() = default; 0104 0105 bool Entry::isValid() const 0106 { 0107 return !d->mUniqueId.isEmpty(); // This should not use the uniqueId getter due to the fallback! 0108 } 0109 0110 QString Entry::name() const 0111 { 0112 return d->mName; 0113 } 0114 0115 void Entry::setName(const QString &name) 0116 { 0117 d->mName = name; 0118 } 0119 0120 QString Entry::uniqueId() const 0121 { 0122 return d->mUniqueId.isEmpty() ? d->mRequestedUniqueId : d->mUniqueId; 0123 } 0124 0125 void Entry::setUniqueId(const QString &id) 0126 { 0127 d->mUniqueId = id; 0128 } 0129 0130 QString Entry::providerId() const 0131 { 0132 return d->mProviderId; 0133 } 0134 0135 void Entry::setProviderId(const QString &id) 0136 { 0137 d->mProviderId = id; 0138 } 0139 0140 QStringList KNSCore::Entry::tags() const 0141 { 0142 return d->mTags; 0143 } 0144 0145 void KNSCore::Entry::setTags(const QStringList &tags) 0146 { 0147 d->mTags = tags; 0148 } 0149 0150 QString Entry::category() const 0151 { 0152 return d->mCategory; 0153 } 0154 0155 void Entry::setCategory(const QString &category) 0156 { 0157 d->mCategory = category; 0158 } 0159 0160 QUrl Entry::homepage() const 0161 { 0162 return d->mHomepage; 0163 } 0164 0165 void Entry::setHomepage(const QUrl &page) 0166 { 0167 d->mHomepage = page; 0168 } 0169 0170 Author Entry::author() const 0171 { 0172 return d->mAuthor; 0173 } 0174 0175 void Entry::setAuthor(const KNSCore::Author &author) 0176 { 0177 d->mAuthor = author; 0178 } 0179 0180 QString Entry::license() const 0181 { 0182 return d->mLicense; 0183 } 0184 0185 void Entry::setLicense(const QString &license) 0186 { 0187 d->mLicense = license; 0188 } 0189 0190 QString Entry::summary() const 0191 { 0192 return d->mSummary; 0193 } 0194 0195 void Entry::setSummary(const QString &summary) 0196 { 0197 d->mSummary = summary; 0198 } 0199 0200 QString Entry::shortSummary() const 0201 { 0202 return d->mShortSummary; 0203 } 0204 0205 void Entry::setShortSummary(const QString &summary) 0206 { 0207 d->mShortSummary = summary; 0208 } 0209 0210 void Entry::setChangelog(const QString &changelog) 0211 { 0212 d->mChangelog = changelog; 0213 } 0214 0215 QString Entry::changelog() const 0216 { 0217 return d->mChangelog; 0218 } 0219 0220 QString Entry::version() const 0221 { 0222 return d->mVersion; 0223 } 0224 0225 void Entry::setVersion(const QString &version) 0226 { 0227 d->mVersion = version; 0228 } 0229 0230 QDate Entry::releaseDate() const 0231 { 0232 return d->mReleaseDate; 0233 } 0234 0235 void Entry::setReleaseDate(const QDate &releasedate) 0236 { 0237 d->mReleaseDate = releasedate; 0238 } 0239 0240 QString Entry::payload() const 0241 { 0242 return d->mPayload; 0243 } 0244 0245 void Entry::setPayload(const QString &url) 0246 { 0247 d->mPayload = url; 0248 } 0249 0250 QDate Entry::updateReleaseDate() const 0251 { 0252 return d->mUpdateReleaseDate; 0253 } 0254 0255 void Entry::setUpdateReleaseDate(const QDate &releasedate) 0256 { 0257 d->mUpdateReleaseDate = releasedate; 0258 } 0259 0260 QString Entry::updateVersion() const 0261 { 0262 return d->mUpdateVersion; 0263 } 0264 0265 void Entry::setUpdateVersion(const QString &version) 0266 { 0267 d->mUpdateVersion = version; 0268 } 0269 0270 QString Entry::previewUrl(PreviewType type) const 0271 { 0272 return d->mPreviewUrl[type]; 0273 } 0274 0275 void Entry::setPreviewUrl(const QString &url, PreviewType type) 0276 { 0277 d->mPreviewUrl[type] = url; 0278 } 0279 0280 QImage Entry::previewImage(PreviewType type) const 0281 { 0282 return d->mPreviewImage[type]; 0283 } 0284 0285 void Entry::setPreviewImage(const QImage &image, PreviewType type) 0286 { 0287 d->mPreviewImage[type] = image; 0288 } 0289 0290 int Entry::rating() const 0291 { 0292 return d->mRating; 0293 } 0294 0295 void Entry::setRating(int rating) 0296 { 0297 d->mRating = rating; 0298 } 0299 0300 int Entry::numberOfComments() const 0301 { 0302 return d->mNumberOfComments; 0303 } 0304 0305 void Entry::setNumberOfComments(int comments) 0306 { 0307 d->mNumberOfComments = comments; 0308 } 0309 0310 int Entry::downloadCount() const 0311 { 0312 return d->mDownloadCount; 0313 } 0314 0315 void Entry::setDownloadCount(int downloads) 0316 { 0317 d->mDownloadCount = downloads; 0318 } 0319 0320 int Entry::numberFans() const 0321 { 0322 return d->mNumberFans; 0323 } 0324 0325 void Entry::setNumberFans(int fans) 0326 { 0327 d->mNumberFans = fans; 0328 } 0329 0330 QString Entry::donationLink() const 0331 { 0332 return d->mDonationLink; 0333 } 0334 0335 void Entry::setDonationLink(const QString &link) 0336 { 0337 d->mDonationLink = link; 0338 } 0339 0340 int Entry::numberKnowledgebaseEntries() const 0341 { 0342 return d->mNumberKnowledgebaseEntries; 0343 } 0344 void Entry::setNumberKnowledgebaseEntries(int num) 0345 { 0346 d->mNumberKnowledgebaseEntries = num; 0347 } 0348 0349 QString Entry::knowledgebaseLink() const 0350 { 0351 return d->mKnowledgebaseLink; 0352 } 0353 void Entry::setKnowledgebaseLink(const QString &link) 0354 { 0355 d->mKnowledgebaseLink = link; 0356 } 0357 0358 Entry::Source Entry::source() const 0359 { 0360 return d->mSource; 0361 } 0362 0363 void Entry::setEntryType(Entry::EntryType type) 0364 { 0365 d->mEntryType = type; 0366 } 0367 0368 Entry::EntryType Entry::entryType() const 0369 { 0370 return d->mEntryType; 0371 } 0372 0373 void Entry::setSource(Source source) 0374 { 0375 d->mSource = source; 0376 } 0377 0378 KNSCore::Entry::Status Entry::status() const 0379 { 0380 return d->mStatus; 0381 } 0382 0383 void Entry::setStatus(KNSCore::Entry::Status status) 0384 { 0385 d->mStatus = status; 0386 } 0387 0388 void KNSCore::Entry::setInstalledFiles(const QStringList &files) 0389 { 0390 d->mInstalledFiles = files; 0391 } 0392 0393 QStringList KNSCore::Entry::installedFiles() const 0394 { 0395 return d->mInstalledFiles; 0396 } 0397 0398 QStringList KNSCore::Entry::uninstalledFiles() const 0399 { 0400 return d->mUnInstalledFiles; 0401 } 0402 0403 int KNSCore::Entry::downloadLinkCount() const 0404 { 0405 return d->mDownloadLinkInformationList.size(); 0406 } 0407 0408 QList<KNSCore::Entry::DownloadLinkInformation> KNSCore::Entry::downloadLinkInformationList() const 0409 { 0410 return d->mDownloadLinkInformationList; 0411 } 0412 0413 void KNSCore::Entry::appendDownloadLinkInformation(const KNSCore::Entry::DownloadLinkInformation &info) 0414 { 0415 d->mDownloadLinkInformationList.append(info); 0416 } 0417 0418 void Entry::clearDownloadLinkInformation() 0419 { 0420 d->mDownloadLinkInformationList.clear(); 0421 } 0422 0423 static QXmlStreamReader::TokenType readNextSkipComments(QXmlStreamReader *xml) 0424 { 0425 do { 0426 xml->readNext(); 0427 } while (xml->tokenType() == QXmlStreamReader::Comment || (xml->tokenType() == QXmlStreamReader::Characters && xml->text().trimmed().isEmpty())); 0428 return xml->tokenType(); 0429 } 0430 0431 static QString readText(QXmlStreamReader *xml) 0432 { 0433 Q_ASSERT(xml->tokenType() == QXmlStreamReader::StartElement); 0434 QString ret; 0435 const auto token = readNextSkipComments(xml); 0436 if (token == QXmlStreamReader::Characters) { 0437 ret = xml->text().toString(); 0438 } 0439 return ret; 0440 } 0441 0442 static QString readStringTrimmed(QXmlStreamReader *xml) 0443 { 0444 Q_ASSERT(xml->tokenType() == QXmlStreamReader::StartElement); 0445 QString ret = readText(xml).trimmed(); 0446 0447 if (xml->tokenType() == QXmlStreamReader::Characters) { 0448 readNextSkipComments(xml); 0449 } 0450 Q_ASSERT(xml->tokenType() == QXmlStreamReader::EndElement); 0451 return ret; 0452 } 0453 0454 static int readInt(QXmlStreamReader *xml) 0455 { 0456 Q_ASSERT(xml->tokenType() == QXmlStreamReader::StartElement); 0457 int ret = readText(xml).toInt(); 0458 0459 xml->readNext(); 0460 Q_ASSERT(xml->tokenType() == QXmlStreamReader::EndElement); 0461 return ret; 0462 } 0463 0464 bool KNSCore::Entry::setEntryXML(QXmlStreamReader &reader) 0465 { 0466 if (reader.name() != QLatin1String("stuff")) { 0467 qCWarning(KNEWSTUFFCORE) << "Parsing Entry from invalid XML. Reader tag name was expected to be \"stuff\", but was found as:" << reader.name(); 0468 return false; 0469 } 0470 0471 d->mCategory = reader.attributes().value(QStringLiteral("category")).toString(); 0472 0473 while (!reader.atEnd()) { 0474 const auto token = readNextSkipComments(&reader); 0475 if (token == QXmlStreamReader::EndElement) { 0476 break; 0477 } else if (token != QXmlStreamReader::StartElement) { 0478 continue; 0479 } 0480 0481 if (reader.name() == QLatin1String("name")) { 0482 // TODO maybe do something with the language attribute? QString lang = e.attribute("lang"); 0483 d->mName = reader.readElementText(QXmlStreamReader::SkipChildElements); 0484 } else if (reader.name() == QLatin1String("author")) { 0485 // ### careful, the following variables are string views that become invalid when we 0486 // proceed with reading from reader, such as the readStringTrimmed call below does! 0487 const auto email = reader.attributes().value(QStringLiteral("email")); 0488 const auto jabber = reader.attributes().value(QStringLiteral("im")); 0489 const auto homepage = reader.attributes().value(QStringLiteral("homepage")); 0490 d->mAuthor.setEmail(email.toString()); 0491 d->mAuthor.setJabber(jabber.toString()); 0492 d->mAuthor.setHomepage(homepage.toString()); 0493 d->mAuthor.setName(readStringTrimmed(&reader)); 0494 } else if (reader.name() == QLatin1String("providerid")) { 0495 d->mProviderId = reader.readElementText(QXmlStreamReader::SkipChildElements); 0496 } else if (reader.name() == QLatin1String("homepage")) { 0497 d->mHomepage = QUrl(reader.readElementText(QXmlStreamReader::SkipChildElements)); 0498 } else if (reader.name() == QLatin1String("licence")) { // krazy:exclude=spelling 0499 d->mLicense = readStringTrimmed(&reader); 0500 } else if (reader.name() == QLatin1String("summary")) { 0501 d->mSummary = reader.readElementText(QXmlStreamReader::SkipChildElements); 0502 } else if (reader.name() == QLatin1String("changelog")) { 0503 d->mChangelog = reader.readElementText(QXmlStreamReader::SkipChildElements); 0504 } else if (reader.name() == QLatin1String("version")) { 0505 d->mVersion = readStringTrimmed(&reader); 0506 } else if (reader.name() == QLatin1String("releasedate")) { 0507 d->mReleaseDate = QDate::fromString(readStringTrimmed(&reader), Qt::ISODate); 0508 } else if (reader.name() == QLatin1String("preview")) { 0509 // TODO support for all 6 image links 0510 d->mPreviewUrl[PreviewSmall1] = readStringTrimmed(&reader); 0511 } else if (reader.name() == QLatin1String("previewBig")) { 0512 d->mPreviewUrl[PreviewBig1] = readStringTrimmed(&reader); 0513 } else if (reader.name() == QLatin1String("payload")) { 0514 d->mPayload = readStringTrimmed(&reader); 0515 } else if (reader.name() == QLatin1String("rating")) { 0516 d->mRating = readInt(&reader); 0517 } else if (reader.name() == QLatin1String("downloads")) { 0518 d->mDownloadCount = readInt(&reader); 0519 } else if (reader.name() == QLatin1String("category")) { 0520 d->mCategory = reader.readElementText(QXmlStreamReader::SkipChildElements); 0521 } else if (reader.name() == QLatin1String("signature")) { 0522 d->mSignature = reader.readElementText(QXmlStreamReader::SkipChildElements); 0523 } else if (reader.name() == QLatin1String("checksum")) { 0524 d->mChecksum = reader.readElementText(QXmlStreamReader::SkipChildElements); 0525 } else if (reader.name() == QLatin1String("installedfile")) { 0526 d->mInstalledFiles.append(reader.readElementText(QXmlStreamReader::SkipChildElements)); 0527 } else if (reader.name() == QLatin1String("id")) { 0528 d->mUniqueId = reader.readElementText(QXmlStreamReader::SkipChildElements); 0529 } else if (reader.name() == QLatin1String("tags")) { 0530 d->mTags = reader.readElementText(QXmlStreamReader::SkipChildElements).split(QLatin1Char(',')); 0531 } else if (reader.name() == QLatin1String("status")) { 0532 const auto statusText = readText(&reader); 0533 if (statusText == QLatin1String("installed")) { 0534 qCDebug(KNEWSTUFFCORE) << "Found an installed entry in registry"; 0535 d->mStatus = KNSCore::Entry::Installed; 0536 } else if (statusText == QLatin1String("updateable")) { 0537 d->mStatus = KNSCore::Entry::Updateable; 0538 } 0539 if (reader.tokenType() == QXmlStreamReader::Characters) { 0540 readNextSkipComments(&reader); 0541 } 0542 } 0543 Q_ASSERT_X(reader.tokenType() == QXmlStreamReader::EndElement, 0544 Q_FUNC_INFO, 0545 QStringLiteral("token name was %1 and the type was %2").arg(reader.name().toString(), reader.tokenString()).toLocal8Bit().data()); 0546 } 0547 0548 // Validation 0549 if (d->mName.isEmpty()) { 0550 qWarning() << "Entry: no name given"; 0551 return false; 0552 } 0553 0554 if (d->mUniqueId.isEmpty()) { 0555 if (!d->mPayload.isEmpty()) { 0556 d->mUniqueId = d->mPayload; 0557 } else { 0558 d->mUniqueId = d->mName; 0559 } 0560 } 0561 0562 if (d->mPayload.isEmpty()) { 0563 qWarning() << "Entry: no payload URL given for: " << d->mName << " - " << d->mUniqueId; 0564 return false; 0565 } 0566 return true; 0567 } 0568 0569 bool KNSCore::Entry::setEntryXML(const QDomElement &xmldata) 0570 { 0571 if (xmldata.tagName() != QLatin1String("stuff")) { 0572 qWarning() << "Parsing Entry from invalid XML"; 0573 return false; 0574 } 0575 0576 d->mCategory = xmldata.attribute(QStringLiteral("category")); 0577 0578 QDomNode n; 0579 for (n = xmldata.firstChild(); !n.isNull(); n = n.nextSibling()) { 0580 QDomElement e = n.toElement(); 0581 if (e.tagName() == QLatin1String("name")) { 0582 // TODO maybe do something with the language attribute? QString lang = e.attribute("lang"); 0583 d->mName = e.text().trimmed(); 0584 } else if (e.tagName() == QLatin1String("author")) { 0585 QString email = e.attribute(QStringLiteral("email")); 0586 QString jabber = e.attribute(QStringLiteral("im")); 0587 QString homepage = e.attribute(QStringLiteral("homepage")); 0588 d->mAuthor.setName(e.text().trimmed()); 0589 d->mAuthor.setEmail(email); 0590 d->mAuthor.setJabber(jabber); 0591 d->mAuthor.setHomepage(homepage); 0592 } else if (e.tagName() == QLatin1String("providerid")) { 0593 d->mProviderId = e.text(); 0594 } else if (e.tagName() == QLatin1String("homepage")) { 0595 d->mHomepage = QUrl(e.text()); 0596 } else if (e.tagName() == QLatin1String("licence")) { // krazy:exclude=spelling 0597 d->mLicense = e.text().trimmed(); 0598 } else if (e.tagName() == QLatin1String("summary")) { 0599 d->mSummary = e.text(); 0600 } else if (e.tagName() == QLatin1String("changelog")) { 0601 d->mChangelog = e.text(); 0602 } else if (e.tagName() == QLatin1String("version")) { 0603 d->mVersion = e.text().trimmed(); 0604 } else if (e.tagName() == QLatin1String("releasedate")) { 0605 d->mReleaseDate = QDate::fromString(e.text().trimmed(), Qt::ISODate); 0606 } else if (e.tagName() == QLatin1String("preview")) { 0607 // TODO support for all 6 image links 0608 d->mPreviewUrl[PreviewSmall1] = e.text().trimmed(); 0609 } else if (e.tagName() == QLatin1String("previewBig")) { 0610 d->mPreviewUrl[PreviewBig1] = e.text().trimmed(); 0611 } else if (e.tagName() == QLatin1String("payload")) { 0612 d->mPayload = e.text().trimmed(); 0613 } else if (e.tagName() == QLatin1String("rating")) { 0614 d->mRating = e.text().toInt(); 0615 } else if (e.tagName() == QLatin1String("downloads")) { 0616 d->mDownloadCount = e.text().toInt(); 0617 } else if (e.tagName() == QLatin1String("category")) { 0618 d->mCategory = e.text(); 0619 } else if (e.tagName() == QLatin1String("signature")) { 0620 d->mSignature = e.text(); 0621 } else if (e.tagName() == QLatin1String("checksum")) { 0622 d->mChecksum = e.text(); 0623 } else if (e.tagName() == QLatin1String("installedfile")) { 0624 // TODO KF6 Add a "installeddirectory" entry to avoid 0625 // all the issues with the "/*" notation which is currently used as a workaround 0626 d->mInstalledFiles.append(e.text()); 0627 } else if (e.tagName() == QLatin1String("id")) { 0628 d->mUniqueId = e.text(); 0629 } else if (e.tagName() == QLatin1String("tags")) { 0630 d->mTags = e.text().split(QLatin1Char(',')); 0631 } else if (e.tagName() == QLatin1String("status")) { 0632 QString statusText = e.text(); 0633 if (statusText == QLatin1String("installed")) { 0634 qCDebug(KNEWSTUFFCORE) << "Found an installed entry in registry"; 0635 d->mStatus = KNSCore::Entry::Installed; 0636 } else if (statusText == QLatin1String("updateable")) { 0637 d->mStatus = KNSCore::Entry::Updateable; 0638 } 0639 } 0640 } 0641 0642 // Validation 0643 if (d->mName.isEmpty()) { 0644 qWarning() << "Entry: no name given"; 0645 return false; 0646 } 0647 0648 if (d->mUniqueId.isEmpty()) { 0649 if (!d->mPayload.isEmpty()) { 0650 d->mUniqueId = d->mPayload; 0651 } else { 0652 d->mUniqueId = d->mName; 0653 } 0654 } 0655 0656 if (d->mPayload.isEmpty()) { 0657 qWarning() << "Entry: no payload URL given for: " << d->mName << " - " << d->mUniqueId; 0658 return false; 0659 } 0660 return true; 0661 } 0662 0663 /** 0664 * get the xml string for the entry 0665 */ 0666 QDomElement KNSCore::Entry::entryXML() const 0667 { 0668 Q_ASSERT(!d->mUniqueId.isEmpty()); 0669 Q_ASSERT(!d->mProviderId.isEmpty()); 0670 0671 QDomDocument doc; 0672 0673 QDomElement el = doc.createElement(QStringLiteral("stuff")); 0674 el.setAttribute(QStringLiteral("category"), d->mCategory); 0675 0676 QString name = d->mName; 0677 0678 QDomElement e; 0679 e = addElement(doc, el, QStringLiteral("name"), name); 0680 // todo: add language attribute 0681 (void)addElement(doc, el, QStringLiteral("providerid"), d->mProviderId); 0682 0683 QDomElement author = addElement(doc, el, QStringLiteral("author"), d->mAuthor.name()); 0684 if (!d->mAuthor.email().isEmpty()) { 0685 author.setAttribute(QStringLiteral("email"), d->mAuthor.email()); 0686 } 0687 if (!d->mAuthor.homepage().isEmpty()) { 0688 author.setAttribute(QStringLiteral("homepage"), d->mAuthor.homepage()); 0689 } 0690 if (!d->mAuthor.jabber().isEmpty()) { 0691 author.setAttribute(QStringLiteral("im"), d->mAuthor.jabber()); 0692 } 0693 // FIXME: 'jabber' or 'im'? consult with kopete guys... 0694 addElement(doc, el, QStringLiteral("homepage"), d->mHomepage.url()); 0695 (void)addElement(doc, el, QStringLiteral("licence"), d->mLicense); // krazy:exclude=spelling 0696 (void)addElement(doc, el, QStringLiteral("version"), d->mVersion); 0697 if ((d->mRating > 0) || (d->mDownloadCount > 0)) { 0698 (void)addElement(doc, el, QStringLiteral("rating"), QString::number(d->mRating)); 0699 (void)addElement(doc, el, QStringLiteral("downloads"), QString::number(d->mDownloadCount)); 0700 } 0701 if (!d->mSignature.isEmpty()) { 0702 (void)addElement(doc, el, QStringLiteral("signature"), d->mSignature); 0703 } 0704 if (!d->mChecksum.isEmpty()) { 0705 (void)addElement(doc, el, QStringLiteral("checksum"), d->mChecksum); 0706 } 0707 for (const QString &file : std::as_const(d->mInstalledFiles)) { 0708 (void)addElement(doc, el, QStringLiteral("installedfile"), file); 0709 } 0710 if (!d->mUniqueId.isEmpty()) { 0711 addElement(doc, el, QStringLiteral("id"), d->mUniqueId); 0712 } 0713 0714 (void)addElement(doc, el, QStringLiteral("releasedate"), d->mReleaseDate.toString(Qt::ISODate)); 0715 0716 e = addElement(doc, el, QStringLiteral("summary"), d->mSummary); 0717 e = addElement(doc, el, QStringLiteral("changelog"), d->mChangelog); 0718 e = addElement(doc, el, QStringLiteral("preview"), d->mPreviewUrl[PreviewSmall1]); 0719 e = addElement(doc, el, QStringLiteral("previewBig"), d->mPreviewUrl[PreviewBig1]); 0720 e = addElement(doc, el, QStringLiteral("payload"), d->mPayload); 0721 e = addElement(doc, el, QStringLiteral("tags"), d->mTags.join(QLatin1Char(','))); 0722 0723 if (d->mStatus == KNSCore::Entry::Installed) { 0724 (void)addElement(doc, el, QStringLiteral("status"), QStringLiteral("installed")); 0725 } 0726 if (d->mStatus == KNSCore::Entry::Updateable) { 0727 (void)addElement(doc, el, QStringLiteral("status"), QStringLiteral("updateable")); 0728 } 0729 0730 return el; 0731 } 0732 0733 void KNSCore::Entry::setEntryDeleted() 0734 { 0735 setStatus(Entry::Deleted); 0736 d->mUnInstalledFiles = installedFiles(); 0737 setInstalledFiles(QStringList()); 0738 } 0739 0740 void KNSCore::Entry::setEntryRequestedId(const QString &id) 0741 { 0742 d->mRequestedUniqueId = id; 0743 } 0744 0745 QString KNSCore::replaceBBCode(const QString &unformattedText) 0746 { 0747 QString text(unformattedText); 0748 text.replace(QLatin1String("[b]"), QLatin1String("<b>")); 0749 text.replace(QLatin1String("[/b]"), QLatin1String("</b>")); 0750 text.replace(QLatin1String("[i]"), QLatin1String("<i>")); 0751 text.replace(QLatin1String("[/i]"), QLatin1String("</i>")); 0752 text.replace(QLatin1String("[u]"), QLatin1String("<i>")); 0753 text.replace(QLatin1String("[/u]"), QLatin1String("</i>")); 0754 text.replace(QLatin1String("\\\""), QLatin1String("\"")); 0755 text.replace(QLatin1String("\\\'"), QLatin1String("\'")); 0756 text.replace(QLatin1String("[li]"), QLatin1String("* ")); // TODO: better replacement for list elements? 0757 text.remove(QStringLiteral("[/li]")); 0758 text.remove(QStringLiteral("[url]")); 0759 text.remove(QStringLiteral("[/url]")); 0760 return text; 0761 } 0762 0763 QDebug KNSCore::operator<<(QDebug debug, const KNSCore::Entry &entry) 0764 { 0765 QDebugStateSaver saver(debug); 0766 0767 const static QMetaEnum metaEnum = QMetaEnum::fromType<KNSCore::Entry::Status>(); 0768 bool deleted = entry.status() == Entry::Status::Deleted; 0769 0770 debug.nospace() << "KNSCore::Entry(uniqueId: " << entry.uniqueId() << ", name:" << entry.name() << ", status: " << metaEnum.valueToKey(entry.status()) 0771 << ", " << (deleted ? "uninstalled" : "installed") << "Files: " // When the entry is installed, it can not have uninstalledFiles 0772 << (deleted ? entry.uninstalledFiles() : entry.installedFiles()) << ')'; 0773 return debug; 0774 } 0775 0776 #include "moc_entry.cpp"