diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/dolphinmainwindow.cpp | 121 | ||||
| -rw-r--r-- | src/dolphinmainwindow.h | 16 | ||||
| -rw-r--r-- | src/dolphinnavigatorswidgetaction.cpp | 243 | ||||
| -rw-r--r-- | src/dolphinnavigatorswidgetaction.h | 149 | ||||
| -rw-r--r-- | src/dolphintabpage.cpp | 113 | ||||
| -rw-r--r-- | src/dolphintabpage.h | 39 | ||||
| -rw-r--r-- | src/dolphintabwidget.cpp | 34 | ||||
| -rw-r--r-- | src/dolphintabwidget.h | 14 | ||||
| -rw-r--r-- | src/dolphinui.rc | 5 | ||||
| -rw-r--r-- | src/dolphinurlnavigator.cpp | 100 | ||||
| -rw-r--r-- | src/dolphinurlnavigator.h | 78 | ||||
| -rw-r--r-- | src/dolphinviewcontainer.cpp | 112 | ||||
| -rw-r--r-- | src/dolphinviewcontainer.h | 34 | ||||
| -rw-r--r-- | src/main.cpp | 7 | ||||
| -rw-r--r-- | src/settings/dolphin_generalsettings.kcfg | 4 | ||||
| -rw-r--r-- | src/views/dolphinurlnavigatorwidgetaction.cpp | 91 | ||||
| -rw-r--r-- | src/views/dolphinurlnavigatorwidgetaction.h | 68 |
18 files changed, 746 insertions, 484 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4610be463..8fad34347 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 381d95013..6a93de078 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -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); } diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h index 251f50d8d..173e017c9 100644 --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -69,17 +69,10 @@ 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. * \pre \a dirs must contain at least one url. @@ -313,12 +306,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. */ void toggleEditLocation(); @@ -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 index 000000000..bd2985d47 --- /dev/null +++ b/src/dolphinnavigatorswidgetaction.cpp @@ -0,0 +1,243 @@ +/* + 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> + +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 index 000000000..c1808d68e --- /dev/null +++ b/src/dolphinnavigatorswidgetaction.h @@ -0,0 +1,149 @@ +/* + 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 + + /** + * 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 diff --git a/src/dolphintabpage.cpp b/src/dolphintabpage.cpp index c2c573e1d..d2fd1d143 100644 --- a/src/dolphintabpage.cpp +++ b/src/dolphintabpage.cpp @@ -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); diff --git a/src/dolphintabpage.h b/src/dolphintabpage.h index 74344acd1..6a8801edd 100644 --- a/src/dolphintabpage.h +++ b/src/dolphintabpage.h @@ -11,8 +11,10 @@ #include <QUrl> #include <QWidget> -class QSplitter; +class DolphinNavigatorsWidgetAction; class DolphinViewContainer; +class QSplitter; +class QVariantAnimation; class KFileItemList; class DolphinTabPage : public QWidget @@ -67,6 +69,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 +107,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; diff --git a/src/dolphintabwidget.cpp b/src/dolphintabwidget.cpp index 3ce8229f9..a09a769d3 100644 --- a/src/dolphintabwidget.cpp +++ b/src/dolphintabwidget.cpp @@ -20,9 +20,10 @@ #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) diff --git a/src/dolphintabwidget.h b/src/dolphintabwidget.h index 9cc03f127..707eb086a 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 <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 diff --git a/src/dolphinui.rc b/src/dolphinui.rc index 10c7c2fa4..01a3778f9 100644 --- a/src/dolphinui.rc +++ b/src/dolphinui.rc @@ -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" /> @@ -120,9 +119,7 @@ <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" /> diff --git a/src/dolphinurlnavigator.cpp b/src/dolphinurlnavigator.cpp index 70f780e55..2b7f3d4eb 100644 --- a/src/dolphinurlnavigator.cpp +++ b/src/dolphinurlnavigator.cpp @@ -1,22 +1,9 @@ /* - * Copyright 2020 Felix Ernst <[email protected]> - * - * 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 <[email protected]> + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #include "dolphinurlnavigator.h" @@ -24,12 +11,12 @@ #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; diff --git a/src/dolphinurlnavigator.h b/src/dolphinurlnavigator.h index 032b81e89..8f8d270ae 100644 --- a/src/dolphinurlnavigator.h +++ b/src/dolphinurlnavigator.h @@ -1,22 +1,9 @@ /* - * Copyright 2020 Felix Ernst <[email protected]> - * - * 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 <[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 @@ -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 diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 59a187e1f..46968e9ff 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -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" @@ -44,10 +43,8 @@ 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())) { diff --git a/src/dolphinviewcontainer.h b/src/dolphinviewcontainer.h index 2fe6b5f89..77b74d189 100644 --- a/src/dolphinviewcontainer.h +++ b/src/dolphinviewcontainer.h @@ -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: 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/settings/dolphin_generalsettings.kcfg b/src/settings/dolphin_generalsettings.kcfg index 9a13493a1..c397b2945 100644 --- a/src/settings/dolphin_generalsettings.kcfg +++ b/src/settings/dolphin_generalsettings.kcfg @@ -50,10 +50,6 @@ <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 index 108a5de13..000000000 --- a/src/views/dolphinurlnavigatorwidgetaction.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2020 Felix Ernst <[email protected]> - * - * 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 index ed07115a6..000000000 --- a/src/views/dolphinurlnavigatorwidgetaction.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020 Felix Ernst <[email protected]> - * - * 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 |
