diff --git a/kate/katemainwindow.h b/kate/katemainwindow.h --- a/kate/katemainwindow.h +++ b/kate/katemainwindow.h @@ -178,6 +178,9 @@ void slotFocusPrevTab(); void slotFocusNextTab(); + void slotUndoCursorMove(); + void slotRedoCursorMove(); + /** * Show quick open */ diff --git a/kate/katemainwindow.cpp b/kate/katemainwindow.cpp --- a/kate/katemainwindow.cpp +++ b/kate/katemainwindow.cpp @@ -1186,12 +1186,21 @@ void KateMainWindow::mousePressEvent(QMouseEvent *e) { + bool shiftPressed = QGuiApplication::keyboardModifiers() == Qt::ShiftModifier; switch (e->button()) { case Qt::ForwardButton: - slotFocusNextTab(); + if(shiftPressed) { + slotRedoCursorMove(); + } else { + slotFocusNextTab(); + } break; case Qt::BackButton: - slotFocusPrevTab(); + if(shiftPressed) { + slotUndoCursorMove(); + } else { + slotFocusPrevTab(); + } break; default:; } @@ -1211,6 +1220,16 @@ } } +void KateMainWindow::slotUndoCursorMove() +{ + m_viewManager->undoCursorMove(); +} + +void KateMainWindow::slotRedoCursorMove() +{ + m_viewManager->redoCursorMove(); +} + void KateMainWindow::slotQuickOpen() { /** diff --git a/kate/kateviewmanager.h b/kate/kateviewmanager.h --- a/kate/kateviewmanager.h +++ b/kate/kateviewmanager.h @@ -85,6 +85,7 @@ private Q_SLOTS: void activateView(KTextEditor::View *view); void activateSpace(KTextEditor::View *v); + void stackCursorPosition(KTextEditor::View *view, const KTextEditor::Cursor &newPosition); public Q_SLOTS: void slotDocumentNew(); @@ -98,6 +99,9 @@ void activateNextView(); void activatePrevView(); + void undoCursorMove(); + void redoCursorMove(); + Q_SIGNALS: void viewChanged(KTextEditor::View *); void viewCreated(KTextEditor::View *); @@ -319,6 +323,14 @@ * activity resource for the view */ KActivities::ResourceInstance *activityResource = nullptr; + + QList cursorMoveHistory; + QList cursorRedoHistory; + /** + * inhibit stackCursorPosition() inside undo/redo. + * This would be caused by setCursorPosition() + * */ + bool cursorMoving = false; }; /** diff --git a/kate/kateviewmanager.cpp b/kate/kateviewmanager.cpp --- a/kate/kateviewmanager.cpp +++ b/kate/kateviewmanager.cpp @@ -456,6 +456,7 @@ connect(view, SIGNAL(dropEventPass(QDropEvent *)), mainWindow(), SLOT(slotDropEvent(QDropEvent *))); connect(view, &KTextEditor::View::focusIn, this, &KateViewManager::activateSpace); + connect(view, &KTextEditor::View::cursorPositionChanged, this, &KateViewManager::stackCursorPosition); viewCreated(view); @@ -1235,3 +1236,64 @@ currentSplitter = qobject_cast(currentSplitter->parentWidget()); } } + +void KateViewManager::stackCursorPosition(KTextEditor::View *view, const KTextEditor::Cursor &newPosition) +{ + if (!m_views.contains(view)) { + return; + } + if (m_views[view].cursorMoving) { + return; + } + QList& history = m_views[view].cursorMoveHistory; + + // Discard small changes + if (history.isEmpty() || (abs(history.last().line() - newPosition.line()) > 10)) { + history.append(newPosition); + } +} + +void KateViewManager::undoCursorMove() +{ + if (!activeView() || !m_views.contains(activeView())) { + return; + } + + ViewData& viewData = m_views[activeView()]; + if (viewData.cursorMoveHistory.isEmpty()) { + return; + } + + // Move action to the Redo stack + viewData.cursorRedoHistory.append(viewData.cursorMoveHistory.last()); + viewData.cursorMoveHistory.removeLast(); + // Use the last position if possible, it defaults to 0 + KTextEditor::Cursor lastPosition; + if (!viewData.cursorMoveHistory.isEmpty()) { + lastPosition = viewData.cursorMoveHistory.last(); + } + viewData.cursorMoving = true; + activeView()->setCursorPosition(lastPosition); + viewData.cursorMoving = false; +} + +void KateViewManager::redoCursorMove() +{ + if (!activeView() || !m_views.contains(activeView())) { + return; + } + + ViewData& viewData = m_views[activeView()]; + if (viewData.cursorRedoHistory.isEmpty()) { + return; + } + + // Move action to the Move stack + KTextEditor::Cursor lastPosition(viewData.cursorRedoHistory.last()); + viewData.cursorMoveHistory.append(lastPosition); + // Use the last position ; + viewData.cursorRedoHistory.removeLast(); + viewData.cursorMoving = true; + activeView()->setCursorPosition(lastPosition); + viewData.cursorMoving = false; +}