7#include "kateundomanager.h"
9#include <ktexteditor/view.h>
11#include "katedocument.h"
12#include "katepartdebug.h"
21 connect(
this, &KateUndoManager::undoEnd,
this, &KateUndoManager::undoChanged);
22 connect(
this, &KateUndoManager::redoEnd,
this, &KateUndoManager::undoChanged);
28 savedUndoItems = std::move(undoItems);
29 savedRedoItems = std::move(redoItems);
30 docChecksumBeforeReload = m_document->
checksum();
36 undoItems = std::move(savedUndoItems);
37 redoItems = std::move(savedRedoItems);
40 docChecksumBeforeReload.
clear();
41 savedUndoItems.clear();
42 savedRedoItems.clear();
46KateUndoManager::~KateUndoManager() =
default;
60 Q_ASSERT(!m_editCurrentUndo.has_value());
66 secondaryCursors = activeView()->plainSecondaryCursors();
70 m_editCurrentUndo =
KateUndoGroup(cursorPosition, primarySelectionRange, secondaryCursors);
72 Q_ASSERT(m_editCurrentUndo.has_value());
82 Q_ASSERT(m_editCurrentUndo.has_value());
89 secondaryCursors = activeView()->plainSecondaryCursors();
92 m_editCurrentUndo->editEnd(cursorPosition, selectionRange, secondaryCursors);
94 bool changedUndo =
false;
96 if (m_editCurrentUndo->isEmpty()) {
97 m_editCurrentUndo.reset();
98 }
else if (!undoItems.empty() && undoItems.back().merge(&*m_editCurrentUndo, m_undoComplexMerge)) {
99 m_editCurrentUndo.reset();
101 undoItems.push_back(std::move(*m_editCurrentUndo));
105 m_editCurrentUndo.reset();
111 Q_ASSERT(!m_editCurrentUndo.has_value());
114void KateUndoManager::inputMethodStart()
120void KateUndoManager::inputMethodEnd()
126void KateUndoManager::startUndo()
132void KateUndoManager::endUndo()
140 if (!m_editCurrentUndo.has_value() || s.
isEmpty()) {
145 item.type = UndoItem::editInsertText;
149 item.lineModFlags.
setFlag(UndoItem::RedoLine1Modified);
151 if (tl.markedAsModified()) {
152 item.lineModFlags.
setFlag(UndoItem::UndoLine1Modified);
154 item.lineModFlags.
setFlag(UndoItem::UndoLine1Saved);
156 addUndoItem(std::move(item));
161 if (!m_editCurrentUndo.has_value() || s.
isEmpty()) {
166 item.type = UndoItem::editRemoveText;
170 item.lineModFlags.
setFlag(UndoItem::RedoLine1Modified);
172 if (tl.markedAsModified()) {
173 item.lineModFlags.
setFlag(UndoItem::UndoLine1Modified);
175 item.lineModFlags.
setFlag(UndoItem::UndoLine1Saved);
177 addUndoItem(std::move(item));
182 if (m_editCurrentUndo.has_value()) {
184 item.type = UndoItem::editMarkLineAutoWrapped;
186 item.autowrapped = autowrapped;
187 addUndoItem(std::move(item));
193 if (!m_editCurrentUndo.has_value()) {
198 item.type = UndoItem::editWrapLine;
202 item.newLine = newLine;
204 if (length > 0 || tl.markedAsModified()) {
205 item.lineModFlags.
setFlag(UndoItem::RedoLine1Modified);
206 }
else if (tl.markedAsSavedOnDisk()) {
207 item.lineModFlags.
setFlag(UndoItem::RedoLine1Saved);
210 if (col > 0 || length == 0 || tl.markedAsModified()) {
211 item.lineModFlags.
setFlag(UndoItem::RedoLine2Modified);
212 }
else if (tl.markedAsSavedOnDisk()) {
213 item.lineModFlags.
setFlag(UndoItem::RedoLine2Saved);
216 if (tl.markedAsModified()) {
217 item.lineModFlags.
setFlag(UndoItem::UndoLine1Modified);
218 }
else if ((length > 0 && col > 0) || tl.markedAsSavedOnDisk()) {
219 item.lineModFlags.
setFlag(UndoItem::UndoLine1Saved);
222 addUndoItem(std::move(item));
227 if (!m_editCurrentUndo.has_value()) {
232 item.type = UndoItem::editUnWrapLine;
236 item.removeLine = lineRemoved;
238 const int len1 = tl.
length();
239 const int len2 = nextLine.
length();
241 if (len1 > 0 && len2 > 0) {
242 item.lineModFlags.
setFlag(UndoItem::RedoLine1Modified);
244 if (tl.markedAsModified()) {
245 item.lineModFlags.
setFlag(UndoItem::UndoLine1Modified);
247 item.lineModFlags.
setFlag(UndoItem::UndoLine1Saved);
250 if (nextLine.markedAsModified()) {
251 item.lineModFlags.
setFlag(UndoItem::UndoLine2Modified);
253 item.lineModFlags.
setFlag(UndoItem::UndoLine2Saved);
255 }
else if (len1 == 0) {
256 if (nextLine.markedAsModified()) {
257 item.lineModFlags.
setFlag(UndoItem::RedoLine1Modified);
258 }
else if (nextLine.markedAsSavedOnDisk()) {
259 item.lineModFlags.
setFlag(UndoItem::RedoLine1Saved);
262 if (tl.markedAsModified()) {
263 item.lineModFlags.
setFlag(UndoItem::UndoLine1Modified);
265 item.lineModFlags.
setFlag(UndoItem::UndoLine1Saved);
268 if (nextLine.markedAsModified()) {
269 item.lineModFlags.
setFlag(UndoItem::UndoLine2Modified);
270 }
else if (nextLine.markedAsSavedOnDisk()) {
271 item.lineModFlags.
setFlag(UndoItem::UndoLine2Saved);
274 if (nextLine.markedAsModified()) {
275 item.lineModFlags.
setFlag(UndoItem::RedoLine1Modified);
276 }
else if (nextLine.markedAsSavedOnDisk()) {
277 item.lineModFlags.
setFlag(UndoItem::RedoLine1Saved);
280 if (tl.markedAsModified()) {
281 item.lineModFlags.
setFlag(UndoItem::UndoLine1Modified);
282 }
else if (tl.markedAsSavedOnDisk()) {
283 item.lineModFlags.
setFlag(UndoItem::UndoLine1Saved);
286 if (nextLine.markedAsModified()) {
287 item.lineModFlags.
setFlag(UndoItem::UndoLine2Modified);
289 item.lineModFlags.
setFlag(UndoItem::UndoLine2Saved);
293 addUndoItem(std::move(item));
298 if (m_editCurrentUndo.has_value()) {
300 item.type = UndoItem::editInsertLine;
303 item.lineModFlags.
setFlag(UndoItem::RedoLine1Modified);
304 addUndoItem(std::move(item));
310 if (m_editCurrentUndo.has_value()) {
312 item.type = UndoItem::editRemoveLine;
315 item.lineModFlags.
setFlag(UndoItem::RedoLine1Modified);
317 if (tl.markedAsModified()) {
318 item.lineModFlags.
setFlag(UndoItem::UndoLine1Modified);
320 item.lineModFlags.
setFlag(UndoItem::UndoLine1Saved);
322 addUndoItem(std::move(item));
326void KateUndoManager::undoCancel()
329 if (m_document->isEditRunning()) {
338 if (!m_editCurrentUndo.has_value() && !undoItems.empty()) {
339 undoItems.back().safePoint();
340 }
else if (m_editCurrentUndo.has_value()) {
341 m_editCurrentUndo.value().safePoint();
345void KateUndoManager::addUndoItem(UndoItem undo)
347 Q_ASSERT(m_editCurrentUndo.has_value());
349 m_editCurrentUndo->addItem(std::move(
undo));
355void KateUndoManager::setActive(
bool enabled)
357 Q_ASSERT(!m_editCurrentUndo.has_value());
358 Q_ASSERT(m_isActive != enabled);
360 m_isActive = enabled;
362 Q_EMIT isActiveChanged(enabled);
367 return undoItems.size();
372 return redoItems.size();
377 Q_ASSERT(!m_editCurrentUndo.has_value());
379 if (!undoItems.empty()) {
380 Q_EMIT undoStart(document());
382 undoItems.back().undo(
this, activeView());
383 redoItems.push_back(std::move(undoItems.back()));
384 undoItems.pop_back();
387 Q_EMIT undoEnd(document());
393 Q_ASSERT(!m_editCurrentUndo.has_value());
395 if (!redoItems.empty()) {
396 Q_EMIT redoStart(document());
398 redoItems.back().redo(
this, activeView());
399 undoItems.push_back(std::move(redoItems.back()));
400 redoItems.pop_back();
403 Q_EMIT redoEnd(document());
407void KateUndoManager::updateModified()
432 unsigned char currentPattern = 0;
433 const unsigned char patterns[] = {5, 16, 21, 24, 26, 88, 90, 93, 133, 144, 149, 154, 165};
434 const unsigned char patternCount =
sizeof(patterns);
438 if (undoItems.empty()) {
441 undoLast = &undoItems.back();
444 if (redoItems.empty()) {
447 redoLast = &redoItems.back();
450 if (docWasSavedWhenUndoWasEmpty) {
453 if (docWasSavedWhenRedoWasEmpty) {
456 if (lastUndoGroupWhenSaved == undoLast) {
457 currentPattern |= 16;
459 if (lastUndoGroupWhenSaved == redoLast) {
460 currentPattern |= 32;
462 if (lastRedoGroupWhenSaved == undoLast) {
463 currentPattern |= 64;
465 if (lastRedoGroupWhenSaved == redoLast) {
466 currentPattern |= 128;
471 qCDebug(LOG_KTE) <<
"Pattern:" <<
static_cast<unsigned int>(currentPattern);
473 for (uint patternIndex = 0; patternIndex < patternCount; ++patternIndex) {
474 if (currentPattern == patterns[patternIndex]) {
476 m_document->setModified(
false);
480 qCDebug(LOG_KTE) <<
"setting modified to false!";
486void KateUndoManager::clearUndo()
490 lastUndoGroupWhenSaved =
nullptr;
491 docWasSavedWhenUndoWasEmpty =
false;
496void KateUndoManager::clearRedo()
500 lastRedoGroupWhenSaved =
nullptr;
501 docWasSavedWhenRedoWasEmpty =
false;
506void KateUndoManager::setModified(
bool modified)
509 if (!undoItems.empty()) {
510 lastUndoGroupWhenSaved = &undoItems.back();
513 if (!redoItems.empty()) {
514 lastRedoGroupWhenSaved = &redoItems.back();
517 docWasSavedWhenUndoWasEmpty = undoItems.empty();
518 docWasSavedWhenRedoWasEmpty = redoItems.empty();
522void KateUndoManager::updateLineModifications()
526 undoGroup.flagSavedAsModified();
530 undoGroup.flagSavedAsModified();
534 QBitArray lines(document()->lines(),
false);
535 for (
int i = undoItems.size() - 1; i >= 0; --i) {
536 undoItems[i].markRedoAsSaved(lines);
540 for (
int i = redoItems.size() - 1; i >= 0; --i) {
541 redoItems[i].markUndoAsSaved(lines);
547 Q_ASSERT(!m_editCurrentUndo.has_value());
548 if (!undoItems.empty()) {
557 Q_ASSERT(!m_editCurrentUndo.has_value());
558 if (!undoItems.empty()) {
559 undoItems.back().redoCursor();
564void KateUndoManager::updateConfig()
571 m_undoComplexMerge = allow;
574KTextEditor::ViewPrivate *KateUndoManager::activeView()
576 return static_cast<KTextEditor::ViewPrivate *
>(m_document->activeView());
579#include "moc_kateundomanager.cpp"
The Cursor represents a position in a Document.
static constexpr Cursor invalid() noexcept
Returns an invalid cursor.
Backend of KTextEditor::Document related public KTextEditor interfaces.
QByteArray checksum() const override
Returns a git compatible sha1 checksum of this document on disk.
bool editStart()
Enclose editor actions with editStart() and editEnd() to group them.
bool editEnd()
End a editor operation.
A KParts derived class representing a text document.
void viewCreated(KTextEditor::Document *document, KTextEditor::View *view)
This signal is emitted whenever the document creates a new view.
void aboutToReload(KTextEditor::Document *document)
Warn anyone listening that the current document is about to reload.
An object representing a section of text, from one Cursor to another.
static constexpr Range invalid() noexcept
Returns an invalid range.
A text widget with KXMLGUIClient that represents a Document.
void cursorPositionChanged(KTextEditor::View *view, KTextEditor::Cursor newPosition)
This signal is emitted whenever the view's cursor position changed.
Class to manage a group of undo items.
void setRedoCursor(const KTextEditor::Cursor cursor)
Set the redo cursor to cursor.
void setUndoCursor(const KTextEditor::Cursor cursor)
Set the undo cursor to cursor.
void slotLineInserted(int line, const QString &s)
Notify KateUndoManager that a line was inserted.
void slotLineUnWrapped(int line, int col, int length, bool lineRemoved, const Kate::TextLine &tl, const Kate::TextLine &nextLine)
Notify KateUndoManager that a line was un-wrapped.
void slotLineRemoved(int line, const QString &s, const Kate::TextLine &tl)
Notify KateUndoManager that a line was removed.
KateUndoManager(KTextEditor::DocumentPrivate *doc)
Creates a clean undo history.
void setUndoRedoCursorsOfLastGroup(const KTextEditor::Cursor undoCursor, const KTextEditor::Cursor redoCursor)
Used by the swap file recovery, this function afterwards manipulates the undo/redo cursors of the las...
void setAllowComplexMerge(bool allow)
Allows or disallows merging of "complex" undo groups.
void slotTextRemoved(int line, int col, const QString &s, const Kate::TextLine &tl)
Notify KateUndoManager that text was removed.
void redo()
Redo the latest undo group.
KTEXTEDITOR_EXPORT void undoSafePoint()
Prevent latest KateUndoGroup from being merged with the next one.
KTextEditor::Cursor lastRedoCursor() const
Returns the redo cursor of the last undo group.
void slotMarkLineAutoWrapped(int line, bool autowrapped)
Notify KateUndoManager that a line was marked as autowrapped.
void slotTextInserted(int line, int col, const QString &s, const Kate::TextLine &tl)
Notify KateUndoManager that text was inserted.
uint redoCount() const
Returns how many redo() actions can be performed.
void undo()
Undo the latest undo group.
uint undoCount() const
Returns how many undo() actions can be performed.
void editEnd()
Notify KateUndoManager about the end of an edit.
void slotLineWrapped(int line, int col, int length, bool newLine, const Kate::TextLine &tl)
Notify KateUndoManager that a line was wrapped.
void editStart()
Notify KateUndoManager about the beginning of an edit.
Class representing a single text line.
int length() const
Returns the line's length.
bool isEmpty() const const
QFlags< T > & setFlag(Enum flag, bool on)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool isEmpty() const const