File indexing completed on 2024-04-28 05:45:14

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2022 Felix Ernst <felixernst@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "bottombar.h"
0009 
0010 #include "backgroundcolorhelper.h"
0011 #include "bottombarcontentscontainer.h"
0012 
0013 #include <QGridLayout>
0014 #include <QResizeEvent>
0015 #include <QScrollArea>
0016 #include <QStyle>
0017 #include <QTimer>
0018 
0019 using namespace SelectionMode;
0020 
0021 BottomBar::BottomBar(KActionCollection *actionCollection, QWidget *parent)
0022     : QWidget{parent}
0023 {
0024     // Showing of this widget is normally animated. We hide it for now and make it small.
0025     hide();
0026     setMaximumHeight(0);
0027 
0028     setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
0029     setMinimumWidth(0);
0030 
0031     auto fillParentLayout = new QGridLayout(this);
0032     fillParentLayout->setContentsMargins(0, 0, 0, 0);
0033 
0034     // Put the contents into a QScrollArea. This prevents increasing the view width
0035     // in case that not enough width for the contents is available. (this trick is also used in dolphinsearchbox.cpp.)
0036     m_scrollArea = new QScrollArea(this);
0037     fillParentLayout->addWidget(m_scrollArea);
0038     m_scrollArea->setFrameShape(QFrame::NoFrame);
0039     m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0040     m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0041     m_scrollArea->setWidgetResizable(true);
0042 
0043     m_contentsContainer = new BottomBarContentsContainer(actionCollection, m_scrollArea);
0044     m_scrollArea->setWidget(m_contentsContainer);
0045     m_contentsContainer->installEventFilter(this); // Adjusts the height of this bar to the height of the contentsContainer
0046     connect(m_contentsContainer, &BottomBarContentsContainer::error, this, &BottomBar::error);
0047     connect(m_contentsContainer, &BottomBarContentsContainer::barVisibilityChangeRequested, this, [this](bool visible) {
0048         if (!m_allowedToBeVisible && visible) {
0049             return;
0050         }
0051         setVisibleInternal(visible, WithAnimation);
0052     });
0053     connect(m_contentsContainer, &BottomBarContentsContainer::selectionModeLeavingRequested, this, &BottomBar::selectionModeLeavingRequested);
0054 
0055     BackgroundColorHelper::instance()->controlBackgroundColor(this);
0056 }
0057 
0058 void BottomBar::setVisible(bool visible, Animated animated)
0059 {
0060     m_allowedToBeVisible = visible;
0061     setVisibleInternal(visible, animated);
0062 }
0063 
0064 void BottomBar::setVisibleInternal(bool visible, Animated animated)
0065 {
0066     Q_ASSERT_X(animated == WithAnimation, "SelectionModeBottomBar::setVisible", "This wasn't implemented.");
0067     if (!visible && contents() == PasteContents) {
0068         return; // The bar with PasteContents should not be hidden or users might not know how to paste what they just copied.
0069                 // Set contents to anything else to circumvent this prevention mechanism.
0070     }
0071     if (visible && !m_contentsContainer->hasSomethingToShow()) {
0072         return; // There is nothing on the bar that we want to show. We keep it invisible and only show it when the selection or the contents change.
0073     }
0074 
0075     setEnabled(visible);
0076     if (m_heightAnimation) {
0077         m_heightAnimation->stop(); // deletes because of QAbstractAnimation::DeleteWhenStopped.
0078     }
0079     m_heightAnimation = new QPropertyAnimation(this, "maximumHeight");
0080     m_heightAnimation->setDuration(2 * style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, this) * GlobalConfig::animationDurationFactor());
0081     m_heightAnimation->setStartValue(height());
0082     m_heightAnimation->setEasingCurve(QEasingCurve::OutCubic);
0083     if (visible) {
0084         show();
0085         m_heightAnimation->setEndValue(sizeHint().height());
0086         connect(m_heightAnimation, &QAbstractAnimation::finished, this, [this]() {
0087             setMaximumHeight(sizeHint().height());
0088         });
0089     } else {
0090         m_heightAnimation->setEndValue(0);
0091         connect(m_heightAnimation, &QAbstractAnimation::finished, this, &QWidget::hide);
0092     }
0093 
0094     m_heightAnimation->start(QAbstractAnimation::DeleteWhenStopped);
0095 }
0096 
0097 QSize BottomBar::sizeHint() const
0098 {
0099     return QSize{1, m_contentsContainer->sizeHint().height()};
0100     // 1 as width because this widget should never be the reason the DolphinViewContainer is made wider.
0101 }
0102 
0103 void BottomBar::slotSelectionChanged(const KFileItemList &selection, const QUrl &baseUrl)
0104 {
0105     m_contentsContainer->slotSelectionChanged(selection, baseUrl);
0106 }
0107 
0108 void BottomBar::slotSplitTabDisabled()
0109 {
0110     switch (contents()) {
0111     case CopyToOtherViewContents:
0112     case MoveToOtherViewContents:
0113         Q_EMIT selectionModeLeavingRequested();
0114     default:
0115         return;
0116     }
0117 }
0118 
0119 void BottomBar::resetContents(BottomBar::Contents contents)
0120 {
0121     m_contentsContainer->resetContents(contents);
0122 
0123     if (m_allowedToBeVisible) {
0124         setVisibleInternal(true, WithAnimation);
0125     }
0126 }
0127 
0128 BottomBar::Contents BottomBar::contents() const
0129 {
0130     return m_contentsContainer->contents();
0131 }
0132 
0133 bool BottomBar::eventFilter(QObject *watched, QEvent *event)
0134 {
0135     Q_ASSERT(qobject_cast<QWidget *>(watched)); // This evenfFilter is only implemented for QWidgets.
0136 
0137     switch (event->type()) {
0138     case QEvent::ChildAdded:
0139     case QEvent::ChildRemoved:
0140         QTimer::singleShot(0, this, [this]() {
0141             // The necessary height might have changed because of the added/removed child so we change the height manually.
0142             if (isVisibleTo(parentWidget()) && isEnabled() && (!m_heightAnimation || m_heightAnimation->state() != QAbstractAnimation::Running)) {
0143                 setMaximumHeight(sizeHint().height());
0144             }
0145         });
0146         // Fall through.
0147     default:
0148         return false;
0149     }
0150 }
0151 
0152 void BottomBar::resizeEvent(QResizeEvent *resizeEvent)
0153 {
0154     if (resizeEvent->oldSize().width() == resizeEvent->size().width()) {
0155         // The width() didn't change so our custom override isn't needed.
0156         return QWidget::resizeEvent(resizeEvent);
0157     }
0158 
0159     m_contentsContainer->adaptToNewBarWidth(width());
0160 
0161     return QWidget::resizeEvent(resizeEvent);
0162 }
0163 
0164 #include "moc_bottombar.cpp"