• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • applications API Reference
  • KDE Home
  • Contact Us
 

Kate

  • kde-4.14
  • applications
  • kate
  • part
  • undo
kateundomanager.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 2009-2010 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 */
18 #include "kateundomanager.h"
19 
20 #include <ktexteditor/view.h>
21 
22 #include "katedocument.h"
23 #include "katemodifiedundo.h"
24 
25 #include <QBitArray>
26 
27 KateUndoManager::KateUndoManager (KateDocument *doc)
28  : QObject (doc)
29  , m_document (doc)
30  , m_undoComplexMerge (false)
31  , m_isActive (true)
32  , m_editCurrentUndo (0)
33  , lastUndoGroupWhenSaved(0)
34  , lastRedoGroupWhenSaved(0)
35  , docWasSavedWhenUndoWasEmpty(true)
36  , docWasSavedWhenRedoWasEmpty(true)
37 {
38  connect(this, SIGNAL(undoEnd(KTextEditor::Document*)), this, SIGNAL(undoChanged()));
39  connect(this, SIGNAL(redoEnd(KTextEditor::Document*)), this, SIGNAL(undoChanged()));
40 
41  connect(doc, SIGNAL(viewCreated(KTextEditor::Document*,KTextEditor::View*)), SLOT(viewCreated(KTextEditor::Document*,KTextEditor::View*)));
42 }
43 
44 KateUndoManager::~KateUndoManager()
45 {
46  delete m_editCurrentUndo;
47 
48  // cleanup the undo/redo items, very important, truee :/
49  qDeleteAll(undoItems);
50  undoItems.clear();
51  qDeleteAll(redoItems);
52  redoItems.clear();
53 }
54 
55 KTextEditor::Document *KateUndoManager::document()
56 {
57  return m_document;
58 }
59 
60 void KateUndoManager::viewCreated (KTextEditor::Document *, KTextEditor::View *newView)
61 {
62  connect(newView, SIGNAL(cursorPositionChanged(KTextEditor::View*,KTextEditor::Cursor)), SLOT(undoCancel()));
63 }
64 
65 void KateUndoManager::editStart()
66 {
67  if (!m_isActive)
68  return;
69 
70  // editStart() and editEnd() must be called in alternating fashion
71  Q_ASSERT(m_editCurrentUndo == 0); // make sure to enter a clean state
72 
73  const KTextEditor::Cursor cursorPosition = activeView() ? activeView()->cursorPosition() : KTextEditor::Cursor::invalid();
74  const KTextEditor::Range selectionRange = activeView() ? activeView()->selectionRange() : KTextEditor::Range::invalid();
75 
76  // new current undo item
77  m_editCurrentUndo = new KateUndoGroup(this, cursorPosition, selectionRange);
78 
79  Q_ASSERT(m_editCurrentUndo != 0); // a new undo group must be created by this method
80 }
81 
82 void KateUndoManager::editEnd()
83 {
84  if (!m_isActive)
85  return;
86 
87  // editStart() and editEnd() must be called in alternating fashion
88  Q_ASSERT(m_editCurrentUndo != 0); // an undo group must have been created by editStart()
89 
90  const KTextEditor::Cursor cursorPosition = activeView() ? activeView()->cursorPosition() : KTextEditor::Cursor::invalid();
91  const KTextEditor::Range selectionRange = activeView() ? activeView()->selectionRange() : KTextEditor::Range::invalid();
92 
93  m_editCurrentUndo->editEnd(cursorPosition, selectionRange);
94 
95  bool changedUndo = false;
96 
97  if (m_editCurrentUndo->isEmpty()) {
98  delete m_editCurrentUndo;
99  } else if (!undoItems.isEmpty()
100  && undoItems.last()->merge(m_editCurrentUndo, m_undoComplexMerge)) {
101  delete m_editCurrentUndo;
102  } else {
103  undoItems.append(m_editCurrentUndo);
104  changedUndo = true;
105  }
106 
107  m_editCurrentUndo = 0L;
108 
109  if (changedUndo)
110  emit undoChanged();
111 
112  Q_ASSERT(m_editCurrentUndo == 0); // must be 0 after calling this method
113 }
114 
115 void KateUndoManager::inputMethodStart()
116 {
117  setActive(false);
118  m_document->editStart();
119 }
120 
121 void KateUndoManager::inputMethodEnd()
122 {
123  m_document->editEnd();
124  setActive(true);
125 }
126 
127 void KateUndoManager::startUndo()
128 {
129  setActive(false);
130  m_document->editStart();
131 }
132 
133 void KateUndoManager::endUndo()
134 {
135  m_document->editEnd();
136  setActive(true);
137 }
138 
139 void KateUndoManager::slotTextInserted(int line, int col, const QString &s)
140 {
141  if (m_editCurrentUndo != 0) // do we care about notifications?
142  addUndoItem(new KateModifiedInsertText(m_document, line, col, s));
143 }
144 
145 void KateUndoManager::slotTextRemoved(int line, int col, const QString &s)
146 {
147  if (m_editCurrentUndo != 0) // do we care about notifications?
148  addUndoItem(new KateModifiedRemoveText(m_document, line, col, s));
149 }
150 
151 void KateUndoManager::slotMarkLineAutoWrapped(int line, bool autowrapped)
152 {
153  if (m_editCurrentUndo != 0) // do we care about notifications?
154  addUndoItem(new KateEditMarkLineAutoWrappedUndo(m_document, line, autowrapped));
155 }
156 
157 void KateUndoManager::slotLineWrapped(int line, int col, int length, bool newLine)
158 {
159  if (m_editCurrentUndo != 0) // do we care about notifications?
160  addUndoItem(new KateModifiedWrapLine(m_document, line, col, length, newLine));
161 }
162 
163 void KateUndoManager::slotLineUnWrapped(int line, int col, int length, bool lineRemoved)
164 {
165  if (m_editCurrentUndo != 0) // do we care about notifications?
166  addUndoItem(new KateModifiedUnWrapLine(m_document, line, col, length, lineRemoved));
167 }
168 
169 void KateUndoManager::slotLineInserted(int line, const QString &s)
170 {
171  if (m_editCurrentUndo != 0) // do we care about notifications?
172  addUndoItem(new KateModifiedInsertLine(m_document, line, s));
173 }
174 
175 void KateUndoManager::slotLineRemoved(int line, const QString &s)
176 {
177  if (m_editCurrentUndo != 0) // do we care about notifications?
178  addUndoItem(new KateModifiedRemoveLine(m_document, line, s));
179 }
180 
181 void KateUndoManager::undoCancel()
182 {
183  // Don't worry about this when an edit is in progress
184  if (m_document->isEditRunning())
185  return;
186 
187  undoSafePoint();
188 }
189 
190 void KateUndoManager::undoSafePoint() {
191  KateUndoGroup *undoGroup = m_editCurrentUndo;
192 
193  if (undoGroup == 0 && !undoItems.isEmpty())
194  undoGroup = undoItems.last();
195 
196  if (undoGroup == 0)
197  return;
198 
199  undoGroup->safePoint();
200 }
201 
202 void KateUndoManager::addUndoItem(KateUndo *undo)
203 {
204  Q_ASSERT(undo != 0); // don't add null pointers to our history
205  Q_ASSERT(m_editCurrentUndo != 0); // make sure there is an undo group for our item
206 
207  m_editCurrentUndo->addItem(undo);
208 
209  // Clear redo buffer
210  qDeleteAll(redoItems);
211  redoItems.clear();
212 }
213 
214 void KateUndoManager::setActive(bool enabled)
215 {
216  Q_ASSERT(m_editCurrentUndo == 0); // must not already be in edit mode
217  Q_ASSERT(m_isActive != enabled);
218 
219  m_isActive = enabled;
220 
221  emit isActiveChanged(enabled);
222 }
223 
224 uint KateUndoManager::undoCount () const
225 {
226  return undoItems.count ();
227 }
228 
229 uint KateUndoManager::redoCount () const
230 {
231  return redoItems.count ();
232 }
233 
234 void KateUndoManager::undo()
235 {
236  Q_ASSERT(m_editCurrentUndo == 0); // undo is not supported while we care about notifications (call editEnd() first)
237 
238  if (undoItems.count() > 0)
239  {
240  emit undoStart(document());
241 
242  undoItems.last()->undo(activeView());
243  redoItems.append (undoItems.last());
244  undoItems.removeLast ();
245  updateModified();
246 
247  emit undoEnd(document());
248  }
249 }
250 
251 void KateUndoManager::redo()
252 {
253  Q_ASSERT(m_editCurrentUndo == 0); // redo is not supported while we care about notifications (call editEnd() first)
254 
255  if (redoItems.count() > 0)
256  {
257  emit redoStart(document());
258 
259  redoItems.last()->redo(activeView());
260  undoItems.append (redoItems.last());
261  redoItems.removeLast ();
262  updateModified();
263 
264  emit redoEnd(document());
265  }
266 }
267 
268 void KateUndoManager::updateModified()
269 {
270  /*
271  How this works:
272 
273  After noticing that there where to many scenarios to take into
274  consideration when using 'if's to toggle the "Modified" flag
275  I came up with this baby, flexible and repetitive calls are
276  minimal.
277 
278  A numeric unique pattern is generated by toggling a set of bits,
279  each bit symbolizes a different state in the Undo Redo structure.
280 
281  undoItems.isEmpty() != null BIT 1
282  redoItems.isEmpty() != null BIT 2
283  docWasSavedWhenUndoWasEmpty == true BIT 3
284  docWasSavedWhenRedoWasEmpty == true BIT 4
285  lastUndoGroupWhenSavedIsLastUndo BIT 5
286  lastUndoGroupWhenSavedIsLastRedo BIT 6
287  lastRedoGroupWhenSavedIsLastUndo BIT 7
288  lastRedoGroupWhenSavedIsLastRedo BIT 8
289 
290  If you find a new pattern, please add it to the patterns array
291  */
292 
293  unsigned char currentPattern = 0;
294  const unsigned char patterns[] = {5,16,21,24,26,88,90,93,133,144,149,154,165};
295  const unsigned char patternCount = sizeof(patterns);
296  KateUndoGroup* undoLast = 0;
297  KateUndoGroup* redoLast = 0;
298 
299  if (undoItems.isEmpty())
300  {
301  currentPattern |= 1;
302  }
303  else
304  {
305  undoLast = undoItems.last();
306  }
307 
308  if (redoItems.isEmpty())
309  {
310  currentPattern |= 2;
311  }
312  else
313  {
314  redoLast = redoItems.last();
315  }
316 
317  if (docWasSavedWhenUndoWasEmpty) currentPattern |= 4;
318  if (docWasSavedWhenRedoWasEmpty) currentPattern |= 8;
319  if (lastUndoGroupWhenSaved == undoLast) currentPattern |= 16;
320  if (lastUndoGroupWhenSaved == redoLast) currentPattern |= 32;
321  if (lastRedoGroupWhenSaved == undoLast) currentPattern |= 64;
322  if (lastRedoGroupWhenSaved == redoLast) currentPattern |= 128;
323 
324  // This will print out the pattern information
325 
326  kDebug() << "Pattern:" << static_cast<unsigned int>(currentPattern);
327 
328  for (uint patternIndex = 0; patternIndex < patternCount; ++patternIndex)
329  {
330  if ( currentPattern == patterns[patternIndex] )
331  {
332  // Note: m_document->setModified() calls KateUndoManager::setModified!
333  m_document->setModified( false );
334  // (dominik) whenever the doc is not modified, succeeding edits
335  // should not be merged
336  undoSafePoint();
337  kDebug() << "setting modified to false!";
338  break;
339  }
340  }
341 }
342 
343 void KateUndoManager::clearUndo()
344 {
345  qDeleteAll(undoItems);
346  undoItems.clear ();
347 
348  lastUndoGroupWhenSaved = 0;
349  docWasSavedWhenUndoWasEmpty = false;
350 
351  emit undoChanged ();
352 }
353 
354 void KateUndoManager::clearRedo()
355 {
356  qDeleteAll(redoItems);
357  redoItems.clear ();
358 
359  lastRedoGroupWhenSaved = 0;
360  docWasSavedWhenRedoWasEmpty = false;
361 
362  emit undoChanged ();
363 }
364 
365 void KateUndoManager::setModified(bool modified)
366 {
367  if ( !modified )
368  {
369  if ( ! undoItems.isEmpty() ) {
370  lastUndoGroupWhenSaved = undoItems.last();
371  }
372 
373  if ( ! redoItems.isEmpty() ) {
374  lastRedoGroupWhenSaved = redoItems.last();
375  }
376 
377  docWasSavedWhenUndoWasEmpty = undoItems.isEmpty();
378  docWasSavedWhenRedoWasEmpty = redoItems.isEmpty();
379  }
380 }
381 
382 void KateUndoManager::updateLineModifications()
383 {
384  // change LineSaved flag of all undo & redo items to LineModified
385  foreach (KateUndoGroup* undoGroup, undoItems)
386  undoGroup->flagSavedAsModified();
387 
388  foreach (KateUndoGroup* undoGroup, redoItems)
389  undoGroup->flagSavedAsModified();
390 
391  // iterate all undo/redo items to find out, which item sets the flag LineSaved
392  QBitArray lines(document()->lines(), false);
393  for (int i = undoItems.size() - 1; i >= 0; --i) {
394  undoItems[i]->markRedoAsSaved(lines);
395  }
396 
397  lines.fill(false);
398  for (int i = redoItems.size() - 1; i >= 0; --i) {
399  redoItems[i]->markUndoAsSaved(lines);
400  }
401 }
402 
403 void KateUndoManager::setUndoRedoCursorsOfLastGroup(const KTextEditor::Cursor undoCursor,
404  const KTextEditor::Cursor redoCursor)
405 {
406  Q_ASSERT(m_editCurrentUndo == 0);
407  if (undoItems.size()) {
408  KateUndoGroup * last = undoItems.last();
409  last->setUndoCursor(undoCursor);
410  last->setRedoCursor(redoCursor);
411  }
412 }
413 
414 KTextEditor::Cursor KateUndoManager::lastRedoCursor() const
415 {
416  Q_ASSERT(m_editCurrentUndo == 0);
417  if (undoItems.size()) {
418  KateUndoGroup * last = undoItems.last();
419  return last->redoCursor();
420  }
421  return KTextEditor::Cursor::invalid();
422 }
423 
424 void KateUndoManager::updateConfig ()
425 {
426  emit undoChanged ();
427 }
428 
429 void KateUndoManager::setAllowComplexMerge(bool allow)
430 {
431  m_undoComplexMerge = allow;
432 }
433 
434 KTextEditor::View* KateUndoManager::activeView()
435 {
436  return m_document->activeView();
437 }
438 
439 // kate: space-indent on; indent-width 2; replace-tabs on;
QList::clear
void clear()
KateUndoManager::setModified
void setModified(bool modified)
Definition: kateundomanager.cpp:365
KateUndoManager::undoStart
void undoStart(KTextEditor::Document *)
KateUndoGroup::addItem
void addItem(KateUndo *u)
add an undo item
Definition: kateundo.cpp:305
KateUndoManager::slotTextInserted
void slotTextInserted(int line, int col, const QString &s)
Notify KateUndoManager that text was inserted.
Definition: kateundomanager.cpp:139
KateUndoGroup::setUndoCursor
void setUndoCursor(const KTextEditor::Cursor &cursor)
Set the undo cursor to cursor.
Definition: kateundo.h:434
KateUndoManager::redo
void redo()
Redo the latest undo group.
Definition: kateundomanager.cpp:251
KateUndoManager::inputMethodStart
void inputMethodStart()
Definition: kateundomanager.cpp:115
KateDocument::activeView
virtual KTextEditor::View * activeView() const
Definition: katedocument.h:156
KateModifiedRemoveText
Definition: katemodifiedundo.h:45
KateUndoManager::editEnd
void editEnd()
Notify KateUndoManager about the end of an edit.
Definition: kateundomanager.cpp:82
katedocument.h
KateUndoGroup::isEmpty
bool isEmpty() const
is this undogroup empty?
Definition: kateundo.h:421
KateModifiedInsertLine
Definition: katemodifiedundo.h:102
KateUndoManager::slotTextRemoved
void slotTextRemoved(int line, int col, const QString &s)
Notify KateUndoManager that text was removed.
Definition: kateundomanager.cpp:145
katemodifiedundo.h
KateUndoManager::inputMethodEnd
void inputMethodEnd()
Definition: kateundomanager.cpp:121
KateModifiedRemoveLine
Definition: katemodifiedundo.h:120
QList::size
int size() const
KateUndoGroup
Class to manage a group of undo items.
Definition: kateundo.h:378
KateUndoGroup::setRedoCursor
void setRedoCursor(const KTextEditor::Cursor &cursor)
Set the redo cursor to cursor.
Definition: kateundo.h:440
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
KateUndoManager::endUndo
void endUndo()
Definition: kateundomanager.cpp:133
KateUndoManager::document
KTextEditor::Document * document()
Definition: kateundomanager.cpp:55
KateUndoManager::startUndo
void startUndo()
Definition: kateundomanager.cpp:127
QObject
KateUndoManager::slotLineInserted
void slotLineInserted(int line, const QString &s)
Notify KateUndoManager that a line was inserted.
Definition: kateundomanager.cpp:169
QList::isEmpty
bool isEmpty() const
KateUndoGroup::redoCursor
const KTextEditor::Cursor & redoCursor() const
Definition: kateundo.h:443
KateUndoManager::setUndoRedoCursorsOfLastGroup
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...
Definition: kateundomanager.cpp:403
KateUndoManager::clearRedo
void clearRedo()
Definition: kateundomanager.cpp:354
QString
KateDocument::setModified
virtual void setModified(bool m)
Definition: katedocument.cpp:2484
QBitArray
KateDocument::isEditRunning
bool isEditRunning() const
Definition: katedocument.cpp:4717
KateUndoManager::redoCount
uint redoCount() const
Returns how many redo() actions can be performed.
Definition: kateundomanager.cpp:229
KateDocument
Definition: katedocument.h:74
KateUndoManager::updateLineModifications
void updateLineModifications()
Definition: kateundomanager.cpp:382
KateUndoGroup::editEnd
void editEnd(const KTextEditor::Cursor &cursorPosition, const KTextEditor::Range selectionRange)
Definition: kateundo.cpp:299
KateModifiedInsertText
Definition: katemodifiedundo.h:26
KateUndoGroup::flagSavedAsModified
void flagSavedAsModified()
Change all LineSaved flags to LineModified of the line modification system.
Definition: kateundo.cpp:345
KateUndoManager::undoSafePoint
void undoSafePoint()
Prevent latest KateUndoGroup from being merged with the next one.
Definition: kateundomanager.cpp:190
KateUndoManager::undoEnd
void undoEnd(KTextEditor::Document *)
KateModifiedWrapLine
Definition: katemodifiedundo.h:64
KateUndoManager::redoEnd
void redoEnd(KTextEditor::Document *)
KateUndoManager::~KateUndoManager
~KateUndoManager()
Definition: kateundomanager.cpp:44
KateUndoManager::KateUndoManager
KateUndoManager(KateDocument *doc)
Creates a clean undo history.
Definition: kateundomanager.cpp:27
KateUndoGroup::safePoint
void safePoint(bool safePoint=true)
set group as as savepoint.
Definition: kateundo.cpp:340
KateUndoManager::lastRedoCursor
KTextEditor::Cursor lastRedoCursor() const
Returns the redo cursor of the last undo group.
Definition: kateundomanager.cpp:414
KateDocument::editEnd
void editEnd()
End a editor operation.
Definition: katedocument.cpp:796
QList::last
T & last()
KateUndoManager::clearUndo
void clearUndo()
Definition: kateundomanager.cpp:343
QList::removeLast
void removeLast()
KateUndoManager::isActiveChanged
void isActiveChanged(bool enabled)
KateUndoManager::undoChanged
void undoChanged()
KateUndoManager::undo
void undo()
Undo the latest undo group.
Definition: kateundomanager.cpp:234
kateundomanager.h
KateUndoManager::slotLineWrapped
void slotLineWrapped(int line, int col, int length, bool newLine)
Notify KateUndoManager that a line was wrapped.
Definition: kateundomanager.cpp:157
KateEditMarkLineAutoWrappedUndo
Definition: kateundo.h:230
QBitArray::fill
bool fill(bool value, int size)
KateUndoManager::slotMarkLineAutoWrapped
void slotMarkLineAutoWrapped(int line, bool autowrapped)
Notify KateUndoManager that a line was marked as autowrapped.
Definition: kateundomanager.cpp:151
KateUndoManager::redoStart
void redoStart(KTextEditor::Document *)
KateUndo
Base class for Kate undo commands.
Definition: kateundo.h:41
KateUndoManager::undoCount
uint undoCount() const
Returns how many undo() actions can be performed.
Definition: kateundomanager.cpp:224
KateDocument::editStart
void editStart()
Enclose editor actions with editStart() and editEnd() to group them.
Definition: katedocument.cpp:776
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KateUndoManager::setAllowComplexMerge
void setAllowComplexMerge(bool allow)
Allows or disallows merging of "complex" undo groups.
Definition: kateundomanager.cpp:429
KateUndoManager::updateConfig
void updateConfig()
Definition: kateundomanager.cpp:424
KateUndoManager::editStart
void editStart()
Notify KateUndoManager about the beginning of an edit.
Definition: kateundomanager.cpp:65
KateUndoManager::slotLineRemoved
void slotLineRemoved(int line, const QString &s)
Notify KateUndoManager that a line was removed.
Definition: kateundomanager.cpp:175
KateModifiedUnWrapLine
Definition: katemodifiedundo.h:83
KateUndoManager::slotLineUnWrapped
void slotLineUnWrapped(int line, int col, int length, bool lineRemoved)
Notify KateUndoManager that a line was un-wrapped.
Definition: kateundomanager.cpp:163
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat May 9 2020 03:56:58 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

applications API Reference

Skip menu "applications API Reference"
  •   kate
  •       kate
  •   KTextEditor
  •   Kate
  • Konsole

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal