KNewStuff

entrydetailsdialog.cpp
1 /*
2  SPDX-FileCopyrightText: 2009 Frederik Gladhorn <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6 
7 #include "entrydetailsdialog_p.h"
8 
9 #include <QMenu>
10 #include <knewstuff_debug.h>
11 #include <KLocalizedString>
12 
13 #include "core/engine.h"
14 #include "core/imageloader_p.h"
15 #include <attica/provider.h>
16 
17 using namespace KNS3;
18 
19 EntryDetails::EntryDetails(KNSCore::Engine *engine, Ui::DownloadWidget *widget)
20  : QObject(widget->m_listView), m_engine(engine), ui(widget)
21 {
22  init();
23 }
24 
25 EntryDetails::~EntryDetails()
26 {
27 }
28 
29 void EntryDetails::init()
30 {
31  connect(ui->preview1, &ImagePreviewWidget::clicked, this, &EntryDetails::preview1Selected);
32  connect(ui->preview2, &ImagePreviewWidget::clicked, this, &EntryDetails::preview2Selected);
33  connect(ui->preview3, &ImagePreviewWidget::clicked, this, &EntryDetails::preview3Selected);
34 
35  ui->ratingWidget->setMaxRating(10);
36  ui->ratingWidget->setHalfStepsEnabled(true);
37 
38  updateButtons();
39  connect(ui->installButton, &QAbstractButton::clicked, this, &EntryDetails::install);
40  connect(ui->uninstallButton, &QAbstractButton::clicked, this, &EntryDetails::uninstall);
41  // updating is the same as installing
42  connect(ui->updateButton, &QAbstractButton::clicked, this, &EntryDetails::install);
43  connect(ui->becomeFanButton, &QAbstractButton::clicked, this, &EntryDetails::becomeFan);
44 
45  ui->installButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok")));
46  ui->updateButton->setIcon(QIcon::fromTheme(QStringLiteral("system-software-update")));
47  ui->uninstallButton->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
48 
49  connect(m_engine, &KNSCore::Engine::signalEntryEvent, this,
50  [this](const KNSCore::EntryInternal &entry, KNSCore::EntryInternal::EntryEvent event) {
51  if (event == KNSCore::EntryInternal::DetailsLoadedEvent) {
52  Q_EMIT entryChanged(entry);
53  } else if (event == KNSCore::EntryInternal::StatusChangedEvent) {
54  updateButtons();
55  }
56  });
57  connect(m_engine, &KNSCore::Engine::signalEntryPreviewLoaded,
58  this, &EntryDetails::slotEntryPreviewLoaded);
59 }
60 
61 void EntryDetails::setEntry(const KNSCore::EntryInternal &entry)
62 {
63  m_entry = entry;
64  // immediately show something
65  entryChanged(m_entry);
66  // fetch more preview images
67  m_engine->loadDetails(m_entry);
68 }
69 
70 void EntryDetails::entryChanged(const KNSCore::EntryInternal &entry)
71 {
72  if (ui->detailsStack->currentIndex() == 0) {
73  return;
74  }
75  m_entry = entry;
76 
77  // FIXME
78  //ui->ratingWidget->setEditable(m_engine->userCanVote(m_entry));
79 
80  if (!m_engine->userCanBecomeFan(m_entry)) {
81  ui->becomeFanButton->setEnabled(false);
82  }
83 
84  ui->m_titleWidget->setText(i18n("Details for %1", m_entry.name()));
85  if (!m_entry.author().homepage().isEmpty()) {
86  ui->authorLabel->setText(QLatin1String("<a href=\"") + m_entry.author().homepage() + QLatin1String("\">") + m_entry.author().name() + QLatin1String("</a>"));
87  } else if (!m_entry.author().email().isEmpty()) {
88  ui->authorLabel->setText(QLatin1String("<a href=\"mailto:") + m_entry.author().email() + QLatin1String("\">") + m_entry.author().name() + QLatin1String("</a>"));
89  } else {
90  ui->authorLabel->setText(m_entry.author().name());
91  }
92 
93  QString summary = KNSCore::replaceBBCode(m_entry.summary()).replace(QLatin1Char('\n'), QLatin1String("<br/>"));
94  QString changelog = KNSCore::replaceBBCode(m_entry.changelog()).replace(QLatin1Char('\n'), QLatin1String("<br/>"));
95 
96  QString description = QLatin1String("<html><body>") + summary;
97  if (!changelog.isEmpty()) {
98  description += QLatin1String("<br/><p><b>") + i18n("Changelog:") + QLatin1String("</b><br/>") + changelog + QLatin1String("</p>");
99  }
100  description += QLatin1String("</body></html>");
101  ui->descriptionLabel->setText(description);
102 
103  QString homepageText(QLatin1String("<a href=\"") + m_entry.homepage().url() + QLatin1String("\">") +
104  i18nc("A link to the description of this Get Hot New Stuff item", "Homepage") + QStringLiteral("</a>"));
105 
106  if (!m_entry.donationLink().isEmpty()) {
107  homepageText += QLatin1String("<br><a href=\"") + m_entry.donationLink() + QLatin1String("\">") + i18nc("A link to make a donation for a Get Hot New Stuff item (opens a web browser)", "Make a donation") + QLatin1String("</a>");
108  }
109  if (!m_entry.knowledgebaseLink().isEmpty()) {
110  homepageText += QLatin1String("<br><a href=\"") + m_entry.knowledgebaseLink() + QLatin1String("\">")
111  + i18ncp("A link to the knowledgebase (like a forum) (opens a web browser)", "Knowledgebase (no entries)", "Knowledgebase (%1 entries)", m_entry.numberKnowledgebaseEntries()) + QStringLiteral("</a>");
112  }
113  ui->homepageLabel->setText(homepageText);
114  ui->homepageLabel->setToolTip(i18nc("Tooltip for a link in a dialog", "Opens in a browser window"));
115 
116  if (m_entry.rating() > 0) {
117  ui->ratingWidget->setVisible(true);
118  disconnect(ui->ratingWidget, static_cast<void(KRatingWidget::*)(uint)>(&KRatingWidget::ratingChanged),
119  this, &EntryDetails::ratingChanged);
120  // Most of the voting is 20 - 80, so rate 20 as 0 stars and 80 as 5 stars
121  int rating = qMax(0, qMin(10, (m_entry.rating() - 20) / 6));
122  ui->ratingWidget->setRating(rating);
123  connect(ui->ratingWidget, static_cast<void(KRatingWidget::*)(uint)>(&KRatingWidget::ratingChanged),
124  this, &EntryDetails::ratingChanged);
125  } else {
126  ui->ratingWidget->setVisible(false);
127  }
128 
129  bool hideSmallPreviews = m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall2).isEmpty()
130  && m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall3).isEmpty();
131 
132  ui->preview1->setVisible(!hideSmallPreviews);
133  ui->preview2->setVisible(!hideSmallPreviews);
134  ui->preview3->setVisible(!hideSmallPreviews);
135 
136  // in static xml we often only get a small preview, use that in details
137  if (m_entry.previewUrl(KNSCore::EntryInternal::PreviewBig1).isEmpty() && !m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1).isEmpty()) {
138  m_entry.setPreviewUrl(m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1), KNSCore::EntryInternal::PreviewBig1);
139  m_entry.setPreviewImage(m_entry.previewImage(KNSCore::EntryInternal::PreviewSmall1), KNSCore::EntryInternal::PreviewBig1);
140  }
141 
142  for (int type = KNSCore::EntryInternal::PreviewSmall1; type <= KNSCore::EntryInternal::PreviewBig3; ++type) {
143  if (m_entry.previewUrl(KNSCore::EntryInternal::PreviewSmall1).isEmpty()) {
144  ui->previewBig->setVisible(false);
145  } else
146 
147  if (!m_entry.previewUrl((KNSCore::EntryInternal::PreviewType)type).isEmpty()) {
148  qCDebug(KNEWSTUFF) << "type: " << type << m_entry.previewUrl((KNSCore::EntryInternal::PreviewType)type);
149  if (m_entry.previewImage((KNSCore::EntryInternal::PreviewType)type).isNull()) {
150  m_engine->loadPreview(m_entry, (KNSCore::EntryInternal::PreviewType)type);
151  } else {
152  slotEntryPreviewLoaded(m_entry, (KNSCore::EntryInternal::PreviewType)type);
153  }
154  }
155  }
156 
157  updateButtons();
158 }
159 
160 void EntryDetails::updateButtons()
161 {
162  if (ui->detailsStack->currentIndex() == 0) {
163  return;
164  }
165  qCDebug(KNEWSTUFF) << "update buttons: " << m_entry.status();
166  ui->installButton->setVisible(false);
167  ui->uninstallButton->setVisible(false);
168  ui->updateButton->setVisible(false);
169 
170  switch (m_entry.status()) {
171  case Entry::Installed:
172  ui->uninstallButton->setVisible(true);
173  ui->uninstallButton->setEnabled(true);
174  break;
175  case Entry::Updateable:
176  ui->updateButton->setVisible(true);
177  ui->updateButton->setEnabled(true);
178  ui->uninstallButton->setVisible(true);
179  ui->uninstallButton->setEnabled(true);
180  break;
181 
182  case Entry::Invalid:
183  case Entry::Downloadable:
184  ui->installButton->setVisible(true);
185  ui->installButton->setEnabled(true);
186  break;
187 
188  case Entry::Installing:
189  ui->installButton->setVisible(true);
190  ui->installButton->setEnabled(false);
191  break;
192  case Entry::Updating:
193  ui->updateButton->setVisible(true);
194  ui->updateButton->setEnabled(false);
195  ui->uninstallButton->setVisible(true);
196  ui->uninstallButton->setEnabled(false);
197  break;
198  case Entry::Deleted:
199  ui->installButton->setVisible(true);
200  ui->installButton->setEnabled(true);
201  break;
202  }
203 
204  if (QMenu *buttonMenu = ui->installButton->menu()) {
205  buttonMenu->clear();
206  ui->installButton->setMenu(nullptr);
207  buttonMenu->deleteLater();
208  }
209  if (ui->installButton->isVisible() && m_entry.downloadLinkCount() > 1) {
210  QMenu *installMenu = new QMenu(ui->installButton);
211  const auto lst = m_entry.downloadLinkInformationList();
212  for (const KNSCore::EntryInternal::DownloadLinkInformation &info : lst) {
213  QString text = info.name;
214  if (!info.distributionType.trimmed().isEmpty()) {
215  text + QStringLiteral(" (") + info.distributionType.trimmed() + QLatin1Char(')');
216  }
217  QAction *installMenuAction = installMenu->addAction(QIcon::fromTheme(QStringLiteral("dialog-ok")), text);
218  installMenuAction->setData(info.id);
219  connect(installMenuAction, &QAction::triggered, this, [this, installMenuAction](){
220  installAction(installMenuAction);
221  });
222  }
223  qCDebug(KNEWSTUFF) << "links: " << m_entry.downloadLinkInformationList().size();
224  ui->installButton->setMenu(installMenu);
225  }
226 }
227 
228 void EntryDetails::install()
229 {
230  m_engine->install(m_entry);
231 }
232 
233 void EntryDetails::uninstall()
234 {
235  m_engine->uninstall(m_entry);
236 }
237 
238 void EntryDetails::slotEntryPreviewLoaded(const KNSCore::EntryInternal &entry, KNSCore::EntryInternal::PreviewType type)
239 {
240  if (!(entry == m_entry)) {
241  return;
242  }
243 
244  switch (type) {
245  case KNSCore::EntryInternal::PreviewSmall1:
246  ui->preview1->setImage(entry.previewImage(KNSCore::EntryInternal::PreviewSmall1));
247  break;
248  case KNSCore::EntryInternal::PreviewSmall2:
249  ui->preview2->setImage(entry.previewImage(KNSCore::EntryInternal::PreviewSmall2));
250  break;
251  case KNSCore::EntryInternal::PreviewSmall3:
252  ui->preview3->setImage(entry.previewImage(KNSCore::EntryInternal::PreviewSmall3));
253  break;
254  case KNSCore::EntryInternal::PreviewBig1:
255  m_currentPreview = entry.previewImage(KNSCore::EntryInternal::PreviewBig1);
256  ui->previewBig->setImage(m_currentPreview);
257  break;
258  default:
259  break;
260  }
261 }
262 
263 void EntryDetails::preview1Selected()
264 {
265  previewSelected(0);
266 }
267 
268 void EntryDetails::preview2Selected()
269 {
270  previewSelected(1);
271 }
272 
273 void EntryDetails::preview3Selected()
274 {
275  previewSelected(2);
276 }
277 
278 void EntryDetails::previewSelected(int current)
279 {
280  KNSCore::EntryInternal::PreviewType type = static_cast<KNSCore::EntryInternal::PreviewType>(KNSCore::EntryInternal::PreviewBig1 + current);
281  m_currentPreview = m_entry.previewImage(type);
282  ui->previewBig->setImage(m_currentPreview);
283 }
284 
285 void EntryDetails::ratingChanged(uint rating)
286 {
287  // engine expects values from 0..100
288  qCDebug(KNEWSTUFF) << "rating: " << rating << " -> " << rating*10;
289  m_engine->vote(m_entry, rating * 10);
290 }
291 
292 void EntryDetails::becomeFan()
293 {
294  m_engine->becomeFan(m_entry);
295 }
296 
297 void EntryDetails::installAction(QAction *action)
298 {
299  m_engine->install(m_entry, action->data().toInt());
300 }
301 
void triggered(bool checked)
QVariant data() const const
KNEWSTUFFCORE_EXPORT QString replaceBBCode(const QString &unformattedText)
function to remove bb code formatting that opendesktop sends
QImage previewImage(PreviewType type=PreviewSmall1) const
This will not be loaded automatically, instead use Engine to load the actual images.
QAction * addAction(const QString &text)
int toInt(bool *ok) const const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
QString trimmed() const const
void clicked(bool checked)
void ratingChanged(unsigned int rating)
const QList< QKeySequence > & replace()
void setData(const QVariant &userData)
QString i18ncp(const char *context, const char *singular, const char *plural, const TYPE &arg...)
QCA_EXPORT void init()
QString i18n(const char *text, const TYPE &arg...)
KNewStuff data entry container.
Definition: entryinternal.h:49
KNewStuff engine.
Definition: engine.h:59
QIcon fromTheme(const QString &name)
The namespace for the KNewStuff classes.
Definition: button.cpp:19
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.