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