File indexing completed on 2024-05-19 11:43:33
0001 /* 0002 SPDX-FileCopyrightText: 2009 Frederik Gladhorn <gladhorn@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "entrydetailsdialog_p.h" 0008 0009 #include <KLocalizedString> 0010 #include <QMenu> 0011 #include <knewstuff_debug.h> 0012 0013 #include "core/engine.h" 0014 #include "core/imageloader_p.h" 0015 #include <attica/provider.h> 0016 0017 using namespace KNS3; 0018 0019 EntryDetails::EntryDetails(KNSCore::Engine *engine, Ui::DownloadWidget *widget) 0020 : QObject(widget->m_listView) 0021 , m_engine(engine) 0022 , ui(widget) 0023 { 0024 init(); 0025 } 0026 0027 EntryDetails::~EntryDetails() 0028 { 0029 } 0030 0031 void EntryDetails::init() 0032 { 0033 connect(ui->preview1, &ImagePreviewWidget::clicked, this, &EntryDetails::preview1Selected); 0034 connect(ui->preview2, &ImagePreviewWidget::clicked, this, &EntryDetails::preview2Selected); 0035 connect(ui->preview3, &ImagePreviewWidget::clicked, this, &EntryDetails::preview3Selected); 0036 0037 ui->ratingWidget->setMaxRating(10); 0038 ui->ratingWidget->setHalfStepsEnabled(true); 0039 0040 updateButtons(); 0041 connect(ui->installButton, &QAbstractButton::clicked, this, &EntryDetails::install); 0042 connect(ui->uninstallButton, &QAbstractButton::clicked, this, &EntryDetails::uninstall); 0043 // updating is the same as installing 0044 connect(ui->updateButton, &QAbstractButton::clicked, this, &EntryDetails::install); 0045 connect(ui->becomeFanButton, &QAbstractButton::clicked, this, &EntryDetails::becomeFan); 0046 0047 ui->installButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok"))); 0048 ui->updateButton->setIcon(QIcon::fromTheme(QStringLiteral("system-software-update"))); 0049 ui->uninstallButton->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); 0050 0051 connect(m_engine, &KNSCore::Engine::signalEntryEvent, this, [this](const KNSCore::EntryInternal &entry, KNSCore::EntryInternal::EntryEvent event) { 0052 if (event == KNSCore::EntryInternal::DetailsLoadedEvent) { 0053 Q_EMIT entryChanged(entry); 0054 } else if (event == KNSCore::EntryInternal::StatusChangedEvent) { 0055 updateButtons(); 0056 } 0057 }); 0058 connect(m_engine, &KNSCore::Engine::signalEntryPreviewLoaded, this, &EntryDetails::slotEntryPreviewLoaded); 0059 } 0060 0061 void EntryDetails::setEntry(const KNSCore::EntryInternal &entry) 0062 { 0063 m_entry = entry; 0064 // immediately show something 0065 entryChanged(m_entry); 0066 // fetch more preview images 0067 m_engine->loadDetails(m_entry); 0068 } 0069 0070 void EntryDetails::entryChanged(const KNSCore::EntryInternal &entry) 0071 { 0072 if (ui->detailsStack->currentIndex() == 0) { 0073 return; 0074 } 0075 m_entry = entry; 0076 0077 // FIXME 0078 // ui->ratingWidget->setEditable(m_engine->userCanVote(m_entry)); 0079 0080 if (!m_engine->userCanBecomeFan(m_entry)) { 0081 ui->becomeFanButton->setEnabled(false); 0082 } 0083 0084 ui->m_titleWidget->setText(i18n("Details for %1", m_entry.name())); 0085 if (!m_entry.author().homepage().isEmpty()) { 0086 ui->authorLabel->setText(QLatin1String("<a href=\"") + m_entry.author().homepage() + QLatin1String("\">") + m_entry.author().name() 0087 + QLatin1String("</a>")); 0088 } else if (!m_entry.author().email().isEmpty()) { 0089 ui->authorLabel->setText(QLatin1String("<a href=\"mailto:") + m_entry.author().email() + QLatin1String("\">") + m_entry.author().name() 0090 + QLatin1String("</a>")); 0091 } else { 0092 ui->authorLabel->setText(m_entry.author().name()); 0093 } 0094 0095 QString summary = KNSCore::replaceBBCode(m_entry.summary()).replace(QLatin1Char('\n'), QLatin1String("<br/>")); 0096 QString changelog = KNSCore::replaceBBCode(m_entry.changelog()).replace(QLatin1Char('\n'), QLatin1String("<br/>")); 0097 0098 QString description = QLatin1String("<html><body>") + summary; 0099 if (!changelog.isEmpty()) { 0100 description += QLatin1String("<br/><p><b>") + i18n("Changelog:") + QLatin1String("</b><br/>") + changelog + QLatin1String("</p>"); 0101 } 0102 description += QLatin1String("</body></html>"); 0103 ui->descriptionLabel->setText(description); 0104 0105 QString homepageText(QLatin1String("<a href=\"") + m_entry.homepage().url() + QLatin1String("\">") 0106 + i18nc("A link to the description of this Get Hot New Stuff item", "Homepage") + QStringLiteral("</a>")); 0107 0108 if (!m_entry.donationLink().isEmpty()) { 0109 homepageText += QLatin1String("<br><a href=\"") + m_entry.donationLink() + QLatin1String("\">") 0110 + i18nc("A link to make a donation for a Get Hot New Stuff item (opens a web browser)", "Make a donation") + QLatin1String("</a>"); 0111 } 0112 if (!m_entry.knowledgebaseLink().isEmpty()) { 0113 homepageText += QLatin1String("<br><a href=\"") + m_entry.knowledgebaseLink() + QLatin1String("\">") 0114 + i18ncp("A link to the knowledgebase (like a forum) (opens a web browser)", 0115 "Knowledgebase (no entries)", 0116 "Knowledgebase (%1 entries)", 0117 m_entry.numberKnowledgebaseEntries()) 0118 + QStringLiteral("</a>"); 0119 } 0120 ui->homepageLabel->setText(homepageText); 0121 ui->homepageLabel->setToolTip(i18nc("Tooltip for a link in a dialog", "Opens in a browser window")); 0122 0123 if (m_entry.rating() > 0) { 0124 ui->ratingWidget->setVisible(true); 0125 disconnect(ui->ratingWidget, &KRatingWidget::ratingChanged, this, &EntryDetails::ratingChanged); 0126 // Most of the voting is 20 - 80, so rate 20 as 0 stars and 80 as 5 stars 0127 int rating = qMax(0, qMin(10, (m_entry.rating() - 20) / 6)); 0128 ui->ratingWidget->setRating(rating); 0129 connect(ui->ratingWidget, &KRatingWidget::ratingChanged, this, &EntryDetails::ratingChanged); 0130 } else { 0131 ui->ratingWidget->setVisible(false); 0132 } 0133 0134 bool hideSmallPreviews = 0135 m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall2).isEmpty() && m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall3).isEmpty(); 0136 0137 ui->preview1->setVisible(!hideSmallPreviews); 0138 ui->preview2->setVisible(!hideSmallPreviews); 0139 ui->preview3->setVisible(!hideSmallPreviews); 0140 0141 // in static xml we often only get a small preview, use that in details 0142 if (m_entry.previewUrl(KNSCore::EntryInternal::PreviewBig1).isEmpty() && !m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1).isEmpty()) { 0143 m_entry.setPreviewUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1), KNSCore::EntryInternal::PreviewBig1); 0144 m_entry.setPreviewImage(m_entry.previewImage(KNSCore::EntryInternal::PreviewSmall1), KNSCore::EntryInternal::PreviewBig1); 0145 } 0146 0147 for (int type = KNSCore::EntryInternal::PreviewSmall1; type <= KNSCore::EntryInternal::PreviewBig3; ++type) { 0148 if (m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1).isEmpty()) { 0149 ui->previewBig->setVisible(false); 0150 } else 0151 0152 if (!m_entry.previewUrl((KNSCore::EntryInternal::PreviewType)type).isEmpty()) { 0153 qCDebug(KNEWSTUFF) << "type: " << type << m_entry.previewUrl((KNSCore::EntryInternal::PreviewType)type); 0154 if (m_entry.previewImage((KNSCore::EntryInternal::PreviewType)type).isNull()) { 0155 m_engine->loadPreview(m_entry, (KNSCore::EntryInternal::PreviewType)type); 0156 } else { 0157 slotEntryPreviewLoaded(m_entry, (KNSCore::EntryInternal::PreviewType)type); 0158 } 0159 } 0160 } 0161 0162 updateButtons(); 0163 } 0164 0165 void EntryDetails::updateButtons() 0166 { 0167 if (ui->detailsStack->currentIndex() == 0) { 0168 return; 0169 } 0170 qCDebug(KNEWSTUFF) << "update buttons: " << m_entry.status(); 0171 ui->installButton->setVisible(false); 0172 ui->uninstallButton->setVisible(false); 0173 ui->updateButton->setVisible(false); 0174 0175 switch (m_entry.status()) { 0176 case Entry::Installed: 0177 ui->uninstallButton->setVisible(true); 0178 ui->uninstallButton->setEnabled(true); 0179 break; 0180 case Entry::Updateable: 0181 ui->updateButton->setVisible(true); 0182 ui->updateButton->setEnabled(true); 0183 ui->uninstallButton->setVisible(true); 0184 ui->uninstallButton->setEnabled(true); 0185 break; 0186 0187 case Entry::Invalid: 0188 case Entry::Downloadable: 0189 ui->installButton->setVisible(true); 0190 ui->installButton->setEnabled(true); 0191 break; 0192 0193 case Entry::Installing: 0194 ui->installButton->setVisible(true); 0195 ui->installButton->setEnabled(false); 0196 break; 0197 case Entry::Updating: 0198 ui->updateButton->setVisible(true); 0199 ui->updateButton->setEnabled(false); 0200 ui->uninstallButton->setVisible(true); 0201 ui->uninstallButton->setEnabled(false); 0202 break; 0203 case Entry::Deleted: 0204 ui->installButton->setVisible(true); 0205 ui->installButton->setEnabled(true); 0206 break; 0207 } 0208 0209 if (QMenu *buttonMenu = ui->installButton->menu()) { 0210 buttonMenu->clear(); 0211 ui->installButton->setMenu(nullptr); 0212 buttonMenu->deleteLater(); 0213 } 0214 if (ui->installButton->isVisible() && m_entry.downloadLinkCount() > 1) { 0215 QMenu *installMenu = new QMenu(ui->installButton); 0216 const auto lst = m_entry.downloadLinkInformationList(); 0217 for (const KNSCore::EntryInternal::DownloadLinkInformation &info : lst) { 0218 QString text = info.name; 0219 if (!info.distributionType.trimmed().isEmpty()) { 0220 text + QStringLiteral(" (") + info.distributionType.trimmed() + QLatin1Char(')'); 0221 } 0222 QAction *installMenuAction = installMenu->addAction(QIcon::fromTheme(QStringLiteral("dialog-ok")), text); 0223 installMenuAction->setData(info.id); 0224 connect(installMenuAction, &QAction::triggered, this, [this, installMenuAction]() { 0225 installAction(installMenuAction); 0226 }); 0227 } 0228 qCDebug(KNEWSTUFF) << "links: " << m_entry.downloadLinkInformationList().size(); 0229 ui->installButton->setMenu(installMenu); 0230 } 0231 } 0232 0233 void EntryDetails::install() 0234 { 0235 m_engine->install(m_entry); 0236 } 0237 0238 void EntryDetails::uninstall() 0239 { 0240 m_engine->uninstall(m_entry); 0241 } 0242 0243 void EntryDetails::slotEntryPreviewLoaded(const KNSCore::EntryInternal &entry, KNSCore::EntryInternal::PreviewType type) 0244 { 0245 if (!(entry == m_entry)) { 0246 return; 0247 } 0248 0249 switch (type) { 0250 case KNSCore::EntryInternal::PreviewSmall1: 0251 ui->preview1->setImage(entry.previewImage(KNSCore::EntryInternal::PreviewSmall1)); 0252 break; 0253 case KNSCore::EntryInternal::PreviewSmall2: 0254 ui->preview2->setImage(entry.previewImage(KNSCore::EntryInternal::PreviewSmall2)); 0255 break; 0256 case KNSCore::EntryInternal::PreviewSmall3: 0257 ui->preview3->setImage(entry.previewImage(KNSCore::EntryInternal::PreviewSmall3)); 0258 break; 0259 case KNSCore::EntryInternal::PreviewBig1: 0260 m_currentPreview = entry.previewImage(KNSCore::EntryInternal::PreviewBig1); 0261 ui->previewBig->setImage(m_currentPreview); 0262 break; 0263 default: 0264 break; 0265 } 0266 } 0267 0268 void EntryDetails::preview1Selected() 0269 { 0270 previewSelected(0); 0271 } 0272 0273 void EntryDetails::preview2Selected() 0274 { 0275 previewSelected(1); 0276 } 0277 0278 void EntryDetails::preview3Selected() 0279 { 0280 previewSelected(2); 0281 } 0282 0283 void EntryDetails::previewSelected(int current) 0284 { 0285 KNSCore::EntryInternal::PreviewType type = static_cast<KNSCore::EntryInternal::PreviewType>(KNSCore::EntryInternal::PreviewBig1 + current); 0286 m_currentPreview = m_entry.previewImage(type); 0287 ui->previewBig->setImage(m_currentPreview); 0288 } 0289 0290 void EntryDetails::ratingChanged(int rating) 0291 { 0292 // engine expects values from 0..100 0293 qCDebug(KNEWSTUFF) << "rating: " << rating << " -> " << rating * 10; 0294 m_engine->vote(m_entry, rating * 10); 0295 } 0296 0297 void EntryDetails::becomeFan() 0298 { 0299 m_engine->becomeFan(m_entry); 0300 } 0301 0302 void EntryDetails::installAction(QAction *action) 0303 { 0304 m_engine->install(m_entry, action->data().toInt()); 0305 } 0306 0307 #include "moc_entrydetailsdialog_p.cpp"