• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

kateundomanager.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2009 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 #include "kateundomanager.h"
00019 
00020 #include "katedocument.h"
00021 #include "kateview.h"
00022 #include "katesearchbar.h"
00023 #include "kateundo.h"
00024 
00025 KateUndoManager::KateUndoManager (KateDocument *doc)
00026   : QObject (doc)
00027   , m_document (doc)
00028   , m_undoComplexMerge (false)
00029   , m_isUndoTrackingEnabled (true)
00030   , m_editCurrentUndo (0)
00031   , m_undoDontMerge (false)
00032   , lastUndoGroupWhenSaved(0)
00033   , lastRedoGroupWhenSaved(0)
00034   , docWasSavedWhenUndoWasEmpty(true)
00035   , docWasSavedWhenRedoWasEmpty(true)
00036 {
00037   connect(this, SIGNAL(undoChanged()), m_document, SIGNAL(undoChanged()));
00038   connect(doc, SIGNAL(viewCreated(KTextEditor::Document*, KTextEditor::View*)), SLOT(viewCreated(KTextEditor::Document*, KTextEditor::View*)));
00039 }
00040 
00041 KateUndoManager::~KateUndoManager()
00042 {
00043   delete m_editCurrentUndo;
00044 
00045   // cleanup the undo/redo items, very important, truee :/
00046   qDeleteAll(undoItems);
00047   undoItems.clear();
00048   qDeleteAll(redoItems);
00049   redoItems.clear();
00050 }
00051 
00052 KateDocument *KateUndoManager::document()
00053 {
00054   return m_document;
00055 }
00056 
00057 void KateUndoManager::viewCreated (KTextEditor::Document *, KTextEditor::View *newView)
00058 {
00059   connect(newView, SIGNAL(cursorPositionChanged(KTextEditor::View*, const KTextEditor::Cursor&)), SLOT(undoCancel()));
00060 }
00061 
00062 void KateUndoManager::editStart()
00063 {
00064   if (!m_isUndoTrackingEnabled)
00065     return;
00066 
00067   // editStart() and editEnd() must be called in alternating fashion
00068   Q_ASSERT(m_editCurrentUndo == 0); // make sure to enter a clean state
00069 
00070   // new current undo item
00071   m_editCurrentUndo = new KateUndoGroup(this);
00072 
00073   Q_ASSERT(m_editCurrentUndo != 0); // a new undo group must be created by this method
00074 }
00075 
00076 void KateUndoManager::editEnd()
00077 {
00078   if (!m_isUndoTrackingEnabled)
00079     return;
00080 
00081   // editStart() and editEnd() must be called in alternating fashion
00082   Q_ASSERT(m_editCurrentUndo != 0); // an undo group must have been created by editStart()
00083 
00084     bool changedUndo = false;
00085 
00086     m_editCurrentUndo->editEnd();
00087 
00088     if (m_editCurrentUndo->isEmpty()) {
00089       delete m_editCurrentUndo;
00090     } else if (!m_undoDontMerge
00091         && !undoItems.isEmpty()
00092         && undoItems.last()->merge(m_editCurrentUndo, m_undoComplexMerge)) {
00093       delete m_editCurrentUndo;
00094     } else {
00095       undoItems.append(m_editCurrentUndo);
00096       changedUndo = true;
00097     }
00098 
00099     m_undoDontMerge = false;
00100 
00101     m_editCurrentUndo = 0L;
00102 
00103     if (changedUndo)
00104       emit undoChanged();
00105 
00106   Q_ASSERT(m_editCurrentUndo == 0); // must be 0 after calling this method
00107 }
00108 
00109 void KateUndoManager::inputMethodStart()
00110 {
00111   setUndoTrackingEnabled(false);
00112   m_document->editStart();
00113 }
00114 
00115 void KateUndoManager::inputMethodEnd()
00116 {
00117   m_document->editEnd();
00118   setUndoTrackingEnabled(true);
00119 }
00120 
00121 void KateUndoManager::undoStart()
00122 {
00123   setUndoTrackingEnabled(false);
00124   m_document->editStart();
00125 }
00126 
00127 void KateUndoManager::undoEnd()
00128 {
00129   m_document->editEnd();
00130   setUndoTrackingEnabled(true);
00131 }
00132 
00133 void KateUndoManager::slotTextInserted(int line, int col, const QString &s)
00134 {
00135   if (m_editCurrentUndo != 0) // do we care about notifications?
00136     addUndoItem(new KateEditInsertTextUndo(m_document, line, col, s));
00137 }
00138 
00139 void KateUndoManager::slotTextRemoved(int line, int col, const QString &s)
00140 {
00141   if (m_editCurrentUndo != 0) // do we care about notifications?
00142     addUndoItem(new KateEditRemoveTextUndo(m_document, line, col, s));
00143 }
00144 
00145 void KateUndoManager::slotMarkLineAutoWrapped(int line, bool autowrapped)
00146 {
00147   if (m_editCurrentUndo != 0) // do we care about notifications?
00148     addUndoItem(new KateEditMarkLineAutoWrappedUndo(m_document, line, autowrapped));
00149 }
00150 
00151 void KateUndoManager::slotLineWrapped(int line, int col, int pos, bool newLine)
00152 {
00153   if (m_editCurrentUndo != 0) // do we care about notifications?
00154     addUndoItem(new KateEditWrapLineUndo(m_document, line, col, pos, newLine));
00155 }
00156 
00157 void KateUndoManager::slotLineUnWrapped(int line, int col, int length, bool lineRemoved)
00158 {
00159   if (m_editCurrentUndo != 0) // do we care about notifications?
00160     addUndoItem(new KateEditUnWrapLineUndo(m_document, line, col, length, lineRemoved));
00161 }
00162 
00163 void KateUndoManager::slotLineInserted(int line, const QString &s)
00164 {
00165   if (m_editCurrentUndo != 0) // do we care about notifications?
00166     addUndoItem(new KateEditInsertLineUndo(m_document, line, s));
00167 }
00168 
00169 void KateUndoManager::slotLineRemoved(int line, const QString &s)
00170 {
00171   if (m_editCurrentUndo != 0) // do we care about notifications?
00172     addUndoItem(new KateEditRemoveLineUndo(m_document, line, s));
00173 }
00174 
00175 void KateUndoManager::undoCancel()
00176 {
00177   // Don't worry about this when an edit is in progress
00178   if (m_document->isEditRunning())
00179     return;
00180 
00181   m_undoDontMerge = true;
00182 
00183   Q_ASSERT(m_editCurrentUndo == 0);
00184 }
00185 
00186 void KateUndoManager::undoSafePoint() {
00187   Q_ASSERT(m_editCurrentUndo != 0); // call this method only in between editStart() and editEnd()
00188 
00189   m_editCurrentUndo->safePoint();
00190 }
00191 
00192 void KateUndoManager::addUndoItem(KateUndo *undo)
00193 {
00194   Q_ASSERT(undo != 0); // don't add null pointers to our history
00195   Q_ASSERT(m_editCurrentUndo != 0); // make sure there is an undo group for our item
00196 
00197   m_editCurrentUndo->addItem(undo);
00198 
00199   // Clear redo buffer
00200   qDeleteAll(redoItems);
00201   redoItems.clear();
00202 }
00203 
00204 void KateUndoManager::setUndoTrackingEnabled(bool enabled)
00205 {
00206   Q_ASSERT(m_editCurrentUndo == 0); // must not already be in edit mode
00207   Q_ASSERT(m_isUndoTrackingEnabled != enabled);
00208 
00209   m_isUndoTrackingEnabled = enabled;
00210 
00211   emit undoTrackingEnabledChanged(enabled);
00212 }
00213 
00214 uint KateUndoManager::undoCount () const
00215 {
00216   return undoItems.count ();
00217 }
00218 
00219 uint KateUndoManager::redoCount () const
00220 {
00221   return redoItems.count ();
00222 }
00223 
00224 void KateUndoManager::undo()
00225 {
00226   Q_ASSERT(m_editCurrentUndo == 0); // undo is not supported while we care about notifications (call editEnd() first)
00227 
00228   if (undoItems.count() > 0)
00229   {
00230     //clearSelection ();
00231     /*Disable searchbar highlights due to performance issue
00232      * if undoGroup contains n items, and there're m search highlight regions,
00233      * the total cost is n*m*log(m),
00234      * to undo a simple Replace operation, n=2*m 
00235      * (replace contains both delete and insert undoItem, assume the replaced regions are highlighted),
00236      * cost = 2*m^2*log(m), too high
00237      * since there's a qStableSort inside KTextEditor::SmartRegion::rebuildChildStruct()
00238      */
00239     foreach (KTextEditor::View *v, m_document->views()) {
00240       KateView *view = qobject_cast<KateView*>(v);
00241 
00242       if (view->searchBar(false))
00243         view->searchBar(false)->enableHighlights(false);
00244     }
00245 
00246     undoItems.last()->undo();
00247     redoItems.append (undoItems.last());
00248     undoItems.removeLast ();
00249     updateModified();
00250     emit undoChanged ();
00251   }
00252 }
00253 
00254 void KateUndoManager::redo()
00255 {
00256   Q_ASSERT(m_editCurrentUndo == 0); // redo is not supported while we care about notifications (call editEnd() first)
00257 
00258   if (redoItems.count() > 0)
00259   {
00260     //clearSelection ();
00261     //Disable searchbar highlights due to performance issue, see ::undo()'s comment
00262     foreach (KTextEditor::View *v, m_document->views()) {
00263       KateView *view = qobject_cast<KateView*>(v);
00264 
00265       if (view->searchBar(false))
00266         view->searchBar(false)->enableHighlights(false);
00267     }
00268 
00269     redoItems.last()->redo();
00270     undoItems.append (redoItems.last());
00271     redoItems.removeLast ();
00272     updateModified();
00273 
00274     emit undoChanged ();
00275   }
00276 }
00277 
00278 void KateUndoManager::updateModified()
00279 {
00280   /*
00281   How this works:
00282 
00283     After noticing that there where to many scenarios to take into
00284     consideration when using 'if's to toggle the "Modified" flag
00285     I came up with this baby, flexible and repetitive calls are
00286     minimal.
00287 
00288     A numeric unique pattern is generated by toggling a set of bits,
00289     each bit symbolizes a different state in the Undo Redo structure.
00290 
00291       undoItems.isEmpty() != null          BIT 1
00292       redoItems.isEmpty() != null          BIT 2
00293       docWasSavedWhenUndoWasEmpty == true  BIT 3
00294       docWasSavedWhenRedoWasEmpty == true  BIT 4
00295       lastUndoGroupWhenSavedIsLastUndo     BIT 5
00296       lastUndoGroupWhenSavedIsLastRedo     BIT 6
00297       lastRedoGroupWhenSavedIsLastUndo     BIT 7
00298       lastRedoGroupWhenSavedIsLastRedo     BIT 8
00299 
00300     If you find a new pattern, please add it to the patterns array
00301   */
00302 
00303   unsigned char currentPattern = 0;
00304   const unsigned char patterns[] = {5,16,21,24,26,88,90,93,133,144,149,165};
00305   const unsigned char patternCount = sizeof(patterns);
00306   KateUndoGroup* undoLast = 0;
00307   KateUndoGroup* redoLast = 0;
00308 
00309   if (undoItems.isEmpty())
00310   {
00311     currentPattern |= 1;
00312   }
00313   else
00314   {
00315     undoLast = undoItems.last();
00316   }
00317 
00318   if (redoItems.isEmpty())
00319   {
00320     currentPattern |= 2;
00321   }
00322   else
00323   {
00324     redoLast = redoItems.last();
00325   }
00326 
00327   if (docWasSavedWhenUndoWasEmpty) currentPattern |= 4;
00328   if (docWasSavedWhenRedoWasEmpty) currentPattern |= 8;
00329   if (lastUndoGroupWhenSaved == undoLast) currentPattern |= 16;
00330   if (lastUndoGroupWhenSaved == redoLast) currentPattern |= 32;
00331   if (lastRedoGroupWhenSaved == undoLast) currentPattern |= 64;
00332   if (lastRedoGroupWhenSaved == redoLast) currentPattern |= 128;
00333 
00334   // This will print out the pattern information
00335 
00336   kDebug() << "Pattern:" << static_cast<unsigned int>(currentPattern);
00337 
00338   for (uint patternIndex = 0; patternIndex < patternCount; ++patternIndex)
00339   {
00340     if ( currentPattern == patterns[patternIndex] )
00341     {
00342       m_document->setModified( false );
00343       // (dominik) whenever the doc is not modified, succeeding edits
00344       // should not be merged
00345       setUndoDontMerge(true);
00346       kDebug() << "setting modified to false!";
00347       break;
00348     }
00349   }
00350 }
00351 
00352 void KateUndoManager::clearUndo()
00353 {
00354   qDeleteAll(undoItems);
00355   undoItems.clear ();
00356 
00357   lastUndoGroupWhenSaved = 0;
00358   docWasSavedWhenUndoWasEmpty = false;
00359 
00360   emit undoChanged ();
00361 }
00362 
00363 void KateUndoManager::clearRedo()
00364 {
00365   qDeleteAll(redoItems);
00366   redoItems.clear ();
00367 
00368   lastRedoGroupWhenSaved = 0;
00369   docWasSavedWhenRedoWasEmpty = false;
00370 
00371   emit undoChanged ();
00372 }
00373 
00374 void KateUndoManager::setModified(bool m) {
00375   if ( m == false )
00376   {
00377     if ( ! undoItems.isEmpty() )
00378     {
00379       lastUndoGroupWhenSaved = undoItems.last();
00380     }
00381 
00382     if ( ! redoItems.isEmpty() )
00383     {
00384       lastRedoGroupWhenSaved = redoItems.last();
00385     }
00386 
00387     docWasSavedWhenUndoWasEmpty = undoItems.isEmpty();
00388     docWasSavedWhenRedoWasEmpty = redoItems.isEmpty();
00389   }
00390 }
00391 
00392 void KateUndoManager::updateConfig ()
00393 {
00394   emit undoChanged ();
00395 }
00396 
00397 bool KateUndoManager::undoDontMerge( ) const
00398 {
00399   return m_undoDontMerge;
00400 }
00401 
00402 void KateUndoManager::setAllowComplexMerge(bool allow)
00403 {
00404   m_undoComplexMerge = allow;
00405 }
00406 
00407 bool KateUndoManager::allowComplexMerge() const
00408 {
00409   return m_undoComplexMerge;
00410 }
00411 
00412 void KateUndoManager::setUndoDontMerge(bool dontMerge)
00413 {
00414   m_undoDontMerge = dontMerge;
00415 }
00416 
00417 // kate: space-indent on; indent-width 2; replace-tabs on;

Kate

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  •     Sodep
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal