]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Add smaller statusbar and set it as default
authorAkseli Lahtinen <akselmo@akselmo.dev>
Mon, 24 Feb 2025 18:39:22 +0000 (18:39 +0000)
committerAkseli Lahtinen <akselmo@akselmo.dev>
Mon, 24 Feb 2025 18:39:22 +0000 (18:39 +0000)
- Statusbar has three modes: Small, FullWidth and Disabled
- FullWidth is the original statusbar
- Small is the new default statusbar
  - This statusbar overlays on top of the items instead of taking space
  - It changes size according to content
- Disabled turns statusbar completely off
- Zoom slider and space information is only shown in full-width statusbar
  - Space information is now always on
- If user navigates with keyboard, or scrolls to selection, the scrolling will take the statusbar into account
  - This makes sure the statusbar does not cover any items

Related discussion: https://invent.kde.org/system/dolphin/-/issues/50

18 files changed:
src/CMakeLists.txt
src/dolphinmainwindow.cpp
src/dolphinviewcontainer.cpp
src/dolphinviewcontainer.h
src/kitemviews/kitemlistview.cpp
src/kitemviews/kitemlistview.h
src/kitemviews/private/kitemlistviewlayouter.cpp
src/kitemviews/private/kitemlistviewlayouter.h
src/settings/dolphin_25.04_update_statusandlocationbarssettings.cpp [new file with mode: 0644]
src/settings/dolphin_generalsettings.kcfg
src/settings/dolphin_statusandlocationbarssettings.upd [new file with mode: 0644]
src/settings/interface/statusandlocationbarssettingspage.cpp
src/settings/interface/statusandlocationbarssettingspage.h
src/statusbar/dolphinstatusbar.cpp
src/statusbar/dolphinstatusbar.h
src/tests/dolphinmainwindowtest.cpp
src/views/dolphinview.cpp
src/views/dolphinview.h

index ef50cf77db8fa3444d5844902836371283b5425c..6e52772e023801a8977baf9dbe1562067aafb233 100644 (file)
@@ -634,8 +634,22 @@ install( FILES settings/dolphin_directoryviewpropertysettings.kcfg
 install( FILES settings/dolphin_detailsmodesettings.upd
                settings/dolphin_directorysizemode.upd
                settings/dolphin_directorysizemode.py
+               settings/dolphin_statusandlocationbarssettings.upd
          DESTINATION ${KDE_INSTALL_KCONFUPDATEDIR} )
 
+# install KF6 kconfig updater C++ scripts to kconf_update_bin
+add_executable(dolphin_25.04_update_statusandlocationbarssettings "settings/dolphin_25.04_update_statusandlocationbarssettings.cpp")
+target_link_libraries(dolphin_25.04_update_statusandlocationbarssettings
+    KF6::ConfigCore
+    KF6::XmlGui
+)
+
+install(
+    TARGETS
+        dolphin_25.04_update_statusandlocationbarssettings
+    DESTINATION ${KDE_INSTALL_LIBDIR}/kconf_update_bin
+)
+
 if(BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index c8538bce492a724cf0db8d595ca61514a077b836..a2d6e0b9c679c4c0abfe8715c33b6a434b06121d 100644 (file)
@@ -2129,14 +2129,6 @@ void DolphinMainWindow::setupActions()
             &DolphinMainWindow::toggleShowMenuBar,
             Qt::QueuedConnection);
 
-    KToggleAction *showStatusBar = KStandardAction::showStatusbar(nullptr, nullptr, actionCollection());
-    showStatusBar->setChecked(GeneralSettings::showStatusBar());
-    connect(GeneralSettings::self(), &GeneralSettings::showStatusBarChanged, showStatusBar, &KToggleAction::setChecked);
-    connect(showStatusBar, &KToggleAction::triggered, this, [this](bool checked) {
-        GeneralSettings::setShowStatusBar(checked);
-        refreshViews();
-    });
-
     KStandardAction::keyBindings(this, &DolphinMainWindow::slotKeyBindings, actionCollection());
     KStandardAction::preferences(this, &DolphinMainWindow::editSettings, actionCollection());
 
index f2df638f6cbfb7a68ed09b151bceee41fb867dbc..99b7a4042377142439d1282545ea90ca12f82a05 100644 (file)
@@ -17,6 +17,7 @@
 #include "dolphinplacesmodelsingleton.h"
 #include "filterbar/filterbar.h"
 #include "global.h"
+#include "kitemviews/kitemlistcontainer.h"
 #include "search/dolphinsearchbox.h"
 #include "selectionmode/topbar.h"
 #include "statusbar/dolphinstatusbar.h"
@@ -42,6 +43,8 @@
 #include <QGridLayout>
 #include <QGuiApplication>
 #include <QRegularExpression>
+#include <QScrollBar>
+#include <QStyle>
 #include <QTimer>
 #include <QUrl>
 #include <QUrlQuery>
@@ -173,6 +176,9 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent)
     connect(m_statusBar, &DolphinStatusBar::showMessage, this, [this](const QString &message, KMessageWidget::MessageType messageType) {
         showMessage(message, messageType);
     });
+    connect(m_statusBar, &DolphinStatusBar::widthUpdated, this, &DolphinViewContainer::updateStatusBarGeometry);
+    connect(m_statusBar, &DolphinStatusBar::urlChanged, this, &DolphinViewContainer::updateStatusBar);
+    connect(this, &DolphinViewContainer::showFilterBarChanged, this, &DolphinViewContainer::updateStatusBar);
 
     m_statusBarTimer = new QTimer(this);
     m_statusBarTimer->setSingleShot(true);
@@ -186,7 +192,24 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent)
     m_topLayout->addWidget(m_messageWidget, positionFor.messageWidget, 0);
     m_topLayout->addWidget(m_view, positionFor.view, 0);
     m_topLayout->addWidget(m_filterBar, positionFor.filterBar, 0);
-    m_topLayout->addWidget(m_statusBar, positionFor.statusBar, 0);
+    if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::FullWidth) {
+        m_topLayout->addWidget(m_statusBar, positionFor.statusBar, 0);
+    }
+    connect(m_statusBar, &DolphinStatusBar::modeUpdated, this, [this]() {
+        const bool statusBarInLayout = m_topLayout->itemAtPosition(positionFor.statusBar, 0);
+        if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::FullWidth) {
+            if (!statusBarInLayout) {
+                m_topLayout->addWidget(m_statusBar, positionFor.statusBar, 0);
+                m_statusBar->setUrl(m_view->url());
+            }
+        } else {
+            if (statusBarInLayout) {
+                m_topLayout->removeWidget(m_statusBar);
+            }
+        }
+        updateStatusBarGeometry();
+    });
+    m_statusBar->setHidden(false);
 
     setSearchModeEnabled(isSearchUrl(url));
 
@@ -200,6 +223,8 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent)
     connect(placesModel, &KFilePlacesModel::rowsRemoved, this, &DolphinViewContainer::slotPlacesModelChanged);
 
     connect(this, &DolphinViewContainer::searchModeEnabledChanged, this, &DolphinViewContainer::captionChanged);
+
+    QApplication::instance()->installEventFilter(this);
 }
 
 DolphinViewContainer::~DolphinViewContainer()
@@ -614,6 +639,7 @@ void DolphinViewContainer::setFilterBarVisible(bool visible)
         m_filterBar->setVisible(true, WithAnimation);
         m_filterBar->setFocus();
         m_filterBar->selectAll();
+        Q_EMIT showFilterBarChanged(true);
     } else {
         closeFilterBar();
     }
@@ -638,6 +664,7 @@ void DolphinViewContainer::updateStatusBar()
 {
     m_statusBarTimestamp.start();
     m_view->requestStatusBarText();
+    updateStatusBarGeometry();
 }
 
 void DolphinViewContainer::slotDirectoryLoadingStarted()
@@ -1043,4 +1070,60 @@ QString DolphinViewContainer::getNearestExistingAncestorOfPath(const QString &pa
     return dir.exists() ? dir.path() : QString{};
 }
 
+void DolphinViewContainer::updateStatusBarGeometry()
+{
+    if (!m_statusBar) {
+        return;
+    }
+    if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::Small) {
+        QRect statusBarRect(preferredSmallStatusBarGeometry());
+        if (view()->layoutDirection() == Qt::RightToLeft) {
+            const int splitterWidth = m_statusBar->clippingAmount();
+            statusBarRect.setLeft(rect().width() - m_statusBar->width() + splitterWidth); // Add clipping amount.
+        }
+        // Move statusbar to bottomLeft, or bottomRight with right-to-left-layout.
+        m_statusBar->setGeometry(statusBarRect);
+        // Add 1 due to how qrect coordinates work.
+        m_view->setStatusBarOffset(m_statusBar->geometry().height() - m_statusBar->clippingAmount() + 1);
+    } else {
+        m_view->setStatusBarOffset(0);
+    }
+}
+
+bool DolphinViewContainer::eventFilter(QObject *object, QEvent *event)
+{
+    if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::Small && object == m_view) {
+        switch (event->type()) {
+        case QEvent::Resize: {
+            m_statusBar->updateWidthToContent();
+            break;
+        }
+        case QEvent::LayoutRequest: {
+            m_statusBar->updateWidthToContent();
+            break;
+        }
+        default:
+            break;
+        }
+    }
+    return false;
+}
+
+QRect DolphinViewContainer::preferredSmallStatusBarGeometry()
+{
+    // Add offset depending if horizontal scrollbar or filterbar is visible.
+    int filterBarHeightOffset = 0;
+    int scrollbarHeightOffset = m_view->horizontalScrollBarHeight();
+
+    if (m_filterBar->isVisible()) {
+        filterBarHeightOffset = m_filterBar->height();
+    }
+
+    // Adjust to clipping, we need to add 1 due to how QRects coordinates work.
+    int clipAdjustment = m_statusBar->clippingAmount() + 1;
+    const int yPos = rect().bottom() - m_statusBar->minimumHeight() - scrollbarHeightOffset - filterBarHeightOffset + clipAdjustment;
+    QRect statusBarRect = rect().adjusted(-clipAdjustment, yPos, 0, 0);
+    return statusBarRect;
+}
+
 #include "moc_dolphinviewcontainer.cpp"
