// vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau 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, Cambridge, MA 02110-1301, USA. */ // Self #include "fullscreencontent.moc" // Qt #include #include #include #include #include #include #include #include #include #include #include // KDE #include #include #include #include #include // Local #include "imagemetainfodialog.h" #include "ui_fullscreenconfigwidget.h" #include #include #include #include #include #include #include #include #include namespace Gwenview { /** * A widget which behaves more or less like a QToolBar, but which uses real * widgets for the toolbar items. We need a real widget to be able to position * the option menu. */ class FullScreenToolBar : public QWidget { public: FullScreenToolBar(QWidget* parent = 0) : QWidget(parent) , mLayout(new QHBoxLayout(this)) { setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); mLayout->setSpacing(0); mLayout->setMargin(0); } void addAction(QAction* action) { QToolButton* button = new QToolButton; button->setDefaultAction(action); button->setToolButtonStyle(Qt::ToolButtonIconOnly); button->setAutoRaise(true); const int extent = KIconLoader::SizeMedium; button->setIconSize(QSize(extent, extent)); mLayout->addWidget(button); } void addSeparator() { mLayout->addSpacing(KDialog::spacingHint()); } void addStretch() { mLayout->addStretch(); } void setDirection(QBoxLayout::Direction direction) { mLayout->setDirection(direction); } private: QBoxLayout* mLayout; }; class FullScreenConfigWidget : public QWidget, public Ui_FullScreenConfigWidget { public: FullScreenConfigWidget(QWidget* parent=0) : QWidget(parent) { setupUi(this); } }; struct FullScreenContentPrivate { FullScreenContent* q; KActionCollection* mActionCollection; FullScreenBar* mAutoHideContainer; SlideShow* mSlideShow; QWidget* mContent; FullScreenToolBar* mToolBar; FullScreenToolBar* mRightToolBar; ThumbnailBarView* mThumbnailBar; QLabel* mInformationLabel; ShadowFilter* mToolBarShadow; ShadowFilter* mRightToolBarShadow; ShadowFilter* mInformationLabelShadow; Document::Ptr mCurrentDocument; QPointer mImageMetaInfoDialog; QPointer mConfigWidget; KAction* mOptionsAction; bool mFullScreenMode; bool mViewPageVisible; void createOptionsAction() { // We do not use a KActionMenu because: // // - It causes the button to show a small down arrow on its right, // which makes it wider // // - We can't control where the menu shows: in no-thumbnail-mode, the // menu should not be aligned to the right edge of the screen because // if the mode is changed to thumbnail-mode, we want the option button // to remain visible mOptionsAction = new KAction(q); mOptionsAction->setPriority(QAction::LowPriority); mOptionsAction->setIcon(KIcon("configure")); mOptionsAction->setToolTip(i18nc("@info:tooltip", "Configure full screen mode")); QObject::connect(mOptionsAction, SIGNAL(triggered()), q, SLOT(showOptionsMenu())); } void updateContainerAppearance() { if (!mFullScreenMode || !mViewPageVisible) { mAutoHideContainer->setActivated(false); return; } mThumbnailBar->setVisible(GwenviewConfig::showFullScreenThumbnails()); mAutoHideContainer->adjustSize(); mAutoHideContainer->setActivated(true); } void updateLayout() { delete mContent->layout(); if (GwenviewConfig::showFullScreenThumbnails()) { mRightToolBar->setDirection(QBoxLayout::TopToBottom); QHBoxLayout* layout = new QHBoxLayout(mContent); layout->setMargin(0); layout->setSpacing(0); QVBoxLayout* vLayout; // First column vLayout = new QVBoxLayout; vLayout->addWidget(mToolBar); vLayout->addWidget(mInformationLabel); layout->addLayout(vLayout); // Second column layout->addSpacing(2); layout->addWidget(mThumbnailBar); layout->addSpacing(2); // Third column vLayout = new QVBoxLayout; vLayout->addWidget(mRightToolBar); layout->addLayout(vLayout); mThumbnailBar->setFixedHeight(GwenviewConfig::fullScreenBarHeight()); mAutoHideContainer->setFixedHeight(GwenviewConfig::fullScreenBarHeight()); // Shadows mToolBarShadow->reset(); mToolBarShadow->setShadow(ShadowFilter::RightEdge, QColor(0, 0, 0, 64)); mToolBarShadow->setShadow(ShadowFilter::BottomEdge, QColor(255, 255, 255, 8)); mInformationLabelShadow->reset(); mInformationLabelShadow->setShadow(ShadowFilter::LeftEdge, QColor(0, 0, 0, 64)); mInformationLabelShadow->setShadow(ShadowFilter::TopEdge, QColor(0, 0, 0, 64)); mInformationLabelShadow->setShadow(ShadowFilter::RightEdge, QColor(0, 0, 0, 128)); mInformationLabelShadow->setShadow(ShadowFilter::BottomEdge, QColor(255, 255, 255, 8)); mRightToolBarShadow->reset(); mRightToolBarShadow->setShadow(ShadowFilter::LeftEdge, QColor(0, 0, 0, 64)); mRightToolBarShadow->setShadow(ShadowFilter::BottomEdge, QColor(255, 255, 255, 8)); } else { mRightToolBar->setDirection(QBoxLayout::RightToLeft); QHBoxLayout* layout = new QHBoxLayout(mContent); layout->setMargin(0); layout->setSpacing(0); layout->addWidget(mToolBar); layout->addWidget(mInformationLabel); layout->addWidget(mRightToolBar); mAutoHideContainer->setFixedHeight(mContent->sizeHint().height()); // Shadows mToolBarShadow->reset(); mInformationLabelShadow->reset(); mInformationLabelShadow->setShadow(ShadowFilter::LeftEdge, QColor(0, 0, 0, 64)); mInformationLabelShadow->setShadow(ShadowFilter::RightEdge, QColor(0, 0, 0, 32)); mRightToolBarShadow->reset(); mRightToolBarShadow->setShadow(ShadowFilter::LeftEdge, QColor(255, 255, 255, 8)); } } }; FullScreenContent::FullScreenContent(QObject* parent) : QObject(parent) , d(new FullScreenContentPrivate) { d->q = this; d->mFullScreenMode = false; d->mViewPageVisible = false; } FullScreenContent::~FullScreenContent() { delete d; } void FullScreenContent::init(KActionCollection* actionCollection, QWidget* autoHideParentWidget, SlideShow* slideShow) { d->mSlideShow = slideShow; d->mActionCollection = actionCollection; connect(actionCollection->action("view"), SIGNAL(toggled(bool)), SLOT(slotViewModeActionToggled(bool))); // mAutoHideContainer d->mAutoHideContainer = new FullScreenBar(autoHideParentWidget); d->mAutoHideContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); QVBoxLayout* layout = new QVBoxLayout(d->mAutoHideContainer); layout->setMargin(0); layout->setSpacing(0); // mContent d->mContent = new QWidget; d->mContent->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); d->mContent->setAutoFillBackground(true); EventWatcher::install(d->mContent, QEvent::Show, this, SLOT(updateCurrentUrlWidgets())); EventWatcher::install(d->mContent, QEvent::PaletteChange, this, SLOT(slotPaletteChanged())); layout->addWidget(d->mContent); d->createOptionsAction(); // mToolBar d->mToolBar = new FullScreenToolBar(d->mContent); #define addAction(name) d->mToolBar->addAction(actionCollection->action(name)) addAction("browse"); addAction("view"); d->mToolBar->addSeparator(); addAction("go_previous"); addAction("toggle_slideshow"); addAction("go_next"); d->mToolBar->addSeparator(); addAction("rotate_left"); addAction("rotate_right"); #undef addAction d->mToolBarShadow = new ShadowFilter(d->mToolBar); // mInformationLabel d->mInformationLabel = new QLabel; d->mInformationLabel->setWordWrap(true); d->mInformationLabel->setContentsMargins(6, 0, 6, 0); d->mInformationLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); d->mInformationLabel->setAutoFillBackground(true); d->mInformationLabelShadow = new ShadowFilter(d->mInformationLabel); // Thumbnail bar d->mThumbnailBar = new ThumbnailBarView(d->mContent); d->mThumbnailBar->setThumbnailScaleMode(ThumbnailView::ScaleToSquare); ThumbnailBarItemDelegate* delegate = new ThumbnailBarItemDelegate(d->mThumbnailBar); d->mThumbnailBar->setItemDelegate(delegate); d->mThumbnailBar->setSelectionMode(QAbstractItemView::ExtendedSelection); // Right bar d->mRightToolBar = new FullScreenToolBar(d->mContent); d->mRightToolBar->addAction(d->mActionCollection->action("leave_fullscreen")); d->mRightToolBar->addAction(d->mOptionsAction); d->mRightToolBar->addStretch(); d->mRightToolBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); d->mRightToolBarShadow = new ShadowFilter(d->mRightToolBar); d->updateLayout(); d->updateContainerAppearance(); } ThumbnailBarView* FullScreenContent::thumbnailBar() const { return d->mThumbnailBar; } void FullScreenContent::setCurrentUrl(const KUrl& url) { if (url.isEmpty()) { d->mCurrentDocument = Document::Ptr(); } else { d->mCurrentDocument = DocumentFactory::instance()->load(url); connect(d->mCurrentDocument.data(), SIGNAL(metaInfoUpdated()), SLOT(updateCurrentUrlWidgets())); } updateCurrentUrlWidgets(); } void FullScreenContent::updateInformationLabel() { if (!d->mCurrentDocument) { return; } if (!d->mInformationLabel->isVisible()) { return; } ImageMetaInfoModel* model = d->mCurrentDocument->metaInfo(); QStringList valueList; Q_FOREACH(const QString & key, GwenviewConfig::fullScreenPreferredMetaInfoKeyList()) { const QString value = model->getValueForKey(key); if (value.length() > 0) { valueList << value; } } QString text = valueList.join(i18nc("@item:intext fullscreen meta info separator", ", ")); d->mInformationLabel->setText(text); } void FullScreenContent::slotPaletteChanged() { QPalette pal = d->mContent->palette(); pal.setColor(QPalette::Window, pal.color(QPalette::Window).dark(110)); d->mInformationLabel->setPalette(pal); } void FullScreenContent::updateCurrentUrlWidgets() { updateInformationLabel(); updateMetaInfoDialog(); } void FullScreenContent::showImageMetaInfoDialog() { if (!d->mImageMetaInfoDialog) { d->mImageMetaInfoDialog = new ImageMetaInfoDialog(d->mInformationLabel); // Do not let the fullscreen theme propagate to this dialog for now, // it's already quite complicated to create a theme d->mImageMetaInfoDialog->setStyle(QApplication::style()); d->mImageMetaInfoDialog->setAttribute(Qt::WA_DeleteOnClose, true); connect(d->mImageMetaInfoDialog, SIGNAL(preferredMetaInfoKeyListChanged(QStringList)), SLOT(slotPreferredMetaInfoKeyListChanged(QStringList))); connect(d->mImageMetaInfoDialog, SIGNAL(destroyed()), SLOT(slotImageMetaInfoDialogClosed())); } if (d->mCurrentDocument) { d->mImageMetaInfoDialog->setMetaInfo(d->mCurrentDocument->metaInfo(), GwenviewConfig::fullScreenPreferredMetaInfoKeyList()); } d->mAutoHideContainer->setAutoHidingEnabled(false); d->mImageMetaInfoDialog->show(); } void FullScreenContent::slotPreferredMetaInfoKeyListChanged(const QStringList& list) { GwenviewConfig::setFullScreenPreferredMetaInfoKeyList(list); GwenviewConfig::self()->writeConfig(); updateInformationLabel(); } void FullScreenContent::updateMetaInfoDialog() { if (!d->mImageMetaInfoDialog) { return; } ImageMetaInfoModel* model = d->mCurrentDocument ? d->mCurrentDocument->metaInfo() : 0; d->mImageMetaInfoDialog->setMetaInfo(model, GwenviewConfig::fullScreenPreferredMetaInfoKeyList()); } static QString formatSlideShowIntervalText(int value) { return i18ncp("Slideshow interval in seconds", "%1 sec", "%1 secs", value); } void FullScreenContent::updateSlideShowIntervalLabel() { Q_ASSERT(d->mConfigWidget); int value = d->mConfigWidget->mSlideShowIntervalSlider->value(); QString text = formatSlideShowIntervalText(value); d->mConfigWidget->mSlideShowIntervalLabel->setText(text); } void FullScreenContent::setFullScreenBarHeight(int value) { d->mThumbnailBar->setFixedHeight(value); d->mAutoHideContainer->setFixedHeight(value); GwenviewConfig::setFullScreenBarHeight(value); } void FullScreenContent::showOptionsMenu() { Q_ASSERT(!d->mConfigWidget); d->mConfigWidget = new FullScreenConfigWidget; FullScreenConfigWidget* widget = d->mConfigWidget; // Put widget in a menu QMenu menu; QWidgetAction* action = new QWidgetAction(&menu); action->setDefaultWidget(widget); menu.addAction(action); // Slideshow checkboxes widget->mSlideShowLoopCheckBox->setChecked(d->mSlideShow->loopAction()->isChecked()); connect(widget->mSlideShowLoopCheckBox, SIGNAL(toggled(bool)), d->mSlideShow->loopAction(), SLOT(trigger())); widget->mSlideShowRandomCheckBox->setChecked(d->mSlideShow->randomAction()->isChecked()); connect(widget->mSlideShowRandomCheckBox, SIGNAL(toggled(bool)), d->mSlideShow->randomAction(), SLOT(trigger())); // Interval slider widget->mSlideShowIntervalSlider->setValue(int(GwenviewConfig::interval())); connect(widget->mSlideShowIntervalSlider, SIGNAL(valueChanged(int)), d->mSlideShow, SLOT(setInterval(int))); connect(widget->mSlideShowIntervalSlider, SIGNAL(valueChanged(int)), SLOT(updateSlideShowIntervalLabel())); // Interval label QString text = formatSlideShowIntervalText(88); int width = widget->mSlideShowIntervalLabel->fontMetrics().width(text); widget->mSlideShowIntervalLabel->setFixedWidth(width); updateSlideShowIntervalLabel(); // Image information connect(widget->mConfigureDisplayedInformationButton, SIGNAL(clicked()), SLOT(showImageMetaInfoDialog())); // Thumbnails widget->mThumbnailGroupBox->setVisible(d->mViewPageVisible); if (d->mViewPageVisible) { widget->mShowThumbnailsCheckBox->setChecked(GwenviewConfig::showFullScreenThumbnails()); widget->mHeightSlider->setMinimum(d->mRightToolBar->sizeHint().height()); widget->mHeightSlider->setValue(d->mThumbnailBar->height()); connect(widget->mShowThumbnailsCheckBox, SIGNAL(toggled(bool)), SLOT(slotShowThumbnailsToggled(bool))); connect(widget->mHeightSlider, SIGNAL(valueChanged(int)), SLOT(setFullScreenBarHeight(int))); } // Show menu below its button QPoint pos; QWidget* button = d->mOptionsAction->associatedWidgets().first(); Q_ASSERT(button); kWarning() << button << button->geometry(); if (QApplication::isRightToLeft()) { pos = button->mapToGlobal(button->rect().bottomLeft()); } else { pos = button->mapToGlobal(button->rect().bottomRight()); pos.rx() -= menu.sizeHint().width(); } kWarning() << pos; menu.exec(pos); } void FullScreenContent::setFullScreenMode(bool fullScreenMode) { d->mFullScreenMode = fullScreenMode; d->updateContainerAppearance(); } void FullScreenContent::setDistractionFreeMode(bool distractionFreeMode) { d->mAutoHideContainer->setAutoHidingEnabled(!distractionFreeMode); } void FullScreenContent::slotImageMetaInfoDialogClosed() { d->mAutoHideContainer->setAutoHidingEnabled(true); } void FullScreenContent::slotShowThumbnailsToggled(bool value) { GwenviewConfig::setShowFullScreenThumbnails(value); GwenviewConfig::self()->writeConfig(); d->mThumbnailBar->setVisible(value); d->updateLayout(); d->mContent->adjustSize(); d->mAutoHideContainer->adjustSize(); } void FullScreenContent::slotViewModeActionToggled(bool value) { d->mViewPageVisible = value; d->updateContainerAppearance(); } } // namespace