X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/ecf1ae6d0b1691bfe36fc0ff64500f111f3abc32..6f632283d022aaf9d8e2bda81a5409aa36242d4d:/src/panels/information/informationpanelcontent.cpp diff --git a/src/panels/information/informationpanelcontent.cpp b/src/panels/information/informationpanelcontent.cpp index 5b7dbbfe9..98c012243 100644 --- a/src/panels/information/informationpanelcontent.cpp +++ b/src/panels/information/informationpanelcontent.cpp @@ -1,32 +1,22 @@ -/*************************************************************************** - * Copyright (C) 2009 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ +/* + * SPDX-FileCopyrightText: 2009 Peter Penz + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ #include "informationpanelcontent.h" #include #include +#include #include #include #include #include #include +#include #include +#include #include #include @@ -45,12 +35,21 @@ #include #include #include +#include #include +#include +#include +#include +#include +#include #include "dolphin_informationpanelsettings.h" #include "phononwidget.h" #include "pixmapviewer.h" +const int PLAY_ARROW_SIZE = 24; +const int PLAY_ARROW_BORDER_SIZE = 2; + InformationPanelContent::InformationPanelContent(QWidget* parent) : QWidget(parent), m_item(), @@ -61,7 +60,8 @@ InformationPanelContent::InformationPanelContent(QWidget* parent) : m_nameLabel(nullptr), m_metaDataWidget(nullptr), m_metaDataArea(nullptr), - m_placesItemModel(nullptr) + m_placesItemModel(nullptr), + m_isVideo(false) { parent->installEventFilter(this); @@ -69,7 +69,7 @@ InformationPanelContent::InformationPanelContent(QWidget* parent) : // delay. This prevents flickering if the new preview can be generated // within a very small timeframe. m_outdatedPreviewTimer = new QTimer(this); - m_outdatedPreviewTimer->setInterval(300); + m_outdatedPreviewTimer->setInterval(100); m_outdatedPreviewTimer->setSingleShot(true); connect(m_outdatedPreviewTimer, &QTimer::timeout, this, &InformationPanelContent::markOutdatedPreview); @@ -86,6 +86,7 @@ InformationPanelContent::InformationPanelContent(QWidget* parent) : m_phononWidget = new PhononWidget(parent); m_phononWidget->hide(); m_phononWidget->setMinimumWidth(minPreviewWidth); + m_phononWidget->setAutoPlay(InformationPanelSettings::previewsAutoPlay()); connect(m_phononWidget, &PhononWidget::hasVideoChanged, this, &InformationPanelContent::slotHasVideoChanged); @@ -97,6 +98,7 @@ InformationPanelContent::InformationPanelContent(QWidget* parent) : m_nameLabel->setTextFormat(Qt::PlainText); m_nameLabel->setAlignment(Qt::AlignHCenter); m_nameLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + m_nameLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); const bool previewsShown = InformationPanelSettings::previewsShown(); m_preview->setVisible(previewsShown); @@ -120,14 +122,14 @@ InformationPanelContent::InformationPanelContent(QWidget* parent) : m_metaDataWidget->setConfigurationMode(Baloo::ConfigurationMode::Accept); m_configureButtons->setVisible(false); m_configureLabel->setVisible(false); - emit configurationFinished(); + Q_EMIT configurationFinished(); } ); connect(m_configureButtons, &QDialogButtonBox::rejected, this, [this]() { m_metaDataWidget->setConfigurationMode(Baloo::ConfigurationMode::Cancel); m_configureButtons->setVisible(false); m_configureLabel->setVisible(false); - emit configurationFinished(); + Q_EMIT configurationFinished(); } ); @@ -137,6 +139,7 @@ InformationPanelContent::InformationPanelContent(QWidget* parent) : m_metaDataArea->setFrameShape(QFrame::NoFrame); QWidget* viewport = m_metaDataArea->viewport(); + QScroller::grabGesture(viewport, QScroller::TouchGesture); viewport->installEventFilter(this); layout->addWidget(m_preview); @@ -147,6 +150,8 @@ InformationPanelContent::InformationPanelContent(QWidget* parent) : layout->addWidget(m_metaDataArea); layout->addWidget(m_configureButtons); + grabGesture(Qt::TapAndHoldGesture); + m_placesItemModel = new PlacesItemModel(this); } @@ -157,10 +162,46 @@ InformationPanelContent::~InformationPanelContent() void InformationPanelContent::showItem(const KFileItem& item) { - m_item = item; + // compares item entries, comparing items only compares urls + if (m_item.entry() != item.entry()) { + m_item = item; + m_preview->stopAnimatedImage(); + refreshMetaData(); + } refreshPreview(); - refreshMetaData(); +} + +void InformationPanelContent::refreshPixmapView() +{ + // If there is a preview job, kill it to prevent that we have jobs for + // multiple items running, and thus a race condition (bug 250787). + if (m_previewJob) { + m_previewJob->kill(); + } + + // try to get a preview pixmap from the item... + + // Mark the currently shown preview as outdated. This is done + // with a small delay to prevent a flickering when the next preview + // can be shown within a short timeframe. + m_outdatedPreviewTimer->start(); + + const KConfigGroup globalConfig(KSharedConfig::openConfig(), "PreviewSettings"); + const QStringList plugins = globalConfig.readEntry("Plugins", KIO::PreviewJob::defaultPlugins()); + m_previewJob = new KIO::PreviewJob(KFileItemList() << m_item, + QSize(m_preview->width(), m_preview->height()), + &plugins); + m_previewJob->setScaleType(KIO::PreviewJob::Unscaled); + m_previewJob->setIgnoreMaximumSize(m_item.isLocalFile()); + if (m_previewJob->uiDelegate()) { + KJobWidgets::setWindow(m_previewJob, this); + } + + connect(m_previewJob.data(), &KIO::PreviewJob::gotPreview, + this, &InformationPanelContent::showPreview); + connect(m_previewJob.data(), &KIO::PreviewJob::failed, + this, &InformationPanelContent::showIcon); } void InformationPanelContent::refreshPreview() @@ -171,56 +212,70 @@ void InformationPanelContent::refreshPreview() m_previewJob->kill(); } + m_preview->setCursor(Qt::ArrowCursor); setNameLabelText(m_item.text()); if (InformationPanelSettings::previewsShown()) { - m_preview->show(); const QUrl itemUrl = m_item.url(); - const bool isSearchUrl = itemUrl.scheme().contains(QStringLiteral("search")) && m_item.localPath().isEmpty(); + const bool isSearchUrl = itemUrl.scheme().contains(QLatin1String("search")) && m_item.localPath().isEmpty(); if (isSearchUrl) { + m_preview->show(); + m_phononWidget->hide(); + // in the case of a search-URL the URL is not readable for humans // (at least not useful to show in the Information Panel) m_preview->setPixmap( - QIcon::fromTheme(QStringLiteral("nepomuk")).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous) + QIcon::fromTheme(QStringLiteral("baloo")).pixmap(m_preview->height(), m_preview->width()) ); } else { - // try to get a preview pixmap from the item... - - // Mark the currently shown preview as outdated. This is done - // with a small delay to prevent a flickering when the next preview - // can be shown within a short timeframe. This timer is not started - // for directories, as directory previews might fail and return the - // same icon. - if (!m_item.isDir()) { - m_outdatedPreviewTimer->start(); - } - QStringList plugins = KIO::PreviewJob::availablePlugins(); - m_previewJob = new KIO::PreviewJob(KFileItemList() << m_item, - QSize(m_preview->width(), m_preview->height()), - &plugins); - m_previewJob->setScaleType(KIO::PreviewJob::Unscaled); - m_previewJob->setIgnoreMaximumSize(m_item.isLocalFile()); - if (m_previewJob->uiDelegate()) { - KJobWidgets::setWindow(m_previewJob, this); - } - - connect(m_previewJob.data(), &KIO::PreviewJob::gotPreview, - this, &InformationPanelContent::showPreview); - connect(m_previewJob.data(), &KIO::PreviewJob::failed, - this, &InformationPanelContent::showIcon); + refreshPixmapView(); const QString mimeType = m_item.mimetype(); - const bool usePhonon = mimeType.startsWith(QLatin1String("audio/")) || mimeType.startsWith(QLatin1String("video/")); + const bool isAnimatedImage = m_preview->isAnimatedMimeType(mimeType); + m_isVideo = !isAnimatedImage && mimeType.startsWith(QLatin1String("video/")); + bool usePhonon = m_isVideo || mimeType.startsWith(QLatin1String("audio/")); + if (usePhonon) { + // change the cursor of the preview + m_preview->setCursor(Qt::PointingHandCursor); + m_preview->installEventFilter(m_phononWidget); m_phononWidget->show(); - m_phononWidget->setUrl(m_item.targetUrl()); - m_phononWidget->setVideoSize(m_preview->size()); + + // if the video is playing, has been paused or stopped + // we don't need to update the preview/phonon widget states + // unless the previewed file has changed, + // or the setting previewshown has changed + if ((m_phononWidget->state() != Phonon::State::PlayingState && + m_phononWidget->state() != Phonon::State::PausedState && + m_phononWidget->state() != Phonon::State::StoppedState) || + m_item.targetUrl() != m_phononWidget->url() || + (!m_preview->isVisible() &&! m_phononWidget->isVisible())) { + + if (InformationPanelSettings::previewsAutoPlay() && m_isVideo) { + // hides the preview now to avoid flickering when the autoplay video starts + m_preview->hide(); + } else { + // the video won't play before the preview is displayed + m_preview->show(); + } + + m_phononWidget->setUrl(m_item.targetUrl(), m_isVideo ? PhononWidget::MediaKind::Video : PhononWidget::MediaKind::Audio); + adjustWidgetSizes(parentWidget()->width()); + } } else { + if (isAnimatedImage) { + m_preview->setAnimatedImageFileName(itemUrl.toLocalFile()); + } + // When we don't need it, hide the phonon widget first to avoid flickering m_phononWidget->hide(); + m_preview->show(); + m_preview->removeEventFilter(m_phononWidget); + m_phononWidget->clearUrl(); } } } else { + m_preview->stopAnimatedImage(); m_preview->hide(); m_phononWidget->hide(); } @@ -248,8 +303,10 @@ void InformationPanelContent::showItems(const KFileItemList& items) m_previewJob->kill(); } + m_preview->stopAnimatedImage(); + m_preview->setPixmap( - QIcon::fromTheme(QStringLiteral("dialog-information")).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous) + QIcon::fromTheme(QStringLiteral("dialog-information")).pixmap(m_preview->height(), m_preview->width()) ); setNameLabelText(i18ncp("@label", "%1 item selected", "%1 items selected", items.count())); @@ -290,10 +347,37 @@ bool InformationPanelContent::eventFilter(QObject* obj, QEvent* event) return QWidget::eventFilter(obj, event); } +bool InformationPanelContent::event(QEvent* event) +{ + if (event->type() == QEvent::Gesture) { + gestureEvent(static_cast(event)); + return true; + } + return QWidget::event(event); +} + +bool InformationPanelContent::gestureEvent(QGestureEvent* event) +{ + if (!underMouse()) { + return false; + } + + QTapAndHoldGesture* tap = static_cast(event->gesture(Qt::TapAndHoldGesture)); + + if (tap) { + if (tap->state() == Qt::GestureFinished) { + Q_EMIT contextMenuRequested(tap->position().toPoint()); + } + event->accept(); + return true; + } + return false; +} + void InformationPanelContent::showIcon(const KFileItem& item) { m_outdatedPreviewTimer->stop(); - QPixmap pixmap = QIcon::fromTheme(item.iconName()).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous); + QPixmap pixmap = QIcon::fromTheme(item.iconName()).pixmap(m_preview->height(), m_preview->width()); KIconLoader::global()->drawOverlays(item.overlays(), pixmap, KIconLoader::Desktop); m_preview->setPixmap(pixmap); } @@ -302,20 +386,62 @@ void InformationPanelContent::showPreview(const KFileItem& item, const QPixmap& pixmap) { m_outdatedPreviewTimer->stop(); - Q_UNUSED(item); QPixmap p = pixmap; KIconLoader::global()->drawOverlays(item.overlays(), p, KIconLoader::Desktop); + + if (m_isVideo) { + // adds a play arrow + + // compute relative pixel positions + const int zeroX = static_cast((p.width() / 2 - PLAY_ARROW_SIZE / 2) / pixmap.devicePixelRatio()); + const int zeroY = static_cast((p.height() / 2 - PLAY_ARROW_SIZE / 2) / pixmap.devicePixelRatio()); + + QPolygon arrow; + arrow << QPoint(zeroX, zeroY); + arrow << QPoint(zeroX, zeroY + PLAY_ARROW_SIZE); + arrow << QPoint(zeroX + PLAY_ARROW_SIZE, zeroY + PLAY_ARROW_SIZE / 2); + + QPainterPath path; + path.addPolygon(arrow); + + QLinearGradient gradient(QPointF(zeroX, zeroY), + QPointF(zeroX + PLAY_ARROW_SIZE,zeroY + PLAY_ARROW_SIZE)); + + QColor whiteColor = Qt::white; + QColor blackColor = Qt::black; + gradient.setColorAt(0, whiteColor); + gradient.setColorAt(1, blackColor); + + QBrush brush(gradient); + + QPainter painter(&p); + + QPen pen(blackColor, PLAY_ARROW_BORDER_SIZE, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + painter.setPen(pen); + + painter.setRenderHint(QPainter::Antialiasing); + painter.drawPolygon(arrow); + painter.fillPath(path, brush); + } + m_preview->setPixmap(p); } void InformationPanelContent::markOutdatedPreview() { - KIconEffect *iconEffect = KIconLoader::global()->iconEffect(); - QPixmap disabledPixmap = iconEffect->apply(m_preview->pixmap(), - KIconLoader::Desktop, - KIconLoader::DisabledState); - m_preview->setPixmap(disabledPixmap); + if (m_item.isDir()) { + // directory preview can be long + // but since we always have icons to display + // use it until the preview is done + showIcon(m_item); + } else { + KIconEffect *iconEffect = KIconLoader::global()->iconEffect(); + QPixmap disabledPixmap = iconEffect->apply(m_preview->pixmap(), + KIconLoader::Desktop, + KIconLoader::DisabledState); + m_preview->setPixmap(disabledPixmap); + } } KFileItemList InformationPanelContent::items() @@ -326,6 +452,15 @@ KFileItemList InformationPanelContent::items() void InformationPanelContent::slotHasVideoChanged(bool hasVideo) { m_preview->setVisible(InformationPanelSettings::previewsShown() && !hasVideo); + if (m_preview->isVisible() && m_preview->size().width() != m_preview->pixmap().size().width()) { + // in case the information panel has been resized when the preview was not displayed + // we need to refresh its content + refreshPixmapView(); + } +} + +void InformationPanelContent::setPreviewAutoPlay(bool autoPlay) { + m_phononWidget->setAutoPlay(autoPlay); } void InformationPanelContent::setNameLabelText(const QString& text)