]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Make UrlNavigators in the toolbar the only option
authorFelix Ernst <fe.a.ernst@gmail.com>
Sun, 20 Sep 2020 16:53:59 +0000 (18:53 +0200)
committerElvis Angelaccio <elvis.angelaccio@kde.org>
Mon, 9 Nov 2020 22:49:07 +0000 (23:49 +0100)
The UrlNavigators will be automatically added to the toolbar. The Sort By
action is removed from the default toolbar to make space.

Remove all options to have UrlNavigators outside the toolbar and remove
those code paths.

Make it so the new NavigatorsWidgetAction contains two UrlNavigators when
in split view mode. Spacing was also added to align these UrlNavigators
with the ViewContainers when enough space is available.

Force the toolbar to be either at the top or bottom of the window.

Set a sane sizeHint for DolphinUrlNavigator. It would be better to do this
in KUrlNavigator in the future.

This commit also contains a changes which should be moved to a separate
merge requests before this gets merged:
- Add an expansion animation when split view is enabled by the user

18 files changed:
src/CMakeLists.txt
src/dolphinmainwindow.cpp
src/dolphinmainwindow.h
src/dolphinnavigatorswidgetaction.cpp [new file with mode: 0644]
src/dolphinnavigatorswidgetaction.h [new file with mode: 0644]
src/dolphintabpage.cpp
src/dolphintabpage.h
src/dolphintabwidget.cpp
src/dolphintabwidget.h
src/dolphinui.rc
src/dolphinurlnavigator.cpp
src/dolphinurlnavigator.h
src/dolphinviewcontainer.cpp
src/dolphinviewcontainer.h
src/main.cpp
src/settings/dolphin_generalsettings.kcfg
src/views/dolphinurlnavigatorwidgetaction.cpp [deleted file]
src/views/dolphinurlnavigatorwidgetaction.h [deleted file]

index 4610be463d2130c5c3f53003af65c2c3aba12d01..8fad3434711a08622ef514b18eaffa2ce14e5bc0 100644 (file)
@@ -203,6 +203,7 @@ set(dolphinstatic_SRCS
     dolphinmainwindow.cpp
     dolphinviewcontainer.cpp
     dolphincontextmenu.cpp
+    dolphinnavigatorswidgetaction.cpp
     dolphintabbar.cpp
     dolphinplacesmodelsingleton.cpp
     dolphinrecenttabsmenu.cpp
@@ -249,7 +250,6 @@ set(dolphinstatic_SRCS
     statusbar/mountpointobservercache.cpp
     statusbar/spaceinfoobserver.cpp
     statusbar/statusbarspaceinfo.cpp
-    views/dolphinurlnavigatorwidgetaction.cpp
     views/zoomlevelinfo.cpp
     dolphindebug.cpp
     global.cpp
index 381d950139bd92b3458e9ffe177a5a567910ff93..6a93de0780c1cf8997886b4adf45acceac239966 100644 (file)
@@ -31,7 +31,7 @@
 #include "views/draganddrophelper.h"
 #include "views/viewproperties.h"
 #include "views/dolphinnewfilemenuobserver.h"
-#include "views/dolphinurlnavigatorwidgetaction.h"
+#include "dolphinnavigatorswidgetaction.h"
 #include "dolphin_generalsettings.h"
 
 #include <KActionCollection>
@@ -49,7 +49,6 @@
 #include <KJobWidgets>
 #include <KLocalizedString>
 #include <KMessageBox>
-#include <KMessageWidget>
 #include <KNS3/KMoreToolsMenuFactory>
 #include <KProtocolInfo>
 #include <KProtocolManager>
@@ -107,7 +106,8 @@ DolphinMainWindow::DolphinMainWindow() :
     m_placesPanel(nullptr),
     m_tearDownFromPlacesRequested(false),
     m_backAction(nullptr),
-    m_forwardAction(nullptr)
+    m_forwardAction(nullptr),
+    m_updateHistoryConnection{}
 {
     Q_INIT_RESOURCE(dolphin);
 
@@ -142,7 +142,12 @@ DolphinMainWindow::DolphinMainWindow() :
 
     setAcceptDrops(true);
 
-    m_tabWidget = new DolphinTabWidget(this);
+    auto *navigatorsWidgetAction = new DolphinNavigatorsWidgetAction(this);
+    navigatorsWidgetAction->setText(i18nc(
+        "@action:inmenu When split view is enabled there are two otherwise one.",
+        "Url Navigator(s)"));
+    actionCollection()->addAction(QStringLiteral("url_navigators"), navigatorsWidgetAction);
+    m_tabWidget = new DolphinTabWidget(navigatorsWidgetAction, this);
     m_tabWidget->setObjectName("tabWidget");
     connect(m_tabWidget, &DolphinTabWidget::activeViewChanged,
             this, &DolphinMainWindow::activeViewChanged);
@@ -167,6 +172,11 @@ DolphinMainWindow::DolphinMainWindow() :
     setupGUI(Keys | Save | Create | ToolBar);
     stateChanged(QStringLiteral("new_file"));
 
+    toolBar()->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
+    toolBar()->setFloatable(false);
+    if (!toolBar()->actions().contains(navigatorsWidgetAction)) {
+        navigatorsWidgetAction->addToToolbarAndSave(this);
+    }
     QClipboard* clipboard = QApplication::clipboard();
     connect(clipboard, &QClipboard::dataChanged,
             this, &DolphinMainWindow::updatePasteAction);
@@ -843,64 +853,6 @@ void DolphinMainWindow::showFilterBar()
     m_activeViewContainer->setFilterBarVisible(true);
 }
 
-void DolphinMainWindow::toggleLocationInToolbar()
-{
-    // collect needed variables
-    QAction *locationInToolbarAction = actionCollection()->action(QStringLiteral("location_in_toolbar"));
-    const bool locationInToolbar = locationInToolbarAction->isChecked();
-    auto viewContainers = this->viewContainers();
-    auto urlNavigatorWidgetAction = static_cast<DolphinUrlNavigatorWidgetAction *>
-        (actionCollection()->action(QStringLiteral("url_navigator")));
-    const bool isEditable = m_activeViewContainer->urlNavigator()->isUrlEditable();
-    const QLineEdit *lineEdit = m_activeViewContainer->urlNavigator()->editor()->lineEdit();
-    const bool hasFocus = lineEdit->hasFocus();
-    const int cursorPosition = lineEdit->cursorPosition();
-    const int selectionStart = lineEdit->selectionStart();
-    const int selectionLength = lineEdit->selectionLength();
-
-    if (locationInToolbar && !toolBar()->actions().contains(urlNavigatorWidgetAction)) {
-        // There is no UrlNavigator on the toolbar. Try to fix it. Otherwise show an error.
-        if (!urlNavigatorWidgetAction->addToToolbarAndSave(this)) {
-            QAction *configureToolbars = actionCollection()->action(KStandardAction::name(KStandardAction::ConfigureToolbars));
-            KMessageWidget *messageWidget = m_activeViewContainer->showMessage(
-            xi18nc("@info 2 is the visible text on a button just below the message",
-            "The location could not be moved onto the toolbar because there is currently "
-            "no \"%1\" item on the toolbar. Select <interface>%2</interface> and add the "
-            "\"%1\" item. Then this will work.", urlNavigatorWidgetAction->iconText(),
-            configureToolbars->iconText()), DolphinViewContainer::Information);
-            messageWidget->addAction(configureToolbars);
-            messageWidget->addAction(locationInToolbarAction);
-            locationInToolbarAction->setChecked(false);
-            return;
-        }
-    }
-
-    // do the switching
-    GeneralSettings::setLocationInToolbar(locationInToolbar);
-    if (locationInToolbar) {
-        for (const auto viewContainer : viewContainers) {
-            viewContainer->disconnectUrlNavigator();
-        }
-        m_activeViewContainer->connectUrlNavigator(urlNavigatorWidgetAction->urlNavigator());
-    } else {
-        m_activeViewContainer->disconnectUrlNavigator();
-        for (const auto viewContainer : viewContainers) {
-            viewContainer->connectToInternalUrlNavigator();
-        }
-    }
-
-    urlNavigatorWidgetAction->setUrlNavigatorVisible(locationInToolbar);
-    m_activeViewContainer->urlNavigator()->setUrlEditable(isEditable);
-    if (hasFocus) { // the rest of this method is unneeded perfectionism
-        m_activeViewContainer->urlNavigator()->editor()->lineEdit()->setText(lineEdit->text());
-        m_activeViewContainer->urlNavigator()->editor()->lineEdit()->setFocus();
-        m_activeViewContainer->urlNavigator()->editor()->lineEdit()->setCursorPosition(cursorPosition);
-        if (selectionStart != -1) {
-            m_activeViewContainer->urlNavigator()->editor()->lineEdit()->setSelection(selectionStart, selectionLength);
-        }
-    }
-}
-
 void DolphinMainWindow::toggleEditLocation()
 {
     clearStatusBar();
@@ -1314,9 +1266,11 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer)
         // view and url navigator) and main window.
         oldViewContainer->disconnect(this);
         oldViewContainer->view()->disconnect(this);
-        oldViewContainer->urlNavigator()->disconnect(this);
-        if (GeneralSettings::locationInToolbar()) {
-            oldViewContainer->disconnectUrlNavigator();
+        auto navigators = static_cast<DolphinNavigatorsWidgetAction *>
+                          (actionCollection()->action(QStringLiteral("url_navigators")));
+        navigators->primaryUrlNavigator()->disconnect(this);
+        if (auto secondaryUrlNavigator = navigators->secondaryUrlNavigator()) {
+            secondaryUrlNavigator->disconnect(this);
         }
 
         // except the requestItemInfo so that on hover the information panel can still be updated
@@ -1324,10 +1278,6 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer)
                 this, &DolphinMainWindow::requestItemInfo);
     }
 
-    if (GeneralSettings::locationInToolbar()) {
-        viewContainer->connectUrlNavigator(static_cast<DolphinUrlNavigatorWidgetAction *>
-            (actionCollection()->action(QStringLiteral("url_navigator")))->urlNavigator());
-    }
     connectViewSignals(viewContainer);
 
     m_actionHandler->setCurrentView(viewContainer->view());
