KNewStuff

downloadwidget.cpp
1 /*
2  knewstuff3/ui/downloaddialog.cpp.
3  SPDX-FileCopyrightText: 2005 Enrico Ros <[email protected]>
4  SPDX-FileCopyrightText: 2005-2007 Josef Spillner <[email protected]>
5  SPDX-FileCopyrightText: 2007 Dirk Mueller <[email protected]>
6  SPDX-FileCopyrightText: 2007-2009 Jeremy Whiting <[email protected]>
7  SPDX-FileCopyrightText: 2009-2010 Frederik Gladhorn <[email protected]>
8  SPDX-FileCopyrightText: 2010 Reza Fatahilah Shah <[email protected]>
9 
10  SPDX-License-Identifier: LGPL-2.1-or-later
11 */
12 
13 #include "downloadwidget.h"
14 #include "downloadwidget_p.h"
15 
16 #include <QTimer>
17 #include <QScrollBar>
18 #include <QCoreApplication>
19 
20 #include <KMessageBox>
21 #include <KLocalizedString>
22 #include <knewstuff_debug.h>
23 
24 #include "core/itemsmodel.h"
25 
26 #include "ui/itemsviewdelegate_p.h"
27 #include "ui/itemsgridviewdelegate_p.h"
28 #include "ui/widgetquestionlistener.h"
29 
30 #include "entry_p.h"
31 
32 using namespace KNS3;
33 
35  : QWidget(parent)
36  , d(new DownloadWidgetPrivate(this))
37 {
39  init(name + QStringLiteral(".knsrc"));
40 }
41 
43  : QWidget(parent)
44  , d(new DownloadWidgetPrivate(this))
45 {
46  init(configFile);
47 }
48 
49 void DownloadWidget::init(const QString &configFile)
50 {
51  d->init(configFile);
52  WidgetQuestionListener::instance();
53 }
54 
56 {
57  delete d;
58 }
59 
61 {
62  d->ui.m_titleWidget->setText(title);
63 }
64 
66 {
67  return d->ui.m_titleWidget->text();
68 }
69 
71 {
72  return d->engine;
73 }
74 
76 {
77  Entry::List entries;
78  entries.reserve(d->changedEntries.count());
79  for (const KNSCore::EntryInternal &e : qAsConst(d->changedEntries)) {
80  entries.append(EntryPrivate::fromInternal(&e));
81  }
82  return entries;
83 }
84 
86 {
87  Entry::List entries;
88  for (const KNSCore::EntryInternal &e : qAsConst(d->changedEntries)) {
89  if (e.status() == Entry::Installed) {
90  entries.append(EntryPrivate::fromInternal(&e));
91  }
92  }
93  return entries;
94 }
95 
96 DownloadWidgetPrivate::DownloadWidgetPrivate(DownloadWidget *q)
97  : q(q)
98  , engine(new KNSCore::Engine)
99  , model(new KNSCore::ItemsModel(engine))
100  , messageTimer(nullptr)
101  , dialogMode(false)
102 {
103 }
104 
105 DownloadWidgetPrivate::~DownloadWidgetPrivate()
106 {
107  delete messageTimer;
108  delete delegate;
109  delete model;
110  delete engine;
111 }
112 
113 void DownloadWidgetPrivate::slotResetMessage() // SLOT
114 {
115  ui.m_titleWidget->setComment(QString());
116 }
117 
118 void DownloadWidgetPrivate::slotNetworkTimeout() // SLOT
119 {
120  displayMessage(i18n("Timeout. Check Internet connection."), KTitleWidget::ErrorMessage);
121 }
122 
123 void DownloadWidgetPrivate::sortingChanged()
124 {
125  KNSCore::Provider::SortMode sortMode = KNSCore::Provider::Downloads;
126  KNSCore::Provider::Filter filter = KNSCore::Provider::None;
127  if (ui.ratingRadio->isChecked()) {
128  sortMode = KNSCore::Provider::Rating;
129  } else if (ui.newestRadio->isChecked()) {
130  sortMode = KNSCore::Provider::Newest;
131  } else if (ui.mostDownloadsRadio->isChecked()) {
132  sortMode = KNSCore::Provider::Downloads;
133  } else if (ui.installedRadio->isChecked()) {
134  filter = KNSCore::Provider::Installed;
135  }
136 
137  model->clearEntries();
138  if (filter == KNSCore::Provider::Installed) {
139  ui.m_searchEdit->clear();
140  }
141  ui.m_searchEdit->setEnabled(filter != KNSCore::Provider::Installed);
142 
143  engine->setSortMode(sortMode);
144  engine->setFilter(filter);
145 }
146 
147 void DownloadWidgetPrivate::slotUpdateSearch()
148 {
149  if (searchTerm == ui.m_searchEdit->text().trimmed()) {
150  return;
151  }
152  searchTerm = ui.m_searchEdit->text().trimmed();
153 }
154 
155 void DownloadWidgetPrivate::slotSearchTextChanged()
156 {
157  if (searchTerm == ui.m_searchEdit->text().trimmed()) {
158  return;
159  }
160  searchTerm = ui.m_searchEdit->text().trimmed();
161  engine->setSearchTerm(searchTerm);
162 }
163 
164 void DownloadWidgetPrivate::slotCategoryChanged(int idx)
165 {
166  if (idx == 0) {
167  // All Categories item selected, reset filter
169 
170  } else {
171  const QString category = ui.m_categoryCombo->currentData().toString();
172 
173  if (!category.isEmpty()) {
174  QStringList filter(category);
175  engine->setCategoriesFilter(filter);
176  }
177  }
178 }
179 
180 void DownloadWidgetPrivate::slotInfo(QString provider, QString server, QString version)
181 {
182  QString link = QStringLiteral("<a href=\"%1\">%1</a>").arg(server);
183  QString infostring = i18n("Server: %1", link);
184  infostring += i18n("<br />Provider: %1", provider);
185  infostring += i18n("<br />Version: %1", version);
186 
187  KMessageBox::information(nullptr,
188  infostring,
189  i18n("Provider information"));
190 }
191 
192 void DownloadWidgetPrivate::slotEntryEvent(const KNSCore::EntryInternal &entry, KNSCore::EntryInternal::EntryEvent event)
193 {
194  if (event == KNSCore::EntryInternal::StatusChangedEvent) {
195  changedEntries.insert(entry);
196  model->slotEntryChanged(entry);
197  }
198 }
199 
200 void DownloadWidgetPrivate::slotPayloadFailed(const KNSCore::EntryInternal &entry)
201 {
202  KMessageBox::error(nullptr, i18n("Could not install %1", entry.name()),
203  i18n("Get Hot New Stuff!"));
204 }
205 
206 void DownloadWidgetPrivate::slotPayloadLoaded(QUrl url)
207 {
208  Q_UNUSED(url)
209 }
210 
211 void DownloadWidgetPrivate::slotError(const QString &message)
212 {
213  KMessageBox::error(nullptr, message, i18n("Get Hot New Stuff"));
214 }
215 
216 void DownloadWidgetPrivate::scrollbarValueChanged(int value)
217 {
218  if (static_cast<double>(value) / ui.m_listView->verticalScrollBar()->maximum() > 0.9) {
219  engine->requestMoreData();
220  }
221 }
222 
223 void DownloadWidgetPrivate::init(const QString &configFile)
224 {
225  m_configFile = configFile;
226  ui.setupUi(q);
227  ui.m_titleWidget->setVisible(false);
228  ui.closeButton->setVisible(dialogMode);
229  ui.backButton->setVisible(false);
230  KStandardGuiItem::assign(ui.backButton, KStandardGuiItem::Back);
231  q->connect(ui.backButton, &QPushButton::clicked, this, &DownloadWidgetPrivate::slotShowOverview);
232 
233  q->connect(engine, &KNSCore::Engine::signalMessage, this, &DownloadWidgetPrivate::slotShowMessage);
234 
235  q->connect(engine, &KNSCore::Engine::signalErrorCode, ui.progressIndicator, &ProgressIndicator::error);
236  q->connect(engine, &KNSCore::Engine::busyStateChanged, this ,[this]() {
237  if (!engine->busyState()) {
238  ui.progressIndicator->idle(QString());
239  } else {
240  ui.progressIndicator->busy(engine->busyMessage());
241  }
242  });
243 
244  q->connect(engine, &KNSCore::Engine::signalProvidersLoaded, this, &DownloadWidgetPrivate::slotProvidersLoaded);
245  // Entries have been fetched and should be shown:
246  q->connect(engine, &KNSCore::Engine::signalEntriesLoaded, this, &DownloadWidgetPrivate::slotEntriesLoaded);
247 
248  // An entry has changes - eg because it was installed
249  q->connect(engine, &KNSCore::Engine::signalEntryEvent, this, &DownloadWidgetPrivate::slotEntryEvent);
250 
251  q->connect(engine, &KNSCore::Engine::signalResetView, model, &KNSCore::ItemsModel::clearEntries);
252  q->connect(engine, &KNSCore::Engine::signalEntryPreviewLoaded,
253  model, &KNSCore::ItemsModel::slotEntryPreviewLoaded);
254 
255  engine->init(configFile);
256  engine->setSortMode(KNSCore::Provider::Downloads);
257 
258  delegate = new ItemsViewDelegate(ui.m_listView, engine, q);
259  ui.m_listView->setItemDelegate(delegate);
260  ui.m_listView->setModel(model);
261 
262  ui.iconViewButton->setIcon(QIcon::fromTheme(QStringLiteral("view-list-icons")));
263  ui.iconViewButton->setToolTip(i18n("Icons view mode"));
264  ui.listViewButton->setIcon(QIcon::fromTheme(QStringLiteral("view-list-details")));
265  ui.listViewButton->setToolTip(i18n("Details view mode"));
266 
267  q->connect(ui.listViewButton, &QPushButton::clicked, this, &DownloadWidgetPrivate::slotListViewListMode);
268  q->connect(ui.iconViewButton, &QPushButton::clicked, this, &DownloadWidgetPrivate::slotListViewIconMode);
269 
270  q->connect(ui.newestRadio, &QRadioButton::clicked, this, &DownloadWidgetPrivate::sortingChanged);
271  q->connect(ui.ratingRadio, &QRadioButton::clicked, this, &DownloadWidgetPrivate::sortingChanged);
272  q->connect(ui.mostDownloadsRadio, &QRadioButton::clicked, this, &DownloadWidgetPrivate::sortingChanged);
273  q->connect(ui.installedRadio, &QRadioButton::clicked, this, &DownloadWidgetPrivate::sortingChanged);
274 
275  q->connect(ui.m_searchEdit, &KLineEdit::textChanged, this, &DownloadWidgetPrivate::slotSearchTextChanged);
276  q->connect(ui.m_searchEdit, &KLineEdit::editingFinished, this, &DownloadWidgetPrivate::slotUpdateSearch);
277 
278  ui.m_providerLabel->setVisible(false);
279  ui.m_providerCombo->setVisible(false);
280  ui.m_providerCombo->addItem(i18n("All Providers"));
281 
282  QStringList categories = engine->categories();
283  if (categories.size() < 2) {
284  ui.m_categoryLabel->setVisible(false);
285  ui.m_categoryCombo->setVisible(false);
286  } else {
287  ui.m_categoryCombo->addItem(i18n("All Categories"));
288  //NOTE: categories will be populated when we will get metadata from the server
289  }
290 
291  connect(engine, &KNSCore::Engine::signalCategoriesMetadataLoded,
292  this, [this](const QList<KNSCore::Provider::CategoryMetadata> &categories) {
293  for (const auto &data : categories) {
294  if (!data.displayName.isEmpty()) {
295  ui.m_categoryCombo->addItem(data.displayName, data.name);
296  } else {
297  ui.m_categoryCombo->addItem(data.name, data.name);
298  }
299  }
300  });
301  ui.detailsStack->widget(0)->layout()->setContentsMargins(0, 0, 0, 0);
302  ui.detailsStack->widget(1)->layout()->setContentsMargins(0, 0, 0, 0);
303 
304  q->connect(ui.m_categoryCombo, static_cast<void(KComboBox::*)(int)>(&KComboBox::activated),
305  this, &DownloadWidgetPrivate::slotCategoryChanged);
306 
307  // let the search line edit trap the enter key, otherwise it closes the dialog
308  ui.m_searchEdit->setTrapReturnKey(true);
309 
310  q->connect(ui.m_listView->verticalScrollBar(), &QScrollBar::valueChanged, this, &DownloadWidgetPrivate::scrollbarValueChanged);
311  q->connect(ui.m_listView, SIGNAL(doubleClicked(QModelIndex)), delegate, SLOT(slotDetailsClicked(QModelIndex)));
312 
313  details = new EntryDetails(engine, &ui);
314  q->connect(delegate, &KNS3::ItemsViewBaseDelegate::signalShowDetails, this, &DownloadWidgetPrivate::slotShowDetails);
315 
316  slotShowOverview();
317 }
318 
319 void DownloadWidgetPrivate::slotListViewListMode()
320 {
321  ui.listViewButton->setChecked(true);
322  ui.iconViewButton->setChecked(false);
323  setListViewMode(QListView::ListMode);
324 }
325 
326 void DownloadWidgetPrivate::slotListViewIconMode()
327 {
328  ui.listViewButton->setChecked(false);
329  ui.iconViewButton->setChecked(true);
330  setListViewMode(QListView::IconMode);
331 }
332 
333 void DownloadWidgetPrivate::setListViewMode(QListView::ViewMode mode)
334 {
335  if (ui.m_listView->viewMode() == mode) {
336  return;
337  }
338 
339  ItemsViewBaseDelegate *oldDelegate = delegate;
340  if (mode == QListView::ListMode) {
341  delegate = new ItemsViewDelegate(ui.m_listView, engine, q);
342  ui.m_listView->setViewMode(QListView::ListMode);
343  ui.m_listView->setResizeMode(QListView::Fixed);
344  } else {
345  delegate = new ItemsGridViewDelegate(ui.m_listView, engine, q);
346  ui.m_listView->setViewMode(QListView::IconMode);
347  ui.m_listView->setResizeMode(QListView::Adjust);
348  }
349  ui.m_listView->setItemDelegate(delegate);
350  delete oldDelegate;
351  q->connect(ui.m_listView, SIGNAL(doubleClicked(QModelIndex)), delegate, SLOT(slotDetailsClicked(QModelIndex)));
352  q->connect(delegate, &KNS3::ItemsViewBaseDelegate::signalShowDetails, this, &DownloadWidgetPrivate::slotShowDetails);
353 }
354 
355 void DownloadWidgetPrivate::slotProvidersLoaded()
356 {
357  qCDebug(KNEWSTUFF) << "providers loaded";
358  engine->reloadEntries();
359 }
360 
361 void DownloadWidgetPrivate::slotEntriesLoaded(const KNSCore::EntryInternal::List &entries)
362 {
363  for (const KNSCore::EntryInternal &entry : entries) {
364  if (!categories.contains(entry.category())) {
365  qCDebug(KNEWSTUFF) << "Found category: " << entry.category();
366  categories.insert(entry.category());
367  }
368  }
369  model->slotEntriesLoaded(entries);
370 }
371 
372 void DownloadWidgetPrivate::slotShowMessage(const QString& msg)
373 {
374  displayMessage(msg, KTitleWidget::InfoMessage);
375 }
376 
377 void DownloadWidgetPrivate::displayMessage(const QString &msg, KTitleWidget::MessageType type, int timeOutMs)
378 {
379  if (!messageTimer) {
380  messageTimer = new QTimer;
381  messageTimer->setSingleShot(true);
382  q->connect(messageTimer, &QTimer::timeout, this, &DownloadWidgetPrivate::slotResetMessage);
383  }
384  // stop the pending timer if present
385  messageTimer->stop();
386 
387  // set text to messageLabel
388  ui.m_titleWidget->setComment(msg, type);
389 
390  // single shot the resetColors timer (and create it if null)
391  if (timeOutMs > 0) {
392  qCDebug(KNEWSTUFF) << "starting the message timer for " << timeOutMs;
393  messageTimer->start(timeOutMs);
394  }
395 }
396 
397 void DownloadWidgetPrivate::slotShowDetails(const KNSCore::EntryInternal &entry)
398 {
399  if (!entry.isValid()) {
400  qCDebug(KNEWSTUFF) << "invalid entry";
401  return;
402  }
403  titleText = ui.m_titleWidget->text();
404 
405  ui.backButton->setVisible(true);
406  ui.detailsStack->setCurrentIndex(1);
407  ui.descriptionScrollArea->verticalScrollBar()->setValue(0);
408  ui.preview1->setImage(QImage());
409  ui.preview2->setImage(QImage());
410  ui.preview3->setImage(QImage());
411  ui.previewBig->setImage(QImage());
412  details->setEntry(entry);
413 }
414 
415 void DownloadWidgetPrivate::slotShowOverview()
416 {
417  ui.backButton->setVisible(false);
418 
419  ui.updateButton->setVisible(false);
420  ui.installButton->setVisible(false);
421  ui.becomeFanButton->setVisible(false);
422  ui.uninstallButton->setVisible(false);
423 
424  ui.detailsStack->setCurrentIndex(0);
425  ui.m_titleWidget->setText(titleText);
426 }
427 
428 #include "moc_downloadwidget.cpp"
KNSCore::Engine * engine()
~DownloadWidget()
destructor
void reserve(int alloc)
KNS3::Entry::List changedEntries()
The list of entries with changed status (installed/uninstalled)
KNS3::Entry::List installedEntries()
The list of entries that have been newly installed.
QStringList categories() const
The list of the server-side names of the categories handled by this engine instance.
Definition: engine.cpp:289
void setSearchTerm(const QString &searchString)
Sets a string search term.
Definition: engine.cpp:545
void setTitle(const QString &title)
Set the title for display purposes in the widget&#39;s title.
void textChanged(const QString &text)
QString title() const
Get the current title.
int size() const const
KNewStuff download widget.
Q_SIGNAL void busyStateChanged()
Signal gets emitted when the busy state changes.
void timeout()
void append(const T &value)
QString & insert(int position, QChar ch)
void setCategoriesFilter(const QStringList &categories)
Set the categories that will be included in searches.
Definition: engine.cpp:497
bool isEmpty() const const
void clicked(bool checked)
void activated(int index)
void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
QString category() const
Retrieve the category of the data object.
bool init(const QString &configfile)
Initializes the engine.
Definition: engine.cpp:187
QString busyMessage
String representation of the engines busy state, in the case of idle this string is empty...
Definition: engine.h:74
void signalMessage(const QString &message)
Indicates a message to be added to the ui&#39;s log, or sent to a messagebox.
void setFilter(Provider::Filter filter)
Set a filter for results (defaults to none), which will allow you to show only installed entries...
Definition: engine.cpp:517
void setSortMode(Provider::SortMode mode)
Set the order the search results are returned in.
Definition: engine.cpp:503
QString i18n(const char *text, const TYPE &arg...)
DownloadWidget(QWidget *parent=nullptr)
Create a download widget that lets the user install, update and uninstall contents.
KNewStuff data entry container.
Definition: entryinternal.h:49
void insert(int i, const T &value)
KNewStuff engine.
Definition: engine.h:59
void valueChanged(int value)
void editingFinished()
QIcon fromTheme(const QString &name)
BusyState busyState
Current state of the engine, the state con contain multiple operations an empty BusyState represents ...
Definition: engine.h:68
void information(QWidget *parent, const QString &text, const QString &caption=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
The namespace for the KNewStuff classes.
Definition: button.cpp:19
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString name() const
Retrieve the name of the data object.
QObject * parent() const const
void signalErrorCode(const KNSCore::ErrorCode &errorCode, const QString &message, const QVariant &metadata)
Fires in the case of any critical or serious errors, such as network or API problems.
virtual bool event(QEvent *event) override
QString applicationName()
void setSingleShot(bool singleShot)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Jan 18 2021 22:43:49 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.