Changeset View
Changeset View
Standalone View
Standalone View
src/panels/information/informationpanelcontent.cpp
Show All 40 Lines | |||||
41 | 41 | | |||
42 | #include <QLabel> | 42 | #include <QLabel> | ||
43 | #include <QDialogButtonBox> | 43 | #include <QDialogButtonBox> | ||
44 | #include <QScrollArea> | 44 | #include <QScrollArea> | ||
45 | #include <QTextLayout> | 45 | #include <QTextLayout> | ||
46 | #include <QTimer> | 46 | #include <QTimer> | ||
47 | #include <QVBoxLayout> | 47 | #include <QVBoxLayout> | ||
48 | #include <QStyle> | 48 | #include <QStyle> | ||
49 | #include <QPainter> | ||||
50 | #include <QBitmap> | ||||
51 | #include <QLinearGradient> | ||||
52 | #include <QPolygon> | ||||
49 | 53 | | |||
50 | #include "dolphin_informationpanelsettings.h" | 54 | #include "dolphin_informationpanelsettings.h" | ||
51 | #include "phononwidget.h" | 55 | #include "phononwidget.h" | ||
52 | #include "pixmapviewer.h" | 56 | #include "pixmapviewer.h" | ||
53 | 57 | | |||
58 | const int PLAY_ARROW_SIZE = 24; | ||||
59 | const int PLAY_ARROW_BORDER_SIZE = 2; | ||||
60 | | ||||
54 | InformationPanelContent::InformationPanelContent(QWidget* parent) : | 61 | InformationPanelContent::InformationPanelContent(QWidget* parent) : | ||
55 | QWidget(parent), | 62 | QWidget(parent), | ||
56 | m_item(), | 63 | m_item(), | ||
57 | m_previewJob(nullptr), | 64 | m_previewJob(nullptr), | ||
58 | m_outdatedPreviewTimer(nullptr), | 65 | m_outdatedPreviewTimer(nullptr), | ||
59 | m_preview(nullptr), | 66 | m_preview(nullptr), | ||
60 | m_phononWidget(nullptr), | 67 | m_phononWidget(nullptr), | ||
61 | m_nameLabel(nullptr), | 68 | m_nameLabel(nullptr), | ||
62 | m_metaDataWidget(nullptr), | 69 | m_metaDataWidget(nullptr), | ||
63 | m_metaDataArea(nullptr), | 70 | m_metaDataArea(nullptr), | ||
64 | m_placesItemModel(nullptr) | 71 | m_placesItemModel(nullptr), | ||
72 | m_usePhonon(false) | ||||
65 | { | 73 | { | ||
66 | parent->installEventFilter(this); | 74 | parent->installEventFilter(this); | ||
67 | 75 | | |||
68 | // Initialize timer for disabling an outdated preview with a small | 76 | // Initialize timer for disabling an outdated preview with a small | ||
69 | // delay. This prevents flickering if the new preview can be generated | 77 | // delay. This prevents flickering if the new preview can be generated | ||
70 | // within a very small timeframe. | 78 | // within a very small timeframe. | ||
71 | m_outdatedPreviewTimer = new QTimer(this); | 79 | m_outdatedPreviewTimer = new QTimer(this); | ||
72 | m_outdatedPreviewTimer->setInterval(300); | 80 | m_outdatedPreviewTimer->setInterval(300); | ||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Line(s) | 168 | { | |||
161 | if (item != m_item) { | 169 | if (item != m_item) { | ||
162 | m_item = item; | 170 | m_item = item; | ||
163 | 171 | | |||
164 | refreshMetaData(); | 172 | refreshMetaData(); | ||
165 | } | 173 | } | ||
166 | refreshPreview(); | 174 | refreshPreview(); | ||
167 | } | 175 | } | ||
168 | 176 | | |||
169 | void InformationPanelContent::refreshPreview() | 177 | void InformationPanelContent::refreshPixmapView() { | ||
170 | { | 178 | | ||
171 | // If there is a preview job, kill it to prevent that we have jobs for | | |||
172 | // multiple items running, and thus a race condition (bug 250787). | | |||
elvisangelaccio: Why remove this comment? We are still killing the preview job here, aren't we? | |||||
The comment was moved to InformationPanelContent::refreshPreview but I have re-added it here as well. meven: The comment was moved to InformationPanelContent::refreshPreview but I have re-added it here as… | |||||
173 | if (m_previewJob) { | 179 | if (m_previewJob) { | ||
174 | m_previewJob->kill(); | 180 | m_previewJob->kill(); | ||
175 | } | 181 | } | ||
176 | 182 | | |||
177 | setNameLabelText(m_item.text()); | | |||
178 | if (InformationPanelSettings::previewsShown()) { | | |||
179 | | ||||
180 | const QUrl itemUrl = m_item.url(); | | |||
181 | const bool isSearchUrl = itemUrl.scheme().contains(QStringLiteral("search")) && m_item.localPath().isEmpty(); | | |||
182 | if (isSearchUrl) { | | |||
183 | m_preview->show(); | | |||
184 | | ||||
185 | // in the case of a search-URL the URL is not readable for humans | | |||
186 | // (at least not useful to show in the Information Panel) | | |||
187 | m_preview->setPixmap( | | |||
188 | QIcon::fromTheme(QStringLiteral("nepomuk")).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous) | | |||
189 | ); | | |||
190 | } else { | | |||
191 | // try to get a preview pixmap from the item... | 183 | // try to get a preview pixmap from the item... | ||
192 | 184 | | |||
193 | // Mark the currently shown preview as outdated. This is done | 185 | // Mark the currently shown preview as outdated. This is done | ||
194 | // with a small delay to prevent a flickering when the next preview | 186 | // with a small delay to prevent a flickering when the next preview | ||
195 | // can be shown within a short timeframe. This timer is not started | 187 | // can be shown within a short timeframe. This timer is not started | ||
196 | // for directories, as directory previews might fail and return the | 188 | // for directories, as directory previews might fail and return the | ||
197 | // same icon. | 189 | // same icon. | ||
198 | if (!m_item.isDir()) { | 190 | if (!m_item.isDir()) { | ||
Show All 9 Lines | |||||
208 | if (m_previewJob->uiDelegate()) { | 200 | if (m_previewJob->uiDelegate()) { | ||
209 | KJobWidgets::setWindow(m_previewJob, this); | 201 | KJobWidgets::setWindow(m_previewJob, this); | ||
210 | } | 202 | } | ||
211 | 203 | | |||
212 | connect(m_previewJob.data(), &KIO::PreviewJob::gotPreview, | 204 | connect(m_previewJob.data(), &KIO::PreviewJob::gotPreview, | ||
213 | this, &InformationPanelContent::showPreview); | 205 | this, &InformationPanelContent::showPreview); | ||
214 | connect(m_previewJob.data(), &KIO::PreviewJob::failed, | 206 | connect(m_previewJob.data(), &KIO::PreviewJob::failed, | ||
215 | this, &InformationPanelContent::showIcon); | 207 | this, &InformationPanelContent::showIcon); | ||
208 | } | ||||
209 | | ||||
210 | void InformationPanelContent::refreshPreview() | ||||
211 | { | ||||
212 | // If there is a preview job, kill it to prevent that we have jobs for | ||||
213 | // multiple items running, and thus a race condition (bug 250787). | ||||
214 | if (m_previewJob) { | ||||
215 | m_previewJob->kill(); | ||||
216 | } | ||||
217 | | ||||
218 | m_preview->setCursor(Qt::ArrowCursor); | ||||
219 | m_usePhonon = false; | ||||
220 | setNameLabelText(m_item.text()); | ||||
221 | if (InformationPanelSettings::previewsShown()) { | ||||
222 | | ||||
223 | const QUrl itemUrl = m_item.url(); | ||||
224 | const bool isSearchUrl = itemUrl.scheme().contains(QStringLiteral("search")) && m_item.localPath().isEmpty(); | ||||
225 | if (isSearchUrl) { | ||||
226 | m_preview->show(); | ||||
227 | | ||||
228 | // in the case of a search-URL the URL is not readable for humans | ||||
229 | // (at least not useful to show in the Information Panel) | ||||
230 | m_preview->setPixmap( | ||||
231 | QIcon::fromTheme(QStringLiteral("nepomuk")).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous) | ||||
232 | ); | ||||
233 | } else { | ||||
234 | | ||||
235 | refreshPixmapView(); | ||||
216 | 236 | | |||
217 | const QString mimeType = m_item.mimetype(); | 237 | const QString mimeType = m_item.mimetype(); | ||
218 | const bool isVideo = mimeType.startsWith(QLatin1String("video/")); | 238 | const bool isVideo = mimeType.startsWith(QLatin1String("video/")); | ||
219 | const bool usePhonon = mimeType.startsWith(QLatin1String("audio/")) || isVideo; | 239 | m_usePhonon = mimeType.startsWith(QLatin1String("audio/")) || isVideo; | ||
220 | 240 | | |||
221 | if (usePhonon) { | 241 | if (m_usePhonon) { | ||
242 | // change the cursor of the preview | ||||
243 | m_preview->setCursor(Qt::PointingHandCursor); | ||||
244 | m_preview->installEventFilter(m_phononWidget); | ||||
245 | | ||||
246 | // if the video is playing, has been paused or stopped | ||||
247 | // we don't need to update the preview/phonon widget states | ||||
248 | // unless the previewed file has changed | ||||
249 | if ((m_phononWidget->state() != Phonon::State::PlayingState && | ||||
250 | m_phononWidget->state() != Phonon::State::PausedState && | ||||
251 | m_phononWidget->state() != Phonon::State::StoppedState) || | ||||
252 | m_item.targetUrl() != m_phononWidget->url()) { | ||||
222 | 253 | | |||
223 | if (InformationPanelSettings::previewsAutoPlay() && isVideo) { | 254 | if (InformationPanelSettings::previewsAutoPlay() && isVideo) { | ||
224 | // hides the preview now to avoid flickering when the autoplay video starts | 255 | // hides the preview now to avoid flickering when the autoplay video starts | ||
225 | m_preview->hide(); | 256 | m_preview->hide(); | ||
226 | } else { | 257 | } else { | ||
227 | // the video won't play before the preview is displayed | 258 | // the video won't play before the preview is displayed | ||
228 | m_preview->show(); | 259 | m_preview->show(); | ||
229 | } | 260 | } | ||
230 | 261 | | |||
231 | m_phononWidget->show(); | 262 | m_phononWidget->show(); | ||
232 | m_phononWidget->setUrl(m_item.targetUrl(), isVideo ? PhononWidget::MediaKind::Video : PhononWidget::MediaKind::Audio); | 263 | m_phononWidget->setUrl(m_item.targetUrl(), isVideo ? PhononWidget::MediaKind::Video : PhononWidget::MediaKind::Audio); | ||
233 | m_phononWidget->setVideoSize(m_preview->size()); | 264 | m_phononWidget->setVideoSize(m_preview->size()); | ||
265 | } | ||||
234 | } else { | 266 | } else { | ||
235 | // When we don't need it, hide the phonon widget first to avoid flickering | 267 | // When we don't need it, hide the phonon widget first to avoid flickering | ||
236 | m_phononWidget->hide(); | 268 | m_phononWidget->hide(); | ||
237 | m_preview->show(); | 269 | m_preview->show(); | ||
270 | m_preview->removeEventFilter(m_phononWidget); | ||||
271 | m_phononWidget->clearUrl(); | ||||
238 | } | 272 | } | ||
239 | } | 273 | } | ||
240 | } else { | 274 | } else { | ||
241 | m_preview->hide(); | 275 | m_preview->hide(); | ||
242 | m_phononWidget->hide(); | 276 | m_phononWidget->hide(); | ||
243 | } | 277 | } | ||
244 | } | 278 | } | ||
245 | 279 | | |||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Line(s) | |||||
318 | void InformationPanelContent::showPreview(const KFileItem& item, | 352 | void InformationPanelContent::showPreview(const KFileItem& item, | ||
319 | const QPixmap& pixmap) | 353 | const QPixmap& pixmap) | ||
320 | { | 354 | { | ||
321 | m_outdatedPreviewTimer->stop(); | 355 | m_outdatedPreviewTimer->stop(); | ||
322 | Q_UNUSED(item); | 356 | Q_UNUSED(item); | ||
323 | 357 | | |||
324 | QPixmap p = pixmap; | 358 | QPixmap p = pixmap; | ||
325 | KIconLoader::global()->drawOverlays(item.overlays(), p, KIconLoader::Desktop); | 359 | KIconLoader::global()->drawOverlays(item.overlays(), p, KIconLoader::Desktop); | ||
360 | | ||||
361 | if (m_usePhonon) { | ||||
362 | // adds a play arrow | ||||
363 | | ||||
364 | // compute relative pixel positions | ||||
365 | const int zeroX = static_cast<int>(p.width() / 2 - PLAY_ARROW_SIZE / 2 / devicePixelRatio()); | ||||
366 | const int zeroY = static_cast<int>(p.height() / 2 - PLAY_ARROW_SIZE / 2 / devicePixelRatio()); | ||||
elvisangelaccio: Please always use camelCase. | |||||
367 | | ||||
368 | QPolygon arrow; | ||||
elvisangelaccio: Is it possible to not hardcode these numbers? | |||||
369 | arrow << QPoint(zeroX, zeroY); | ||||
370 | arrow << QPoint(zeroX, zeroY + PLAY_ARROW_SIZE); | ||||
371 | arrow << QPoint(zeroX + PLAY_ARROW_SIZE, zeroY + PLAY_ARROW_SIZE / 2); | ||||
372 | | ||||
373 | QPainterPath path; | ||||
374 | path.addPolygon(arrow); | ||||
375 | | ||||
elvisangelaccio: Coding style: opening brace should go to the end of previous line. | |||||
376 | QLinearGradient gradient(QPointF(zeroX, zeroY), | ||||
377 | QPointF(zeroX + PLAY_ARROW_SIZE,zeroY + PLAY_ARROW_SIZE)); | ||||
378 | | ||||
379 | QColor whiteColor = Qt::white; | ||||
380 | QColor blackColor = Qt::black; | ||||
381 | gradient.setColorAt(0, whiteColor); | ||||
382 | gradient.setColorAt(1, blackColor); | ||||
383 | | ||||
384 | QBrush brush(gradient); | ||||
385 | | ||||
386 | QPainter painter(&p); | ||||
387 | | ||||
388 | QPen pen(blackColor, PLAY_ARROW_BORDER_SIZE, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); | ||||
389 | painter.setPen(pen); | ||||
390 | | ||||
391 | painter.setRenderHint(QPainter::Antialiasing); | ||||
392 | painter.drawPolygon(arrow); | ||||
393 | painter.fillPath(path, brush); | ||||
394 | } | ||||
395 | | ||||
326 | m_preview->setPixmap(p); | 396 | m_preview->setPixmap(p); | ||
327 | } | 397 | } | ||
328 | 398 | | |||
329 | void InformationPanelContent::markOutdatedPreview() | 399 | void InformationPanelContent::markOutdatedPreview() | ||
330 | { | 400 | { | ||
331 | KIconEffect *iconEffect = KIconLoader::global()->iconEffect(); | 401 | KIconEffect *iconEffect = KIconLoader::global()->iconEffect(); | ||
332 | QPixmap disabledPixmap = iconEffect->apply(m_preview->pixmap(), | 402 | QPixmap disabledPixmap = iconEffect->apply(m_preview->pixmap(), | ||
333 | KIconLoader::Desktop, | 403 | KIconLoader::Desktop, | ||
334 | KIconLoader::DisabledState); | 404 | KIconLoader::DisabledState); | ||
335 | m_preview->setPixmap(disabledPixmap); | 405 | m_preview->setPixmap(disabledPixmap); | ||
336 | } | 406 | } | ||
337 | 407 | | |||
338 | KFileItemList InformationPanelContent::items() | 408 | KFileItemList InformationPanelContent::items() | ||
339 | { | 409 | { | ||
340 | return m_metaDataWidget->items(); | 410 | return m_metaDataWidget->items(); | ||
341 | } | 411 | } | ||
342 | 412 | | |||
343 | void InformationPanelContent::slotHasVideoChanged(bool hasVideo) | 413 | void InformationPanelContent::slotHasVideoChanged(bool hasVideo) | ||
344 | { | 414 | { | ||
345 | m_preview->setVisible(InformationPanelSettings::previewsShown() && !hasVideo); | 415 | m_preview->setVisible(InformationPanelSettings::previewsShown() && !hasVideo); | ||
416 | if (m_preview->isVisible() && m_preview->size().width() != m_preview->pixmap().size().width()) { | ||||
417 | // in case the information panel has been resized when the preview was not displayed | ||||
418 | // we need to refresh its content | ||||
419 | refreshPixmapView(); | ||||
420 | } | ||||
346 | } | 421 | } | ||
347 | 422 | | |||
348 | void InformationPanelContent::setPreviewAutoPlay(bool autoPlay) { | 423 | void InformationPanelContent::setPreviewAutoPlay(bool autoPlay) { | ||
349 | m_phononWidget->setAutoPlay(autoPlay); | 424 | m_phononWidget->setAutoPlay(autoPlay); | ||
350 | } | 425 | } | ||
351 | 426 | | |||
352 | void InformationPanelContent::setNameLabelText(const QString& text) | 427 | void InformationPanelContent::setNameLabelText(const QString& text) | ||
353 | { | 428 | { | ||
▲ Show 20 Lines • Show All 52 Lines • Show Last 20 Lines |
Why remove this comment? We are still killing the preview job here, aren't we?