┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorElvis Angelaccio <[email protected]>2020-11-10 00:05:27 +0100
committerElvis Angelaccio <[email protected]>2020-11-10 00:05:27 +0100
commit6719072837f30c1822768da65e6ea222e987e32f (patch)
treeb61a3c588561946e9d462e23379d44fbdeed185b /src
parente5d137b81debbbfe51c18d16d361fd28a3448416 (diff)
parent63f4981fe01d88b2ef1b27e0577d7f5d4c8cc485 (diff)
Merge branch 'release/20.12'
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/dolphinmainwindow.cpp69
-rw-r--r--src/dolphinmainwindow.h3
-rw-r--r--src/dolphinnavigatorswidgetaction.cpp259
-rw-r--r--src/dolphinnavigatorswidgetaction.h159
-rw-r--r--src/dolphintabpage.cpp90
-rw-r--r--src/dolphintabpage.h37
-rw-r--r--src/dolphintabwidget.cpp50
-rw-r--r--src/dolphintabwidget.h24
-rw-r--r--src/dolphinui.rc4
-rw-r--r--src/dolphinurlnavigator.cpp109
-rw-r--r--src/dolphinurlnavigator.h77
-rw-r--r--src/dolphinurlnavigatorscontroller.cpp69
-rw-r--r--src/dolphinurlnavigatorscontroller.h76
-rw-r--r--src/dolphinviewcontainer.cpp187
-rw-r--r--src/dolphinviewcontainer.h77
-rw-r--r--src/main.cpp7
-rw-r--r--src/panels/places/placesitemlistwidget.cpp15
18 files changed, 1114 insertions, 201 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bff52cf0f..1955ce558 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -203,11 +203,14 @@ set(dolphinstatic_SRCS
dolphinmainwindow.cpp
dolphinviewcontainer.cpp
dolphincontextmenu.cpp
+ dolphinnavigatorswidgetaction.cpp
dolphintabbar.cpp
dolphinplacesmodelsingleton.cpp
dolphinrecenttabsmenu.cpp
dolphintabpage.cpp
dolphintabwidget.cpp
+ dolphinurlnavigator.cpp
+ dolphinurlnavigatorscontroller.cpp
trash/dolphintrash.cpp
filterbar/filterbar.cpp
panels/places/placespanel.cpp
diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp
index 97ced73b4..0c4c3c881 100644
--- a/src/dolphinmainwindow.cpp
+++ b/src/dolphinmainwindow.cpp
@@ -14,8 +14,10 @@
#include "dolphinbookmarkhandler.h"
#include "dolphindockwidget.h"
#include "dolphincontextmenu.h"
+#include "dolphinnavigatorswidgetaction.h"
#include "dolphinnewfilemenu.h"
#include "dolphinrecenttabsmenu.h"
+#include "dolphinurlnavigatorscontroller.h"
#include "dolphinviewcontainer.h"
#include "dolphintabpage.h"
#include "middleclickactioneventfilter.h"
@@ -140,7 +142,9 @@ DolphinMainWindow::DolphinMainWindow() :
setAcceptDrops(true);
- m_tabWidget = new DolphinTabWidget(this);
+ auto *navigatorsWidgetAction = new DolphinNavigatorsWidgetAction(this);
+ actionCollection()->addAction(QStringLiteral("url_navigators"), navigatorsWidgetAction);
+ m_tabWidget = new DolphinTabWidget(navigatorsWidgetAction, this);
m_tabWidget->setObjectName("tabWidget");
connect(m_tabWidget, &DolphinTabWidget::activeViewChanged,
this, &DolphinMainWindow::activeViewChanged);
@@ -165,6 +169,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);
@@ -356,7 +365,7 @@ void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection)
void DolphinMainWindow::updateHistory()
{
- const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
+ const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory();
const int index = urlNavigator->historyIndex();
QAction* backAction = actionCollection()->action(KStandardAction::name(KStandardAction::Back));
@@ -727,7 +736,7 @@ void DolphinMainWindow::slotToolBarActionMiddleClicked(QAction *action)
void DolphinMainWindow::slotAboutToShowBackPopupMenu()
{
- KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
+ const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory();
int entries = 0;
m_backAction->menu()->clear();
for (int i = urlNavigator->historyIndex() + 1; i < urlNavigator->historySize() && entries < MaxNumberOfNavigationentries; ++i, ++entries) {
@@ -740,7 +749,7 @@ void DolphinMainWindow::slotAboutToShowBackPopupMenu()
void DolphinMainWindow::slotGoBack(QAction* action)
{
int gotoIndex = action->data().value<int>();
- KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
+ const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory();
for (int i = gotoIndex - urlNavigator->historyIndex(); i > 0; --i) {
goBack();
}
@@ -749,14 +758,14 @@ void DolphinMainWindow::slotGoBack(QAction* action)
void DolphinMainWindow::slotBackForwardActionMiddleClicked(QAction* action)
{
if (action) {
- KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator();
+ const KUrlNavigator *urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory();
openNewTabAfterCurrentTab(urlNavigator->locationUrl(action->data().value<int>()));
}
}
void DolphinMainWindow::slotAboutToShowForwardPopupMenu()
{
- KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
+ const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory();
int entries = 0;
m_forwardAction->menu()->clear();
for (int i = urlNavigator->historyIndex() - 1; i >= 0 && entries < MaxNumberOfNavigationentries; --i, ++entries) {
@@ -769,7 +778,7 @@ void DolphinMainWindow::slotAboutToShowForwardPopupMenu()
void DolphinMainWindow::slotGoForward(QAction* action)
{
int gotoIndex = action->data().value<int>();
- KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
+ const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory();
for (int i = urlNavigator->historyIndex() - gotoIndex; i > 0; --i) {
goForward();
}
@@ -891,7 +900,7 @@ void DolphinMainWindow::slotTerminalPanelVisibilityChanged()
void DolphinMainWindow::goBack()
{
- KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
+ DolphinUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory();
urlNavigator->goBack();
if (urlNavigator->locationState().isEmpty()) {
@@ -903,29 +912,29 @@ void DolphinMainWindow::goBack()
void DolphinMainWindow::goForward()
{
- m_activeViewContainer->urlNavigator()->goForward();
+ m_activeViewContainer->urlNavigatorInternalWithHistory()->goForward();
}
void DolphinMainWindow::goUp()
{
- m_activeViewContainer->urlNavigator()->goUp();
+ m_activeViewContainer->urlNavigatorInternalWithHistory()->goUp();
}
void DolphinMainWindow::goHome()
{
- m_activeViewContainer->urlNavigator()->goHome();
+ m_activeViewContainer->urlNavigatorInternalWithHistory()->goHome();
}
void DolphinMainWindow::goBackInNewTab()
{
- KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator();
+ const KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory();
const int index = urlNavigator->historyIndex() + 1;
openNewTabAfterCurrentTab(urlNavigator->locationUrl(index));
}
void DolphinMainWindow::goForwardInNewTab()
{
- KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator();
+ const KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory();
const int index = urlNavigator->historyIndex() - 1;
openNewTabAfterCurrentTab(urlNavigator->locationUrl(index));
}
@@ -1057,6 +1066,8 @@ void DolphinMainWindow::editSettings()
const QUrl url = container->url();
DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(url, this);
connect(settingsDialog, &DolphinSettingsDialog::settingsChanged, this, &DolphinMainWindow::refreshViews);
+ connect(settingsDialog, &DolphinSettingsDialog::settingsChanged,
+ &DolphinUrlNavigatorsController::slotReadSettings);
settingsDialog->setAttribute(Qt::WA_DeleteOnClose);
settingsDialog->show();
m_settingsDialog = settingsDialog;
@@ -1253,7 +1264,12 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer)
// view and url navigator) and main window.
oldViewContainer->disconnect(this);
oldViewContainer->view()->disconnect(this);
- oldViewContainer->urlNavigator()->disconnect(this);
+ 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
connect(oldViewContainer->view(), &DolphinView::requestItemInfo,
@@ -1883,14 +1899,14 @@ void DolphinMainWindow::setupDockWidgets()
connect(this, &DolphinMainWindow::urlChanged,
m_placesPanel, &PlacesPanel::setUrl);
connect(placesDock, &DolphinDockWidget::visibilityChanged,
- m_tabWidget, &DolphinTabWidget::slotPlacesPanelVisibilityChanged);
+ &DolphinUrlNavigatorsController::slotPlacesPanelVisibilityChanged);
connect(this, &DolphinMainWindow::settingsChanged,
m_placesPanel, &PlacesPanel::readSettings);
connect(m_placesPanel, &PlacesPanel::storageTearDownRequested,
this, &DolphinMainWindow::slotStorageTearDownFromPlacesRequested);
connect(m_placesPanel, &PlacesPanel::storageTearDownExternallyRequested,
this, &DolphinMainWindow::slotStorageTearDownExternallyRequested);
- m_tabWidget->slotPlacesPanelVisibilityChanged(m_placesPanel->isVisible());
+ DolphinUrlNavigatorsController::slotPlacesPanelVisibilityChanged(m_placesPanel->isVisible());
auto actionShowAllPlaces = new QAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18nc("@item:inmenu", "Show Hidden Places"), this);
actionShowAllPlaces->setCheckable(true);
@@ -2023,10 +2039,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()
@@ -2162,15 +2174,26 @@ 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")));
+
+ const KUrlNavigator *navigator = m_tabWidget->currentTabPage()->primaryViewActive() ?
+ navigators->primaryUrlNavigator() :
+ navigators->secondaryUrlNavigator();
+
connect(navigator, &KUrlNavigator::urlChanged,
this, &DolphinMainWindow::changeUrl);
- connect(navigator, &KUrlNavigator::historyChanged,
- this, &DolphinMainWindow::updateHistory);
+ 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);
+
+ disconnect(m_updateHistoryConnection);
+ m_updateHistoryConnection = connect(
+ container->urlNavigatorInternalWithHistory(), &KUrlNavigator::historyChanged,
+ this, &DolphinMainWindow::updateHistory);
}
void DolphinMainWindow::updateSplitAction()
diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h
index a56215fa7..29ab6326d 100644
--- a/src/dolphinmainwindow.h
+++ b/src/dolphinmainwindow.h
@@ -649,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
index 000000000..984e1f35c
--- /dev/null
+++ b/src/dolphinnavigatorswidgetaction.cpp
@@ -0,0 +1,259 @@
+/*
+ This file is part of the KDE project
+ SPDX-FileCopyrightText: 2020 Felix Ernst <[email protected]>
+
+ 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>
+
+#include <limits>
+
+DolphinNavigatorsWidgetAction::DolphinNavigatorsWidgetAction(QWidget *parent) :
+ QWidgetAction{parent},
+ m_splitter{new QSplitter(Qt::Horizontal)},
+ m_adjustSpacingTimer{new QTimer(this)},
+ m_globalXOfSplitter{INT_MIN},
+ m_globalXOfPrimary{INT_MIN},
+ m_widthOfPrimary{INT_MIN},
+ m_globalXOfSecondary{INT_MIN},
+ m_widthOfSecondary{INT_MIN}
+{
+ updateText();
+ setIcon(QIcon::fromTheme(QStringLiteral("dialog-scripts")));
+
+ 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.firstChildElement(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);
+ updateText();
+}
+
+void DolphinNavigatorsWidgetAction::followViewContainerGeometry(
+ int globalXOfPrimary, int widthOfPrimary)
+{
+ followViewContainersGeometry(globalXOfPrimary, widthOfPrimary, INT_MIN, INT_MIN);
+}
+
+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 m_splitter->widget(0)->findChild<DolphinUrlNavigator *>();
+}
+
+DolphinUrlNavigator* DolphinNavigatorsWidgetAction::secondaryUrlNavigator() const
+{
+ Q_ASSERT(m_splitter);
+ if (m_splitter->count() < 2) {
+ return nullptr;
+ }
+ return m_splitter->widget(1)->findChild<DolphinUrlNavigator *>();
+}
+
+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);
+ }
+ updateText();
+}
+
+void DolphinNavigatorsWidgetAction::adjustSpacing()
+{
+ Q_ASSERT(m_globalXOfSplitter != INT_MIN);
+ Q_ASSERT(m_globalXOfPrimary != INT_MIN);
+ Q_ASSERT(m_widthOfPrimary != INT_MIN);
+ 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 == INT_MIN) {
+ Q_ASSERT(m_widthOfSecondary == INT_MIN);
+ 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, [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, this, [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();
+}
+
+void DolphinNavigatorsWidgetAction::updateText()
+{
+ const int urlNavigatorsAmount = m_splitter->count() > 1 && m_splitter->widget(1)->isVisible() ?
+ 2 : 1;
+ setText(i18ncp("@action:inmenu", "Url Navigator", "Url Navigators", urlNavigatorsAmount));
+}
diff --git a/src/dolphinnavigatorswidgetaction.h b/src/dolphinnavigatorswidgetaction.h
new file mode 100644
index 000000000..f343e6a1c
--- /dev/null
+++ b/src/dolphinnavigatorswidgetaction.h
@@ -0,0 +1,159 @@
+/*
+ This file is part of the KDE project
+ SPDX-FileCopyrightText: 2020 Felix Ernst <[email protected]>
+
+ 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
+
+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);
+
+ /**
+ * The secondary UrlNavigator is only created on-demand. Such an action is not necessary
+ * for the primary UrlNavigator which is created preemptively.
+ *
+ * This method should preferably only be called when:
+ * - Split view is activated in the active tab
+ * OR
+ * - A switch to a tab that is already in split view mode is occuring
+ */
+ 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);
+
+private:
+ /**
+ * 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();
+
+ /**
+ * In Left-to-right languages the Primary side will be the left one.
+ */
+ enum Side {
+ Primary,
+ Secondary
+ };
+ /**
+ * 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;
+
+ /**
+ * Sets this action's text depending on the amount of visible UrlNavigators.
+ */
+ void updateText();
+
+ /**
+ * 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
diff --git a/src/dolphintabpage.cpp b/src/dolphintabpage.cpp
index 837793b10..7f945dce2 100644
--- a/src/dolphintabpage.cpp
+++ b/src/dolphintabpage.cpp
@@ -24,6 +24,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 +36,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 +46,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();
}
@@ -68,17 +72,30 @@ void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
const QUrl& url = (secondaryUrl.isEmpty()) ? m_primaryViewContainer->url() : secondaryUrl;
m_secondaryViewContainer = createViewContainer(url);
- const bool placesSelectorVisible = m_primaryViewContainer->urlNavigator()->isPlacesSelectorVisible();
- m_secondaryViewContainer->urlNavigator()->setPlacesSelectorVisible(placesSelectorVisible);
+ 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->installEventFilter(this);
m_secondaryViewContainer->show();
m_secondaryViewContainer->setActive(true);
} 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);
@@ -87,6 +104,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);
@@ -134,6 +155,51 @@ int DolphinTabPage::selectedItemsCount() const
return selectedItemsCount;
}
+void DolphinTabPage::connectNavigators(DolphinNavigatorsWidgetAction *navigatorsWidget)
+{
+ m_navigatorsWidget = navigatorsWidget;
+ auto primaryNavigator = navigatorsWidget->primaryUrlNavigator();
+ m_primaryViewContainer->connectUrlNavigator(primaryNavigator);
+ if (m_splitViewEnabled) {
+ auto secondaryNavigator = navigatorsWidget->secondaryUrlNavigator();
+ 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;
+ }
+ return QWidget::eventFilter(watched, event);
+}
+
+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);
@@ -150,14 +216,6 @@ void DolphinTabPage::markUrlAsCurrent(const QUrl& url)
}
}
-void DolphinTabPage::setPlacesSelectorVisible(bool visible)
-{
- m_primaryViewContainer->urlNavigator()->setPlacesSelectorVisible(visible);
- if (m_splitViewEnabled) {
- m_secondaryViewContainer->urlNavigator()->setPlacesSelectorVisible(visible);
- }
-}
-
void DolphinTabPage::refreshViews()
{
m_primaryViewContainer->readSettings();
@@ -176,12 +234,12 @@ QByteArray DolphinTabPage::saveState() const
stream << m_splitViewEnabled;
stream << m_primaryViewContainer->url();
- stream << m_primaryViewContainer->urlNavigator()->isUrlEditable();
+ stream << m_primaryViewContainer->urlNavigatorInternalWithHistory()->isUrlEditable();
m_primaryViewContainer->view()->saveState(stream);
if (m_splitViewEnabled) {
stream << m_secondaryViewContainer->url();
- stream << m_secondaryViewContainer->urlNavigator()->isUrlEditable();
+ stream << m_secondaryViewContainer->urlNavigatorInternalWithHistory()->isUrlEditable();
m_secondaryViewContainer->view()->saveState(stream);
}
@@ -217,7 +275,7 @@ void DolphinTabPage::restoreState(const QByteArray& state)
m_primaryViewContainer->setUrl(primaryUrl);
bool primaryUrlEditable;
stream >> primaryUrlEditable;
- m_primaryViewContainer->urlNavigator()->setUrlEditable(primaryUrlEditable);
+ m_primaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(primaryUrlEditable);
m_primaryViewContainer->view()->restoreState(stream);
if (isSplitViewEnabled) {
@@ -226,7 +284,7 @@ void DolphinTabPage::restoreState(const QByteArray& state)
m_secondaryViewContainer->setUrl(secondaryUrl);
bool secondaryUrlEditable;
stream >> secondaryUrlEditable;
- m_secondaryViewContainer->urlNavigator()->setUrlEditable(secondaryUrlEditable);
+ m_secondaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(secondaryUrlEditable);
m_secondaryViewContainer->view()->restoreState(stream);
}
@@ -261,7 +319,7 @@ void DolphinTabPage::restoreStateV1(const QByteArray& state)
m_primaryViewContainer->setUrl(primaryUrl);
bool primaryUrlEditable;
stream >> primaryUrlEditable;
- m_primaryViewContainer->urlNavigator()->setUrlEditable(primaryUrlEditable);
+ m_primaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(primaryUrlEditable);
if (isSplitViewEnabled) {
QUrl secondaryUrl;
@@ -269,7 +327,7 @@ void DolphinTabPage::restoreStateV1(const QByteArray& state)
m_secondaryViewContainer->setUrl(secondaryUrl);
bool secondaryUrlEditable;
stream >> secondaryUrlEditable;
- m_secondaryViewContainer->urlNavigator()->setUrlEditable(secondaryUrlEditable);
+ m_secondaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(secondaryUrlEditable);
}
stream >> m_primaryViewActive;
diff --git a/src/dolphintabpage.h b/src/dolphintabpage.h
index 74344acd1..b874d128f 100644
--- a/src/dolphintabpage.h
+++ b/src/dolphintabpage.h
@@ -11,8 +11,9 @@
#include <QUrl>
#include <QWidget>
-class QSplitter;
+class DolphinNavigatorsWidgetAction;
class DolphinViewContainer;
+class QSplitter;
class KFileItemList;
class DolphinTabPage : public QWidget
@@ -67,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
* gets selected if no loading of a directory has been triggered
@@ -81,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 +142,7 @@ public:
signals:
void activeViewChanged(DolphinViewContainer* viewContainer);
void activeViewUrlChanged(const QUrl& url);
+ void splitterMoved(int pos, int index);
private slots:
/**
@@ -153,6 +171,7 @@ private:
private:
QSplitter* m_splitter;
+ QPointer<DolphinNavigatorsWidgetAction> m_navigatorsWidget;
QPointer<DolphinViewContainer> m_primaryViewContainer;
QPointer<DolphinViewContainer> m_secondaryViewContainer;
diff --git a/src/dolphintabwidget.cpp b/src/dolphintabwidget.cpp
index 5ef39dac6..da8f76d7c 100644
--- a/src/dolphintabwidget.cpp
+++ b/src/dolphintabwidget.cpp
@@ -8,7 +8,6 @@
#include "dolphin_generalsettings.h"
#include "dolphintabbar.h"
-#include "dolphintabpage.h"
#include "dolphinviewcontainer.h"
#include <KConfigGroup>
@@ -20,10 +19,10 @@
#include <QApplication>
#include <QDropEvent>
-DolphinTabWidget::DolphinTabWidget(QWidget* parent) :
+DolphinTabWidget::DolphinTabWidget(DolphinNavigatorsWidgetAction *navigatorsWidget, QWidget* parent) :
QTabWidget(parent),
- m_placesSelectorVisible(true),
- m_lastViewedTab(0)
+ m_lastViewedTab(nullptr),
+ m_navigatorsWidget{navigatorsWidget}
{
KAcceleratorManager::setNoAccel(this);
@@ -127,11 +126,16 @@ bool DolphinTabWidget::isUrlOpen(const QUrl &url) const
void DolphinTabWidget::openNewActivatedTab()
{
+ std::unique_ptr<DolphinUrlNavigator::VisualState> oldNavigatorState;
+ if (currentTabPage()->primaryViewActive() || !m_navigatorsWidget->secondaryUrlNavigator()) {
+ oldNavigatorState = m_navigatorsWidget->primaryUrlNavigator()->visualState();
+ } else {
+ 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();
@@ -139,7 +143,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();
@@ -157,7 +161,6 @@ void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryU
DolphinTabPage* tabPage = new DolphinTabPage(primaryUrl, secondaryUrl, this);
tabPage->setActive(false);
- tabPage->setPlacesSelectorVisible(m_placesSelectorVisible);
connect(tabPage, &DolphinTabPage::activeViewChanged,
this, &DolphinTabWidget::activeViewChanged);
connect(tabPage, &DolphinTabPage::activeViewUrlChanged,
@@ -288,19 +291,6 @@ void DolphinTabWidget::activatePrevTab()
setCurrentIndex(index >= 0 ? index : (count() - 1));
}
-void DolphinTabWidget::slotPlacesPanelVisibilityChanged(bool visible)
-{
- // The places-selector from the URL navigator should only be shown
- // if the places dock is invisible
- m_placesSelectorVisible = !visible;
-
- const int tabCount = count();
- for (int i = 0; i < tabCount; ++i) {
- DolphinTabPage* tabPage = tabPageAt(i);
- tabPage->setPlacesSelectorVisible(m_placesSelectorVisible);
- }
-}
-
void DolphinTabWidget::restoreClosedTab(const QByteArray& state)
{
openNewActivatedTab();
@@ -399,16 +389,24 @@ 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);
+ }
+ if (tabPage->splitViewEnabled() && !m_navigatorsWidget->secondaryUrlNavigator()) {
+ m_navigatorsWidget->createSecondaryUrlNavigator();
}
- 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 = tabPage;
}
void DolphinTabWidget::tabInserted(int index)
diff --git a/src/dolphintabwidget.h b/src/dolphintabwidget.h
index 1eca71c5d..4a1b9d99c 100644
--- a/src/dolphintabwidget.h
+++ b/src/dolphintabwidget.h
@@ -7,11 +7,13 @@
#ifndef DOLPHIN_TAB_WIDGET_H
#define DOLPHIN_TAB_WIDGET_H
+#include "dolphinnavigatorswidgetaction.h"
+#include "dolphintabpage.h"
+
#include <QTabWidget>
#include <QUrl>
class DolphinViewContainer;
-class DolphinTabPage;
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)
@@ -164,13 +171,6 @@ public slots:
void activatePrevTab();
/**
- * Is invoked if the Places panel got visible/invisible and takes care
- * that the places-selector of all views is only shown if the Places panel
- * is invisible.
- */
- void slotPlacesPanelVisibilityChanged(bool visible);
-
- /**
* Is called when the user wants to reopen a previously closed tab from
* the recent tabs menu.
*/
@@ -231,10 +231,8 @@ private:
QPair<int, bool> indexByUrl(const QUrl& url) const;
private:
- /** Caches the (negated) places panel visibility */
- bool m_placesSelectorVisible;
-
- int m_lastViewedTab;
+ QPointer<DolphinTabPage> m_lastViewedTab;
+ QPointer<DolphinNavigatorsWidgetAction> m_navigatorsWidget;
};
#endif
diff --git a/src/dolphinui.rc b/src/dolphinui.rc
index 46a4bac51..01a3778f9 100644
--- a/src/dolphinui.rc
+++ b/src/dolphinui.rc
@@ -119,9 +119,7 @@
<Action name="icons" />
<Action name="compact" />
<Action name="details" />
- <Separator name="separator_0" />
- <Action name="sort" />
- <Spacer name="spacer_0" />
+ <Action name="url_navigators" />
<Action name="split_view" />
<Action name="split_stash" />
<Action name="toggle_search" />
diff --git a/src/dolphinurlnavigator.cpp b/src/dolphinurlnavigator.cpp
new file mode 100644
index 000000000..1dfe5420f
--- /dev/null
+++ b/src/dolphinurlnavigator.cpp
@@ -0,0 +1,109 @@
+/*
+ This file is part of the KDE project
+ SPDX-FileCopyrightText: 2020 Felix Ernst <[email protected]>
+
+ SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+*/
+
+#include "dolphinurlnavigator.h"
+
+#include "dolphin_generalsettings.h"
+#include "dolphinplacesmodelsingleton.h"
+#include "dolphinurlnavigatorscontroller.h"
+#include "global.h"
+
+#include <KUrlComboBox>
+#include <KLocalizedString>
+
+#include <QAbstractButton>
+#include <QLayout>
+#include <QLineEdit>
+
+DolphinUrlNavigator::DolphinUrlNavigator(QWidget *parent) :
+ DolphinUrlNavigator(QUrl(), parent)
+{}
+
+DolphinUrlNavigator::DolphinUrlNavigator(const QUrl &url, QWidget *parent) :
+ KUrlNavigator(DolphinPlacesModelSingleton::instance().placesModel(), url, parent)
+{
+ const GeneralSettings* settings = GeneralSettings::self();
+ setUrlEditable(settings->editableUrl());
+ setShowFullPath(settings->showFullPath());
+ setHomeUrl(Dolphin::homeUrl());
+ setPlacesSelectorVisible(DolphinUrlNavigatorsController::placesSelectorVisible());
+ editor()->setCompletionMode(KCompletion::CompletionMode(settings->urlCompletionMode()));
+ setWhatsThis(xi18nc("@info:whatsthis location bar",
+ "<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 "
+ "the <emphasis>path</emphasis> to the current location because "
+ "following these folders from left to right leads here.</para>"
+ "<para>This interactive path "
+ "is more powerful than one would expect. To learn more "
+ "about the basic and advanced features of the location bar "
+ "<link url='help:/dolphin/location-bar.html'>click here</link>. "
+ "This will open the dedicated page in the Handbook.</para>"));
+
+ DolphinUrlNavigatorsController::registerDolphinUrlNavigator(this);
+
+ connect(this, &KUrlNavigator::returnPressed,
+ this, &DolphinUrlNavigator::slotReturnPressed);
+}
+
+DolphinUrlNavigator::~DolphinUrlNavigator()
+{
+ DolphinUrlNavigatorsController::unregisterDolphinUrlNavigator(this);
+}
+
+QSize DolphinUrlNavigator::sizeHint() const
+{
+ 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);
+ }
+ }
+}
+
+void DolphinUrlNavigator::slotReturnPressed()
+{
+ if (!GeneralSettings::editableUrl()) {
+ setUrlEditable(false);
+ }
+}
diff --git a/src/dolphinurlnavigator.h b/src/dolphinurlnavigator.h
new file mode 100644
index 000000000..9bcc32b4d
--- /dev/null
+++ b/src/dolphinurlnavigator.h
@@ -0,0 +1,77 @@
+/*
+ This file is part of the KDE project
+ SPDX-FileCopyrightText: 2020 Felix Ernst <[email protected]>
+
+ SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+*/
+
+#ifndef DOLPHINURLNAVIGATOR_H
+#define DOLPHINURLNAVIGATOR_H
+
+#include <KUrlNavigator>
+
+/**
+ * @brief Extends KUrlNavigator in a Dolphin-specific way.
+ *
+ * Makes sure that Dolphin preferences and settings are
+ * applied to all constructed DolphinUrlNavigators.
+ * @see KUrlNavigator
+ *
+ * To apply changes to all instances of this class @see DolphinUrlNavigatorsController.
+ */
+class DolphinUrlNavigator : public KUrlNavigator
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Applies all Dolphin-specific settings to a KUrlNavigator
+ * @see KUrlNavigator::KurlNavigator()
+ */
+ DolphinUrlNavigator(QWidget *parent = nullptr);
+
+ /**
+ * Applies all Dolphin-specific settings to a KUrlNavigator
+ * @see KUrlNavigator::KurlNavigator()
+ */
+ DolphinUrlNavigator(const QUrl &url, QWidget *parent = nullptr);
+
+ virtual ~DolphinUrlNavigator();
+
+ // TODO: Fix KUrlNavigator::sizeHint() 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.
+ *
+ * @return a copy of the visualState of this object. Ownership of this copy is transferred
+ * to the caller via std::unique_ptr.
+ */
+ 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:
+ /**
+ * Switches to "breadcrumb" mode if the editable mode is not set to be
+ * preferred in the Dolphin settings.
+ */
+ void slotReturnPressed();
+};
+
+#endif // DOLPHINURLNAVIGATOR_H
diff --git a/src/dolphinurlnavigatorscontroller.cpp b/src/dolphinurlnavigatorscontroller.cpp
new file mode 100644
index 000000000..59e1d6356
--- /dev/null
+++ b/src/dolphinurlnavigatorscontroller.cpp
@@ -0,0 +1,69 @@
+/*
+ This file is part of the KDE project
+ SPDX-FileCopyrightText: 2020 Felix Ernst <[email protected]>
+
+ SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+*/
+
+#include "dolphinurlnavigatorscontroller.h"
+
+#include "dolphin_generalsettings.h"
+#include "dolphinurlnavigator.h"
+#include "global.h"
+
+#include <KUrlComboBox>
+
+void DolphinUrlNavigatorsController::slotReadSettings()
+{
+ // The startup settings should (only) get applied if they have been
+ // modified by the user. Otherwise keep the (possibly) different current
+ // settings of the URL navigators and split view.
+ if (GeneralSettings::modifiedStartupSettings()) {
+ for (DolphinUrlNavigator *urlNavigator : s_instances) {
+ urlNavigator->setUrlEditable(GeneralSettings::editableUrl());
+ urlNavigator->setShowFullPath(GeneralSettings::showFullPath());
+ urlNavigator->setHomeUrl(Dolphin::homeUrl());
+ }
+ }
+}
+
+void DolphinUrlNavigatorsController::slotPlacesPanelVisibilityChanged(bool visible)
+{
+ // The places-selector from the URL navigator should only be shown
+ // if the places dock is invisible
+ s_placesSelectorVisible = !visible;
+
+ for (DolphinUrlNavigator *urlNavigator : s_instances) {
+ urlNavigator->setPlacesSelectorVisible(s_placesSelectorVisible);
+ }
+}
+
+bool DolphinUrlNavigatorsController::placesSelectorVisible()
+{
+ return s_placesSelectorVisible;
+}
+
+void DolphinUrlNavigatorsController::registerDolphinUrlNavigator(DolphinUrlNavigator *dolphinUrlNavigator)
+{
+ s_instances.push_front(dolphinUrlNavigator);
+ connect(dolphinUrlNavigator->editor(), &KUrlComboBox::completionModeChanged,
+ DolphinUrlNavigatorsController::setCompletionMode);
+}
+
+void DolphinUrlNavigatorsController::unregisterDolphinUrlNavigator(DolphinUrlNavigator *dolphinUrlNavigator)
+{
+ s_instances.remove(dolphinUrlNavigator);
+}
+
+void DolphinUrlNavigatorsController::setCompletionMode(const KCompletion::CompletionMode completionMode)
+{
+ if (completionMode != GeneralSettings::urlCompletionMode()) {
+ GeneralSettings::setUrlCompletionMode(completionMode);
+ for (const DolphinUrlNavigator *urlNavigator : s_instances) {
+ urlNavigator->editor()->setCompletionMode(completionMode);
+ }
+ }
+}
+
+std::forward_list<DolphinUrlNavigator *> DolphinUrlNavigatorsController::s_instances;
+bool DolphinUrlNavigatorsController::s_placesSelectorVisible = true;
diff --git a/src/dolphinurlnavigatorscontroller.h b/src/dolphinurlnavigatorscontroller.h
new file mode 100644
index 000000000..797cbf4f9
--- /dev/null
+++ b/src/dolphinurlnavigatorscontroller.h
@@ -0,0 +1,76 @@
+/*
+ This file is part of the KDE project
+ SPDX-FileCopyrightText: 2020 Felix Ernst <[email protected]>
+
+ SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+*/
+
+#ifndef DOLPHINURLNAVIGATORSCONTROLLER_H
+#define DOLPHINURLNAVIGATORSCONTROLLER_H
+
+#include <KCompletion>
+
+#include <QObject>
+
+#include <forward_list>
+
+class DolphinUrlNavigator;
+
+/**
+ * @brief A controller managing all DolphinUrlNavigators.
+ *
+ * This class is used to apply settings changes to all constructed DolphinUrlNavigators.
+ *
+ * @see DolphinUrlNavigator
+ */
+class DolphinUrlNavigatorsController : public QObject
+{
+ Q_OBJECT
+
+public:
+ DolphinUrlNavigatorsController() = delete;
+
+public slots:
+ /**
+ * Refreshes all DolphinUrlNavigators to get synchronized with the
+ * Dolphin settings if they were changed.
+ */
+ static void slotReadSettings();
+
+ static void slotPlacesPanelVisibilityChanged(bool visible);
+
+private:
+ /**
+ * @return wether the places selector of DolphinUrlNavigators should be visible.
+ */
+ static bool placesSelectorVisible();
+
+ /**
+ * Adds \p dolphinUrlNavigator to the list of DolphinUrlNavigators
+ * controlled by this class.
+ */
+ static void registerDolphinUrlNavigator(DolphinUrlNavigator *dolphinUrlNavigator);
+
+ /**
+ * Removes \p dolphinUrlNavigator from the list of DolphinUrlNavigators
+ * controlled by this class.
+ */
+ static void unregisterDolphinUrlNavigator(DolphinUrlNavigator *dolphinUrlNavigator);
+
+private slots:
+ /**
+ * Sets the completion mode for all DolphinUrlNavigators and saves it in settings.
+ */
+ static void setCompletionMode(const KCompletion::CompletionMode completionMode);
+
+private:
+ /** Contains all currently constructed DolphinUrlNavigators */
+ static std::forward_list<DolphinUrlNavigator *> s_instances;
+
+ /** Caches the (negated) places panel visibility */
+ static bool s_placesSelectorVisible;
+
+ friend class DolphinUrlNavigator;
+};
+
+#endif // DOLPHINURLNAVIGATORSCONTROLLER_H
diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp
index b1b67447f..0fe8ee9d3 100644
--- a/src/dolphinviewcontainer.cpp
+++ b/src/dolphinviewcontainer.cpp
@@ -7,13 +7,12 @@
#include "dolphinviewcontainer.h"
#include "dolphin_generalsettings.h"
-#include "dolphinplacesmodelsingleton.h"
#include "dolphindebug.h"
+#include "dolphinplacesmodelsingleton.h"
#include "filterbar/filterbar.h"
#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"
@@ -31,6 +30,7 @@
#include <KProtocolManager>
#include <KShell>
#include <KUrlComboBox>
+#include <KUrlNavigator>
#include <QDropEvent>
#include <QLoggingCategory>
@@ -43,9 +43,8 @@
DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
QWidget(parent),
m_topLayout(nullptr),
- m_navigatorWidget(nullptr),
- m_urlNavigator(nullptr),
- m_emptyTrashButton(nullptr),
+ m_urlNavigator{new DolphinUrlNavigator(url)},
+ m_urlNavigatorConnected{nullptr},
m_searchBox(nullptr),
m_searchModeEnabled(false),
m_messageWidget(nullptr),
@@ -65,43 +64,6 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
m_topLayout->setSpacing(0);
m_topLayout->setContentsMargins(0, 0, 0, 0);
- m_navigatorWidget = new QWidget(this);
- QHBoxLayout* navigatorLayout = new QHBoxLayout(m_navigatorWidget);
- navigatorLayout->setSpacing(0);
- navigatorLayout->setContentsMargins(0, 0, 0, 0);
- m_navigatorWidget->setWhatsThis(xi18nc("@info:whatsthis location bar",
- "<para>This line 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 "
- "the <emphasis>path</emphasis> to the current location because "
- "following these folders from left to right leads here.</para>"
- "<para>The path is displayed on the <emphasis>location bar</emphasis> "
- "which is more powerful than one would expect. To learn more "
- "about the basic and advanced features of the location bar "
- "<link url='help:/dolphin/location-bar.html'>click here</link>. "
- "This will open the dedicated page in the Handbook.</para>"));
-
- m_urlNavigator = new KUrlNavigator(DolphinPlacesModelSingleton::instance().placesModel(), url, this);
- connect(m_urlNavigator, &KUrlNavigator::activated,
- this, &DolphinViewContainer::activate);
- connect(m_urlNavigator->editor(), &KUrlComboBox::completionModeChanged,
- this, &DolphinViewContainer::saveUrlCompletionMode);
-
- const GeneralSettings* settings = GeneralSettings::self();
- m_urlNavigator->setUrlEditable(settings->editableUrl());
- m_urlNavigator->setShowFullPath(settings->showFullPath());
- m_urlNavigator->setHomeUrl(Dolphin::homeUrl());
- KUrlComboBox* editor = m_urlNavigator->editor();
- editor->setCompletionMode(KCompletion::CompletionMode(settings->urlCompletionMode()));
-
- 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);
@@ -135,7 +97,7 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
// Initialize filter bar
m_filterBar = new FilterBar(this);
- m_filterBar->setVisible(settings->filterBar());
+ m_filterBar->setVisible(GeneralSettings::filterBar());
connect(m_filterBar, &FilterBar::filterChanged,
this, &DolphinViewContainer::setNameFilter);
@@ -149,9 +111,13 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
connect(m_view, &DolphinView::urlChanged,
m_filterBar, &FilterBar::slotUrlChanged);
connect(m_view, &DolphinView::urlChanged,
- m_urlNavigator, &KUrlNavigator::setLocationUrl);
- connect(m_view, &DolphinView::urlChanged,
m_messageWidget, &KMessageWidget::hide);
+ // 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.get(), &DolphinUrlNavigator::setLocationUrl);
+ connect(m_urlNavigator.get(), &DolphinUrlNavigator::urlChanged,
+ this, &DolphinViewContainer::slotUrlNavigatorLocationChanged);
connect(m_view, &DolphinView::writeStateChanged,
this, &DolphinViewContainer::writeStateChanged);
connect(m_view, &DolphinView::requestItemInfo,
@@ -183,22 +149,6 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) :
connect(m_view, &DolphinView::activated,
this, &DolphinViewContainer::activate);
- connect(m_urlNavigator, &KUrlNavigator::urlAboutToBeChanged,
- this, &DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged);
- connect(m_urlNavigator, &KUrlNavigator::urlChanged,
- this, &DolphinViewContainer::slotUrlNavigatorLocationChanged);
- connect(m_urlNavigator, &KUrlNavigator::urlSelectionRequested,
- this, &DolphinViewContainer::slotUrlSelectionRequested);
- connect(m_urlNavigator, &KUrlNavigator::returnPressed,
- this, &DolphinViewContainer::slotReturnPressed);
- connect(m_urlNavigator, &KUrlNavigator::urlsDropped, this, [=](const QUrl &destination, QDropEvent *event) {
- m_view->dropUrls(destination, event, m_urlNavigator->dropWidget());
- });
-
- 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());
@@ -225,10 +175,6 @@ 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);
@@ -263,7 +209,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
@@ -277,7 +225,6 @@ void DolphinViewContainer::setActive(bool active)
bool DolphinViewContainer::isActive() const
{
- Q_ASSERT(m_view->isActive() == m_urlNavigator->isActive());
return m_view->isActive();
}
@@ -306,14 +253,24 @@ DolphinStatusBar* DolphinViewContainer::statusBar()
return m_statusBar;
}
-const KUrlNavigator* DolphinViewContainer::urlNavigator() const
+const DolphinUrlNavigator* DolphinViewContainer::urlNavigator() const
{
- return m_urlNavigator;
+ return m_urlNavigatorConnected;
}
-KUrlNavigator* DolphinViewContainer::urlNavigator()
+DolphinUrlNavigator* DolphinViewContainer::urlNavigator()
{
- return m_urlNavigator;
+ return m_urlNavigatorConnected;
+}
+
+const DolphinUrlNavigator *DolphinViewContainer::urlNavigatorInternalWithHistory() const
+{
+ return m_urlNavigator.get();
+}
+
+DolphinUrlNavigator *DolphinViewContainer::urlNavigatorInternalWithHistory()
+{
+ return m_urlNavigator.get();
}
const DolphinView* DolphinViewContainer::view() const
@@ -326,6 +283,61 @@ DolphinView* DolphinViewContainer::view()
return m_view;
}
+void DolphinViewContainer::connectUrlNavigator(DolphinUrlNavigator *urlNavigator)
+{
+ Q_CHECK_PTR(urlNavigator);
+ Q_ASSERT(!m_urlNavigatorConnected);
+ Q_ASSERT(m_urlNavigator.get() != urlNavigator);
+ Q_CHECK_PTR(m_view);
+
+ urlNavigator->setLocationUrl(m_view->url());
+ if (m_urlNavigatorVisualState) {
+ urlNavigator->setVisualState(*m_urlNavigatorVisualState.get());
+ m_urlNavigatorVisualState.reset();
+ }
+ urlNavigator->setActive(isActive());
+
+ connect(m_view, &DolphinView::urlChanged,
+ urlNavigator, &DolphinUrlNavigator::setLocationUrl);
+ connect(urlNavigator, &DolphinUrlNavigator::urlChanged,
+ this, &DolphinViewContainer::slotUrlNavigatorLocationChanged);
+ connect(urlNavigator, &DolphinUrlNavigator::activated,
+ this, &DolphinViewContainer::activate);
+ connect(urlNavigator, &DolphinUrlNavigator::urlAboutToBeChanged,
+ this, &DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged);
+ connect(urlNavigator, &DolphinUrlNavigator::urlSelectionRequested,
+ this, &DolphinViewContainer::slotUrlSelectionRequested);
+ connect(urlNavigator, &DolphinUrlNavigator::urlsDropped,
+ this, [=](const QUrl &destination, QDropEvent *event) {
+ m_view->dropUrls(destination, event, urlNavigator->dropWidget());
+ });
+
+ m_urlNavigatorConnected = urlNavigator;
+}
+
+void DolphinViewContainer::disconnectUrlNavigator()
+{
+ if (!m_urlNavigatorConnected) {
+ return;
+ }
+
+ 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);
+ disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlAboutToBeChanged,
+ this, &DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged);
+ disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlSelectionRequested,
+ this, &DolphinViewContainer::slotUrlSelectionRequested);
+ disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlsDropped,
+ this, nullptr);
+
+ m_urlNavigatorVisualState = m_urlNavigatorConnected->visualState();
+ m_urlNavigatorConnected = nullptr;
+}
+
void DolphinViewContainer::showMessage(const QString& msg, MessageType type)
{
if (msg.isEmpty()) {
@@ -359,13 +371,10 @@ void DolphinViewContainer::showMessage(const QString& msg, MessageType type)
void DolphinViewContainer::readSettings()
{
+ // The startup settings should (only) get applied if they have been
+ // modified by the user. Otherwise keep the (possibly) different current
+ // setting of the filterbar.
if (GeneralSettings::modifiedStartupSettings()) {
- // The startup settings should only get applied if they have been
- // modified by the user. Otherwise keep the (possibly) different current
- // settings of the URL navigator and the filterbar.
- m_urlNavigator->setUrlEditable(GeneralSettings::editableUrl());
- m_urlNavigator->setShowFullPath(GeneralSettings::showFullPath());
- m_urlNavigator->setHomeUrl(Dolphin::homeUrl());
setFilterBarVisible(GeneralSettings::filterBar());
}
@@ -381,10 +390,9 @@ bool DolphinViewContainer::isFilterBarVisible() const
void DolphinViewContainer::setSearchModeEnabled(bool enabled)
{
m_searchBox->setVisible(enabled);
- m_navigatorWidget->setVisible(!enabled);
if (enabled) {
- const QUrl& locationUrl = m_urlNavigator->locationUrl();
+ const QUrl& locationUrl = m_urlNavigatorConnected->locationUrl();
m_searchBox->fromSearchUrl(locationUrl);
}
@@ -405,7 +413,7 @@ void DolphinViewContainer::setSearchModeEnabled(bool enabled)
if (url.isEmpty() || !url.isValid() || isSearchUrl(url)) {
url = Dolphin::homeUrl();
}
- m_urlNavigator->setLocationUrl(url);
+ m_urlNavigatorConnected->setLocationUrl(url);
}
m_searchModeEnabled = enabled;
@@ -680,7 +688,9 @@ void DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged(const QUrl&)
void DolphinViewContainer::slotUrlNavigatorLocationChanged(const QUrl& url)
{
- slotReturnPressed();
+ if (m_urlNavigatorConnected) {
+ m_urlNavigatorConnected->slotReturnPressed();
+ }
if (KProtocolManager::supportsListing(url)) {
setSearchModeEnabled(isSearchUrl(url));
@@ -739,24 +749,13 @@ void DolphinViewContainer::requestFocus()
m_view->setFocus();
}
-void DolphinViewContainer::saveUrlCompletionMode(KCompletion::CompletionMode completion)
-{
- GeneralSettings::setUrlCompletionMode(completion);
-}
-
-void DolphinViewContainer::slotReturnPressed()
-{
- if (!GeneralSettings::editableUrl()) {
- m_urlNavigator->setUrlEditable(false);
- }
-}
-
void DolphinViewContainer::startSearching()
{
+ Q_CHECK_PTR(m_urlNavigatorConnected);
const QUrl url = m_searchBox->urlForSearching();
if (url.isValid() && !url.isEmpty()) {
m_view->setViewPropertiesContext(QStringLiteral("search"));
- m_urlNavigator->setLocationUrl(url);
+ m_urlNavigatorConnected->setLocationUrl(url);
}
}
diff --git a/src/dolphinviewcontainer.h b/src/dolphinviewcontainer.h
index ee1193f19..77b74d189 100644
--- a/src/dolphinviewcontainer.h
+++ b/src/dolphinviewcontainer.h
@@ -8,9 +8,9 @@
#define DOLPHINVIEWCONTAINER_H
#include "config-kactivities.h"
+#include "dolphinurlnavigator.h"
#include "views/dolphinview.h"
-#include <KCompletion>
#include <KFileItem>
#include <KIO/Job>
#include <KUrlNavigator>
@@ -85,13 +85,54 @@ public:
const DolphinStatusBar* statusBar() const;
DolphinStatusBar* statusBar();
- const KUrlNavigator* urlNavigator() const;
- KUrlNavigator* urlNavigator();
+ /**
+ * @return An UrlNavigator that is controlling this view
+ * or nullptr if there is none.
+ * @see connectUrlNavigator()
+ * @see disconnectUrlNavigator()
+ *
+ * Use urlNavigatorInternalWithHistory() if you want to access the history.
+ * @see urlNavigatorInternalWithHistory()
+ */
+ const DolphinUrlNavigator *urlNavigator() const;
+ /**
+ * @return An UrlNavigator that is controlling this view
+ * or nullptr if there is none.
+ * @see connectUrlNavigator()
+ * @see disconnectUrlNavigator()
+ *
+ * Use urlNavigatorInternalWithHistory() if you want to access the history.
+ * @see urlNavigatorInternalWithHistory()
+ */
+ DolphinUrlNavigator *urlNavigator();
+
+ /**
+ * @return An UrlNavigator that contains this view's history.
+ * Use urlNavigator() instead when not accessing the history.
+ */
+ const DolphinUrlNavigator *urlNavigatorInternalWithHistory() const;
+ /**
+ * @return An UrlNavigator that contains this view's history.
+ * Use urlNavigator() instead when not accessing the history.
+ */
+ DolphinUrlNavigator *urlNavigatorInternalWithHistory();
const DolphinView* view() const;
DolphinView* view();
/**
+ * @param urlNavigator The UrlNavigator that is supposed to control
+ * this view.
+ */
+ void connectUrlNavigator(DolphinUrlNavigator *urlNavigator);
+
+ /**
+ * Disconnects the navigator that is currently controling the view.
+ * This method completely reverses connectUrlNavigator().
+ */
+ void disconnectUrlNavigator();
+
+ /**
* Shows the message \msg with the given type non-modal above
* the view-content.
*/
@@ -282,14 +323,6 @@ private slots:
void requestFocus();
/**
- * Saves the currently used URL completion mode of
- * the URL navigator.
- */
- void saveUrlCompletionMode(KCompletion::CompletionMode completion);
-
- void slotReturnPressed();
-
- /**
* Gets the search URL from the searchbox and starts searching.
*/
void startSearching();
@@ -328,9 +361,20 @@ private:
private:
QVBoxLayout* m_topLayout;
- QWidget* m_navigatorWidget;
- KUrlNavigator* m_urlNavigator;
- QPushButton* m_emptyTrashButton;
+
+ /**
+ * 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.
+ */
+ std::unique_ptr<DolphinUrlNavigator> m_urlNavigator;
+
+ /**
+ * 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;
DolphinSearchBox* m_searchBox;
bool m_searchModeEnabled;
KMessageWidget* m_messageWidget;
@@ -343,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:
diff --git a/src/main.cpp b/src/main.cpp
index ef2905d77..a4b1b1963 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -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();
diff --git a/src/panels/places/placesitemlistwidget.cpp b/src/panels/places/placesitemlistwidget.cpp
index 745a6ae1b..38bc13438 100644
--- a/src/panels/places/placesitemlistwidget.cpp
+++ b/src/panels/places/placesitemlistwidget.cpp
@@ -12,6 +12,8 @@
#include <KColorScheme>
#include <KIO/FileSystemFreeSpaceJob>
+#include <Solid/Device>
+#include <Solid/NetworkShare>
#define CAPACITYBAR_HEIGHT 2
#define CAPACITYBAR_MARGIN 2
@@ -41,12 +43,19 @@ QPalette::ColorRole PlacesItemListWidget::normalTextColorRole() const
void PlacesItemListWidget::updateCapacityBar()
{
- const bool isDevice = !data().value("udi").toString().isEmpty();
- const QUrl url = data().value("url").toUrl();
- if (!(isDevice && url.isLocalFile())) {
+ const QString udi = data().value("udi").toString();
+ if (udi.isEmpty()) {
resetCapacityBar();
return;
}
+ const Solid::Device device = Solid::Device(udi);
+ if (device.isDeviceInterface(Solid::DeviceInterface::NetworkShare)
+ || device.isDeviceInterface(Solid::DeviceInterface::OpticalDrive)
+ || device.isDeviceInterface(Solid::DeviceInterface::OpticalDisc)) {
+ resetCapacityBar();
+ return;
+ }
+ const QUrl url = data().value("url").toUrl();
if (m_freeSpaceInfo.job || !m_freeSpaceInfo.lastUpdated.hasExpired()) {
// Job running or cache is still valid.