diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ set(NON_KIOCORE_LINK_QCHS Qt5Widgets_QCH Qt5Network_QCH + Qt5Core_QCH KF5Completion_QCH KF5WidgetsAddons_QCH KF5JobWidgets_QCH diff --git a/src/filewidgets/CMakeLists.txt b/src/filewidgets/CMakeLists.txt --- a/src/filewidgets/CMakeLists.txt +++ b/src/filewidgets/CMakeLists.txt @@ -12,7 +12,7 @@ kpreviewwidgetbase.cpp krecentdirs.cpp defaultviewadapter.cpp - + keypressedeventfilter.cpp kdiroperator.cpp kdiroperatordetailview.cpp kdirsortfilterproxymodel.cpp #used in combination with kdirmodel.cpp @@ -39,8 +39,6 @@ kurlnavigator.cpp kurlnavigatormenu.cpp kurlnavigatorpathselectoreventfilter.cpp - - ) qt5_add_resources(kiofilewidgets_SRCS ../new_file_templates/templates.qrc) diff --git a/src/filewidgets/keypressedeventfilter.h b/src/filewidgets/keypressedeventfilter.h new file mode 100644 --- /dev/null +++ b/src/filewidgets/keypressedeventfilter.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2019 Mikhail Krutov * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KEYPRESSED_EVENT_FILTER +#define KEYPRESSED_EVENT_FILTER + +#include "kiofilewidgets_export.h" +#include +#include + +/** + * Filter to allow detection of key_up presses in the editable mode + */ + + +class KeyPressedEventFilter : public QObject +{ + Q_OBJECT + +public: + explicit KeyPressedEventFilter(); + ~KeyPressedEventFilter() override; + +Q_SIGNALS: + void keyUpPressed(); + void keyDownPressed(); + +protected: + bool eventFilter(QObject *watched, QEvent *event) override; +}; +#endif diff --git a/src/filewidgets/keypressedeventfilter.cpp b/src/filewidgets/keypressedeventfilter.cpp new file mode 100644 --- /dev/null +++ b/src/filewidgets/keypressedeventfilter.cpp @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2019 Mikhail Krutov * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + + +#include "keypressedeventfilter.h" +#include +#include +#include + +KeyPressedEventFilter::KeyPressedEventFilter() +{ + +} + +KeyPressedEventFilter::~KeyPressedEventFilter() = default; + + +bool KeyPressedEventFilter::eventFilter(QObject* watched, QEvent* event) +{ + if (event -> type() == QEvent::KeyRelease) { + QKeyEvent *actualEvent = static_cast(event); + if (actualEvent->key() == Qt::Key_Up) { + emit keyUpPressed(); + return true; + } else if (actualEvent->key() == Qt::Key_Down) { + emit keyDownPressed(); + return true; + } + } + return QObject::eventFilter(watched, event); +} diff --git a/src/filewidgets/kurlnavigator.h b/src/filewidgets/kurlnavigator.h --- a/src/filewidgets/kurlnavigator.h +++ b/src/filewidgets/kurlnavigator.h @@ -25,6 +25,7 @@ #include "kiofilewidgets_export.h" +#include "keypressedeventfilter.h" #include #include #include @@ -483,16 +484,18 @@ Q_PRIVATE_SLOT(d, void dropUrls(const QUrl &destination, QDropEvent *)) Q_PRIVATE_SLOT(d, void slotNavigatorButtonClicked(const QUrl &url, Qt::MouseButton button, Qt::KeyboardModifiers modifiers)) Q_PRIVATE_SLOT(d, void openContextMenu(QPoint)) + Q_PRIVATE_SLOT(d, void openHierarchyMenu()) Q_PRIVATE_SLOT(d, void openPathSelectorMenu()) Q_PRIVATE_SLOT(d, void updateButtonVisibility()) Q_PRIVATE_SLOT(d, void switchToBreadcrumbMode()) Q_PRIVATE_SLOT(d, void slotPathBoxChanged(const QString &text)) Q_PRIVATE_SLOT(d, void updateContent()) + Q_PRIVATE_SLOT(d, void slotUpButtonPressed()) + private: class Private; Private *const d; - Q_DISABLE_COPY(KUrlNavigator) }; diff --git a/src/filewidgets/kurlnavigator.cpp b/src/filewidgets/kurlnavigator.cpp --- a/src/filewidgets/kurlnavigator.cpp +++ b/src/filewidgets/kurlnavigator.cpp @@ -37,6 +37,8 @@ #include #include #include +#include "keypressedeventfilter.h" + #include #include @@ -51,7 +53,9 @@ #include #include #include +#include #include +#include using namespace KDEPrivate; @@ -77,6 +81,8 @@ void slotReturnPressed(); void slotProtocolChanged(const QString &); void openPathSelectorMenu(); + void openHierarchyMenu(); + QString parentDirectory(const QUrl ¤t) const; /** * Appends the widget at the end of the URL navigator. It is assured @@ -107,6 +113,8 @@ */ void slotNavigatorButtonClicked(const QUrl &url, Qt::MouseButton button, Qt::KeyboardModifiers modifiers); + void slotUpButtonPressed(); + void openContextMenu(const QPoint &p); void slotPathBoxChanged(const QString &text); @@ -164,7 +172,7 @@ bool isCompressedPath(const QUrl &path) const; void removeTrailingSlash(QString &url) const; - + /** * Returns the current history index, if \a historyIndex is * smaller than 0. If \a historyIndex is greater or equal than @@ -193,6 +201,7 @@ QStringList m_customProtocols; QWidget *m_dropWidget; KUrlNavigator * const q; + KeyPressedEventFilter *m_keyPressedEventFilter; }; KUrlNavigator::Private::Private(KUrlNavigator *q, KFilePlacesModel *placesModel) : @@ -211,7 +220,8 @@ m_homeUrl(), m_customProtocols(QStringList()), m_dropWidget(nullptr), - q(q) + q(q), + m_keyPressedEventFilter(nullptr) { m_layout->setSpacing(0); m_layout->setContentsMargins(0, 0, 0, 0); @@ -281,6 +291,10 @@ q->setContextMenuPolicy(Qt::CustomContextMenu); connect(q, SIGNAL(customContextMenuRequested(QPoint)), q, SLOT(openContextMenu(QPoint))); + m_keyPressedEventFilter = new KeyPressedEventFilter(); + connect(m_keyPressedEventFilter, SIGNAL(keyUpPressed()), q, SLOT(slotUpButtonPressed())); + connect(m_keyPressedEventFilter, SIGNAL(keyDownPressed()), + q, SLOT(openHierarchyMenu())); } void KUrlNavigator::Private::initialize(const QUrl &url) @@ -327,6 +341,16 @@ m_pathBox->setUrl(currentUrl); } +void KUrlNavigator::Private::slotUpButtonPressed() +{ + emit q->goUp(); + /* + * Ugly hack to get focus back + */ + slotToggleEditableButtonPressed(); + QTimer::singleShot(10, q->editor()->lineEdit(), SLOT(setFocus())); +} + void KUrlNavigator::Private::slotReturnPressed() { applyUncommittedUrl(); @@ -358,6 +382,42 @@ m_pathBox->setEditUrl(url); } + QString KUrlNavigator::Private::parentDirectory(const QUrl ¤t) const + { + const QString currentPath = current.path(); + const int slash = currentPath.lastIndexOf(QLatin1Char('/')); + if (slash == -1) + return QString(); + else if (slash == 0) + return QString(QLatin1Char('/')); + else if (slash == currentPath.length()-1) + return parentDirectory(QUrl(currentPath.left(slash))); + return currentPath.left(slash); + } + +void KUrlNavigator::Private::openHierarchyMenu() { + QUrl currentDirectory = q->locationUrl(); + QList* hierarchyList = new QList(); + QUrl levelUp(QStringLiteral("/../")); + bool hasParent = true; + while (hasParent) { + hierarchyList->prepend(currentDirectory); + hasParent = (currentDirectory != currentDirectory.resolved(levelUp)); + currentDirectory = QUrl(parentDirectory(currentDirectory)); + } + QMenu *dropdown = new QMenu(q); + auto itBegin = hierarchyList->begin(); + const auto itEnd = hierarchyList->end(); + while (itBegin != itEnd) { + QAction* action = new QAction(QIcon::fromTheme(QStringLiteral("folder")),itBegin->path(), dropdown); + action->setData(QVariant(itBegin->toString())); + dropdown->addAction(action); + ++itBegin; + } + auto lineEdit = q->editor()->lineEdit(); + dropdown->popup(lineEdit->mapToGlobal(QPoint(0, lineEdit->height()))); +} + void KUrlNavigator::Private::openPathSelectorMenu() { if (m_navButtons.count() <= 0) { @@ -421,6 +481,9 @@ { if (m_editable) { applyUncommittedUrl(); + m_pathBox->removeEventFilter(m_keyPressedEventFilter); + } else { + m_pathBox->installEventFilter(m_keyPressedEventFilter); } switchView();