File indexing completed on 2024-03-24 15:36:50

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