@@ -1559,16 +1509,6 @@ void DolphinMainWindow::setupActions()
     stop->setIcon(QIcon::fromTheme(QStringLiteral("process-stop")));
     connect(stop, &QAction::triggered, this, &DolphinMainWindow::stopLoading);
 
-    KToggleAction* locationInToolbar = actionCollection()->add<KToggleAction>(QStringLiteral("location_in_toolbar"));
-    locationInToolbar->setText(i18nc("@action:inmenu Navigation Bar", "Location in Toolbar"));
-    locationInToolbar->setWhatsThis(xi18nc("@info:whatsthis",
-        "This toggles between showing the <emphasis>path</emphasis> in the "
-        "<emphasis>Location Bar</emphasis> and in the <emphasis>Toolbar</emphasis>."));
-    actionCollection()->setDefaultShortcut(locationInToolbar, Qt::Key_F12);
-    locationInToolbar->setChecked(GeneralSettings::locationInToolbar());
-    connect(locationInToolbar, &KToggleAction::triggered, this, &DolphinMainWindow::toggleLocationInToolbar);
-    DolphinUrlNavigator::addToContextMenu(locationInToolbar);
-
     KToggleAction* editableLocation = actionCollection()->add<KToggleAction>(QStringLiteral("editable_location"));
     editableLocation->setText(i18nc("@action:inmenu Navigation Bar", "Editable Location"));
     editableLocation->setWhatsThis(xi18nc("@info:whatsthis",
@@ -1770,12 +1710,6 @@ void DolphinMainWindow::setupActions()
     connect(activatePrevTab, &QAction::triggered, m_tabWidget, &DolphinTabWidget::activatePrevTab);
     actionCollection()->setDefaultShortcuts(activatePrevTab, prevTabKeys);
 
-    auto *urlNavigatorWidgetAction = new DolphinUrlNavigatorWidgetAction(this);
-    urlNavigatorWidgetAction->setText(i18nc("@action:inmenu auto-hide: "
-        "Depending on the settings this Widget is blank/invisible.",
-        "Url Navigator (auto-hide)"));
-    actionCollection()->addAction(QStringLiteral("url_navigator"), urlNavigatorWidgetAction);
-
     // for context menu
     QAction* showTarget = actionCollection()->addAction(QStringLiteral("show_target"));
     showTarget->setText(i18nc("@action:inmenu", "Show Target"));
@@ -2107,10 +2041,6 @@ void DolphinMainWindow::updateViewActions()
     showFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible());
 
     updateSplitAction();
-
-    QAction* editableLocactionAction = actionCollection()->action(QStringLiteral("editable_location"));
-    const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
-    editableLocactionAction->setChecked(urlNavigator->isUrlEditable());
 }
 
 void DolphinMainWindow::updateGoActions()
@@ -2246,15 +2176,24 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
     connect(view, &DolphinView::goUpRequested,
             this, &DolphinMainWindow::goUp);
 
-    const KUrlNavigator* navigator = container->urlNavigator();
+    auto navigators = static_cast<DolphinNavigatorsWidgetAction *>
+        (actionCollection()->action(QStringLiteral("url_navigators")));
+    KUrlNavigator *navigator = m_tabWidget->currentTabPage()->primaryViewActive() ?
+                               navigators->primaryUrlNavigator() :
+                               navigators->secondaryUrlNavigator();
+
     connect(navigator, &KUrlNavigator::urlChanged,
             this, &DolphinMainWindow::changeUrl);
+    QAction* editableLocactionAction = actionCollection()->action(QStringLiteral("editable_location"));
+    editableLocactionAction->setChecked(navigator->isUrlEditable());
     connect(navigator, &KUrlNavigator::editableStateChanged,
             this, &DolphinMainWindow::slotEditableStateChanged);
     connect(navigator, &KUrlNavigator::tabRequested,
             this, &DolphinMainWindow::openNewTabAfterLastTab);
 
-    connect(container->urlNavigatorInternalWithHistory(), &KUrlNavigator::historyChanged,
+    disconnect(m_updateHistoryConnection);
+    m_updateHistoryConnection = connect(
+            container->urlNavigatorInternalWithHistory(), &KUrlNavigator::historyChanged,
             this, &DolphinMainWindow::updateHistory);
 }
 
index 251f50d8d0fbd2d4488c2dab4bd1797d69fa96e4..173e017c9a75ce4032f64133f25e31938d2cd947 100644 (file)
@@ -69,16 +69,9 @@ public:
 
     /**
      * Returns the active view containers of all tabs.
-     * @see activeViewContainer()
-     * Use viewContainers() to also include the inactive ones.
      */
     QVector<DolphinViewContainer *> activeViewContainers() const;
 
-    /**
-     * Returns all view containers.
-     */
-    QVector<DolphinViewContainer *> viewContainers() const;
-
     /**
      * Opens each directory in \p dirs in a separate tab. If \a splitView is set,
      * 2 directories are collected within one tab.
@@ -312,12 +305,6 @@ private slots:
 
     void showFilterBar();
 
-    /**
-     * Toggle between either using an UrlNavigator in the toolbar or the
-     * ones in the location bar for navigating.
-     */
-    void toggleLocationInToolbar();
-
     /**
      * Toggles between edit and browse mode of the navigation bar.
      */
@@ -662,6 +649,9 @@ private:
     KToolBarPopupAction* m_backAction;
     KToolBarPopupAction* m_forwardAction;
 
+    /** Makes sure that only one object is ever connected to the history. */
+    QMetaObject::Connection m_updateHistoryConnection;
+
     QMenu m_searchTools;
 
 };
