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_isVideo(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 | 179 | // 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). | 180 | // 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) { | 181 | if (m_previewJob) { | ||
174 | m_previewJob->kill(); | 182 | m_previewJob->kill(); | ||
175 | } | 183 | } | ||
176 | 184 | | |||
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... | 185 | // try to get a preview pixmap from the item... | ||
192 | 186 | | |||
193 | // Mark the currently shown preview as outdated. This is done | 187 | // Mark the currently shown preview as outdated. This is done | ||
194 | // with a small delay to prevent a flickering when the next preview | 188 | // 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 | 189 | // can be shown within a short timeframe. This timer is not started | ||
196 | // for directories, as directory previews might fail and return the | 190 | // for directories, as directory previews might fail and return the | ||
197 | // same icon. | 191 | // same icon. | ||
198 | if (!m_item.isDir()) { | 192 | if (!m_item.isDir()) { | ||
Show All 9 Lines | |||||
208 | if (m_previewJob->uiDelegate()) { | 202 | if (m_previewJob->uiDelegate()) { | ||
209 | KJobWidgets::setWindow(m_previewJob, this); | 203 | KJobWidgets::setWindow(m_previewJob, this); | ||
210 | } | 204 | } | ||
211 | 205 | | |||
212 | connect(m_previewJob.data(), &KIO::PreviewJob::gotPreview, | 206 | connect(m_previewJob.data(), &KIO::PreviewJob::gotPreview, | ||
213 | this, &InformationPanelContent::showPreview); | 207 | this, &InformationPanelContent::showPreview); | ||
214 | connect(m_previewJob.data(), &KIO::PreviewJob::failed, | 208 | connect(m_previewJob.data(), &KIO::PreviewJob::failed, | ||
215 | this, &InformationPanelContent::showIcon); | 209 | this, &InformationPanelContent::showIcon); | ||
210 | } | ||||
211 | | ||||
212 | void InformationPanelContent::refreshPreview() | ||||
213 | { | ||||
214 | // If there is a preview job, kill it to prevent that we have jobs for | ||||
215 | // multiple items running, and thus a race condition (bug 250787). | ||||
216 | if (m_previewJob) { | ||||
217 | m_previewJob->kill(); | ||||
218 | } | ||||
219 | | ||||
220 | m_preview->setCursor(Qt::ArrowCursor); | ||||
221 | bool usePhonon = false; | ||||
222 | setNameLabelText(m_item.text()); | ||||
223 | if (InformationPanelSettings::previewsShown()) { | ||||
224 | | ||||
225 | const QUrl itemUrl = m_item.url(); | ||||
226 | const bool isSearchUrl = itemUrl.scheme().contains(QStringLiteral("search")) && m_item.localPath().isEmpty(); | ||||
227 | if (isSearchUrl) { | ||||
228 | m_preview->show(); | ||||
229 | | ||||
230 | // in the case of a search-URL the URL is not readable for humans | ||||
231 | // (at least not useful to show in the Information Panel) | ||||
232 | m_preview->setPixmap( | ||||
233 | QIcon::fromTheme(QStringLiteral("nepomuk")).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous) | ||||
234 | ); | ||||
235 | } else { | ||||
236 | | ||||
237 | refreshPixmapView(); | ||||
216 | 238 | | |||
217 | const QString mimeType = m_item.mimetype(); | 239 | const QString mimeType = m_item.mimetype(); | ||
218 | const bool isVideo = mimeType.startsWith(QLatin1String("video/")); | 240 | m_isVideo = mimeType.startsWith(QLatin1String("video/")); | ||
219 | const bool usePhonon = mimeType.startsWith(QLatin1String("audio/")) || isVideo; | 241 | usePhonon = m_isVideo || mimeType.startsWith(QLatin1String("audio/")); | ||
220 | 242 | | |||
221 | if (usePhonon) { | 243 | if (usePhonon) { | ||
244 | // change the cursor of the preview | ||||
245 | m_preview->setCursor(Qt::PointingHandCursor); | ||||
246 | m_preview->installEventFilter(m_phononWidget); | ||||
247 | | ||||
248 | // if the video is playing, has been paused or stopped | ||||
249 | // we don't need to update the preview/phonon widget states | ||||
250 | // unless the previewed file has changed, | ||||
251 | // or the setting previewshown has changed | ||||
252 | if ((m_phononWidget->state() != Phonon::State::PlayingState && | ||||
253 | m_phononWidget->state() != Phonon::State::PausedState && | ||||
254 | m_phononWidget->state() != Phonon::State::StoppedState) || | ||||
255 | m_item.targetUrl() != m_phononWidget->url() || | ||||
256 | (!m_preview->isVisible() &&! m_phononWidget->isVisible())) { | ||||
222 | 257 | | |||
223 | if (InformationPanelSettings::previewsAutoPlay() && isVideo) { | 258 | if (InformationPanelSettings::previewsAutoPlay() && m_isVideo) { | ||
224 | // hides the preview now to avoid flickering when the autoplay video starts | 259 | // hides the preview now to avoid flickering when the autoplay video starts | ||
225 | m_preview->hide(); | 260 | m_preview->hide(); | ||
226 | } else { | 261 | } else { | ||
227 | // the video won't play before the preview is displayed | 262 | // the video won't play before the preview is displayed | ||
228 | m_preview->show(); | 263 | m_preview->show(); | ||
229 | } | 264 | } | ||
230 | 265 | | |||
231 | m_phononWidget->show(); | 266 | m_phononWidget->show(); | ||
232 | m_phononWidget->setUrl(m_item.targetUrl(), isVideo ? PhononWidget::MediaKind::Video : PhononWidget::MediaKind::Audio); | 267 | m_phononWidget->setUrl(m_item.targetUrl(), m_isVideo ? PhononWidget::MediaKind::Video : PhononWidget::MediaKind::Audio); | ||
233 | m_phononWidget->setVideoSize(m_preview->size()); | 268 | adjustWidgetSizes(parentWidget()->width()); | ||
269 | } | ||||
234 | } else { | 270 | } else { | ||
235 | // When we don't need it, hide the phonon widget first to avoid flickering | 271 | // When we don't need it, hide the phonon widget first to avoid flickering | ||
236 | m_phononWidget->hide(); | 272 | m_phononWidget->hide(); | ||
237 | m_preview->show(); | 273 | m_preview->show(); | ||
274 | m_preview->removeEventFilter(m_phononWidget); | ||||
275 | m_phononWidget->clearUrl(); | ||||
238 | } | 276 | } | ||
239 | } | 277 | } | ||
240 | } else { | 278 | } else { | ||
241 | m_preview->hide(); | 279 | m_preview->hide(); | ||
242 | m_phononWidget->hide(); | 280 | m_phononWidget->hide(); | ||
243 | } | 281 | } | ||
244 | } | 282 | } | ||
245 | 283 | | |||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Line(s) | 349 | { | |||
314 | KIconLoader::global()->drawOverlays(item.overlays(), pixmap, KIconLoader::Desktop); | 352 | KIconLoader::global()->drawOverlays(item.overlays(), pixmap, KIconLoader::Desktop); | ||
315 | m_preview->setPixmap(pixmap); | 353 | m_preview->setPixmap(pixmap); | ||
316 | } | 354 | } | ||
317 | 355 | | |||
318 | void InformationPanelContent::showPreview(const KFileItem& item, | 356 | void InformationPanelContent::showPreview(const KFileItem& item, | ||
319 | const QPixmap& pixmap) | 357 | const QPixmap& pixmap) | ||
320 | { | 358 | { | ||
321 | m_outdatedPreviewTimer->stop(); | 359 | m_outdatedPreviewTimer->stop(); | ||
322 | Q_UNUSED(item); | 360 | Q_UNUSED(item) | ||
323 | 361 | | |||
324 | QPixmap p = pixmap; | 362 | QPixmap p = pixmap; | ||
325 | KIconLoader::global()->drawOverlays(item.overlays(), p, KIconLoader::Desktop); | 363 | KIconLoader::global()->drawOverlays(item.overlays(), p, KIconLoader::Desktop); | ||
364 | | ||||
365 | if (m_isVideo) { | ||||
366 | // adds a play arrow | ||||
367 | | ||||
368 | // compute relative pixel positions | ||||
369 | const int zeroX = static_cast<int>(p.width() / 2 - PLAY_ARROW_SIZE / 2 / devicePixelRatio()); | ||||
370 | const int zeroY = static_cast<int>(p.height() / 2 - PLAY_ARROW_SIZE / 2 / devicePixelRatio()); | ||||
elvisangelaccio: Please always use camelCase. | |||||
371 | | ||||
372 | QPolygon arrow; | ||||
elvisangelaccio: Is it possible to not hardcode these numbers? | |||||
373 | arrow << QPoint(zeroX, zeroY); | ||||
374 | arrow << QPoint(zeroX, zeroY + PLAY_ARROW_SIZE); | ||||
375 | arrow << QPoint(zeroX + PLAY_ARROW_SIZE, zeroY + PLAY_ARROW_SIZE / 2); | ||||
376 | | ||||
377 | QPainterPath path; | ||||
378 | path.addPolygon(arrow); | ||||
379 | | ||||
elvisangelaccio: Coding style: opening brace should go to the end of previous line. | |||||
380 | QLinearGradient gradient(QPointF(zeroX, zeroY), | ||||
381 | QPointF(zeroX + PLAY_ARROW_SIZE,zeroY + PLAY_ARROW_SIZE)); | ||||
382 | | ||||
383 | QColor whiteColor = Qt::white; | ||||
384 | QColor blackColor = Qt::black; | ||||
385 | gradient.setColorAt(0, whiteColor); | ||||
386 | gradient.setColorAt(1, blackColor); | ||||
387 | | ||||
388 | QBrush brush(gradient); | ||||
389 | | ||||
390 | QPainter painter(&p); | ||||
391 | | ||||
392 | QPen pen(blackColor, PLAY_ARROW_BORDER_SIZE, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); | ||||
393 | painter.setPen(pen); | ||||
394 | | ||||
395 | painter.setRenderHint(QPainter::Antialiasing); | ||||
396 | painter.drawPolygon(arrow); | ||||
397 | painter.fillPath(path, brush); | ||||
398 | } | ||||
399 | | ||||
326 | m_preview->setPixmap(p); | 400 | m_preview->setPixmap(p); | ||
327 | } | 401 | } | ||
328 | 402 | | |||
329 | void InformationPanelContent::markOutdatedPreview() | 403 | void InformationPanelContent::markOutdatedPreview() | ||
330 | { | 404 | { | ||
331 | KIconEffect *iconEffect = KIconLoader::global()->iconEffect(); | 405 | KIconEffect *iconEffect = KIconLoader::global()->iconEffect(); | ||
332 | QPixmap disabledPixmap = iconEffect->apply(m_preview->pixmap(), | 406 | QPixmap disabledPixmap = iconEffect->apply(m_preview->pixmap(), | ||
333 | KIconLoader::Desktop, | 407 | KIconLoader::Desktop, | ||
334 | KIconLoader::DisabledState); | 408 | KIconLoader::DisabledState); | ||
335 | m_preview->setPixmap(disabledPixmap); | 409 | m_preview->setPixmap(disabledPixmap); | ||
336 | } | 410 | } | ||
337 | 411 | | |||
338 | KFileItemList InformationPanelContent::items() | 412 | KFileItemList InformationPanelContent::items() | ||
339 | { | 413 | { | ||
340 | return m_metaDataWidget->items(); | 414 | return m_metaDataWidget->items(); | ||
341 | } | 415 | } | ||
342 | 416 | | |||
343 | void InformationPanelContent::slotHasVideoChanged(bool hasVideo) | 417 | void InformationPanelContent::slotHasVideoChanged(bool hasVideo) | ||
344 | { | 418 | { | ||
345 | m_preview->setVisible(InformationPanelSettings::previewsShown() && !hasVideo); | 419 | m_preview->setVisible(InformationPanelSettings::previewsShown() && !hasVideo); | ||
420 | if (m_preview->isVisible() && m_preview->size().width() != m_preview->pixmap().size().width()) { | ||||
421 | // in case the information panel has been resized when the preview was not displayed | ||||
422 | // we need to refresh its content | ||||
423 | refreshPixmapView(); | ||||
424 | } | ||||
346 | } | 425 | } | ||
347 | 426 | | |||
348 | void InformationPanelContent::setPreviewAutoPlay(bool autoPlay) { | 427 | void InformationPanelContent::setPreviewAutoPlay(bool autoPlay) { | ||
349 | m_phononWidget->setAutoPlay(autoPlay); | 428 | m_phononWidget->setAutoPlay(autoPlay); | ||
350 | } | 429 | } | ||
351 | 430 | | |||
352 | void InformationPanelContent::setNameLabelText(const QString& text) | 431 | void InformationPanelContent::setNameLabelText(const QString& text) | ||
353 | { | 432 | { | ||
▲ 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?