From 5454283008f26d377a6403861a3cdd7992dbbd38 Mon Sep 17 00:00:00 2001 From: Andreas Krutzler Date: Fri, 27 Oct 2017 07:01:54 -0600 Subject: [PATCH] Two clicks on file/folder to rename Summary: Make renaming of files/folders faster by clicking a second time on the items text to start renaming. BUG: 205157 Test Plan: This feature works as follows: 1. select an item by single-click, or one is already selected 2. wait the "double-click-interval" 3. click on the items text 4. none of the cancellations (see below) happens within the double-click-interval 5. inline-renaming starts Cancellations: * open any file/folder * select different item(s) * start dragging items * Dolphin loses focus This feature is just enabled while "Double-click to open files and folders" in system-settings and "Rename inline" in Dolphin are enabled. Reviewers: #dolphin, #kde_applications, elvisangelaccio, emmanuelp, ngraham, markg, rkflx Reviewed By: #dolphin, #kde_applications, elvisangelaccio, ngraham, rkflx Subscribers: rkflx, markg, funkybomber, sars, elvisangelaccio, ngraham Differential Revision: https://phabricator.kde.org/D7647 --- src/kitemviews/kitemlistcontroller.cpp | 4 ++ src/kitemviews/kitemlistcontroller.h | 2 + src/kitemviews/kitemlistview.cpp | 13 +++++++ src/kitemviews/kitemlistview.h | 1 + src/views/dolphinview.cpp | 53 +++++++++++++++++++++++--- src/views/dolphinview.h | 8 ++++ 6 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index 3731895d0a..753d7915d0 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -583,6 +583,10 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const // -> remember that the user pressed an item which had been selected already and // clear the selection in mouseReleaseEvent(), unless the items are dragged. m_clearSelectionIfItemsAreNotDragged = true; + + if (m_selectionManager->selectedItems().count() == 1 && m_view->isAboveText(m_pressedIndex, m_pressedMousePos)) { + emit selectedItemTextPressed(m_pressedIndex); + } } if (!shiftPressed) { diff --git a/src/kitemviews/kitemlistcontroller.h b/src/kitemviews/kitemlistcontroller.h index 5e5e6b7c3e..f293774434 100644 --- a/src/kitemviews/kitemlistcontroller.h +++ b/src/kitemviews/kitemlistcontroller.h @@ -237,6 +237,8 @@ signals: void modelChanged(KItemModelBase* current, KItemModelBase* previous); void viewChanged(KItemListView* current, KItemListView* previous); + void selectedItemTextPressed(int index); + private slots: void slotViewScrollOffsetChanged(qreal current, qreal previous); diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index d840509da7..660bffe579 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -453,6 +453,19 @@ bool KItemListView::isAboveExpansionToggle(int index, const QPointF& pos) const return false; } +bool KItemListView::isAboveText(int index, const QPointF &pos) const +{ + const KItemListWidget* widget = m_visibleItems.value(index); + if (widget) { + const QRectF &textRect = widget->textRect(); + if (!textRect.isEmpty()) { + const QPointF mappedPos = widget->mapFromItem(this, pos); + return textRect.contains(mappedPos); + } + } + return false; +} + int KItemListView::firstVisibleIndex() const { return m_layouter->firstVisibleIndex(); diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index ed1199877f..e64ac7e31a 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -183,6 +183,7 @@ public: int itemAt(const QPointF& pos) const; bool isAboveSelectionToggle(int index, const QPointF& pos) const; bool isAboveExpansionToggle(int index, const QPointF& pos) const; + bool isAboveText(int index, const QPointF& pos) const; /** * @return Index of the first item that is at least partly visible. diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index 2ca51f52dc..4485c17079 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -99,7 +99,8 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) : m_selectedUrls(), m_clearSelectionBeforeSelectingNewItems(false), m_markFirstNewlySelectedItemAsCurrent(false), - m_versionControlObserver(0) + m_versionControlObserver(0), + m_twoClicksRenamingTimer(nullptr) { m_topLayout = new QVBoxLayout(this); m_topLayout->setSpacing(0); @@ -150,6 +151,7 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) : connect(controller, &KItemListController::itemDropEvent, this, &DolphinView::slotItemDropEvent); connect(controller, &KItemListController::escapePressed, this, &DolphinView::stopLoading); connect(controller, &KItemListController::modelChanged, this, &DolphinView::slotModelChanged); + connect(controller, &KItemListController::selectedItemTextPressed, this, &DolphinView::slotSelectedItemTextPressed); connect(m_model, &KFileItemModel::directoryLoadingStarted, this, &DolphinView::slotDirectoryLoadingStarted); connect(m_model, &KFileItemModel::directoryLoadingCompleted, this, &DolphinView::slotDirectoryLoadingCompleted); @@ -190,6 +192,10 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) : connect(m_versionControlObserver, &VersionControlObserver::errorMessage, this, &DolphinView::errorMessage); connect(m_versionControlObserver, &VersionControlObserver::operationCompletedMessage, this, &DolphinView::operationCompletedMessage); + m_twoClicksRenamingTimer = new QTimer(this); + m_twoClicksRenamingTimer->setSingleShot(true); + connect(m_twoClicksRenamingTimer, &QTimer::timeout, this, &DolphinView::slotTwoClicksRenamingTimerTimeout); + applyViewProperties(); m_topLayout->addWidget(m_container); @@ -726,6 +732,12 @@ void DolphinView::updatePalette() update(); } +void DolphinView::abortTwoClicksRenaming() +{ + m_twoClicksRenamingItemUrl.clear(); + m_twoClicksRenamingTimer->stop(); +} + bool DolphinView::eventFilter(QObject* watched, QEvent* event) { switch (event->type()) { @@ -793,13 +805,14 @@ void DolphinView::hideEvent(QHideEvent* event) bool DolphinView::event(QEvent* event) { - /* See Bug 297355 - * Dolphin leaves file preview tooltips open even when is not visible. - * - * Hide tool-tip when Dolphin loses focus. - */ if (event->type() == QEvent::WindowDeactivate) { + /* See Bug 297355 + * Dolphin leaves file preview tooltips open even when is not visible. + * + * Hide tool-tip when Dolphin loses focus. + */ hideToolTip(); + abortTwoClicksRenaming(); } return QWidget::event(event); @@ -812,6 +825,8 @@ void DolphinView::activate() void DolphinView::slotItemActivated(int index) { + abortTwoClicksRenaming(); + const KFileItem item = m_model->fileItem(index); if (!item.isNull()) { emit itemActivated(item); @@ -822,6 +837,8 @@ void DolphinView::slotItemsActivated(const KItemSet& indexes) { Q_ASSERT(indexes.count() >= 2); + abortTwoClicksRenaming(); + if (indexes.count() > 5) { QString question = i18np("Are you sure you want to open 1 item?", "Are you sure you want to open %1 items?", indexes.count()); const int answer = KMessageBox::warningYesNo(this, question); @@ -1105,6 +1122,14 @@ void DolphinView::slotMouseButtonPressed(int itemIndex, Qt::MouseButtons buttons } } +void DolphinView::slotSelectedItemTextPressed(int index) +{ + if (GeneralSettings::renameInline()) { + m_twoClicksRenamingItemUrl = m_model->fileItem(index).url(); + m_twoClicksRenamingTimer->start(QApplication::doubleClickInterval()); + } +} + void DolphinView::slotItemCreated(const QUrl& url) { if (m_markFirstNewlySelectedItemAsCurrent) { @@ -1401,6 +1426,22 @@ void DolphinView::calculateItemCount(int& fileCount, } } +void DolphinView::slotTwoClicksRenamingTimerTimeout() +{ + const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager(); + + // verify that only one item is selected and that no item is dragged + if (selectionManager->selectedItems().count() == 1 && !m_dragging) { + const int index = selectionManager->currentItem(); + const QUrl fileItemUrl = m_model->fileItem(index).url(); + + // check if the selected item was the same item that started the twoClicksRenaming + if (fileItemUrl.isValid() && m_twoClicksRenamingItemUrl == fileItemUrl) { + renameSelectedItems(); + } + } +} + void DolphinView::slotTrashFileFinished(KJob* job) { if (job->error() == 0) { diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index 911103b5d7..2df1cf9e4c 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -577,6 +577,7 @@ private slots: void slotModelChanged(KItemModelBase* current, KItemModelBase* previous); void slotMouseButtonPressed(int itemIndex, Qt::MouseButtons buttons); void slotRenameDialogRenamingFinished(const QList& urls); + void slotSelectedItemTextPressed(int index); /* * Is called when new items get pasted or dropped. @@ -707,6 +708,8 @@ private slots: */ void calculateItemCount(int& fileCount, int& folderCount, KIO::filesize_t& totalFileSize) const; + void slotTwoClicksRenamingTimerTimeout(); + private: void loadDirectory(const QUrl& url, bool reload = false); @@ -769,6 +772,8 @@ private: */ void forceUrlsSelection(const QUrl& current, const QList& selected); + void abortTwoClicksRenaming(); + private: void updatePalette(); @@ -804,6 +809,9 @@ private: VersionControlObserver* m_versionControlObserver; + QTimer* m_twoClicksRenamingTimer; + QUrl m_twoClicksRenamingItemUrl; + // For unit tests friend class TestBase; friend class DolphinDetailsViewTest;