diff --git a/src/dolphinnavigatorswidgetaction.cpp b/src/dolphinnavigatorswidgetaction.cpp
new file mode 100644 (file)
index 0000000..bd2985d
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+    This file is part of the KDE project
+    SPDX-FileCopyrightText: 2020 Felix Ernst <fe.a.ernst@gmail.com>
+
+    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+*/
+
+#include "dolphinnavigatorswidgetaction.h"
+
+#include "trash/dolphintrash.h"
+
+#include <KLocalizedString>
+#include <KXMLGUIFactory>
+#include <KXmlGuiWindow>
+
+#include <QDomDocument>
+#include <QHBoxLayout>
+#include <QPushButton>
+#include <QSplitter>
+
+DolphinNavigatorsWidgetAction::DolphinNavigatorsWidgetAction(QWidget *parent) :
+    QWidgetAction{parent},
+    m_splitter{new QSplitter(Qt::Horizontal)},
+    m_adjustSpacingTimer{new QTimer(this)},
+    m_globalXOfPrimary{-1},
+    m_widthOfPrimary{-1},
+    m_globalXOfSecondary{-1},
+    m_widthOfSecondary{-1}
+{
+    setText(i18nc("@action:inmenu", "Url navigator"));
+
+    m_splitter->setChildrenCollapsible(false);
+    setDefaultWidget(m_splitter.get());
+
+    m_splitter->addWidget(createNavigatorWidget(Primary));
+
+    m_adjustSpacingTimer->setInterval(100);
+    m_adjustSpacingTimer->setSingleShot(true);
+    connect(m_adjustSpacingTimer.get(), &QTimer::timeout,
+            this, &DolphinNavigatorsWidgetAction::adjustSpacing);
+}
+
+bool DolphinNavigatorsWidgetAction::addToToolbarAndSave(KXmlGuiWindow *mainWindow)
+{
+    const QString rawXml = KXMLGUIFactory::readConfigFile(mainWindow->xmlFile());
+    QDomDocument domDocument;
+    if (rawXml.isEmpty() || !domDocument.setContent(rawXml) || domDocument.isNull()) {
+        return false;
+    }
+    QDomNode toolbar = domDocument.elementsByTagName(QStringLiteral("ToolBar")).at(0);
+    if (toolbar.isNull()) {
+        return false;
+    }
+
+    QDomElement urlNavigatorElement = domDocument.createElement(QStringLiteral("Action"));
+    urlNavigatorElement.setAttribute(QStringLiteral("name"), QStringLiteral("url_navigators"));
+
+    QDomNode position = toolbar.lastChildElement(QStringLiteral("Spacer"));
+    if (position.isNull()) {
+        toolbar.appendChild(urlNavigatorElement);
+    } else {
+        toolbar.replaceChild(urlNavigatorElement, position);
+    }
+
+    KXMLGUIFactory::saveConfigFile(domDocument, mainWindow->xmlFile());
+    mainWindow->reloadXML();
+    mainWindow->createGUI();
+    return true;
+}
+
+void DolphinNavigatorsWidgetAction::createSecondaryUrlNavigator()
+{
+    Q_ASSERT(m_splitter->count() == 1);
+    m_splitter->addWidget(createNavigatorWidget(Secondary));
+    Q_ASSERT(m_splitter->count() == 2);
+}
+
+void DolphinNavigatorsWidgetAction::followViewContainerGeometry(
+                                    int globalXOfPrimary,   int widthOfPrimary)
+{
+    followViewContainersGeometry(globalXOfPrimary, widthOfPrimary, -1, -1);
+}
+
+void DolphinNavigatorsWidgetAction::followViewContainersGeometry(
+                                    int globalXOfPrimary,   int widthOfPrimary,
+                                    int globalXOfSecondary, int widthOfSecondary)
+{
+    m_globalXOfSplitter = m_splitter->mapToGlobal(QPoint(0,0)).x();
+    m_globalXOfPrimary = globalXOfPrimary;
+    m_widthOfPrimary = widthOfPrimary;
+    m_globalXOfSecondary = globalXOfSecondary;
+    m_widthOfSecondary = widthOfSecondary;
+    adjustSpacing();
+}
+
+DolphinUrlNavigator* DolphinNavigatorsWidgetAction::primaryUrlNavigator() const
+{
+    Q_ASSERT(m_splitter);
+    return static_cast<DolphinUrlNavigator *>(m_splitter->widget(0)->findChild<KUrlNavigator *>());
+}
+
+DolphinUrlNavigator* DolphinNavigatorsWidgetAction::secondaryUrlNavigator() const
+{
+    Q_ASSERT(m_splitter);
+    if (m_splitter->count() < 2) {
+        return nullptr;
+    }
+    return static_cast<DolphinUrlNavigator *>(m_splitter->widget(1)->findChild<KUrlNavigator *>());
+}
+
+void DolphinNavigatorsWidgetAction::setSecondaryNavigatorVisible(bool visible)
+{
+    if (visible) {
+        Q_ASSERT(m_splitter->count() == 2);
+        m_splitter->widget(1)->setVisible(true);
+    } else if (m_splitter->count() > 1) {
+        m_splitter->widget(1)->setVisible(false);
+        // Fix an unlikely event of wrong trash button visibility.
+        emptyTrashButton(Secondary)->setVisible(false);
+    }
+}
+
+void DolphinNavigatorsWidgetAction::adjustSpacing()
+{
+    const int widthOfSplitterPrimary = m_globalXOfPrimary + m_widthOfPrimary - m_globalXOfSplitter;
+    const QList<int> splitterSizes = {widthOfSplitterPrimary,
+                                      m_splitter->width() - widthOfSplitterPrimary};
+    m_splitter->setSizes(splitterSizes);
+
+    // primary side of m_splitter
+    int leadingSpacing = m_globalXOfPrimary - m_globalXOfSplitter;
+    if (leadingSpacing < 0) {
+        leadingSpacing = 0;
+    }
+    int trailingSpacing = (m_globalXOfSplitter + m_splitter->width())
+                          - (m_globalXOfPrimary + m_widthOfPrimary);
+    if (trailingSpacing < 0 || emptyTrashButton(Primary)->isVisible()) {
+        trailingSpacing = 0;
+    }
+    const int widthLeftForUrlNavigator = m_splitter->widget(0)->width() - leadingSpacing - trailingSpacing;
+    const int widthNeededForUrlNavigator = primaryUrlNavigator()->sizeHint().width() - widthLeftForUrlNavigator;
+    if (widthNeededForUrlNavigator > 0) {
+        trailingSpacing -= widthNeededForUrlNavigator;
+        if (trailingSpacing < 0) {
+            leadingSpacing += trailingSpacing;
+            trailingSpacing = 0;
+        }
+        if (leadingSpacing < 0) {
+            leadingSpacing = 0;
+        }
+    }
+    spacing(Primary, Leading)->setMinimumWidth(leadingSpacing);
+    spacing(Primary, Trailing)->setFixedWidth(trailingSpacing);
+
+    // secondary side of m_splitter
+    if (m_globalXOfSecondary == -1) {
+        Q_ASSERT(m_widthOfSecondary == -1);
+        return;
+    }
+    spacing(Primary, Trailing)->setFixedWidth(0);
+
+    trailingSpacing = (m_globalXOfSplitter + m_splitter->width())
+                      - (m_globalXOfSecondary + m_widthOfSecondary);
+    if (trailingSpacing < 0 || emptyTrashButton(Secondary)->isVisible()) {
+        trailingSpacing = 0;
+    } else {
+        const int widthLeftForUrlNavigator2 = m_splitter->widget(1)->width() - trailingSpacing;
+        const int widthNeededForUrlNavigator2 = secondaryUrlNavigator()->sizeHint().width() - widthLeftForUrlNavigator2;
+        if (widthNeededForUrlNavigator2 > 0) {
+            trailingSpacing -= widthNeededForUrlNavigator2;
+            if (trailingSpacing < 0) {
+                trailingSpacing = 0;
+            }
+        }
+    }
+    spacing(Secondary, Trailing)->setMinimumWidth(trailingSpacing);
+}
+
+QWidget *DolphinNavigatorsWidgetAction::createNavigatorWidget(Side side) const
+{
+    auto navigatorWidget = new QWidget(m_splitter.get());
+    auto layout = new QHBoxLayout{navigatorWidget};
+    layout->setSpacing(0);
+    layout->setContentsMargins(0, 0, 0, 0);
+    if (side == Primary) {
+        auto leadingSpacing = new QWidget{navigatorWidget};
+        layout->addWidget(leadingSpacing);
+    }
+    auto urlNavigator = new DolphinUrlNavigator(navigatorWidget);
+    layout->addWidget(urlNavigator);
+
+    auto emptyTrashButton = newEmptyTrashButton(urlNavigator, navigatorWidget);
+    layout->addWidget(emptyTrashButton);
+
+    connect(urlNavigator, &KUrlNavigator::urlChanged, [this]() {
+                // We have to wait for DolphinUrlNavigator::sizeHint() to update which
+                // happens a little bit later than when urlChanged is emitted.
+                this->m_adjustSpacingTimer->start();
+            });
+
+    auto trailingSpacing = new QWidget{navigatorWidget};
+    layout->addWidget(trailingSpacing);
+    return navigatorWidget;
+}
+
+QPushButton * DolphinNavigatorsWidgetAction::emptyTrashButton(DolphinNavigatorsWidgetAction::Side side)
+{
+    int sideIndex = (side == Primary ? 0 : 1);
+    if (side == Primary) {
+        return static_cast<QPushButton *>(m_splitter->widget(sideIndex)->layout()->itemAt(2)->widget());
+    }
+    return static_cast<QPushButton *>(m_splitter->widget(sideIndex)->layout()->itemAt(1)->widget());
+}
+
+QPushButton *DolphinNavigatorsWidgetAction::newEmptyTrashButton(const DolphinUrlNavigator *urlNavigator, QWidget *parent) const
+{
+    auto emptyTrashButton = new QPushButton(QIcon::fromTheme(QStringLiteral("user-trash")),
+                                        i18nc("@action:button", "Empty Trash"), parent);
+    emptyTrashButton->setFlat(true);
+    connect(emptyTrashButton, &QPushButton::clicked,
+            this, [parent]() { Trash::empty(parent); });
+    connect(&Trash::instance(), &Trash::emptinessChanged,
+            emptyTrashButton, &QPushButton::setDisabled);
+    emptyTrashButton->hide();
+    connect(urlNavigator, &KUrlNavigator::urlChanged, [emptyTrashButton, urlNavigator]() {
+        emptyTrashButton->setVisible(urlNavigator->locationUrl().scheme() == QLatin1String("trash"));
+    });
+    emptyTrashButton->setDisabled(Trash::isEmpty());
+    return emptyTrashButton;
+}
+
+QWidget *DolphinNavigatorsWidgetAction::spacing(Side side, Position position) const
+{
+    int sideIndex = (side == Primary ? 0 : 1);
+    if (position == Leading) {
+        Q_ASSERT(side == Primary); // The secondary side of the splitter has no leading spacing.
+        return m_splitter->widget(sideIndex)->layout()->itemAt(0)->widget();
+    }
+    if (side == Primary) {
+        return m_splitter->widget(sideIndex)->layout()->itemAt(3)->widget();
+    }
+    return m_splitter->widget(sideIndex)->layout()->itemAt(2)->widget();
+}
diff --git a/src/dolphinnavigatorswidgetaction.h b/src/dolphinnavigatorswidgetaction.h
new file mode 100644 (file)
index 0000000..c1808d6
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+    This file is part of the KDE project
+    SPDX-FileCopyrightText: 2020 Felix Ernst <fe.a.ernst@gmail.com>
+
+    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+*/
+
+#ifndef DOLPHINNAVIGATORSWIDGETACTION_H
+#define DOLPHINNAVIGATORSWIDGETACTION_H
+
+#include "dolphinurlnavigator.h"
+
+#include <QSplitter>
+#include <QTimer>
+#include <QWidgetAction>
+
+#include <memory>
+
+class KXmlGuiWindow;
+class QPushButton;
+
+/**
+ * @brief QWidgetAction that allows to use DolphinUrlNavigators in a toolbar.
+ *
+ * This class is mainly a container that manages up to two DolphinUrlNavigator objects so they
+ * can be added to a toolbar. It also deals with alignment.
+ *
+ * The structure of the defaultWidget() of this QWidgetAction is as follows:
+ * - A QSplitter manages up to two sides which each correspond to one DolphinViewContainer.
+ *      The secondary side only exists for split view and is created by
+ *      createSecondaryUrlNavigator() when necessary.
+ * - Each side is a QWidget which I call NavigatorWidget with a QHBoxLayout.
+ * - Each NavigatorWidget consists an UrlNavigator, an emptyTrashButton and spacing.
+ * - Only the primary navigatorWidget has leading spacing. Both have trailing spacing.
+ *      The spacing is there to align the UrlNavigator with its DolphinViewContainer.
+ */
+class DolphinNavigatorsWidgetAction : public QWidgetAction
+{
+    Q_OBJECT
+
+    /**
+     * In Left-to-right languages the Primary side will be the left one.
+     */
+    enum Side {
+        Primary,
+        Secondary
+    };
+
+public:
+    DolphinNavigatorsWidgetAction(QWidget *parent = nullptr);
+
+    /**
+     * Adds this action to the mainWindow's toolbar and saves the change
+     * in the users ui configuration file.
+     * @return true if successful. Otherwise false.
+     */
+    bool addToToolbarAndSave(KXmlGuiWindow *mainWindow);
+
+    /**
+     * Different to the primary UrlNavigator, the secondary UrlNavigator is only created on-demand.
+     */
+    void createSecondaryUrlNavigator();
+
+    /**
+     * Notify the primary UrlNavigator of changes in geometry of the ViewContainer it tries to be
+     * aligned with. Only call this method if there is no secondary UrlNavigator.
+     */
+    void followViewContainerGeometry(int globalXOfPrimary,   int widthOfPrimary);
+    /**
+     * Notify this widget of changes in geometry of the ViewContainers it tries to be
+     * aligned with.
+     */
+    void followViewContainersGeometry(int globalXOfPrimary,   int widthOfPrimary,
+                                      int globalXOfSecondary, int widthOfSecondary);
+
+    /**
+     * @return the primary UrlNavigator.
+     */
+    DolphinUrlNavigator *primaryUrlNavigator() const;
+    /**
+     * @return the secondary UrlNavigator and nullptr if it doesn't exist.
+     */
+    DolphinUrlNavigator *secondaryUrlNavigator() const;
+
+    /**
+     * Change the visibility of the secondary UrlNavigator including spacing.
+     * @param visible Setting this to false will completely hide the secondary side of this
+     *                WidgetAction's QSplitter making the QSplitter effectively disappear.
+     */
+    void setSecondaryNavigatorVisible(bool visible);
+
+protected:
+    /**
+     * Adjusts the width of the spacings used to align the UrlNavigators with ViewContainers.
+     * This can only work nicely if up-to-date geometry of ViewContainers is cached so
+     * followViewContainersGeometry() has to have been called at least once before.
+     */
+    void adjustSpacing();
+
+    /**
+     * Used to create the navigatorWidgets for both sides of the QSplitter.
+     */
+    QWidget *createNavigatorWidget(Side side) const;
+
+    /**
+     * Used to retrieve the emptyTrashButtons for the navigatorWidgets on both sides.
+     */
+    QPushButton *emptyTrashButton(Side side);
+
+    /**
+     * Creates a new empty trash button.
+     * @param urlNavigator Only when this UrlNavigator shows the trash directory
+     *                     will the the button be visible.
+     * @param parent       Aside from the usual QObject deletion mechanisms,
+     *                     this parameter influences the positioning of dialog windows
+     *                     pertaining to this trash button.
+     */
+    QPushButton *newEmptyTrashButton(const DolphinUrlNavigator *urlNavigator, QWidget *parent) const;
+
+    enum Position {
+        Leading,
+        Trailing
+    };
+    /**
+     * Used to retrieve both the leading and trailing spacing for the navigatorWidgets
+     * on both sides. A secondary leading spacing does not exist.
+     */
+    QWidget *spacing(Side side, Position position) const;
+
+    /**
+     * The defaultWidget() of this QWidgetAction.
+     */
+    std::unique_ptr<QSplitter> m_splitter;
+
+    /**
+     * adjustSpacing() has to be called slightly later than when urlChanged is emitted.
+     * This timer bridges that time.
+     */
+    std::unique_ptr<QTimer> m_adjustSpacingTimer;
+
+    // cached values
+    int m_globalXOfSplitter;
+    int m_globalXOfPrimary;
+    int m_widthOfPrimary;
+    int m_globalXOfSecondary;
+    int m_widthOfSecondary;
+};
+
+#endif // DOLPHINNAVIGATORSWIDGETACTION_H
index c2c573e1dc7096f31b967680a63c97aea27daf7c..d2fd1d1437ce5c1d1ca235404f4396869458ae6d 100644 (file)
@@ -9,6 +9,7 @@
 #include "dolphin_generalsettings.h"
 #include "dolphinviewcontainer.h"
 