index be28ecdebd71098ae7462740ee861dc688cb6846..a509bab3d91a514517205ed2c24a1865621505a7 100644 (file)
@@ -33,6 +33,7 @@ class QGridLayout;
 class QUrl;
 class DolphinSearchBox;
 class DolphinStatusBar;
+class KFileItemList;
 namespace SelectionMode
 {
 class TopBar;
@@ -432,6 +433,19 @@ private:
      */
     QString getNearestExistingAncestorOfPath(const QString &path) const;
 
+    /**
+     * Update the geometry of statusbar depending on what mode it is using.
+     */
+    void updateStatusBarGeometry();
+
+    /**
+     * @return Preferred geometry of the small statusbar.
+     */
+    QRect preferredSmallStatusBarGeometry();
+
+protected:
+    bool eventFilter(QObject *object, QEvent *event) override;
+
 private:
     QGridLayout *m_topLayout;
 
index 369415f1ba73c4552f93397af205d03379e1f2ec..c56785c36f5af2c6099ae6404a11473fc4feae23 100644 (file)
@@ -106,6 +106,7 @@ KItemListView::KItemListView(QGraphicsWidget *parent)
     , m_header(nullptr)
     , m_headerWidget(nullptr)
     , m_indicatorAnimation(nullptr)
+    , m_statusBarOffset(0)
     , m_dropIndicator()
     , m_sizeHintResolver(nullptr)
 {
@@ -192,7 +193,7 @@ qreal KItemListView::scrollOffset() const
 
 qreal KItemListView::maximumScrollOffset() const
 {
-    return m_layouter->maximumScrollOffset();
+    return m_layouter->maximumScrollOffset() + m_statusBarOffset;
 }
 
 void KItemListView::setItemOffset(qreal offset)
@@ -554,6 +555,9 @@ void KItemListView::scrollToItem(int index, ViewItemPosition viewItemPosition)
         const qreal headerHeight = m_headerWidget->size().height();
         viewGeometry.adjust(0, headerHeight, 0, 0);
     }
+    if (m_statusBarOffset != 0) {
+        viewGeometry.adjust(0, 0, 0, -m_statusBarOffset);
+    }
     QRectF currentRect = itemRect(index);
 
     if (layoutDirection() == Qt::RightToLeft && scrollOrientation() == Qt::Horizontal) {
@@ -829,6 +833,16 @@ void KItemListView::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
     }
 }
 
