File indexing completed on 2024-10-06 12:23:26
0001 /* 0002 knewstuff3/ui/downloaddialog.cpp. 0003 SPDX-FileCopyrightText: 2005 Enrico Ros <eros.kde@email.it> 0004 SPDX-FileCopyrightText: 2005-2007 Josef Spillner <spillner@kde.org> 0005 SPDX-FileCopyrightText: 2007 Dirk Mueller <mueller@kde.org> 0006 SPDX-FileCopyrightText: 2007-2009 Jeremy Whiting <jpwhiting@kde.org> 0007 SPDX-FileCopyrightText: 2009-2010 Frederik Gladhorn <gladhorn@kde.org> 0008 SPDX-FileCopyrightText: 2010 Reza Fatahilah Shah <rshah0385@kireihana.com> 0009 0010 SPDX-License-Identifier: LGPL-2.1-or-later 0011 */ 0012 0013 #include "downloadwidget.h" 0014 0015 #if KNEWSTUFF_BUILD_DEPRECATED_SINCE(5, 80) 0016 0017 #include "downloadwidget_p.h" 0018 0019 #include <QCoreApplication> 0020 #include <QScrollBar> 0021 #include <QTimer> 0022 0023 #include <KLocalizedString> 0024 #include <KMessageBox> 0025 #include <knewstuff_debug.h> 0026 0027 #include "core/itemsmodel.h" 0028 0029 #include "ui/itemsgridviewdelegate_p.h" 0030 #include "ui/itemsviewdelegate_p.h" 0031 #include "ui/widgetquestionlistener.h" 0032 0033 #include "entry_p.h" 0034 0035 using namespace KNS3; 0036 0037 DownloadWidget::DownloadWidget(QWidget *parent) 0038 : QWidget(parent) 0039 , d(new DownloadWidgetPrivate(this)) 0040 { 0041 const QString name = QCoreApplication::applicationName(); 0042 init(name + QStringLiteral(".knsrc")); 0043 } 0044 0045 DownloadWidget::DownloadWidget(const QString &configFile, QWidget *parent) 0046 : QWidget(parent) 0047 , d(new DownloadWidgetPrivate(this)) 0048 { 0049 init(configFile); 0050 } 0051 0052 void DownloadWidget::init(const QString &configFile) 0053 { 0054 d->init(configFile); 0055 WidgetQuestionListener::instance(); 0056 } 0057 0058 DownloadWidget::~DownloadWidget() 0059 { 0060 delete d; 0061 } 0062 0063 void DownloadWidget::setTitle(const QString &title) 0064 { 0065 d->ui.m_titleWidget->setText(title); 0066 } 0067 0068 QString DownloadWidget::title() const 0069 { 0070 return d->ui.m_titleWidget->text(); 0071 } 0072 0073 KNSCore::Engine *DownloadWidget::engine() 0074 { 0075 return d->engine; 0076 } 0077 0078 Entry::List DownloadWidget::changedEntries() 0079 { 0080 Entry::List entries; 0081 entries.reserve(d->changedEntries.count()); 0082 for (const KNSCore::EntryInternal &e : std::as_const(d->changedEntries)) { 0083 entries.append(EntryPrivate::fromInternal(&e)); 0084 } 0085 return entries; 0086 } 0087 0088 Entry::List DownloadWidget::installedEntries() 0089 { 0090 Entry::List entries; 0091 for (const KNSCore::EntryInternal &e : std::as_const(d->changedEntries)) { 0092 if (e.status() == Entry::Installed) { 0093 entries.append(EntryPrivate::fromInternal(&e)); 0094 } 0095 } 0096 return entries; 0097 } 0098 0099 DownloadWidgetPrivate::DownloadWidgetPrivate(DownloadWidget *qq) 0100 : q(qq) 0101 , engine(new KNSCore::Engine) 0102 , model(new KNSCore::ItemsModel(engine)) 0103 , messageTimer(nullptr) 0104 , dialogMode(false) 0105 { 0106 } 0107 0108 DownloadWidgetPrivate::~DownloadWidgetPrivate() 0109 { 0110 delete messageTimer; 0111 delete delegate; 0112 delete model; 0113 delete engine; 0114 } 0115 0116 void DownloadWidgetPrivate::slotResetMessage() // SLOT 0117 { 0118 ui.m_titleWidget->setComment(QString()); 0119 } 0120 0121 void DownloadWidgetPrivate::slotNetworkTimeout() // SLOT 0122 { 0123 displayMessage(i18n("Timeout. Check Internet connection."), KTitleWidget::ErrorMessage); 0124 } 0125 0126 void DownloadWidgetPrivate::sortingChanged() 0127 { 0128 KNSCore::Provider::SortMode sortMode = KNSCore::Provider::Downloads; 0129 KNSCore::Provider::Filter filter = KNSCore::Provider::None; 0130 if (ui.ratingRadio->isChecked()) { 0131 sortMode = KNSCore::Provider::Rating; 0132 } else if (ui.newestRadio->isChecked()) { 0133 sortMode = KNSCore::Provider::Newest; 0134 } else if (ui.mostDownloadsRadio->isChecked()) { 0135 sortMode = KNSCore::Provider::Downloads; 0136 } else if (ui.installedRadio->isChecked()) { 0137 filter = KNSCore::Provider::Installed; 0138 } 0139 0140 model->clearEntries(); 0141 if (filter == KNSCore::Provider::Installed) { 0142 ui.m_searchEdit->clear(); 0143 } 0144 ui.m_searchEdit->setEnabled(filter != KNSCore::Provider::Installed); 0145 0146 engine->setSortMode(sortMode); 0147 engine->setFilter(filter); 0148 } 0149 0150 void DownloadWidgetPrivate::slotUpdateSearch() 0151 { 0152 if (searchTerm == ui.m_searchEdit->text().trimmed()) { 0153 return; 0154 } 0155 searchTerm = ui.m_searchEdit->text().trimmed(); 0156 } 0157 0158 void DownloadWidgetPrivate::slotSearchTextChanged() 0159 { 0160 if (searchTerm == ui.m_searchEdit->text().trimmed()) { 0161 return; 0162 } 0163 searchTerm = ui.m_searchEdit->text().trimmed(); 0164 engine->setSearchTerm(searchTerm); 0165 } 0166 0167 void DownloadWidgetPrivate::slotCategoryChanged(int idx) 0168 { 0169 if (idx == 0) { 0170 // All Categories item selected, reset filter 0171 engine->setCategoriesFilter(QStringList()); 0172 0173 } else { 0174 const QString category = ui.m_categoryCombo->currentData().toString(); 0175 0176 if (!category.isEmpty()) { 0177 QStringList filter(category); 0178 engine->setCategoriesFilter(filter); 0179 } 0180 } 0181 } 0182 0183 void DownloadWidgetPrivate::slotInfo(QString provider, QString server, QString version) 0184 { 0185 QString link = QStringLiteral("<a href=\"%1\">%1</a>").arg(server); 0186 QString infostring = i18n("Server: %1", link); 0187 infostring += i18n("<br />Provider: %1", provider); 0188 infostring += i18n("<br />Version: %1", version); 0189 0190 KMessageBox::information(nullptr, infostring, i18n("Provider information")); 0191 } 0192 0193 void DownloadWidgetPrivate::slotEntryEvent(const KNSCore::EntryInternal &entry, KNSCore::EntryInternal::EntryEvent event) 0194 { 0195 if (event == KNSCore::EntryInternal::StatusChangedEvent) { 0196 changedEntries.insert(entry); 0197 model->slotEntryChanged(entry); 0198 } 0199 } 0200 0201 void DownloadWidgetPrivate::slotPayloadFailed(const KNSCore::EntryInternal &entry) 0202 { 0203 KMessageBox::error(nullptr, i18n("Could not install %1", entry.name()), i18n("Get Hot New Stuff!")); 0204 } 0205 0206 void DownloadWidgetPrivate::slotPayloadLoaded(QUrl url) 0207 { 0208 Q_UNUSED(url) 0209 } 0210 0211 void DownloadWidgetPrivate::slotError(const QString &message) 0212 { 0213 KMessageBox::error(nullptr, message, i18n("Get Hot New Stuff")); 0214 } 0215 0216 void DownloadWidgetPrivate::scrollbarValueChanged(int value) 0217 { 0218 if (static_cast<double>(value) / ui.m_listView->verticalScrollBar()->maximum() > 0.9) { 0219 engine->requestMoreData(); 0220 } 0221 } 0222 0223 void DownloadWidgetPrivate::init(const QString &configFile) 0224 { 0225 m_configFile = configFile; 0226 ui.setupUi(q); 0227 ui.m_titleWidget->setVisible(false); 0228 ui.closeButton->setVisible(dialogMode); 0229 ui.backButton->setVisible(false); 0230 KStandardGuiItem::assign(ui.backButton, KStandardGuiItem::Back); 0231 q->connect(ui.backButton, &QPushButton::clicked, this, &DownloadWidgetPrivate::slotShowOverview); 0232 0233 q->connect(engine, &KNSCore::Engine::signalMessage, this, &DownloadWidgetPrivate::slotShowMessage); 0234 0235 q->connect(engine, &KNSCore::Engine::signalErrorCode, ui.progressIndicator, &ProgressIndicator::error); 0236 q->connect(engine, &KNSCore::Engine::busyStateChanged, this, [this]() { 0237 if (!engine->busyState()) { 0238 ui.progressIndicator->idle(QString()); 0239 } else { 0240 ui.progressIndicator->busy(engine->busyMessage()); 0241 } 0242 }); 0243 0244 q->connect(engine, &KNSCore::Engine::signalProvidersLoaded, this, &DownloadWidgetPrivate::slotProvidersLoaded); 0245 // Entries have been fetched and should be shown: 0246 q->connect(engine, &KNSCore::Engine::signalEntriesLoaded, this, &DownloadWidgetPrivate::slotEntriesLoaded); 0247 0248 // An entry has changes - eg because it was installed 0249 q->connect(engine, &KNSCore::Engine::signalEntryEvent, this, &DownloadWidgetPrivate::slotEntryEvent); 0250 0251 q->connect(engine, &KNSCore::Engine::signalResetView, model, &KNSCore::ItemsModel::clearEntries); 0252 q->connect(engine, &KNSCore::Engine::signalEntryPreviewLoaded, model, &KNSCore::ItemsModel::slotEntryPreviewLoaded); 0253 0254 engine->init(configFile); 0255 engine->setSortMode(KNSCore::Provider::Downloads); 0256 0257 delegate = new ItemsViewDelegate(ui.m_listView, engine, q); 0258 ui.m_listView->setItemDelegate(delegate); 0259 ui.m_listView->setModel(model); 0260 0261 ui.iconViewButton->setIcon(QIcon::fromTheme(QStringLiteral("view-list-icons"))); 0262 ui.iconViewButton->setToolTip(i18n("Icons view mode")); 0263 ui.listViewButton->setIcon(QIcon::fromTheme(QStringLiteral("view-list-details"))); 0264 ui.listViewButton->setToolTip(i18n("Details view mode")); 0265 0266 q->connect(ui.listViewButton, &QPushButton::clicked, this, &DownloadWidgetPrivate::slotListViewListMode); 0267 q->connect(ui.iconViewButton, &QPushButton::clicked, this, &DownloadWidgetPrivate::slotListViewIconMode); 0268 0269 q->connect(ui.newestRadio, &QRadioButton::clicked, this, &DownloadWidgetPrivate::sortingChanged); 0270 q->connect(ui.ratingRadio, &QRadioButton::clicked, this, &DownloadWidgetPrivate::sortingChanged); 0271 q->connect(ui.mostDownloadsRadio, &QRadioButton::clicked, this, &DownloadWidgetPrivate::sortingChanged); 0272 q->connect(ui.installedRadio, &QRadioButton::clicked, this, &DownloadWidgetPrivate::sortingChanged); 0273 0274 q->connect(ui.m_searchEdit, &KLineEdit::textChanged, this, &DownloadWidgetPrivate::slotSearchTextChanged); 0275 q->connect(ui.m_searchEdit, &KLineEdit::editingFinished, this, &DownloadWidgetPrivate::slotUpdateSearch); 0276 0277 ui.m_providerLabel->setVisible(false); 0278 ui.m_providerCombo->setVisible(false); 0279 ui.m_providerCombo->addItem(i18n("All Providers")); 0280 0281 QStringList categories = engine->categories(); 0282 if (categories.size() < 2) { 0283 ui.m_categoryLabel->setVisible(false); 0284 ui.m_categoryCombo->setVisible(false); 0285 } else { 0286 ui.m_categoryCombo->addItem(i18n("All Categories")); 0287 // NOTE: categories will be populated when we will get metadata from the server 0288 } 0289 0290 connect(engine, &KNSCore::Engine::signalCategoriesMetadataLoded, this, [this](const QList<KNSCore::Provider::CategoryMetadata> &categories) { 0291 for (const auto &data : categories) { 0292 if (!data.displayName.isEmpty()) { 0293 ui.m_categoryCombo->addItem(data.displayName, data.name); 0294 } else { 0295 ui.m_categoryCombo->addItem(data.name, data.name); 0296 } 0297 } 0298 }); 0299 ui.detailsStack->widget(0)->layout()->setContentsMargins(0, 0, 0, 0); 0300 ui.detailsStack->widget(1)->layout()->setContentsMargins(0, 0, 0, 0); 0301 0302 q->connect(ui.m_categoryCombo, static_cast<void (KComboBox::*)(int)>(&KComboBox::activated), this, &DownloadWidgetPrivate::slotCategoryChanged); 0303 0304 // let the search line edit trap the enter key, otherwise it closes the dialog 0305 ui.m_searchEdit->setTrapReturnKey(true); 0306 0307 q->connect(ui.m_listView->verticalScrollBar(), &QScrollBar::valueChanged, this, &DownloadWidgetPrivate::scrollbarValueChanged); 0308 q->connect(ui.m_listView, SIGNAL(doubleClicked(QModelIndex)), delegate, SLOT(slotDetailsClicked(QModelIndex))); 0309 0310 details = new EntryDetails(engine, &ui); 0311 q->connect(delegate, &KNS3::ItemsViewBaseDelegate::signalShowDetails, this, &DownloadWidgetPrivate::slotShowDetails); 0312 0313 slotShowOverview(); 0314 } 0315 0316 void DownloadWidgetPrivate::slotListViewListMode() 0317 { 0318 ui.listViewButton->setChecked(true); 0319 ui.iconViewButton->setChecked(false); 0320 setListViewMode(QListView::ListMode); 0321 } 0322 0323 void DownloadWidgetPrivate::slotListViewIconMode() 0324 { 0325 ui.listViewButton->setChecked(false); 0326 ui.iconViewButton->setChecked(true); 0327 setListViewMode(QListView::IconMode); 0328 } 0329 0330 void DownloadWidgetPrivate::setListViewMode(QListView::ViewMode mode) 0331 { 0332 if (ui.m_listView->viewMode() == mode) { 0333 return; 0334 } 0335 0336 ItemsViewBaseDelegate *oldDelegate = delegate; 0337 if (mode == QListView::ListMode) { 0338 delegate = new ItemsViewDelegate(ui.m_listView, engine, q); 0339 ui.m_listView->setViewMode(QListView::ListMode); 0340 ui.m_listView->setResizeMode(QListView::Fixed); 0341 } else { 0342 delegate = new ItemsGridViewDelegate(ui.m_listView, engine, q); 0343 ui.m_listView->setViewMode(QListView::IconMode); 0344 ui.m_listView->setResizeMode(QListView::Adjust); 0345 } 0346 ui.m_listView->setItemDelegate(delegate); 0347 delete oldDelegate; 0348 q->connect(ui.m_listView, SIGNAL(doubleClicked(QModelIndex)), delegate, SLOT(slotDetailsClicked(QModelIndex))); 0349 q->connect(delegate, &KNS3::ItemsViewBaseDelegate::signalShowDetails, this, &DownloadWidgetPrivate::slotShowDetails); 0350 } 0351 0352 void DownloadWidgetPrivate::slotProvidersLoaded() 0353 { 0354 qCDebug(KNEWSTUFF) << "providers loaded"; 0355 engine->reloadEntries(); 0356 } 0357 0358 void DownloadWidgetPrivate::slotEntriesLoaded(const KNSCore::EntryInternal::List &entries) 0359 { 0360 for (const KNSCore::EntryInternal &entry : entries) { 0361 if (!categories.contains(entry.category())) { 0362 qCDebug(KNEWSTUFF) << "Found category: " << entry.category(); 0363 categories.insert(entry.category()); 0364 } 0365 } 0366 model->slotEntriesLoaded(entries); 0367 } 0368 0369 void DownloadWidgetPrivate::slotShowMessage(const QString &msg) 0370 { 0371 displayMessage(msg, KTitleWidget::InfoMessage); 0372 } 0373 0374 void DownloadWidgetPrivate::displayMessage(const QString &msg, KTitleWidget::MessageType type, int timeOutMs) 0375 { 0376 if (!messageTimer) { 0377 messageTimer = new QTimer; 0378 messageTimer->setSingleShot(true); 0379 q->connect(messageTimer, &QTimer::timeout, this, &DownloadWidgetPrivate::slotResetMessage); 0380 } 0381 // stop the pending timer if present 0382 messageTimer->stop(); 0383 0384 // set text to messageLabel 0385 ui.m_titleWidget->setComment(msg, type); 0386 0387 // single shot the resetColors timer (and create it if null) 0388 if (timeOutMs > 0) { 0389 qCDebug(KNEWSTUFF) << "starting the message timer for " << timeOutMs; 0390 messageTimer->start(timeOutMs); 0391 } 0392 } 0393 0394 void DownloadWidgetPrivate::slotShowDetails(const KNSCore::EntryInternal &entry) 0395 { 0396 if (!entry.isValid()) { 0397 qCDebug(KNEWSTUFF) << "invalid entry"; 0398 return; 0399 } 0400 titleText = ui.m_titleWidget->text(); 0401 0402 ui.backButton->setVisible(true); 0403 ui.detailsStack->setCurrentIndex(1); 0404 ui.descriptionScrollArea->verticalScrollBar()->setValue(0); 0405 ui.preview1->setImage(QImage()); 0406 ui.preview2->setImage(QImage()); 0407 ui.preview3->setImage(QImage()); 0408 ui.previewBig->setImage(QImage()); 0409 details->setEntry(entry); 0410 } 0411 0412 void DownloadWidgetPrivate::slotShowOverview() 0413 { 0414 ui.backButton->setVisible(false); 0415 0416 ui.updateButton->setVisible(false); 0417 ui.installButton->setVisible(false); 0418 ui.becomeFanButton->setVisible(false); 0419 ui.uninstallButton->setVisible(false); 0420 0421 ui.detailsStack->setCurrentIndex(0); 0422 ui.m_titleWidget->setText(titleText); 0423 } 0424 0425 #include "moc_downloadwidget.cpp" 0426 #include "moc_downloadwidget_p.cpp" 0427 0428 #endif