+#include <QPropertyAnimation>
 #include <QSplitter>
 #include <QVBoxLayout>
 
@@ -24,6 +25,8 @@ DolphinTabPage::DolphinTabPage(const QUrl &primaryUrl, const QUrl &secondaryUrl,
 
     m_splitter = new QSplitter(Qt::Horizontal, this);
     m_splitter->setChildrenCollapsible(false);
+    connect(m_splitter, &QSplitter::splitterMoved,
+            this, &DolphinTabPage::splitterMoved);
     layout->addWidget(m_splitter);
 
     // Create a new primary view
@@ -34,6 +37,7 @@ 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()) {
@@ -43,6 +47,7 @@ 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();
     }
 
@@ -65,17 +70,59 @@ void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
         m_splitViewEnabled = enabled;
 
         if (enabled) {
+            int splitterTotalWidth = m_splitter->width();
             const QUrl& url = (secondaryUrl.isEmpty()) ? m_primaryViewContainer->url() : secondaryUrl;
             m_secondaryViewContainer = createViewContainer(url);
 
+            auto secondaryNavigator = m_navigatorsWidget->secondaryUrlNavigator();
+            if (!secondaryNavigator) {
+                m_navigatorsWidget->createSecondaryUrlNavigator();
+                secondaryNavigator = m_navigatorsWidget->secondaryUrlNavigator();
+            }
+            m_secondaryViewContainer->connectUrlNavigator(secondaryNavigator);
+            m_navigatorsWidget->setSecondaryNavigatorVisible(true);
+
             m_splitter->addWidget(m_secondaryViewContainer);
-            m_secondaryViewContainer->show();
+            m_secondaryViewContainer->installEventFilter(this);
             m_secondaryViewContainer->setActive(true);
+
+            // opening animation
+            m_splitter->widget(1)->setMinimumWidth(1);
+            const QList<int> splitterSizes = {m_splitter->width(), 0};
+            m_splitter->setSizes(splitterSizes);
+
+            // TODO: This is only here to test the robustness of DolphinNavigatorsWidgetAction! I still have to move it to another merge request!
+            m_splitViewAnimation = new QVariantAnimation(m_splitter);
+            m_splitViewAnimation->setDuration(200); // TODO: where do I get the animation times from again?
+            m_splitViewAnimation->setStartValue(splitterTotalWidth);
+            m_splitViewAnimation->setEndValue(splitterTotalWidth / 2);
+            m_splitViewAnimation->setEasingCurve(QEasingCurve::OutCubic);
+
+            connect(m_splitViewAnimation, &QVariantAnimation::valueChanged, [=]() {
+                if (m_splitter->count() != 2) {
+                    return;
+                }
+                int value = m_splitViewAnimation->currentValue().toInt();
+                const QList<int> splitterSizes = {value, m_splitter->width() - value};
+                m_splitter->setSizes(splitterSizes);
+                if (value == m_splitViewAnimation->endValue().toInt()) {
+                    m_splitter->widget(1)->setMinimumWidth(m_splitter->widget(1)->minimumSizeHint().width());
+                }
+            });
+            m_splitViewAnimation->start(QAbstractAnimation::DeleteWhenStopped);
+            m_secondaryViewContainer->show();
         } else {
+            m_navigatorsWidget->setSecondaryNavigatorVisible(false);
+            m_secondaryViewContainer->disconnectUrlNavigator();
+
             DolphinViewContainer* view;
             if (GeneralSettings::closeActiveSplitView()) {
                 view = activeViewContainer();
                 if (m_primaryViewActive) {
+                    m_primaryViewContainer->disconnectUrlNavigator();
+                    m_secondaryViewContainer->connectUrlNavigator(
+                            m_navigatorsWidget->primaryUrlNavigator());
+
                     // If the primary view is active, we have to swap the pointers
                     // because the secondary view will be the new primary view.
                     qSwap(m_primaryViewContainer, m_secondaryViewContainer);
@@ -84,6 +131,10 @@ void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
             } else {
                 view = m_primaryViewActive ? m_secondaryViewContainer : m_primaryViewContainer;
                 if (!m_primaryViewActive) {
+                    m_primaryViewContainer->disconnectUrlNavigator();
+                    m_secondaryViewContainer->connectUrlNavigator(
+                            m_navigatorsWidget->primaryUrlNavigator());
+
                     // If the secondary view is active, we have to swap the pointers
                     // because the secondary view will be the new primary view.
                     qSwap(m_primaryViewContainer, m_secondaryViewContainer);
@@ -93,6 +144,10 @@ void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
             m_primaryViewContainer->setActive(true);
             view->close();
             view->deleteLater();
+            if (m_splitViewAnimation) {
+                delete m_splitViewAnimation;
+                m_splitter->widget(0)->setMinimumWidth(m_splitter->widget(0)->minimumSizeHint().width());
+            }
         }
     }
 }
@@ -131,6 +186,56 @@ int DolphinTabPage::selectedItemsCount() const
     return selectedItemsCount;
 }
 
+void DolphinTabPage::connectNavigators(DolphinNavigatorsWidgetAction *navigatorsWidget)
+{
+    m_navigatorsWidget = navigatorsWidget;
+    auto primaryNavigator = navigatorsWidget->primaryUrlNavigator();
+    primaryNavigator->setActive(m_primaryViewActive);
+    m_primaryViewContainer->connectUrlNavigator(primaryNavigator);
+    if (m_splitViewEnabled) {
+        auto secondaryNavigator = navigatorsWidget->secondaryUrlNavigator();
+        if (!secondaryNavigator) {
+            navigatorsWidget->createSecondaryUrlNavigator();
+            secondaryNavigator = navigatorsWidget->secondaryUrlNavigator();
+        }
+        secondaryNavigator->setActive(!m_primaryViewActive);
+        m_secondaryViewContainer->connectUrlNavigator(secondaryNavigator);
+    }
+    resizeNavigators();
+}
+
+void DolphinTabPage::disconnectNavigators()
+{
+    m_navigatorsWidget = nullptr;
+    m_primaryViewContainer->disconnectUrlNavigator();
+    if (m_splitViewEnabled) {
+        m_secondaryViewContainer->disconnectUrlNavigator();
+    }
+}
+
+bool DolphinTabPage::eventFilter(QObject */* watched */, QEvent *event)
+{
+    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());
+    } else {
+        m_navigatorsWidget->followViewContainersGeometry(
+                m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
+                m_primaryViewContainer->width(),
+                m_secondaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
+                m_secondaryViewContainer->width());
+    }
+}
+
 void DolphinTabPage::markUrlsAsSelected(const QList<QUrl>& urls)
 {
     m_primaryViewContainer->view()->markUrlsAsSelected(urls);
@@ -222,11 +327,17 @@ void DolphinTabPage::restoreState(const QByteArray& state)
     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);
     }
 
+    if (m_splitViewAnimation) {
+        delete m_splitViewAnimation;
+        m_splitter->widget(0)->setMinimumWidth(m_splitter->widget(0)->minimumSizeHint().width());
+    }
     QByteArray splitterState;
     stream >> splitterState;
     m_splitter->restoreState(splitterState);
index 74344acd1800b2b1919a2f7a4ee398880c9101f3..6a8801eddcbadf414485ea169cefab559a963464 100644 (file)
 #include <QUrl>
 #include <QWidget>
 
