When renaming files, move to next file using tab key or up/down

To rename previous file:
 Up or Shift-Tab

To rename next file:
 Down or Tab

Credit goes to msciubidlo

FEATURE: 403931
FEATURE: 269987
BUG: 334533
FIXED-IN: 21.08
This commit is contained in:
Méven Car 2021-04-19 05:10:11 +00:00
parent a27b4c5c60
commit 5a0da4a9c8
9 changed files with 95 additions and 15 deletions

View file

@ -208,6 +208,8 @@ void KItemListContainer::slotViewChanged(KItemListView* current, KItemListView*
disconnect(previous, &KItemListView::maximumItemOffsetChanged,
this, &KItemListContainer::updateItemOffsetScrollBar);
disconnect(previous, &KItemListView::scrollTo, this, &KItemListContainer::scrollTo);
disconnect(m_horizontalSmoothScroller, &KItemListSmoothScroller::scrollingStopped, previous, &KItemListView::scrollingStopped);
disconnect(m_verticalSmoothScroller, &KItemListSmoothScroller::scrollingStopped, previous, &KItemListView::scrollingStopped);
m_horizontalSmoothScroller->setTargetObject(nullptr);
m_verticalSmoothScroller->setTargetObject(nullptr);
}
@ -224,6 +226,9 @@ void KItemListContainer::slotViewChanged(KItemListView* current, KItemListView*
connect(current, &KItemListView::maximumItemOffsetChanged,
this, &KItemListContainer::updateItemOffsetScrollBar);
connect(current, &KItemListView::scrollTo, this, &KItemListContainer::scrollTo);
connect(m_horizontalSmoothScroller, &KItemListSmoothScroller::scrollingStopped, current, &KItemListView::scrollingStopped);
connect(m_verticalSmoothScroller, &KItemListSmoothScroller::scrollingStopped, current, &KItemListView::scrollingStopped);
m_horizontalSmoothScroller->setTargetObject(current);
m_verticalSmoothScroller->setTargetObject(current);
updateSmoothScrollers(current->scrollOrientation());

View file

@ -526,8 +526,11 @@ void KItemListView::scrollToItem(int index)
if (newOffset != scrollOffset()) {
Q_EMIT scrollTo(newOffset);
return;
}
}
Q_EMIT scrollingStopped();
}
void KItemListView::beginTransaction()
@ -1602,16 +1605,16 @@ void KItemListView::slotRoleEditingCanceled(int index, const QByteArray& role, c
{
disconnectRoleEditingSignals(index);
Q_EMIT roleEditingCanceled(index, role, value);
m_editingRole = false;
Q_EMIT roleEditingCanceled(index, role, value);
}
void KItemListView::slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value)
{
disconnectRoleEditingSignals(index);
Q_EMIT roleEditingFinished(index, role, value);
m_editingRole = false;
Q_EMIT roleEditingFinished(index, role, value);
}
void KItemListView::setController(KItemListController* controller)

View file

@ -307,6 +307,12 @@ Q_SIGNALS:
void roleEditingCanceled(int index, const QByteArray& role, const QVariant& value);
void roleEditingFinished(int index, const QByteArray& role, const QVariant& value);
/**
* Emitted once scrolling has finished, or immediately if no scrolling was necessary
* to get item in view in scrollToItem.
*/
void scrollingStopped();
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
void setItemSize(const QSizeF& size);

View file

@ -764,6 +764,7 @@ void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const
m_roleEditor = new KItemListRoleEditor(parent);
m_roleEditor->setRole(current);
m_roleEditor->setAllowUpDownKeyChainEdit(m_layout != IconsLayout);
m_roleEditor->setFont(styleOption().font);
const QString text = data().value(current).toString();

View file

@ -40,6 +40,11 @@ QByteArray KItemListRoleEditor::role() const
return m_role;
}
void KItemListRoleEditor::setAllowUpDownKeyChainEdit(bool allowChainEdit)
{
m_allowUpDownKeyChainEdit = allowChainEdit;
}
bool KItemListRoleEditor::eventFilter(QObject* watched, QEvent* event)
{
if (watched == parentWidget() && event->type() == QEvent::Resize) {
@ -78,6 +83,20 @@ void KItemListRoleEditor::keyPressEvent(QKeyEvent* event)
emitRoleEditingFinished();
event->accept();
return;
case Qt::Key_Tab:
case Qt::Key_Down:
if (m_allowUpDownKeyChainEdit || event->key() == Qt::Key_Tab) {
emitRoleEditingFinished(EditNext);
event->accept();
return;
}
case Qt::Key_Backtab:
case Qt::Key_Up:
if (m_allowUpDownKeyChainEdit || event->key() == Qt::Key_Backtab) {
emitRoleEditingFinished(EditPrevious);
event->accept();
return;
}
case Qt::Key_Left:
case Qt::Key_Right: {
QTextCursor cursor = textCursor();
@ -143,10 +162,13 @@ void KItemListRoleEditor::autoAdjustSize()
}
}
void KItemListRoleEditor::emitRoleEditingFinished()
void KItemListRoleEditor::emitRoleEditingFinished(EditResultDirection direction)
{
QVariant ret;
ret.setValue(EditResult {KIO::encodeFileName(toPlainText()), direction});
if (!m_blockFinishedSignal) {
Q_EMIT roleEditingFinished(m_role, KIO::encodeFileName(toPlainText()));
Q_EMIT roleEditingFinished(m_role, ret);
}
}

View file

@ -11,12 +11,26 @@
#include <KTextEdit>
enum EditResultDirection{
EditDone,
EditNext,
EditPrevious,
};
Q_DECLARE_METATYPE(EditResultDirection)
struct EditResult
{
QString newName;
EditResultDirection direction;
};
Q_DECLARE_METATYPE(EditResult)
/**
* @brief Editor for renaming roles of a KItemListWidget.
*
* Provides signals when the editing got cancelled (e.g. by
* pressing Escape or when losing the focus) or when the editing
* got finished (e.g. by pressing Enter or Return).
* got finished (e.g. by pressing Enter, Tab or Return).
*
* The size automatically gets increased if the text does not fit.
*/
@ -31,6 +45,7 @@ public:
void setRole(const QByteArray& role);
QByteArray role() const;
void setAllowUpDownKeyChainEdit(bool allowChainEdit);
bool eventFilter(QObject* watched, QEvent* event) override;
Q_SIGNALS:
@ -53,11 +68,12 @@ private:
* Emits the signal roleEditingFinished if m_blockFinishedSignal
* is false.
*/
void emitRoleEditingFinished();
void emitRoleEditingFinished(EditResultDirection direction = EditDone);
private:
QByteArray m_role;
bool m_blockFinishedSignal;
bool m_allowUpDownKeyChainEdit;
};
#endif