+void KItemListView::setStatusBarOffset(int offset)
+{
+    if (m_statusBarOffset != offset) {
+        m_statusBarOffset = offset;
+        if (m_layouter) {
+            m_layouter->setStatusBarOffset(offset);
+        }
+    }
+}
+
 QVariant KItemListView::itemChange(GraphicsItemChange change, const QVariant &value)
 {
     if (change == QGraphicsItem::ItemSceneHasChanged && scene()) {
index 30ce4d871fc285d82967ed83aedd252178e4fa15..7fb3344b472fce2a50094e98a256d1133b1185d8 100644 (file)
@@ -302,6 +302,12 @@ public:
 
     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
 
+    /**
+     * Set the bottom offset for moving the view so that the small overlayed statusbar
+     * won't cover any items by accident.
+     */
+    void setStatusBarOffset(int offset);
+
 Q_SIGNALS:
     void scrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous);
     void scrollOffsetChanged(qreal current, qreal previous);
@@ -776,6 +782,8 @@ private:
 
     QPropertyAnimation *m_indicatorAnimation;
 
+    int m_statusBarOffset;
+
     // When dragging items into the view where the sort-role of the model
     // is empty, a visual indicator should be shown during dragging where
     // the dropping will happen. This indicator is specified by an index
index 99a95d98c7e7babd83b69088745aa8543133758d..3ed2343a83c2ace6ae93af4b6acbf727a67fa677 100644 (file)
@@ -40,6 +40,7 @@ KItemListViewLayouter::KItemListViewLayouter(KItemListSizeHintResolver *sizeHint
     , m_groupHeaderHeight(0)
     , m_groupHeaderMargin(0)
     , m_itemInfos()
+    , m_statusBarOffset(0)
 {
     Q_ASSERT(m_sizeHintResolver);
 }
@@ -341,6 +342,13 @@ void KItemListViewLayouter::markAsDirty()
     m_dirty = true;
 }
 
+void KItemListViewLayouter::setStatusBarOffset(int offset)
+{
+    if (m_statusBarOffset != offset) {
+        m_statusBarOffset = offset;
+    }
+}
+
 #ifndef QT_NO_DEBUG
 bool KItemListViewLayouter::isDirty()
 {
@@ -378,6 +386,7 @@ void KItemListViewLayouter::doLayout()
         itemSize.transpose();
         itemMargin.transpose();
         size.transpose();
+        size.rwidth() -= m_statusBarOffset;
 
         if (grouped) {
             // In the horizontal scrolling case all groups are aligned
index 77d59c947e914d642bd07fae9c99cf52732b40c6..fed541a4c084991939b638a79ec7969ca4dd0319 100644 (file)
@@ -154,6 +154,12 @@ public:
         return m_columnCount;
     }
 
+    /**
+     * Set the bottom offset for moving the view so that the small overlayed statusbar
+     * won't cover any items by accident.
+     */
+    void setStatusBarOffset(int offset);
+
 #ifndef QT_NO_DEBUG
     /**
      * @return True if the layouter has been marked as dirty and hence has
@@ -219,6 +225,8 @@ private:
     };
     QVector<ItemInfo> m_itemInfos;
 
+    int m_statusBarOffset;
+
     friend class KItemListControllerTest;
 };
 
diff --git a/src/settings/dolphin_25.04_update_statusandlocationbarssettings.cpp b/src/settings/dolphin_25.04_update_statusandlocationbarssettings.cpp
new file mode 100644 (file)
index 0000000..2188fcb
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+    SPDX-FileCopyrightText: 2025 Akseli Lahtinen <akselmo@akselmo.dev>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#include <KConfigGroup>
+#include <KSharedConfig>
+
+int main()
+{
+    const auto showStatusBar = QStringLiteral("ShowStatusBar");
+    auto config = KSharedConfig::openConfig(QStringLiteral("dolphinrc"));
+
+    KConfigGroup general = config->group(QStringLiteral("General"));
+    if (!general.hasKey(showStatusBar)) {
+        return EXIT_SUCCESS;
+    }
+
+    const auto value = general.readEntry(showStatusBar);
+    if (value == QStringLiteral("true")) {
+        general.writeEntry(showStatusBar, QStringLiteral("Small"));
+    } else if (value == QStringLiteral("false")) {
+        general.writeEntry(showStatusBar, QStringLiteral("Disabled"));
+    }
+
+    return general.sync() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
index c800eadb8f353401e1c54cc3da7d831f4bcd693d..e950099ec2015cd74c9425815e4e38f708562001 100644 (file)
             <label>Use auto-expanding folders for all view types</label>
             <default>false</default>
         </entry>
-        <entry name="ShowStatusBar" type="Bool">
-            <label>Show the statusbar</label>
-            <default>true</default>
+        <entry name="ShowStatusBar" type="Enum">
+            <choices>
+                <choice name="Small" />
+                <choice name="FullWidth" />
+                <choice name="Disabled" />
+            </choices>
+            <label>Statusbar</label>
+            <default>0</default>
             <emit signal="showStatusBarChanged" />
         </entry>
         <entry name="ShowZoomSlider" type="Bool">
             <label>Show zoom slider in the statusbar</label>
-            <default>true</default>
-        </entry>
-        <entry name="ShowSpaceInfo" type="Bool">
-            <label>Show the space information in the statusbar</label>
-            <default>true</default>
+            <default>false</default>
         </entry>
         <entry name="LockPanels" type="Bool">
             <label>Lock the layout of the panels</label>
diff --git a/src/settings/dolphin_statusandlocationbarssettings.upd b/src/settings/dolphin_statusandlocationbarssettings.upd
new file mode 100644 (file)
index 0000000..d7dd095
--- /dev/null
@@ -0,0 +1,9 @@
+#SPDX-FileCopyrightText: 2025 Akseli Lahtinen <akselmo@akselmo.dev>
+#SPDX-License-Identifier: GPL-2.0-or-later
+
+#Configuration update for Dolphin
+Version=6
+
+#Convert bool ShowStatusBar to enum ShowStatusBar
+Id=25.04-convert-bool-showstatusbar-to-enum-showstatusbar
+Script=dolphin_25.04_update_statusandlocationbarssettings
index 5e0536a6e7b4cc5ec9adcb3aa8261a2904d2947f..14b5c818858d6d3a1efd42c402f41737913ba834 100644 (file)
 #include <QCheckBox>
 #include <QFormLayout>
 
+#include <QButtonGroup>
 #include <QRadioButton>
 #include <QSpacerItem>
+#include <QStyle>
+#include <QStyleOption>
 
 StatusAndLocationBarsSettingsPage::StatusAndLocationBarsSettingsPage(QWidget *parent, FoldersTabsSettingsPage *foldersPage)
     : SettingsPageBase(parent)
     , m_editableUrl(nullptr)
     , m_showFullPath(nullptr)
-    , m_showStatusBar(nullptr)
+    , m_statusBarButtonGroup(nullptr)
+    , m_showStatusBarSmall(nullptr)
+    , m_showStatusBarFullWidth(nullptr)
     , m_showZoomSlider(nullptr)
-    , m_showSpaceInfo(nullptr)
+    , m_disableStatusBar(nullptr)
 {
     // We need to update some urls at the Folders & Tabs tab. We get that from foldersPage and set it on a private attribute
     // foldersTabsPage. That way, we can modify the necessary stuff from here. Specifically, any changes on locationUpdateInitialViewOptions()
@@ -33,14 +38,30 @@ StatusAndLocationBarsSettingsPage::StatusAndLocationBarsSettingsPage(QWidget *pa
     QFormLayout *topLayout = new QFormLayout(this);
 
     // Status bar
-    m_showStatusBar = new QCheckBox(i18nc("@option:check", "Show status bar"), this);
+    m_statusBarButtonGroup = new QButtonGroup(this);
+    m_showStatusBarSmall = new QRadioButton(i18nc("@option:radio", "Small"), this);
+    m_showStatusBarFullWidth = new QRadioButton(i18nc("@option:radio", "Full width"), this);
     m_showZoomSlider = new QCheckBox(i18nc("@option:check", "Show zoom slider"), this);
-    m_showSpaceInfo = new QCheckBox(i18nc("@option:check", "Show space information"), this);
+    m_disableStatusBar = new QRadioButton(i18nc("@option:check", "Disabled"), this);
 
-    topLayout->addRow(i18nc("@title:group", "Status Bar: "), m_showStatusBar);
-    topLayout->addRow(QString(), m_showZoomSlider);
-    topLayout->addRow(QString(), m_showSpaceInfo);
+    m_statusBarButtonGroup->addButton(m_showStatusBarSmall, GeneralSettings::EnumShowStatusBar::Small);
+    m_statusBarButtonGroup->addButton(m_showStatusBarFullWidth, GeneralSettings::EnumShowStatusBar::FullWidth);
+    m_statusBarButtonGroup->addButton(m_disableStatusBar, GeneralSettings::EnumShowStatusBar::Disabled);
 
+    topLayout->addRow(i18nc("@title:group", "Status Bar:"), m_showStatusBarSmall);
+    topLayout->addRow(QString(), m_showStatusBarFullWidth);
+
+    // Indent the m_showZoomSlider checkbox under m_showStatusBarFullWidth.
+    QHBoxLayout *zoomSliderLayout = new QHBoxLayout;
+    QStyleOption opt;
+    opt.initFrom(this);
+    zoomSliderLayout->addItem(
+        new QSpacerItem(style()->pixelMetric(QStyle::PM_IndicatorWidth, &opt, this), Dolphin::VERTICAL_SPACER_HEIGHT, QSizePolicy::Fixed, QSizePolicy::Fixed));
+    zoomSliderLayout->addWidget(m_showZoomSlider);
+
+    topLayout->addRow(QString(), zoomSliderLayout);
+
+    topLayout->addRow(QString(), m_disableStatusBar);
     topLayout->addItem(new QSpacerItem(0, Dolphin::VERTICAL_SPACER_HEIGHT, QSizePolicy::Fixed, QSizePolicy::Fixed));
 
     // Location bar
@@ -57,10 +78,9 @@ StatusAndLocationBarsSettingsPage::StatusAndLocationBarsSettingsPage(QWidget *pa
     connect(m_editableUrl, &QCheckBox::toggled, this, &StatusAndLocationBarsSettingsPage::locationSlotSettingsChanged);
     connect(m_showFullPath, &QCheckBox::toggled, this, &StatusAndLocationBarsSettingsPage::locationSlotSettingsChanged);
 
-    connect(m_showStatusBar, &QCheckBox::toggled, this, &StatusAndLocationBarsSettingsPage::changed);
-    connect(m_showStatusBar, &QCheckBox::toggled, this, &StatusAndLocationBarsSettingsPage::onShowStatusBarToggled);
+    connect(m_statusBarButtonGroup, &QButtonGroup::idClicked, this, &StatusAndLocationBarsSettingsPage::changed);
+    connect(m_statusBarButtonGroup, &QButtonGroup::idClicked, this, &StatusAndLocationBarsSettingsPage::onShowStatusBarToggled);
     connect(m_showZoomSlider, &QCheckBox::toggled, this, &StatusAndLocationBarsSettingsPage::changed);
-    connect(m_showSpaceInfo, &QCheckBox::toggled, this, &StatusAndLocationBarsSettingsPage::changed);
 }
 
 StatusAndLocationBarsSettingsPage::~StatusAndLocationBarsSettingsPage()
@@ -74,18 +94,16 @@ void StatusAndLocationBarsSettingsPage::applySettings()
     settings->setEditableUrl(m_editableUrl->isChecked());
     settings->setShowFullPath(m_showFullPath->isChecked());
 
-    settings->setShowStatusBar(m_showStatusBar->isChecked());
+    settings->setShowStatusBar(m_statusBarButtonGroup->checkedId());
     settings->setShowZoomSlider(m_showZoomSlider->isChecked());
-    settings->setShowSpaceInfo(m_showSpaceInfo->isChecked());
 
     settings->save();
 }
 
 void StatusAndLocationBarsSettingsPage::onShowStatusBarToggled()
 {
-    const bool checked = m_showStatusBar->isChecked();
+    const bool checked = (m_statusBarButtonGroup->checkedId() == GeneralSettings::EnumShowStatusBar::FullWidth);
     m_showZoomSlider->setEnabled(checked);
-    m_showSpaceInfo->setEnabled(checked);
 }
 
 void StatusAndLocationBarsSettingsPage::restoreDefaults()
@@ -118,9 +136,8 @@ void StatusAndLocationBarsSettingsPage::loadSettings()
 {
     m_editableUrl->setChecked(GeneralSettings::editableUrl());
     m_showFullPath->setChecked(GeneralSettings::showFullPath());
-    m_showStatusBar->setChecked(GeneralSettings::showStatusBar());
+    m_statusBarButtonGroup->button(GeneralSettings::showStatusBar())->setChecked(true);
     m_showZoomSlider->setChecked(GeneralSettings::showZoomSlider());
-    m_showSpaceInfo->setChecked(GeneralSettings::showSpaceInfo());
 
     onShowStatusBarToggled();
 }
index c22ff2041dff4f2c0dbe35d1baaeb5f44eda603a..3b8049782bcd08332f58727268445d2298b38788 100644 (file)
@@ -16,6 +16,7 @@ class QCheckBox;
 class QLineEdit;
 class QLabel;
 class QRadioButton;
+class QButtonGroup;
 
 /**
  * @brief Tab page for the 'Behavior' settings of the Dolphin settings dialog.
@@ -47,9 +48,11 @@ private:
     QCheckBox *m_editableUrl;
     QCheckBox *m_showFullPath;
 
-    QCheckBox *m_showStatusBar;
+    QButtonGroup *m_statusBarButtonGroup;
+    QRadioButton *m_showStatusBarSmall;
+    QRadioButton *m_showStatusBarFullWidth;
     QCheckBox *m_showZoomSlider;
-    QCheckBox *m_showSpaceInfo;
+    QRadioButton *m_disableStatusBar;
 };
 
 #endif
index 6da4b4ddf7c38f23d8bcb4a48b68d5f11759c91f..d9ed1076e0ce6de09ce10fe3dced02903b88502a 100644 (file)
@@ -20,6 +20,7 @@
 #include <QIcon>
 #include <QMenu>
 #include <QPainter>
+#include <QPainterPath>
 #include <QProgressBar>
 #include <QSlider>
 #include <QStyleOption>
@@ -136,8 +137,7 @@ DolphinStatusBar::DolphinStatusBar(QWidget *parent)
     m_topLayout->addWidget(m_progressTextLabel);
     m_topLayout->addWidget(m_progressBar);
 
-    setVisible(GeneralSettings::showStatusBar(), WithoutAnimation);
-    setExtensionsVisible(true);
+    readSettings();
     setWhatsThis(xi18nc("@info:whatsthis Statusbar",
                         "<para>This is "
                         "the <emphasis>Statusbar</emphasis>. It contains three elements "
@@ -203,6 +203,7 @@ void DolphinStatusBar::showProgress(const QString &currentlyRunningTaskTitle, in
     }
 
     m_progressTextLabel->setText(currentlyRunningTaskTitle);
+    updateWidthToContent();
 }
 
 QString DolphinStatusBar::progressText() const
@@ -240,8 +241,9 @@ QString DolphinStatusBar::defaultText() const
 
 void DolphinStatusBar::setUrl(const QUrl &url)
 {
-    if (GeneralSettings::showSpaceInfo()) {
+    if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::FullWidth && m_spaceInfo && m_spaceInfo->url() != url) {
         m_spaceInfo->setUrl(url);
+        Q_EMIT urlChanged();
     }
 }
 
@@ -264,7 +266,7 @@ int DolphinStatusBar::zoomLevel() const
 
 void DolphinStatusBar::readSettings()
 {
-    setVisible(GeneralSettings::showStatusBar(), WithAnimation);
+    updateMode();
     setExtensionsVisible(true);
 }
 
@@ -273,6 +275,66 @@ void DolphinStatusBar::updateSpaceInfo()
     m_spaceInfo->update();
 }
 
+void DolphinStatusBar::updateWidthToContent()
+{
+    if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::Small) {
+        QStyleOptionSlider opt;
+        opt.initFrom(this);
+        opt.orientation = Qt::Vertical;
+        const QSize labelSize = QFontMetrics(font()).size(Qt::TextSingleLine, m_label->fullText());
+        // Make sure minimum height takes clipping into account.
+        setMinimumHeight(m_label->height() + clippingAmount());
+        const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent, &opt, this);
+        const int maximumViewWidth = parentWidget()->width() - scrollbarWidth;
+        if (m_stopButton->isVisible() || m_progressTextLabel->isVisible() || m_progressBar->isVisible()) {
+            // Use maximum width when interactable elements are shown, to keep them
+            // from "jumping around" when user tries to interact with them.
+            setFixedWidth(maximumViewWidth);
+        } else {
+            const int contentWidth = labelSize.width() + 15;
+            setFixedWidth(qMin(contentWidth, maximumViewWidth));
+        }
+        Q_EMIT widthUpdated();
+    } else {
+        setMinimumHeight(0);
+        setFixedWidth(QWIDGETSIZE_MAX);
+        Q_EMIT widthUpdated();
+    }
+}
+
+int DolphinStatusBar::clippingAmount() const
+{
+    QStyleOption opt;
+    opt.initFrom(this);
+    // Add 2 for extra padding due to how QRect coordinates work.
+    const int val = 2 + style()->pixelMetric(QStyle::PM_SplitterWidth, &opt, this) * 2;
+    return val;
+}
+
+void DolphinStatusBar::updateMode()
+{
+    switch (GeneralSettings::showStatusBar()) {
+    case GeneralSettings::EnumShowStatusBar::Small:
+        setEnabled(true);
+        m_spaceInfo->setShown(false);
+        m_zoomSlider->setVisible(false);
+        m_zoomLabel->setVisible(false);
+        setVisible(true, WithAnimation);
+        break;
+    case GeneralSettings::EnumShowStatusBar::FullWidth:
+        setEnabled(true);
+        m_spaceInfo->setShown(true);
+        setVisible(true, WithAnimation);
+        break;
+    case GeneralSettings::EnumShowStatusBar::Disabled:
+        setEnabled(false);
+        setVisible(false, WithoutAnimation);
+        break;
+    }
+    Q_EMIT modeUpdated();
+    updateWidthToContent();
+}
+
 void DolphinStatusBar::contextMenuEvent(QContextMenuEvent *event)
 {
     Q_UNUSED(event)
@@ -283,20 +345,12 @@ void DolphinStatusBar::contextMenuEvent(QContextMenuEvent *event)
     showZoomSliderAction->setCheckable(true);
     showZoomSliderAction->setChecked(GeneralSettings::showZoomSlider());
 
-    QAction *showSpaceInfoAction = menu.addAction(i18nc("@action:inmenu", "Show Space Information"));
-    showSpaceInfoAction->setCheckable(true);
-    showSpaceInfoAction->setChecked(GeneralSettings::showSpaceInfo());
-
     const QAction *action = menu.exec(event->reason() == QContextMenuEvent::Reason::Mouse ? QCursor::pos() : mapToGlobal(QPoint(width() / 2, height() / 2)));
     if (action == showZoomSliderAction) {
         const bool visible = showZoomSliderAction->isChecked();
         GeneralSettings::setShowZoomSlider(visible);
         m_zoomSlider->setVisible(visible);
         m_zoomLabel->setVisible(visible);
-    } else if (action == showSpaceInfoAction) {
-        const bool visible = showSpaceInfoAction->isChecked();
-        GeneralSettings::setShowSpaceInfo(visible);
-        m_spaceInfo->setShown(visible);
     }
     updateContentsMargins();
 }
@@ -326,12 +380,14 @@ void DolphinStatusBar::updateProgressInfo()
         m_progressBar->hide();
         setExtensionsVisible(true);
     }
+    updateWidthToContent();
 }
 
 void DolphinStatusBar::updateLabelText()
 {
     const QString text = m_text.isEmpty() ? m_defaultText : m_text;
     m_label->setText(text);
+    updateWidthToContent();
 }
 
 void DolphinStatusBar::updateZoomSliderToolTip(int zoomLevel)
@@ -342,14 +398,11 @@ void DolphinStatusBar::updateZoomSliderToolTip(int zoomLevel)
 
 void DolphinStatusBar::setExtensionsVisible(bool visible)
 {
-    bool showSpaceInfo = visible;
     bool showZoomSlider = visible;
     if (visible) {
-        showSpaceInfo = GeneralSettings::showSpaceInfo();
-        showZoomSlider = GeneralSettings::showZoomSlider();
+        showZoomSlider = GeneralSettings::showZoomSlider() && GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::FullWidth;
     }
 
-    m_spaceInfo->setShown(showSpaceInfo);
     m_zoomSlider->setVisible(showZoomSlider);
     m_zoomLabel->setVisible(showZoomSlider);
     updateContentsMargins();
@@ -357,12 +410,14 @@ void DolphinStatusBar::setExtensionsVisible(bool visible)
 
 void DolphinStatusBar::updateContentsMargins()
 {
-    if (GeneralSettings::showSpaceInfo()) {
+    if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::FullWidth) {
         // We reduce the outside margin for the flat button so it visually has the same margin as the status bar text label on the other end of the bar.
         m_topLayout->setContentsMargins(6, 0, 2, 0);
     } else {
-        m_topLayout->setContentsMargins(6, 0, 6, 0);
+        // Add extra margins to toplayout to avoid clipping too early.
+        m_topLayout->setContentsMargins(clippingAmount() * 2, 0, clippingAmount(), clippingAmount());
     }
+    setContentsMargins(0, 0, 0, 0);
 }
 
 void DolphinStatusBar::paintEvent(QPaintEvent *paintEvent)
@@ -371,7 +426,28 @@ void DolphinStatusBar::paintEvent(QPaintEvent *paintEvent)
     QPainter p(this);
     QStyleOption opt;
     opt.initFrom(this);
-    style()->drawPrimitive(QStyle::PE_PanelStatusBar, &opt, &p, this);
+    // Draw statusbar only if there is text.
+    if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::Small) {
+        if (m_label && !m_label->fullText().isEmpty()) {
+            opt.state = QStyle::State_Sunken;
+            QPainterPath path;
+            // Clip the left and bottom border off.
+            QRect clipRect;
+            if (layoutDirection() == Qt::RightToLeft) {
+                clipRect = QRect(opt.rect.topLeft(), opt.rect.bottomRight()).adjusted(0, 0, -clippingAmount(), -clippingAmount());
+            } else {
+                clipRect = QRect(opt.rect.topLeft(), opt.rect.bottomRight()).adjusted(clippingAmount(), 0, 0, -clippingAmount());
+            }
+            path.addRect(clipRect);
+            p.setClipPath(path);
+            opt.palette.setColor(QPalette::Base, palette().window().color());
+            style()->drawPrimitive(QStyle::PE_Frame, &opt, &p, this);
+        }
+    }
+    // Draw regular statusbar.
+    else {
+        style()->drawPrimitive(QStyle::PE_PanelStatusBar, &opt, &p, this);
+    }
 }
 
 int DolphinStatusBar::preferredHeight() const
index a620a011783466a990347e18db9b61a00ba6a9c0..b4ddcd95efb273d754a87b616acf1f7359dbd1bf 100644 (file)
@@ -39,7 +39,10 @@ public:
 
     QString text() const;
 
-    enum class CancelLoading { Allowed, Disallowed };
+    enum class CancelLoading {
+        Allowed,
+        Disallowed
+    };
     /**
      * Shows progress for a task on the status bar.
      *
@@ -85,6 +88,22 @@ public:
      */
     void updateSpaceInfo();
 
+    /**
+     * Changes the statusbar between disabled, small, and full width
+     * depending on settings enabled.
+     */
+    void updateMode();
+
+    /**
+     * Updates the statusbar width to fit all content.
+     */
+    void updateWidthToContent();
+
+    /**
+     * @return The amount of clipping done to the small statusbar side and bottom.
+     */
+    int clippingAmount() const;
+
 public Q_SLOTS:
     void setText(const QString &text);
     void setUrl(const QUrl &url);
@@ -103,6 +122,21 @@ Q_SIGNALS:
      */
     void showMessage(const QString &message, KMessageWidget::MessageType messageType);
 
+    /**
+     * Emitted when statusbar mode is changed.
+     */
+    void modeUpdated();
+
+    /**
+     * Emitted when statusbar width is updated to fit content.
+     */
+    void widthUpdated();
+
+    /**
+     * Emitted when statusbar url has changed.
+     */
+    void urlChanged();
+
 protected:
     void contextMenuEvent(QContextMenuEvent *event) override;
     void paintEvent(QPaintEvent *paintEvent) override;
index d7cb763fd8f6658f79bc9e8efe42b666df6c08a2..c7d2f4b6d7fee2870e92c51151414b0674498524 100644 (file)
@@ -9,6 +9,7 @@
 #include "dolphintabpage.h"
 #include "dolphintabwidget.h"
 #include "dolphinviewcontainer.h"
+#include "dolphin_generalsettings.h"
 #include "kitemviews/kfileitemmodel.h"
 #include "kitemviews/kfileitemmodelrolesupdater.h"
 #include "kitemviews/kitemlistcontainer.h"
@@ -75,6 +76,11 @@ private:
 void DolphinMainWindowTest::initTestCase()
 {
     QStandardPaths::setTestModeEnabled(true);
+    // Use fullWidth statusbar during testing, to test out most of the features.
+    GeneralSettings *settings = GeneralSettings::self();
+    settings->setShowStatusBar(GeneralSettings::EnumShowStatusBar::FullWidth);
+    settings->setShowZoomSlider(true);
+    settings->save();
 }
 
 void DolphinMainWindowTest::init()
index a18f5376986d79f9d456ce73284256b67ddac12e..fc4f5e2df9905b37b45177c14b319f31d3c7e0d4 100644 (file)
@@ -2285,6 +2285,22 @@ bool DolphinView::isFolderWritable() const
     return m_isFolderWritable;
 }
 
+int DolphinView::horizontalScrollBarHeight() const
+{
+    if (m_container && m_container->horizontalScrollBar() && m_container->horizontalScrollBar()->isVisible()) {
+        return m_container->horizontalScrollBar()->height();
+    }
+    return 0;
+}
+
+void DolphinView::setStatusBarOffset(int offset)
+{
+    KItemListView *view = m_container->controller()->view();
+    if (view) {
+        view->setStatusBarOffset(offset);
+    }
+}
+
 QUrl DolphinView::viewPropertiesUrl() const
 {
     if (m_viewPropertiesContext.isEmpty()) {
index d1667334e30d39336dd7dd05284f599ff735e409..de4bc1af2ca28374c41d669e95425802f451899a 100644 (file)
@@ -357,6 +357,18 @@ public:
      */
     bool isFolderWritable() const;
 
+    /**
+     * @returns the height of the scrollbar at the bottom of the view or zero if no such scroll bar is visible.
+     */
+    int horizontalScrollBarHeight() const;
+
+    /**
+     * Set the offset for any view items that small statusbar would otherwise
+     * cover. For example, in compact view this is used to make sure no
+     * item is covered by statusbar.
+     */
+    void setStatusBarOffset(int offset);
+
 public Q_SLOTS:
 
     void reload();