-class QSplitter;
+class DolphinNavigatorsWidgetAction;
 class DolphinViewContainer;
+class QSplitter;
+class QVariantAnimation;
 class KFileItemList;
 
 class DolphinTabPage : public QWidget
@@ -66,6 +68,30 @@ public:
      */
     int selectedItemsCount() const;
 
+    /**
+     * Connects a navigatorsWidget to this. It will be connected to the DolphinViewContainers
+     * managed by this tab. For alignment purposes this will from now on notify the
+     * navigatorsWidget when this tab or its viewContainers are resized.
+     */
+    void connectNavigators(DolphinNavigatorsWidgetAction *navigatorsWidget);
+
+    /**
+     * Makes it so this tab and its DolphinViewContainers aren't controlled by any
+     * UrlNavigators anymore.
+     */
+    void disconnectNavigators();
+
+    /**
+     * Calls resizeNavigators() when a watched object is resized.
+     */
+    bool eventFilter(QObject */* watched */, QEvent *event) override;
+
+    /**
+     * Notify the connected DolphinNavigatorsWidgetAction of geometry changes which it
+     * needs for visual alignment.
+     */
+    void resizeNavigators() const;
+
     /**
      * Marks the items indicated by \p urls to get selected after the
      * directory DolphinView::url() has been loaded. Note that nothing
@@ -80,14 +106,6 @@ public:
      */
     void markUrlAsCurrent(const QUrl& url);
 
-    /**
-     * Sets the places selector visible, if \a visible is true.
-     * The places selector allows to select the places provided
-     * by the places model passed in the constructor. Per default
-     * the places selector is visible.
-     */
-    void setPlacesSelectorVisible(bool visible);
-
     /**
      * Refreshes the views of the main window by recreating them according to
      * the given Dolphin settings.
@@ -125,6 +143,7 @@ public:
 signals:
     void activeViewChanged(DolphinViewContainer* viewContainer);
     void activeViewUrlChanged(const QUrl& url);
+    void splitterMoved(int pos, int index);
 
 private slots:
     /**
@@ -153,8 +172,10 @@ private:
 private:
     QSplitter* m_splitter;
 
+    QPointer<DolphinNavigatorsWidgetAction> m_navigatorsWidget;
     QPointer<DolphinViewContainer> m_primaryViewContainer;
     QPointer<DolphinViewContainer> m_secondaryViewContainer;
+    QPointer<QVariantAnimation> m_splitViewAnimation;
 
     bool m_primaryViewActive;
     bool m_splitViewEnabled;
index 3ce8229f9325aaae10bedd1c3ae74a1d833da177..a09a769d37c7497a9e2f185821daa93c713b1158 100644 (file)
 #include <QApplication>
 #include <QDropEvent>
 
-DolphinTabWidget::DolphinTabWidget(QWidget* parent) :
+DolphinTabWidget::DolphinTabWidget(DolphinNavigatorsWidgetAction *navigatorsWidget, QWidget* parent) :
     QTabWidget(parent),
-    m_lastViewedTab(0)
+    m_lastViewedTab(nullptr),
+    m_navigatorsWidget{navigatorsWidget}
 {
     KAcceleratorManager::setNoAccel(this);
 
@@ -126,11 +127,19 @@ bool DolphinTabWidget::isUrlOpen(const QUrl &url) const
 
 void DolphinTabWidget::openNewActivatedTab()
 {
+    std::unique_ptr<DolphinUrlNavigator::VisualState> oldNavigatorState;
+    if (currentTabPage()->primaryViewActive()) {
+        oldNavigatorState = m_navigatorsWidget->primaryUrlNavigator()->visualState();
+    } else {
+        if (!m_navigatorsWidget->secondaryUrlNavigator()) {
+            m_navigatorsWidget->createSecondaryUrlNavigator();
+        }
+        oldNavigatorState = m_navigatorsWidget->secondaryUrlNavigator()->visualState();
+    }
+
     const DolphinViewContainer* oldActiveViewContainer = currentTabPage()->activeViewContainer();
     Q_ASSERT(oldActiveViewContainer);
 
-    const bool isUrlEditable = oldActiveViewContainer->urlNavigator()->isUrlEditable();
-
     openNewActivatedTab(oldActiveViewContainer->url());
 
     DolphinViewContainer* newActiveViewContainer = currentTabPage()->activeViewContainer();
@@ -138,7 +147,7 @@ void DolphinTabWidget::openNewActivatedTab()
 
     // The URL navigator of the new tab should have the same editable state
     // as the current tab
-    newActiveViewContainer->urlNavigator()->setUrlEditable(isUrlEditable);
+    newActiveViewContainer->urlNavigator()->setVisualState(*oldNavigatorState.get());
 
     // Always focus the new tab's view
     newActiveViewContainer->view()->setFocus();
@@ -384,16 +393,21 @@ void DolphinTabWidget::tabUrlChanged(const QUrl& url)
 
 void DolphinTabWidget::currentTabChanged(int index)
 {
-    // last-viewed tab deactivation
-    if (DolphinTabPage* tabPage = tabPageAt(m_lastViewedTab)) {
-        tabPage->setActive(false);
+    DolphinTabPage *tabPage = tabPageAt(index);
+    if (tabPage == m_lastViewedTab) {
+        return;
+    }
+    if (m_lastViewedTab) {
+        m_lastViewedTab->disconnectNavigators();
+        m_lastViewedTab->setActive(false);
     }
-    DolphinTabPage* tabPage = tabPageAt(index);
     DolphinViewContainer* viewContainer = tabPage->activeViewContainer();
     Q_EMIT activeViewChanged(viewContainer);
     Q_EMIT currentUrlChanged(viewContainer->url());
     tabPage->setActive(true);
-    m_lastViewedTab = index;
+    tabPage->connectNavigators(m_navigatorsWidget);
+    m_navigatorsWidget->setSecondaryNavigatorVisible(tabPage->splitViewEnabled());
+    m_lastViewedTab = tabPageAt(index);
 }
 
 void DolphinTabWidget::tabInserted(int index)
index 9cc03f127659e2a453157c29142f75a721fd84ba..707eb086ad4cd73468d4b1034e25e8ed1110fe55 100644 (file)
@@ -7,11 +7,13 @@
 #ifndef DOLPHIN_TAB_WIDGET_H
 #define DOLPHIN_TAB_WIDGET_H
 
+#include "dolphinnavigatorswidgetaction.h"
+
 #include <QTabWidget>
 #include <QUrl>
 
-class DolphinViewContainer;
 class DolphinTabPage;
+class DolphinViewContainer;
 class KConfigGroup;
 
 class DolphinTabWidget : public QTabWidget
@@ -32,7 +34,12 @@ public:
           */
         AfterLastTab
     };
-    explicit DolphinTabWidget(QWidget* parent);
+
+    /**
+     * @param navigatorsWidget The navigatorsWidget which is always going to be connected
+     *                         to the active tabPage.
+     */
+    explicit DolphinTabWidget(DolphinNavigatorsWidgetAction *navigatorsWidget, QWidget *parent);
 
     /**
      * @return Tab page at the current index (can be 0 if tabs count is smaller than 1)
@@ -224,7 +231,8 @@ private:
     QPair<int, bool> indexByUrl(const QUrl& url) const;
 
 private:
-    int m_lastViewedTab;
+    QPointer<DolphinTabPage> m_lastViewedTab;
+    QPointer<DolphinNavigatorsWidgetAction> m_navigatorsWidget;
 };
 
 #endif
index 10c7c2fa4cc04fd54364e099d7f08023ec39c393..01a3778f9cfd38018fd7d72138c569db118eb651 100644 (file)
@@ -56,7 +56,6 @@
                 <text context="@title:menu">Location Bar</text>
                 <Action name="editable_location" />
                 <Action name="replace_location" />
-                <Action name="location_in_toolbar" />
             </Menu>
             <Separator/>
             <Action name="view_properties" />
         <Action name="icons" />
         <Action name="compact" />
         <Action name="details" />
-        <Separator name="separator_0" />
-        <Action name="sort" />
-        <Action name="url_navigator" />
+        <Action name="url_navigators" />
         <Action name="split_view" />
         <Action name="split_stash" />
         <Action name="toggle_search" />
index 70f780e55e229618ef9afc063c8080a67b3437c8..2b7f3d4eb4d55d90c23c33821ded1b1260f29199 100644 (file)
@@ -1,22 +1,9 @@
 /*
- * Copyright 2020  Felix Ernst <fe.a.ernst@gmail.com>
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) version 3, or any
- * later version accepted by the membership of KDE e.V. (or its
- * successor approved by the membership of KDE e.V.), which shall
- * act as a proxy defined in Section 6 of version 3 of the license.
- * 
- * This library 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library.  If not, see <https://www.gnu.org/licenses/>.
- */
+    This file is part of the KDE project
+    SPDX-FileCopyrightText: 2020 Felix Ernst <fe.a.ernst@gmail.com>
+
+    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+*/
 
 #include "dolphinurlnavigator.h"
 
 #include "dolphinplacesmodelsingleton.h"
 #include "global.h"
 
-#include <KToggleAction>
 #include <KUrlComboBox>
 #include <KLocalizedString>
 
+#include <QAbstractButton>
+#include <QLayout>
 #include <QLineEdit>
-#include <QMenu>
 
 DolphinUrlNavigator::DolphinUrlNavigator(QWidget *parent) :
     KUrlNavigator(DolphinPlacesModelSingleton::instance().placesModel(), QUrl(), parent)
@@ -51,10 +38,8 @@ void DolphinUrlNavigator::init()
     setHomeUrl(Dolphin::homeUrl());
     setPlacesSelectorVisible(s_placesSelectorVisible);
     editor()->setCompletionMode(KCompletion::CompletionMode(settings->urlCompletionMode()));
-    editor()->lineEdit()->installEventFilter(this);
-    installEventFilter(this);
     setWhatsThis(xi18nc("@info:whatsthis location bar",
-        "<para>This line describes the location of the files and folders "
+        "<para>This describes the location of the files and folders "
         "displayed below.</para><para>The name of the currently viewed "
         "folder can be read at the very right. To the left of it is the "
         "name of the folder that contains it. The whole line is called "
@@ -79,30 +64,50 @@ DolphinUrlNavigator::~DolphinUrlNavigator()
     s_instances.remove(this);
 }
 
-bool DolphinUrlNavigator::eventFilter(QObject* watched, QEvent* event)
+QSize DolphinUrlNavigator::sizeHint() const
 {
-    Q_UNUSED(watched)
-    if (event->type() == QEvent::ChildPolished) {
-        QChildEvent *childEvent = static_cast<QChildEvent *>(event);
-        QMenu *popup = qobject_cast<QMenu *>(childEvent->child());
-        if (popup) {
-            // The popups of the "breadcrumb mode" navigation buttons
-            // should not get the action added. They can currently be
-            // identified by their number of separators: 0 or 1
-            // The popups we are interested in have 2 or more separators.
-            int separatorCount = 0;
-            for (QAction *action : popup->actions()) {
-                if (action->isSeparator()) {
-                    separatorCount++;
-                }
-            }
-            if (separatorCount > 1) {
-                q_check_ptr(s_ActionForContextMenu);
-                popup->addAction(s_ActionForContextMenu);
-            }
+    // Change sizeHint() in KUrlNavigator instead.
+    if (isUrlEditable()) {
+        return editor()->lineEdit()->sizeHint();
+    }
+    int widthHint = 0;
+    for (int i = 0; i < layout()->count(); ++i) {
+        QWidget *widget = layout()->itemAt(i)->widget();
+        const QAbstractButton *button = qobject_cast<QAbstractButton *>(widget);
+        if (button && button->icon().isNull()) {
+            widthHint += widget->minimumSizeHint().width();
+        }
+    }
+    return QSize(widthHint, KUrlNavigator::sizeHint().height());
+}
+
+std::unique_ptr<DolphinUrlNavigator::VisualState> DolphinUrlNavigator::visualState() const
+{
+    std::unique_ptr<VisualState> visualState{new VisualState};
+    visualState->isUrlEditable = (isUrlEditable());
+    const QLineEdit *lineEdit = editor()->lineEdit();
+    visualState->hasFocus = lineEdit->hasFocus();
+    visualState->text = lineEdit->text();
+    visualState->cursorPosition = lineEdit->cursorPosition();
+    visualState->selectionStart = lineEdit->selectionStart();
+    visualState->selectionLength = lineEdit->selectionLength();
+    return visualState;
+}
+
+void DolphinUrlNavigator::setVisualState(const VisualState& visualState)
+{
+    setUrlEditable(visualState.isUrlEditable);
+    if (!visualState.isUrlEditable) {
+        return;
+    }
+    editor()->lineEdit()->setText(visualState.text);
+    if (visualState.hasFocus) {
+        editor()->lineEdit()->setFocus();
+        editor()->lineEdit()->setCursorPosition(visualState.cursorPosition);
+        if (visualState.selectionStart != -1) {
+            editor()->lineEdit()->setSelection(visualState.selectionStart, visualState.selectionLength);
         }
     }
-    return false;
 }
 
 void DolphinUrlNavigator::slotReadSettings()
@@ -126,12 +131,6 @@ void DolphinUrlNavigator::slotReturnPressed()
     }
 }
 
-void DolphinUrlNavigator::addToContextMenu(QAction* action)
-{
-    s_ActionForContextMenu = action;
-}
-
-
 void DolphinUrlNavigator::slotPlacesPanelVisibilityChanged(bool visible)
 {
     // The places-selector from the URL navigator should only be shown
@@ -157,4 +156,3 @@ void DolphinUrlNavigator::setCompletionMode(const KCompletion::CompletionMode co
 
 std::forward_list<DolphinUrlNavigator *> DolphinUrlNavigator::s_instances;
 bool DolphinUrlNavigator::s_placesSelectorVisible = true;
-QAction *DolphinUrlNavigator::s_ActionForContextMenu = nullptr;
index 032b81e894e95e3d937c69b8d8e6d14e13a0c88d..8f8d270aebe445f9159e41e29c376f4585d2d5a4 100644 (file)
@@ -1,22 +1,9 @@
 /*
- * Copyright 2020  Felix Ernst <fe.a.ernst@gmail.com>
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) version 3, or any
- * later version accepted by the membership of KDE e.V. (or its
- * successor approved by the membership of KDE e.V.), which shall
- * act as a proxy defined in Section 6 of version 3 of the license.
- * 
- * This library 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library.  If not, see <https://www.gnu.org/licenses/>.
- */
+    This file is part of the KDE project
+    SPDX-FileCopyrightText: 2020 Felix Ernst <fe.a.ernst@gmail.com>
+
+    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+*/
 
 #ifndef DOLPHINURLNAVIGATOR_H
 #define DOLPHINURLNAVIGATOR_H
@@ -30,10 +17,10 @@ class KToggleAction;
 
 /**
  * @brief Extends KUrlNavigator in a Dolphin-specific way
- * 
+ *
  * Makes sure that Dolphin preferences, settings and settings changes are
  * applied to all constructed DolphinUrlNavigators.
- * 
+ *
  * @see KUrlNavigator
  */
 class DolphinUrlNavigator : public KUrlNavigator
@@ -55,6 +42,36 @@ public:
 
     virtual ~DolphinUrlNavigator();
 
+    /**
+     * This method is needed so the DolphinNavigatorWidgetAction knows when there is not enough
+     * space to neatly align the UrlNavigator with the ViewContainers. Unfortunately KUrlNavigator
+     * does not have a useful sizeHint() currently. It would make more sense to change
+     * KUrlNavigator instead.
+     */
+    QSize sizeHint() const override;
+
+    /**
+     * Wraps the visual state of a DolphinUrlNavigator so it can be passed around.
+     * This notably doesn't involve the locationUrl or history.
+     */
+    struct VisualState {
+        bool isUrlEditable;
+        bool hasFocus;
+        QString text;
+        int cursorPosition;
+        int selectionStart;
+        int selectionLength;
+    };
+    /**
+     * Retrieve the visual state of this DolphinUrlNavigator.
+     * If two DolphinUrlNavigators have the same visual state they should look identical.
+     */
+    std::unique_ptr<VisualState> visualState() const;
+    /**
+     * @param visualState A struct describing the new visual state of this object.
+     */
+    void setVisualState(const VisualState &visualState);
+
 public slots:
     /**
      * Refreshes all DolphinUrlNavigators to get synchronized with the
@@ -68,16 +85,6 @@ public slots:
      */
     void slotReturnPressed();
 
-    /**
-     * This method is specifically here so the locationInToolbar
-     * KToggleAction that is created in DolphinMainWindow can be passed to
-     * this class and then appear in all context menus. This last part is
-     * done by eventFilter().
-     * For any other use parts of this class need to be rewritten.
-     * @param action The locationInToolbar-action from DolphinMainWindow
-     */
-    static void addToContextMenu(QAction *action);
-
     static void slotPlacesPanelVisibilityChanged(bool visible);
 
 protected:
@@ -86,14 +93,6 @@ protected:
      */
     void init();
 
-    /**
-     * This filter adds the s_ActionForContextMenu action to QMenus which
-     * are spawned by the watched QObject if that QMenu contains at least
-     * two separators.
-     * @see addToContextMenu()
-     */
-    bool eventFilter(QObject * watched, QEvent * event) override;
-
 protected slots:
     /**
      * Sets the completion mode for all DolphinUrlNavigators
@@ -107,9 +106,6 @@ protected:
 
     /** Caches the (negated) places panel visibility */
     static bool s_placesSelectorVisible;
-
-    /** An action that is added to the context menu */
-    static QAction *s_ActionForContextMenu;
 };
 
 #endif // DOLPHINURLNAVIGATOR_H
index 59a187e1ffaa6320b8c932ba9701fcc88516ed2b..46968e9ff6003f6c6a775eb8ef59c79eec8fbd39 100644 (file)
@@ -13,7 +13,6 @@
 #include "global.h"
 #include "search/dolphinsearchbox.h"
 #include "statusbar/dolphinstatusbar.h"
-#include "trash/dolphintrash.h"
 #include "views/viewmodecontroller.h"
 #include "views/viewproperties.h"
 #include "dolphin_detailsmodesettings.h"
 DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
     QWidget(parent),
     m_topLayout(nullptr),
-    m_navigatorWidget(nullptr),
-    m_urlNavigator(nullptr),
-    m_urlNavigatorConnected(nullptr),
-    m_emptyTrashButton(nullptr),
+    m_urlNavigator{new DolphinUrlNavigator(url)},
+    m_urlNavigatorConnected{nullptr},
     m_searchBox(nullptr),
     m_searchModeEnabled(false),
     m_messageWidget(nullptr),
@@ -56,7 +53,8 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
     m_statusBar(nullptr),
     m_statusBarTimer(nullptr),
     m_statusBarTimestamp(),
-    m_autoGrabFocus(true)
+    m_autoGrabFocus(true),
+    m_urlNavigatorVisualState{}
 #ifdef HAVE_KACTIVITIES
     , m_activityResourceInstance(nullptr)
 #endif
@@ -67,20 +65,6 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
     m_topLayout->setSpacing(0);
     m_topLayout->setContentsMargins(0, 0, 0, 0);
 
-    m_navigatorWidget = new QWidget(this);
-    m_navigatorWidget->setVisible(false);
-    QHBoxLayout* navigatorLayout = new QHBoxLayout(m_navigatorWidget);
-    navigatorLayout->setSpacing(0);
-    navigatorLayout->setContentsMargins(0, 0, 0, 0);
-    m_urlNavigator = new DolphinUrlNavigator(url, m_navigatorWidget);
-
-    m_emptyTrashButton = new QPushButton(QIcon::fromTheme(QStringLiteral("user-trash")), i18nc("@action:button", "Empty Trash"), this);
-    m_emptyTrashButton->setFlat(true);
-    connect(m_emptyTrashButton, &QPushButton::clicked, this, [this]() { Trash::empty(this); });
-    connect(&Trash::instance(), &Trash::emptinessChanged, m_emptyTrashButton, &QPushButton::setDisabled);
-    m_emptyTrashButton->setDisabled(Trash::isEmpty());
-    m_emptyTrashButton->hide();
-
     m_searchBox = new DolphinSearchBox(this);
     m_searchBox->hide();
     connect(m_searchBox, &DolphinSearchBox::activated, this, &DolphinViewContainer::activate);
@@ -132,8 +116,8 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
     // m_urlNavigator stays in sync with m_view's location changes and
     // keeps track of them so going back and forth in the history works.
     connect(m_view, &DolphinView::urlChanged,
-            m_urlNavigator, &DolphinUrlNavigator::setLocationUrl);
-    connect(m_urlNavigator, &DolphinUrlNavigator::urlChanged,
+            m_urlNavigator.get(), &DolphinUrlNavigator::setLocationUrl);
+    connect(m_urlNavigator.get(), &DolphinUrlNavigator::urlChanged,
             this, &DolphinViewContainer::slotUrlNavigatorLocationChanged);
     connect(m_view, &DolphinView::writeStateChanged,
             this, &DolphinViewContainer::writeStateChanged);
@@ -166,10 +150,6 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
     connect(m_view, &DolphinView::activated,
             this, &DolphinViewContainer::activate);
 
-    connect(m_view, &DolphinView::directoryLoadingCompleted, this, [this]() {
-        m_emptyTrashButton->setVisible(m_view->url().scheme() == QLatin1String("trash"));
-    });
-
     // Initialize status bar
     m_statusBar = new DolphinStatusBar(this);
     m_statusBar->setUrl(m_view->url());
@@ -196,19 +176,12 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
     connect(undoManager, &KIO::FileUndoManager::jobRecordingFinished,
             this, &DolphinViewContainer::delayedStatusBarUpdate);
 
-    navigatorLayout->addWidget(m_urlNavigator);
-    navigatorLayout->addWidget(m_emptyTrashButton);
-
-    m_topLayout->addWidget(m_navigatorWidget);
     m_topLayout->addWidget(m_searchBox);
     m_topLayout->addWidget(m_messageWidget);
     m_topLayout->addWidget(m_view);
     m_topLayout->addWidget(m_filterBar);
     m_topLayout->addWidget(m_statusBar);
 
-    if (!GeneralSettings::locationInToolbar()) {
-        connectToInternalUrlNavigator();
-    }
     setSearchModeEnabled(isSearchUrl(url));
 
     connect(DetailsModeSettings::self(), &KCoreConfigSkeleton::configChanged, this, [=]() {
@@ -237,7 +210,9 @@ QUrl DolphinViewContainer::url() const
 void DolphinViewContainer::setActive(bool active)
 {
     m_searchBox->setActive(active);
-    m_urlNavigator->setActive(active);
+    if (m_urlNavigatorConnected) {
+        m_urlNavigatorConnected->setActive(active);
+    }
     m_view->setActive(active);
 
 #ifdef HAVE_KACTIVITIES
@@ -251,7 +226,6 @@ void DolphinViewContainer::setActive(bool active)
 
 bool DolphinViewContainer::isActive() const
 {
-    Q_ASSERT(!m_urlNavigatorConnected || m_urlNavigatorConnected->isActive() == m_view->isActive());
     return m_view->isActive();
 }
 
@@ -292,12 +266,12 @@ DolphinUrlNavigator* DolphinViewContainer::urlNavigator()
 
 const DolphinUrlNavigator *DolphinViewContainer::urlNavigatorInternalWithHistory() const
 {
-    return m_urlNavigator;
+    return m_urlNavigator.get();
 }
 
 DolphinUrlNavigator *DolphinViewContainer::urlNavigatorInternalWithHistory()
 {
-    return m_urlNavigator;
+    return m_urlNavigator.get();
 }
 
 const DolphinView* DolphinViewContainer::view() const
@@ -314,19 +288,20 @@ void DolphinViewContainer::connectUrlNavigator(DolphinUrlNavigator *urlNavigator
 {
     Q_CHECK_PTR(urlNavigator);
     Q_ASSERT(!m_urlNavigatorConnected);
+    Q_ASSERT(m_urlNavigator.get() != urlNavigator);
     Q_CHECK_PTR(m_view);
 
-    m_urlNavigatorConnected = urlNavigator;
+    urlNavigator->setLocationUrl(m_view->url());
+    urlNavigator->setActive(isActive());
+    if (m_urlNavigatorVisualState) {
+        urlNavigator->setVisualState(*m_urlNavigatorVisualState.get());
+        m_urlNavigatorVisualState.reset();
+    }
 
-    // m_urlNavigator is already connected through urlChanged signals.
-    if (urlNavigator != m_urlNavigator) {
-        urlNavigator->setLocationUrl(m_view->url());
-        connect(m_view, &DolphinView::urlChanged,
+    connect(m_view, &DolphinView::urlChanged,
             urlNavigator, &DolphinUrlNavigator::setLocationUrl);
-        connect(urlNavigator, &DolphinUrlNavigator::urlChanged,
+    connect(urlNavigator, &DolphinUrlNavigator::urlChanged,
             this, &DolphinViewContainer::slotUrlNavigatorLocationChanged);
-    }
-
     connect(urlNavigator, &DolphinUrlNavigator::activated,
             this, &DolphinViewContainer::activate);
     connect(urlNavigator, &DolphinUrlNavigator::urlAboutToBeChanged,
@@ -337,7 +312,7 @@ void DolphinViewContainer::connectUrlNavigator(DolphinUrlNavigator *urlNavigator
         m_view->dropUrls(destination, event, urlNavigator->dropWidget());
     });
 
-    updateNavigatorWidgetVisibility();
+    m_urlNavigatorConnected = urlNavigator;
 }
 
 void DolphinViewContainer::disconnectUrlNavigator()
@@ -346,34 +321,27 @@ void DolphinViewContainer::disconnectUrlNavigator()
         return;
     }
 
-    // m_urlNavigator stays connected through the urlChanged signals.
-    if (m_urlNavigatorConnected != m_urlNavigator) {
-        disconnect(m_view, &DolphinView::urlChanged,
-            m_urlNavigatorConnected, &DolphinUrlNavigator::setLocationUrl);
-        disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlChanged,
-            this, &DolphinViewContainer::slotUrlNavigatorLocationChanged);
-    }
-
+    disconnect(m_view, &DolphinView::urlChanged,
+               m_urlNavigatorConnected, &DolphinUrlNavigator::setLocationUrl);
+    disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlChanged,
+               this, &DolphinViewContainer::slotUrlNavigatorLocationChanged);
     disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::activated,
-            this, &DolphinViewContainer::activate);
+               this, &DolphinViewContainer::activate);
     disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlAboutToBeChanged,
-            this, &DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged);
+               this, &DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged);
     disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlSelectionRequested,
-            this, &DolphinViewContainer::slotUrlSelectionRequested);
+               this, &DolphinViewContainer::slotUrlSelectionRequested);
     disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlsDropped,
