X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/a418d6229e31dac254660da2a417b4306f066ae3..c836cf010c12858a7f3a4943c06f9de2b9f31a14:/src/dolphintabpage.cpp diff --git a/src/dolphintabpage.cpp b/src/dolphintabpage.cpp index d196508a8..33c77c42a 100644 --- a/src/dolphintabpage.cpp +++ b/src/dolphintabpage.cpp @@ -1,5 +1,6 @@ /* * SPDX-FileCopyrightText: 2014 Emmanuel Pescosta + * SPDX-FileCopyrightText: 2020 Felix Ernst * * SPDX-License-Identifier: GPL-2.0-or-later */ @@ -8,17 +9,22 @@ #include "dolphin_generalsettings.h" #include "dolphinviewcontainer.h" +#include "global.h" +#include #include -#include +#include +#include +#include DolphinTabPage::DolphinTabPage(const QUrl &primaryUrl, const QUrl &secondaryUrl, QWidget* parent) : QWidget(parent), + m_expandingContainer{nullptr}, m_primaryViewActive(true), m_splitViewEnabled(false), m_active(true) { - QVBoxLayout* layout = new QVBoxLayout(this); + QGridLayout *layout = new QGridLayout(this); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); @@ -26,7 +32,8 @@ DolphinTabPage::DolphinTabPage(const QUrl &primaryUrl, const QUrl &secondaryUrl, m_splitter->setChildrenCollapsible(false); connect(m_splitter, &QSplitter::splitterMoved, this, &DolphinTabPage::splitterMoved); - layout->addWidget(m_splitter); + layout->addWidget(m_splitter, 1, 0); + layout->setRowStretch(1, 1); // Create a new primary view m_primaryViewContainer = createViewContainer(primaryUrl); @@ -36,7 +43,6 @@ DolphinTabPage::DolphinTabPage(const QUrl &primaryUrl, const QUrl &secondaryUrl, this, &DolphinTabPage::slotViewUrlRedirection); m_splitter->addWidget(m_primaryViewContainer); - m_primaryViewContainer->installEventFilter(this); m_primaryViewContainer->show(); if (secondaryUrl.isValid() || GeneralSettings::splitView()) { @@ -46,7 +52,6 @@ DolphinTabPage::DolphinTabPage(const QUrl &primaryUrl, const QUrl &secondaryUrl, const QUrl& url = secondaryUrl.isValid() ? secondaryUrl : primaryUrl; m_secondaryViewContainer = createViewContainer(url); m_splitter->addWidget(m_secondaryViewContainer); - m_secondaryViewContainer->installEventFilter(this); m_secondaryViewContainer->show(); } @@ -63,12 +68,24 @@ bool DolphinTabPage::splitViewEnabled() const return m_splitViewEnabled; } -void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl) +void DolphinTabPage::setSplitViewEnabled(bool enabled, Animated animated, const QUrl &secondaryUrl) { if (m_splitViewEnabled != enabled) { m_splitViewEnabled = enabled; + if (animated == WithAnimation && ( + style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, this) < 1 || + GlobalConfig::animationDurationFactor() <= 0.0)) { + animated = WithoutAnimation; + } + if (m_expandViewAnimation) { + m_expandViewAnimation->stop(); // deletes because of QAbstractAnimation::DeleteWhenStopped. + if (animated == WithoutAnimation) { + slotAnimationFinished(); + } + } if (enabled) { + QList splitterSizes = m_splitter->sizes(); const QUrl& url = (secondaryUrl.isEmpty()) ? m_primaryViewContainer->url() : secondaryUrl; m_secondaryViewContainer = createViewContainer(url); @@ -79,11 +96,19 @@ void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl) } m_secondaryViewContainer->connectUrlNavigator(secondaryNavigator); m_navigatorsWidget->setSecondaryNavigatorVisible(true); + m_navigatorsWidget->followViewContainersGeometry(m_primaryViewContainer, + m_secondaryViewContainer); m_splitter->addWidget(m_secondaryViewContainer); - m_secondaryViewContainer->installEventFilter(this); - m_secondaryViewContainer->show(); m_secondaryViewContainer->setActive(true); + + if (animated == WithAnimation) { + m_secondaryViewContainer->setMinimumWidth(1); + splitterSizes.append(1); + m_splitter->setSizes(splitterSizes); + startExpandViewAnimation(m_secondaryViewContainer); + } + m_secondaryViewContainer->show(); } else { m_navigatorsWidget->setSecondaryNavigatorVisible(false); m_secondaryViewContainer->disconnectUrlNavigator(); @@ -115,8 +140,19 @@ void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl) } } m_primaryViewContainer->setActive(true); - view->close(); - view->deleteLater(); + m_navigatorsWidget->followViewContainersGeometry(m_primaryViewContainer, nullptr); + + if (animated == WithoutAnimation) { + view->close(); + view->deleteLater(); + } else { + // Kill it but keep it as a zombie for the closing animation. + m_secondaryViewContainer = nullptr; + view->blockSignals(true); + view->view()->blockSignals(true); + view->setDisabled(true); + startExpandViewAnimation(m_primaryViewContainer); + } } } } @@ -157,16 +193,16 @@ int DolphinTabPage::selectedItemsCount() const void DolphinTabPage::connectNavigators(DolphinNavigatorsWidgetAction *navigatorsWidget) { + insertNavigatorsWidget(navigatorsWidget); m_navigatorsWidget = navigatorsWidget; auto primaryNavigator = navigatorsWidget->primaryUrlNavigator(); - primaryNavigator->setActive(m_primaryViewActive); m_primaryViewContainer->connectUrlNavigator(primaryNavigator); if (m_splitViewEnabled) { auto secondaryNavigator = navigatorsWidget->secondaryUrlNavigator(); - secondaryNavigator->setActive(!m_primaryViewActive); m_secondaryViewContainer->connectUrlNavigator(secondaryNavigator); } - resizeNavigators(); + m_navigatorsWidget->followViewContainersGeometry(m_primaryViewContainer, + m_secondaryViewContainer); } void DolphinTabPage::disconnectNavigators() @@ -178,26 +214,16 @@ void DolphinTabPage::disconnectNavigators() } } -bool DolphinTabPage::eventFilter(QObject */* watched */, QEvent *event) +void DolphinTabPage::insertNavigatorsWidget(DolphinNavigatorsWidgetAction* navigatorsWidget) { - if (event->type() == QEvent::Resize && m_navigatorsWidget) { - resizeNavigators(); - } - return false; -} - -void DolphinTabPage::resizeNavigators() const -{ - if (!m_splitViewEnabled) { - m_navigatorsWidget->followViewContainerGeometry( - m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x(), - m_primaryViewContainer->width()); + QGridLayout *gridLayout = static_cast(layout()); + if (navigatorsWidget->isInToolbar()) { + gridLayout->setRowMinimumHeight(0, 0); } else { - m_navigatorsWidget->followViewContainersGeometry( - m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x(), - m_primaryViewContainer->width(), - m_secondaryViewContainer->mapToGlobal(QPoint(0,0)).x(), - m_secondaryViewContainer->width()); + // We set a row minimum height, so the height does not visibly change whenever + // navigatorsWidget is inserted which happens every time the current tab is changed. + gridLayout->setRowMinimumHeight(0, navigatorsWidget->primaryUrlNavigator()->height()); + gridLayout->addWidget(navigatorsWidget->requestWidget(this), 0, 0); } } @@ -269,7 +295,7 @@ void DolphinTabPage::restoreState(const QByteArray& state) bool isSplitViewEnabled = false; stream >> isSplitViewEnabled; - setSplitViewEnabled(isSplitViewEnabled); + setSplitViewEnabled(isSplitViewEnabled, WithoutAnimation); QUrl primaryUrl; stream >> primaryUrl; @@ -289,50 +315,6 @@ void DolphinTabPage::restoreState(const QByteArray& state) m_secondaryViewContainer->view()->restoreState(stream); } - stream >> m_primaryViewActive; - if (m_primaryViewActive) { - m_primaryViewContainer->setActive(true); - m_navigatorsWidget->primaryUrlNavigator()->setActive(true); - } else { - Q_ASSERT(m_splitViewEnabled); - m_secondaryViewContainer->setActive(true); - m_navigatorsWidget->primaryUrlNavigator()->setActive(false); - } - - QByteArray splitterState; - stream >> splitterState; - m_splitter->restoreState(splitterState); -} - -void DolphinTabPage::restoreStateV1(const QByteArray& state) -{ - if (state.isEmpty()) { - return; - } - - QByteArray sd = state; - QDataStream stream(&sd, QIODevice::ReadOnly); - - bool isSplitViewEnabled = false; - stream >> isSplitViewEnabled; - setSplitViewEnabled(isSplitViewEnabled); - - QUrl primaryUrl; - stream >> primaryUrl; - m_primaryViewContainer->setUrl(primaryUrl); - bool primaryUrlEditable; - stream >> primaryUrlEditable; - m_primaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(primaryUrlEditable); - - if (isSplitViewEnabled) { - QUrl secondaryUrl; - stream >> secondaryUrl; - m_secondaryViewContainer->setUrl(secondaryUrl); - bool secondaryUrlEditable; - stream >> secondaryUrlEditable; - m_secondaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(secondaryUrlEditable); - } - stream >> m_primaryViewActive; if (m_primaryViewActive) { m_primaryViewContainer->setActive(true); @@ -358,6 +340,72 @@ void DolphinTabPage::setActive(bool active) activeViewContainer()->setActive(active); } +void DolphinTabPage::slotAnimationFinished() +{ + for (int i = 0; i < m_splitter->count(); ++i) { + QWidget *viewContainer = m_splitter->widget(i); + if (viewContainer != m_primaryViewContainer && + viewContainer != m_secondaryViewContainer) { + viewContainer->close(); + viewContainer->deleteLater(); + } + } + for (int i = 0; i < m_splitter->count(); ++i) { + QWidget *viewContainer = m_splitter->widget(i); + viewContainer->setMinimumWidth(viewContainer->minimumSizeHint().width()); + } + m_expandingContainer = nullptr; +} + +void DolphinTabPage::slotAnimationValueChanged(const QVariant& value) +{ + Q_CHECK_PTR(m_expandingContainer); + const int indexOfExpandingContainer = m_splitter->indexOf(m_expandingContainer); + int indexOfNonExpandingContainer = -1; + if (m_expandingContainer == m_primaryViewContainer) { + indexOfNonExpandingContainer = m_splitter->indexOf(m_secondaryViewContainer); + } else { + indexOfNonExpandingContainer = m_splitter->indexOf(m_primaryViewContainer); + } + std::vector widgetsToRemove; + const QList oldSplitterSizes = m_splitter->sizes(); + QList newSplitterSizes{oldSplitterSizes}; + int expansionWidthNeeded = value.toInt() - oldSplitterSizes.at(indexOfExpandingContainer); + + // Reduce the size of the other widgets to make space for the expandingContainer. + for (int i = m_splitter->count() - 1; i >= 0; --i) { + if (m_splitter->widget(i) == m_primaryViewContainer || + m_splitter->widget(i) == m_secondaryViewContainer) { + continue; + } + newSplitterSizes[i] = oldSplitterSizes.at(i) - expansionWidthNeeded; + expansionWidthNeeded = 0; + if (indexOfNonExpandingContainer != -1) { + // Make sure every zombie container is at least slightly reduced in size + // so it doesn't seem like they are here to stay. + newSplitterSizes[i]--; + newSplitterSizes[indexOfNonExpandingContainer]++; + } + if (newSplitterSizes.at(i) <= 0) { + expansionWidthNeeded -= newSplitterSizes.at(i); + newSplitterSizes[i] = 0; + widgetsToRemove.emplace_back(m_splitter->widget(i)); + } + } + if (expansionWidthNeeded > 1 && indexOfNonExpandingContainer != -1) { + Q_ASSERT(m_splitViewEnabled); + newSplitterSizes[indexOfNonExpandingContainer] -= expansionWidthNeeded; + } + newSplitterSizes[indexOfExpandingContainer] = value.toInt(); + m_splitter->setSizes(newSplitterSizes); + while (!widgetsToRemove.empty()) { + widgetsToRemove.back()->close(); + widgetsToRemove.back()->deleteLater(); + widgetsToRemove.pop_back(); + } +} + + void DolphinTabPage::slotViewActivated() { const DolphinView* oldActiveView = activeViewContainer()->view(); @@ -427,3 +475,33 @@ DolphinViewContainer* DolphinTabPage::createViewContainer(const QUrl& url) const return container; } + +void DolphinTabPage::startExpandViewAnimation(DolphinViewContainer *expandingContainer) +{ + Q_CHECK_PTR(expandingContainer); + Q_ASSERT(expandingContainer == m_primaryViewContainer || + expandingContainer == m_secondaryViewContainer); + m_expandingContainer = expandingContainer; + + m_expandViewAnimation = new QVariantAnimation(m_splitter); + m_expandViewAnimation->setDuration(2 * + style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, this) * + GlobalConfig::animationDurationFactor()); + for (int i = 0; i < m_splitter->count(); ++i) { + m_splitter->widget(i)->setMinimumWidth(1); + } + connect(m_expandViewAnimation, &QAbstractAnimation::finished, + this, &DolphinTabPage::slotAnimationFinished); + connect(m_expandViewAnimation, &QVariantAnimation::valueChanged, + this, &DolphinTabPage::slotAnimationValueChanged); + + m_expandViewAnimation->setStartValue(expandingContainer->width()); + if (m_splitViewEnabled) { // A new viewContainer is being opened. + m_expandViewAnimation->setEndValue(m_splitter->width() / 2); + m_expandViewAnimation->setEasingCurve(QEasingCurve::OutCubic); + } else { // A viewContainer is being closed. + m_expandViewAnimation->setEndValue(m_splitter->width()); + m_expandViewAnimation->setEasingCurve(QEasingCurve::InCubic); + } + m_expandViewAnimation->start(QAbstractAnimation::DeleteWhenStopped); +}