View file

@ -175,6 +175,9 @@ void KItemListSmoothScroller::slotAnimationStateChanged(QAbstractAnimation::Stat
if (newState == QAbstractAnimation::Stopped && m_smoothScrolling && !m_scrollBarPressed) {
m_smoothScrolling = false;
}
if (newState == QAbstractAnimation::Stopped) {
Q_EMIT scrollingStopped();
}
}
void KItemListSmoothScroller::handleWheelEvent(QWheelEvent* event)

View file

@ -69,6 +69,11 @@ public:
*/
void handleWheelEvent(QWheelEvent* event);
Q_SIGNALS:
/**
* Emitted when the scrolling animation has finished
*/
void scrollingStopped();
protected:
bool eventFilter(QObject* obj, QEvent* event) override;

View file

@ -18,6 +18,7 @@
#include "kitemviews/kitemlistcontroller.h"
#include "kitemviews/kitemlistheader.h"
#include "kitemviews/kitemlistselectionmanager.h"
#include "kitemviews/private/kitemlistroleeditor.h"
#include "versioncontrol/versioncontrolobserver.h"
#include "viewproperties.h"
#include "views/tooltips/tooltipmanager.h"
@ -674,12 +675,21 @@ void DolphinView::renameSelectedItems()
if (items.count() == 1 && GeneralSettings::renameInline()) {
const int index = m_model->index(items.first());
m_view->editRole(index, "text");
hideToolTip();
QMetaObject::Connection * const connection = new QMetaObject::Connection;
*connection = connect(m_view, &KItemListView::scrollingStopped, this, [=](){
QObject::disconnect(*connection);
delete connection;
m_view->editRole(index, "text");
hideToolTip();
connect(m_view, &DolphinItemListView::roleEditingFinished,
this, &DolphinView::slotRoleEditingFinished);
});
m_view->scrollToItem(index);
connect(m_view, &DolphinItemListView::roleEditingFinished,
this, &DolphinView::slotRoleEditingFinished);
} else {
KIO::RenameFileDialog* dialog = new KIO::RenameFileDialog(items, this);
connect(dialog, &KIO::RenameFileDialog::renamingFinished,
@ -1736,13 +1746,15 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, con
disconnect(m_view, &DolphinItemListView::roleEditingFinished,
this, &DolphinView::slotRoleEditingFinished);
if (index < 0 || index >= m_model->count()) {
const KFileItemList items = selectedItems();
if (items.count() != 1) {
return;
}
if (role == "text") {
const KFileItem oldItem = m_model->fileItem(index);
const QString newName = value.toString();
const KFileItem oldItem = items.first();
const EditResult retVal = value.value<EditResult>();
const QString newName = retVal.newName;
if (!newName.isEmpty() && newName != oldItem.text() && newName != QLatin1Char('.') && newName != QLatin1String("..")) {
const QUrl oldUrl = oldItem.url();
@ -1773,14 +1785,14 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, con
#endif
const bool newNameExistsAlready = (m_model->index(newUrl) >= 0);
if (!newNameExistsAlready) {
if (!newNameExistsAlready && m_model->index(oldUrl) == index) {
// Only change the data in the model if no item with the new name
// is in the model yet. If there is an item with the new name
// already, calling KIO::CopyJob will open a dialog
// asking for a new name, and KFileItemModel will update the
// data when the dir lister signals that the file name has changed.
QHash<QByteArray, QVariant> data;
data.insert(role, value);
data.insert(role, retVal.newName);
m_model->setData(index, data);
}
@ -1797,6 +1809,13 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, con
connect(job, &KJob::result, this, &DolphinView::slotRenamingResult);
}
}
if (retVal.direction != EditDone) {
const short indexShift = retVal.direction == EditNext ? 1 : -1;
m_container->controller()->selectionManager()->setSelected(index, 1, KItemListSelectionManager::Deselect);
m_container->controller()->selectionManager()->setSelected(index + indexShift, 1,
KItemListSelectionManager::Select);
renameSelectedItems();
}
}
}