-            this, nullptr);
+               this, nullptr);
 
+    m_urlNavigatorVisualState = m_urlNavigatorConnected->visualState();
     m_urlNavigatorConnected = nullptr;
-    updateNavigatorWidgetVisibility();
 }
 
-KMessageWidget *DolphinViewContainer::showMessage(const QString& msg, MessageType type)
+void DolphinViewContainer::showMessage(const QString& msg, MessageType type)
 {
     if (msg.isEmpty()) {
-        return m_messageWidget;
-    }
-    for (auto action : m_messageWidget->actions()) {
-        m_messageWidget->removeAction(action);
+        return;
     }
 
     m_messageWidget->setText(msg);
@@ -399,7 +367,6 @@ KMessageWidget *DolphinViewContainer::showMessage(const QString& msg, MessageTyp
         m_messageWidget->hide();
     }
     m_messageWidget->animatedShow();
-    return m_messageWidget;
 }
 
 void DolphinViewContainer::readSettings()
@@ -423,7 +390,6 @@ bool DolphinViewContainer::isFilterBarVisible() const
 void DolphinViewContainer::setSearchModeEnabled(bool enabled)
 {
     m_searchBox->setVisible(enabled);
-    updateNavigatorWidgetVisibility();
 
     if (enabled) {
         const QUrl& locationUrl = m_urlNavigatorConnected->locationUrl();
@@ -540,9 +506,8 @@ QString DolphinViewContainer::caption() const
 
 void DolphinViewContainer::setUrl(const QUrl& newUrl)
 {
-    Q_CHECK_PTR(m_urlNavigatorConnected);
-    if (newUrl != m_urlNavigatorConnected->locationUrl()) {
-        m_urlNavigatorConnected->setLocationUrl(newUrl);
+    if (newUrl != m_urlNavigator->locationUrl()) {
+        m_urlNavigator->setLocationUrl(newUrl);
     }
 
 #ifdef HAVE_KACTIVITIES
@@ -603,15 +568,6 @@ void DolphinViewContainer::updateDirectorySortingProgress(int percent)
     m_statusBar->setProgress(percent);
 }
 
-void DolphinViewContainer::updateNavigatorWidgetVisibility()
-{
-    if (m_urlNavigatorConnected == m_urlNavigator && !m_searchBox->isVisible()) {
-        m_navigatorWidget->setVisible(true);
-    } else {
-        m_navigatorWidget->setVisible(false);
-    }
-}
-
 void DolphinViewContainer::slotDirectoryLoadingStarted()
 {
     if (isSearchUrl(url())) {
index 2fe6b5f89eaec7263177512b10c3f689e89eeb64..77b74d18999b2bda5dac5ae960d8413a47a8ca89 100644 (file)
@@ -90,7 +90,7 @@ public:
      *          or nullptr if there is none.
      * @see connectUrlNavigator()
      * @see disconnectUrlNavigator()
-     * 
+     *
      * Use urlNavigatorInternalWithHistory() if you want to access the history.
      * @see urlNavigatorInternalWithHistory()
      */
@@ -100,7 +100,7 @@ public:
      *          or nullptr if there is none.
      * @see connectUrlNavigator()
      * @see disconnectUrlNavigator()
-     * 
+     *
      * Use urlNavigatorInternalWithHistory() if you want to access the history.
      * @see urlNavigatorInternalWithHistory()
      */
@@ -126,11 +126,6 @@ public:
      */
     void connectUrlNavigator(DolphinUrlNavigator *urlNavigator);
 
-    inline void connectToInternalUrlNavigator()
-    {
-        connectUrlNavigator(m_urlNavigator);
-    }
-
     /**
      * Disconnects the navigator that is currently controling the view.
      * This method completely reverses connectUrlNavigator().
@@ -140,9 +135,8 @@ public:
     /**
      * Shows the message \msg with the given type non-modal above
      * the view-content.
-     * @return the KMessageWidget used to show the message
      */
-    KMessageWidget *showMessage(const QString& msg, MessageType type);
+    void showMessage(const QString& msg, MessageType type);
 
     /**
      * Refreshes the view container to get synchronized with the (updated) Dolphin settings.
@@ -244,8 +238,6 @@ private slots:
 
     void updateDirectorySortingProgress(int percent);
 
-    void updateNavigatorWidgetVisibility();
-
     /**
      * Updates the statusbar to show an undetermined progress with the correct
      * context information whether a searching or a directory loading is done.
@@ -369,21 +361,20 @@ private:
 
 private:
     QVBoxLayout* m_topLayout;
-    QWidget* m_navigatorWidget;
 
     /**
-     * The UrlNavigator within the m_navigatorWidget. m_urlNavigator is
-     * used even when another UrlNavigator is controlling the view to keep
-     * track of this view containers history.
+     * The internal UrlNavigator which is never visible to the user.
+     * m_urlNavigator is used even when another UrlNavigator is controlling
+     * the view to keep track of this object's history.
      */
-    DolphinUrlNavigator *m_urlNavigator;
+    std::unique_ptr<DolphinUrlNavigator> m_urlNavigator;
 
     /**
-     * The UrlNavigator that is currently connected to the view. This could
-     * either be m_urlNavigator, the urlNavigator in the toolbar or nullptr.
+     * The UrlNavigator that is currently connected to the view.
+     * This is a nullptr if no UrlNavigator is connected.
+     * Otherwise it's one of the UrlNavigators visible in the toolbar.
      */
     QPointer<DolphinUrlNavigator> m_urlNavigatorConnected;
-    QPushButton* m_emptyTrashButton;
     DolphinSearchBox* m_searchBox;
     bool m_searchModeEnabled;
     KMessageWidget* m_messageWidget;
@@ -396,6 +387,11 @@ private:
     QTimer* m_statusBarTimer;            // Triggers a delayed update
     QElapsedTimer m_statusBarTimestamp;  // Time in ms since last update
     bool m_autoGrabFocus;
+    /**
+     * The visual state to be applied to the next UrlNavigator that gets
+     * connected to this ViewContainer.
+     */
+    std::unique_ptr<DolphinUrlNavigator::VisualState> m_urlNavigatorVisualState;
 
 #ifdef HAVE_KACTIVITIES
 private:
index ef2905d776ade988e669f67dd134e78cce10f146..a4b1b1963fc61683ccaf31bf214b25b926648443 100644 (file)
@@ -21,6 +21,7 @@
 #include <KCrash>
 #include <KDBusService>
 #include <KLocalizedString>
+#include <KToolBar>
 #include <Kdelibs4ConfigMigrator>
 #include <KConfigGui>
 
@@ -213,6 +214,12 @@ extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv)
             }
         }
     }
+    Qt::ToolBarArea area = mainWindow->toolBarArea(mainWindow->toolBar());
+    if (area != Qt::TopToolBarArea && area != Qt::BottomToolBarArea) {
+        // Migrate users with disabled tool bar positions.
+        // Remove this a few years from now (2020).
+        mainWindow->addToolBar(Qt::TopToolBarArea, mainWindow->toolBar());
+    }
 
 #ifdef HAVE_KUSERFEEDBACK
     auto feedbackProvider = DolphinFeedbackProvider::instance();
index 9a13493a126275297d0103f75fa376313f20bc6b..c397b2945124a49ab4867ff608337842c8d75e3d 100644 (file)
             <label>Split the view into two panes</label>
             <default>false</default>
         </entry>
-        <entry name="LocationInToolbar" type="Bool">
-            <label>Should the location be shown in the toolbar instead</label>
-            <default>false</default>
-        </entry>
         <entry name="FilterBar" type="Bool">
             <label>Should the filter bar be shown</label>
             <default>false</default>
diff --git a/src/views/dolphinurlnavigatorwidgetaction.cpp b/src/views/dolphinurlnavigatorwidgetaction.cpp
deleted file mode 100644 (file)
index 108a5de..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2020  Felix Ernst <fe.a.ernst@gmail.com>
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) version 3, or any
- * later version accepted by the membership of KDE e.V. (or its
- * successor approved by the membership of KDE e.V.), which shall
- * act as a proxy defined in Section 6 of version 3 of the license.
- * 
- * This library 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "dolphinurlnavigatorwidgetaction.h"
-
-#include "dolphin_generalsettings.h"
-#include "dolphinviewcontainer.h"
-
-#include <KLocalizedString>
-#include <KXMLGUIFactory>
-#include <KXmlGuiWindow>
-
-#include <QDomDocument>
-#include <QStackedWidget>
-
-DolphinUrlNavigatorWidgetAction::DolphinUrlNavigatorWidgetAction(QWidget *parent) :
-    QWidgetAction(parent)
-{
-    setText(i18nc("@action:inmenu", "Url navigator"));
-
-    m_stackedWidget = new QStackedWidget(parent);
-
-    auto expandingSpacer = new QWidget(m_stackedWidget);
-    expandingSpacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
-    m_stackedWidget->addWidget(expandingSpacer); // index 0 of QStackedWidget
-
-    auto urlNavigator = new DolphinUrlNavigator(m_stackedWidget);
-    m_stackedWidget->addWidget(urlNavigator); // index 1 of QStackedWidget
-
-    setDefaultWidget(m_stackedWidget);
-    setUrlNavigatorVisible(GeneralSettings::locationInToolbar());
-}
-
-DolphinUrlNavigator* DolphinUrlNavigatorWidgetAction::urlNavigator() const
-{
-    return static_cast<DolphinUrlNavigator *>(m_stackedWidget->widget(1));
-}
-
-void DolphinUrlNavigatorWidgetAction::setUrlNavigatorVisible(bool visible)
-{
-    if (!visible) {
-        m_stackedWidget->setCurrentIndex(0); // expandingSpacer
-    } else {
-        m_stackedWidget->setCurrentIndex(1); // urlNavigator
-    }
-}
-
-bool DolphinUrlNavigatorWidgetAction::addToToolbarAndSave(KXmlGuiWindow *mainWindow)
-{
-    const QString rawXml = KXMLGUIFactory::readConfigFile(mainWindow->xmlFile());
-    QDomDocument domDocument;
-    if (rawXml.isEmpty() || !domDocument.setContent(rawXml) || domDocument.isNull()) {
-        return false;
-    }
-    QDomNode toolbar = domDocument.elementsByTagName(QStringLiteral("ToolBar")).at(0);
-    if (toolbar.isNull()) {
-        return false;
-    }
-
-    QDomElement urlNavigatorElement = domDocument.createElement(QStringLiteral("Action"));
-    urlNavigatorElement.setAttribute(QStringLiteral("name"), QStringLiteral("url_navigator"));
-
-    QDomNode position = toolbar.lastChildElement(QStringLiteral("Spacer"));
-    if (position.isNull()) {
-        toolbar.appendChild(urlNavigatorElement);
-    } else {
-        toolbar.replaceChild(urlNavigatorElement, position);
-    }
-
-    KXMLGUIFactory::saveConfigFile(domDocument, mainWindow->xmlFile());
-    mainWindow->reloadXML();
-    mainWindow->createGUI();
-    return true;
-}
diff --git a/src/views/dolphinurlnavigatorwidgetaction.h b/src/views/dolphinurlnavigatorwidgetaction.h
deleted file mode 100644 (file)
index ed07115..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2020  Felix Ernst <fe.a.ernst@gmail.com>
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) version 3, or any
- * later version accepted by the membership of KDE e.V. (or its
- * successor approved by the membership of KDE e.V.), which shall
- * act as a proxy defined in Section 6 of version 3 of the license.
- * 
- * This library 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#ifndef DOLPHINURLNAVIGATORWIDGETACTION_H
-#define DOLPHINURLNAVIGATORWIDGETACTION_H
-
-#include "dolphinurlnavigator.h"
-
-#include <QWidgetAction>
-
-class KXmlGuiWindow;
-class QStackedWidget;
-
-/**
- * @brief QWidgetAction that allows to use a KUrlNavigator in a toolbar.
- * 
- * When the UrlNavigator of this object is not in use,
- * setUrlNavigatorVisible(false) is used to hide it. It will then be
- * replaced in the toolbar by an empty expanding spacer. This makes sure
- * that the other widgets in the toolbar will not change location when
- * switching the UrlNavigators visibility.
- */
-class DolphinUrlNavigatorWidgetAction : public QWidgetAction
-{
-    Q_OBJECT
-
-public:
-    DolphinUrlNavigatorWidgetAction(QWidget *parent = nullptr);
-
-    DolphinUrlNavigator *urlNavigator() const;
-
-    /**
-     * Sets the QStackedWidget which is the defaultWidget() to either
-     * show a KUrlNavigator or an expanding spacer.
-     */
-    void setUrlNavigatorVisible(bool visible);
-
-    /**
-     * Adds this action to the mainWindow's toolbar and saves the change
-     * in the users ui configuration file.
-     * @return true if successful. Otherwise false.
-     * @note This method does multiple things which are discouraged in
-     *       the API documentation.
-     */
-    bool addToToolbarAndSave(KXmlGuiWindow *mainWindow);
-
-private:
-    QStackedWidget *m_stackedWidget;
-};
-
-#endif // DOLPHINURLNAVIGATORWIDGETACTION_H