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

Kate

katetexthistory.cpp

Go to the documentation of this file.
00001 /*  This file is part of the Kate project.
00002  *
00003  *  Copyright (C) 2010 Christoph Cullmann <cullmann@kde.org>
00004  *
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Library General Public
00007  *  License as published by the Free Software Foundation; either
00008  *  version 2 of the License, or (at your option) any later version.
00009  *
00010  *  This library is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  Library General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU Library General Public License
00016  *  along with this library; see the file COPYING.LIB.  If not, write to
00017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  *  Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "katetexthistory.h"
00022 #include "katetextbuffer.h"
00023 
00024 namespace Kate {
00025 
00026 TextHistory::TextHistory (TextBuffer &buffer)
00027   : m_buffer (buffer)
00028   , m_lastSavedRevision (-1)
00029   , m_firstHistoryEntryRevision (0)
00030 {
00031   // just call clear to init
00032   clear ();
00033 }
00034 
00035 TextHistory::~TextHistory ()
00036 {
00037 }
00038 
00039 qint64 TextHistory::revision () const
00040 {
00041   // just output last revisions of buffer
00042   return m_buffer.revision ();
00043 }
00044 
00045 void TextHistory::clear ()
00046 {
00047   // reset last saved revision
00048   m_lastSavedRevision = -1;
00049 
00050   // remove all history entries and add no-change dummy for first revision
00051   m_historyEntries.clear ();
00052   m_historyEntries.push_back (Entry ());
00053 
00054   // first entry will again belong to first revision
00055   m_firstHistoryEntryRevision = 0;
00056 }
00057 
00058 void TextHistory::setLastSavedRevision ()
00059 {
00060   // current revision was succesful saved
00061   m_lastSavedRevision = revision ();
00062 }
00063 
00064 void TextHistory::wrapLine (const KTextEditor::Cursor &position)
00065 {
00066   // create and add new entry
00067   Entry entry;
00068   entry.type = Entry::WrapLine;
00069   entry.line = position.line ();
00070   entry.column = position.column ();
00071   addEntry (entry);
00072 }
00073 
00074 void TextHistory::unwrapLine (int line, int oldLineLength)
00075 {
00076   // create and add new entry
00077   Entry entry;
00078   entry.type = Entry::UnwrapLine;
00079   entry.line = line;
00080   entry.column = 0;
00081   entry.oldLineLength = oldLineLength;
00082   addEntry (entry);
00083 }
00084 
00085 void TextHistory::insertText (const KTextEditor::Cursor &position, int length, int oldLineLength)
00086 {
00087   // create and add new entry
00088   Entry entry;
00089   entry.type = Entry::InsertText;
00090   entry.line = position.line ();
00091   entry.column = position.column ();
00092   entry.length = length;
00093   entry.oldLineLength = oldLineLength;
00094   addEntry (entry);
00095 }
00096 
00097 void TextHistory::removeText (const KTextEditor::Range &range, int oldLineLength)
00098 {
00099   // create and add new entry
00100   Entry entry;
00101   entry.type = Entry::RemoveText;
00102   entry.line = range.start().line ();
00103   entry.column = range.start().column ();
00104   entry.length = range.end().column() - range.start().column();
00105   entry.oldLineLength = oldLineLength;
00106   addEntry (entry);
00107 }
00108 
00109 void TextHistory::addEntry (const Entry &entry)
00110 {
00114   Q_ASSERT (!m_historyEntries.empty ());
00115 
00120   if ((m_historyEntries.size () == 1) && !m_historyEntries.first().referenceCounter) {
00124     m_firstHistoryEntryRevision = revision () + 1;
00125 
00129     m_historyEntries.first() = entry;
00130 
00134     return;
00135   }
00136 
00140   m_historyEntries.push_back (entry);
00141 }
00142 
00143 void TextHistory::lockRevision (qint64 revision)
00144 {
00148   Q_ASSERT (!m_historyEntries.empty ());
00149   Q_ASSERT (revision >= m_firstHistoryEntryRevision);
00150   Q_ASSERT (revision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
00151 
00155   Entry &entry = m_historyEntries[revision - m_firstHistoryEntryRevision];
00156   ++entry.referenceCounter;
00157 }
00158 
00159 void TextHistory::unlockRevision (qint64 revision)
00160 {
00164   Q_ASSERT (!m_historyEntries.empty ());
00165   Q_ASSERT (revision >= m_firstHistoryEntryRevision);
00166   Q_ASSERT (revision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
00167 
00171   Entry &entry = m_historyEntries[revision - m_firstHistoryEntryRevision];
00172   Q_ASSERT (entry.referenceCounter);
00173   --entry.referenceCounter;
00174 
00178   if (!entry.referenceCounter) {
00182     int unreferencedEdits = 0;
00183     for (int i = 0; i + 1 < m_historyEntries.size(); ++i) {
00184       if (m_historyEntries.at(i).referenceCounter)
00185         break;
00186 
00187       // remember deleted count
00188       ++unreferencedEdits;
00189     }
00190 
00194     if (unreferencedEdits > 0) {
00195       // remove stuff from history
00196       m_historyEntries.erase (m_historyEntries.begin(), m_historyEntries.begin() + unreferencedEdits);
00197 
00198       // patch first entry revision
00199       m_firstHistoryEntryRevision += unreferencedEdits;
00200     }
00201   }
00202 }
00203 
00204 void TextHistory::Entry::transformCursor (int &cursorLine, int &cursorColumn, bool moveOnInsert) const
00205 {
00213   if (line > cursorLine)
00214     return;
00215 
00219   switch (type) {
00223     case WrapLine:
00227       if (cursorLine == line) {
00231         if (cursorColumn <= column) {
00232           if (cursorColumn < column || !moveOnInsert)
00233             return;
00234         }
00235 
00239         cursorColumn =  cursorColumn - column;
00240       }
00241 
00245       cursorLine +=  1;
00246       return;
00247 
00251     case UnwrapLine:
00255       if (cursorLine == line)
00256         cursorColumn +=  oldLineLength;
00257 
00261       cursorLine -= 1;
00262       return;
00263 
00267     case InsertText:
00271       if (cursorLine != line)
00272         return;
00273 
00274       // skip cursors with too small column
00275       if (cursorColumn <= column)
00276         if (cursorColumn < column || !moveOnInsert)
00277           return;
00278 
00279       // patch column of cursor
00280       if (cursorColumn <= oldLineLength)
00281         cursorColumn += length;
00282 
00283       // special handling if cursor behind the real line, e.g. non-wrapping cursor in block selection mode
00284       else if (cursorColumn < oldLineLength + length)
00285         cursorColumn =  oldLineLength + length;
00286 
00287       return;
00288 
00292     case RemoveText:
00296       if (cursorLine != line)
00297         return;
00298 
00299       // skip cursors with too small column
00300       if (cursorColumn <= column)
00301           return;
00302 
00303       // patch column of cursor
00304       if (cursorColumn <= column + length)
00305         cursorColumn =  column;
00306       else
00307         cursorColumn -=  length;
00308 
00309       return;
00310 
00314     default:
00315       return;
00316   }
00317 }
00318 
00319 void TextHistory::Entry::reverseTransformCursor (int &cursorLine, int &cursorColumn, bool moveOnInsert) const
00320 {   
00324   switch (type) {
00328     case WrapLine:
00332       if (cursorLine <= line)
00333           return;
00334         
00338       if (cursorLine == line + 1) {
00342         cursorColumn = cursorColumn + column;
00343       }
00344 
00348       cursorLine -=  1;
00349       return;
00350 
00354     case UnwrapLine:
00358       if (cursorLine < line - 1)
00359           return;
00360         
00364       if (cursorLine == line - 1) {
00368         if (cursorColumn <= oldLineLength) {
00369             if (cursorColumn < oldLineLength || !moveOnInsert)
00370                 return;
00371         }
00372           
00373         cursorColumn -= oldLineLength;
00374       }
00375       
00379       cursorLine += 1;
00380       return;
00381 
00385     case InsertText:
00389       if (cursorLine != line)
00390         return;
00391 
00392       // skip cursors with too small column
00393       if (cursorColumn <= column)
00394         return;
00395 
00396       // patch column of cursor
00397       if (cursorColumn - length < column)
00398         cursorColumn = column;
00399       else
00400         cursorColumn -= length;
00401 
00402       return;
00403 
00407     case RemoveText:
00411       if (cursorLine != line)
00412         return;
00413 
00414       // skip cursors with too small column
00415       if (cursorColumn <= column)
00416         if (cursorColumn < column || !moveOnInsert)
00417           return;
00418 
00419       // patch column of cursor
00420       if (cursorColumn <= oldLineLength)
00421         cursorColumn += length;
00422 
00423       // special handling if cursor behind the real line, e.g. non-wrapping cursor in block selection mode
00424       else if (cursorColumn < oldLineLength + length)
00425         cursorColumn =  oldLineLength + length;
00426       return;
00427 
00431     default:
00432       return;
00433   }
00434 }
00435 
00436 void TextHistory::transformCursor (int& line, int& column, KTextEditor::MovingCursor::InsertBehavior insertBehavior, qint64 fromRevision, qint64 toRevision)
00437 {
00441   if (fromRevision == -1)
00442     fromRevision = revision ();
00443   
00444   if (toRevision == -1)
00445     toRevision = revision ();
00446 
00450   if (fromRevision == toRevision)
00451     return;
00452 
00456   Q_ASSERT (!m_historyEntries.empty ());
00457   Q_ASSERT (fromRevision != toRevision);
00458   Q_ASSERT (fromRevision >= m_firstHistoryEntryRevision);
00459   Q_ASSERT (fromRevision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
00460   Q_ASSERT (toRevision >= m_firstHistoryEntryRevision);
00461   Q_ASSERT (toRevision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
00462 
00466   bool moveOnInsert = insertBehavior == KTextEditor::MovingCursor::MoveOnInsert;
00467   
00471   if (toRevision > fromRevision) {
00472     for (int rev = fromRevision - m_firstHistoryEntryRevision + 1; rev <= (toRevision - m_firstHistoryEntryRevision); ++rev) {
00473         const Entry &entry = m_historyEntries.at(rev);
00474         entry.transformCursor (line, column, moveOnInsert);
00475     }
00476   } else {
00477     for (int rev = fromRevision - m_firstHistoryEntryRevision; rev >= (toRevision - m_firstHistoryEntryRevision + 1); --rev) {
00478         const Entry &entry = m_historyEntries.at(rev);
00479         entry.reverseTransformCursor (line, column, moveOnInsert);
00480     }
00481   }
00482 }
00483 
00484 void TextHistory::transformRange (KTextEditor::Range &range, KTextEditor::MovingRange::InsertBehaviors insertBehaviors, KTextEditor::MovingRange::EmptyBehavior emptyBehavior, qint64 fromRevision, qint64 toRevision)
00485 {
00489   bool invalidateIfEmpty = emptyBehavior == KTextEditor::MovingRange::InvalidateIfEmpty;
00490   if (invalidateIfEmpty && range.end() <= range.start()) {
00491     range = KTextEditor::Range::invalid();
00492     return;
00493   }
00494 
00498   if (fromRevision == -1)
00499     fromRevision = revision ();
00500 
00501   if (toRevision == -1)
00502     toRevision = revision ();
00503 
00507   if (fromRevision == toRevision)
00508     return;
00509 
00513   Q_ASSERT (!m_historyEntries.empty ());
00514   Q_ASSERT (fromRevision != toRevision);
00515   Q_ASSERT (fromRevision >= m_firstHistoryEntryRevision);
00516   Q_ASSERT (fromRevision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
00517   Q_ASSERT (toRevision >= m_firstHistoryEntryRevision);
00518   Q_ASSERT (toRevision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
00519   
00524   // first: copy cursors, without range association
00525   int startLine = range.start().line(), startColumn = range.start().column(), endLine = range.end().line(), endColumn = range.end().column();
00526   
00527   bool moveOnInsertStart = !(insertBehaviors & KTextEditor::MovingRange::ExpandLeft);
00528   bool moveOnInsertEnd = (insertBehaviors & KTextEditor::MovingRange::ExpandRight);
00529   
00533   if (toRevision > fromRevision) {
00534     for (int rev = fromRevision - m_firstHistoryEntryRevision + 1; rev <= (toRevision - m_firstHistoryEntryRevision); ++rev) {
00535         const Entry &entry = m_historyEntries.at(rev);
00536         
00537         entry.transformCursor (startLine, startColumn, moveOnInsertStart);
00538         
00539         entry.transformCursor (endLine, endColumn, moveOnInsertEnd);
00540 
00541         // got empty?
00542         if(endLine < startLine || (endLine == startLine && endColumn <= startColumn))
00543         {
00544             if (invalidateIfEmpty) {
00545                 range = KTextEditor::Range::invalid();
00546                 return;
00547             }
00548             else{
00549                 // else normalize them
00550                 endLine = startLine;
00551                 endColumn = startColumn;
00552             }
00553         }
00554     }
00555   } else {
00556     for (int rev = fromRevision - m_firstHistoryEntryRevision ; rev >= (toRevision - m_firstHistoryEntryRevision + 1); --rev) {
00557         const Entry &entry = m_historyEntries.at(rev);
00558         
00559         entry.reverseTransformCursor (startLine, startColumn, moveOnInsertStart);
00560         
00561         entry.reverseTransformCursor (endLine, endColumn, moveOnInsertEnd);
00562 
00563         // got empty?
00564         if(endLine < startLine || (endLine == startLine && endColumn <= startColumn))
00565         {
00566             if (invalidateIfEmpty) {
00567                 range = KTextEditor::Range::invalid();
00568                 return;
00569             }
00570             else{
00571                 // else normalize them
00572                 endLine = startLine;
00573                 endColumn = startColumn;
00574             }
00575         }
00576     }
00577   }
00578 
00579   // now, copy cursors back
00580   range.start().setLine(startLine);
00581   range.start().setColumn(startColumn);
00582   range.end().setLine(endLine);
00583   range.end().setColumn(endColumn);
00584   
00585 }
00586 
00587 }

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
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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