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

Kate

katesmartmanager.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2005 Hamish Rodda <rodda@kde.org>
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 "katesmartmanager.h"
00019 
00020 #include "katedocument.h"
00021 #include "katesmartcursor.h"
00022 #include "katesmartrange.h"
00023 
00024 #include <QThread>
00025 #include <QMutexLocker>
00026 
00027 #include <kdebug.h>
00028 
00029 //Uncomment this to debug the translation of ranges. If that is enabled,
00030 //all ranges are first translated completely separately out of the translation process,
00031 //and at the end the result is compared. If the result mismatches, an assertion is triggered.
00032 // #define DEBUG_TRANSLATION
00033 
00034 static const int s_defaultGroupSize = 40;
00035 static const int s_minimumGroupSize = 20;
00036 static const int s_maximumGroupSize = 60;
00037 
00038 using namespace KTextEditor;
00039 
00040 static void translate(KateEditInfo* edit, Cursor& ret, SmartCursor::InsertBehavior insertBehavior)
00041 {
00042   // NOTE: copied from KateSmartCursor::translate()
00043   // If this cursor is before the edit, no action is required
00044   if (ret < edit->start())
00045     return;
00046 
00047   // If this cursor is on a line affected by the edit
00048   if (edit->oldRange().overlapsLine(ret.line())) {
00049     // If this cursor is at the start of the edit
00050     if (ret == edit->start()) {
00051       // And it doesn't need to move, no action is required
00052       if (insertBehavior == SmartCursor::StayOnInsert)
00053         return;
00054     }
00055 
00056     // Calculate the new position
00057     Cursor newPos;
00058     if (edit->oldRange().contains(ret)) {
00059       if (insertBehavior == SmartCursor::MoveOnInsert)
00060         ret = edit->newRange().end();
00061       else
00062         ret = edit->start();
00063 
00064     } else {
00065       ret += edit->translate();
00066     }
00067 
00068     return;
00069   }
00070 
00071   // just need to adjust line number
00072   ret.setLine(ret.line() + edit->translate().line());
00073 }
00074 
00075 #ifdef DEBUG_TRANSLATION
00076 struct KateSmartManager::KateTranslationDebugger {
00077   KateTranslationDebugger(KateSmartManager* manager, KateEditInfo* edit) : m_manager(manager), m_edit(edit) {
00078     manager->m_currentKateTranslationDebugger = this;
00079     foreach(KateSmartRange* range, manager->m_topRanges)
00080       addRange(range);
00081   }
00082 
00083   ~KateTranslationDebugger() {
00084     m_manager->m_currentKateTranslationDebugger = 0;
00085   }
00086 
00087   void addRange(SmartRange* _range) {
00088 
00089     KateSmartRange* range = dynamic_cast<KateSmartRange*>(_range);
00090     Q_ASSERT(range);
00091 
00092     RangeTranslation translation;
00093     translation.from = *range;
00094     KTextEditor::Cursor toStart = range->start();
00095     KTextEditor::Cursor toEnd = range->end();
00096 
00097     translate(m_edit, toStart, (range->insertBehavior() & SmartRange::ExpandLeft) ? SmartCursor::StayOnInsert : SmartCursor::MoveOnInsert);
00098     translate(m_edit, toEnd, (range->insertBehavior() & SmartRange::ExpandRight) ? SmartCursor::MoveOnInsert : SmartCursor::StayOnInsert);
00099     translation.to = KTextEditor::Range(toStart, toEnd);
00100 
00101     m_rangeTranslations[range] = translation;
00102     m_cursorTranslations[&range->smartStart()] = CursorTranslation(range->start(), toStart);
00103     m_cursorTranslations[&range->smartEnd()] = CursorTranslation(range->end(), toEnd);
00104 
00105     foreach(SmartRange* child, range->childRanges())
00106       addRange(child);
00107   }
00108 
00109   void verifyAll() {
00110     for(QMap<const SmartRange*, RangeTranslation>::iterator it = m_rangeTranslations.begin(); it != m_rangeTranslations.end(); ++it) {
00111       if(*it.key() != it.value().to) {
00112     kDebug() << "mismatch. Translation should be:" << it.value().to << "translation is:" << *it.key() << "from:" << it.value().from;
00113       kDebug() << "edit:" << m_edit->oldRange() << m_edit->newRange();
00114     Q_ASSERT(0);
00115       }
00116     }
00117   }
00118 
00119   void verifyChange(SmartCursor* _cursor) {
00120     if(!m_cursorTranslations.contains(_cursor))
00121       return;
00122     return;
00123     KateSmartCursor* cursor = dynamic_cast<KateSmartCursor*>(_cursor);
00124     Q_ASSERT(cursor);
00125     KTextEditor::Cursor realPos( cursor->m_line + cursor->m_smartGroup->m_newStartLine, cursor->m_column);
00126     kDebug() << "changing cursor from" << m_cursorTranslations[cursor].from << "to" << realPos;
00127 
00128     if(m_cursorTranslations[cursor].to != realPos) {
00129       kDebug() << "mismatch. Translation of cursor should be:" << m_cursorTranslations[cursor].to << "is:" << realPos << "from:" << m_cursorTranslations[cursor].from;
00130       kDebug() << "edit:" << m_edit->oldRange() << m_edit->newRange();
00131       Q_ASSERT(0);
00132     }
00133   }
00134 
00135   struct RangeTranslation {
00136     KTextEditor::Range from, to;
00137   };
00138 
00139   struct CursorTranslation {
00140     CursorTranslation() {
00141     }
00142     CursorTranslation(const KTextEditor::Cursor& _from, const KTextEditor::Cursor& _to) : from(_from), to(_to) {
00143     }
00144     KTextEditor::Cursor from, to;
00145   };
00146 
00147   QMap<const SmartRange*, RangeTranslation> m_rangeTranslations;
00148   QMap<const SmartCursor*, CursorTranslation> m_cursorTranslations;
00149   KateSmartManager* m_manager;
00150   KateEditInfo* m_edit;
00151 };
00152 #endif
00153 KateSmartManager::KateSmartManager(KateDocument* parent)
00154   : QObject(parent)
00155   , m_firstGroup(new KateSmartGroup(0, 0, 0L, 0L))
00156   , m_invalidGroup(new KateSmartGroup(-1, -1, 0L, 0L))
00157   , m_clearing(false)
00158   , m_currentKateTranslationDebugger(0)
00159 {
00160   connect(doc()->history(), SIGNAL(editDone(KateEditInfo*)), SLOT(slotTextChanged(KateEditInfo*)));
00161   //connect(doc(), SIGNAL(textChanged(Document*)), SLOT(verifyCorrect()));
00162 }
00163 
00164 KateSmartManager::~KateSmartManager()
00165 {
00166   clear(true);
00167 
00168   KateSmartGroup* smartGroup = m_firstGroup;
00169   while (smartGroup) {
00170     KateSmartGroup* toDelete = smartGroup;
00171     smartGroup = smartGroup->next();
00172     delete toDelete;
00173   }
00174 
00175   delete m_invalidGroup;
00176 }
00177 
00178 KateDocument * KateSmartManager::doc( ) const
00179 {
00180   return static_cast<KateDocument*>(parent());
00181 }
00182 
00183 KateSmartCursor * KateSmartManager::newSmartCursor( const Cursor & position, SmartCursor::InsertBehavior insertBehavior, bool internal )
00184 {
00185   QMutexLocker l(internal ? doc()->smartMutex() : 0);
00186 
00187   KateSmartCursor* c;
00188   if (usingRevision() != -1 && !internal)
00189     c = new KateSmartCursor(translateFromRevision(position), doc(), insertBehavior);
00190   else
00191     c = new KateSmartCursor(position, doc(), insertBehavior);
00192 
00193   if (internal)
00194     c->setInternal();
00195   return c;
00196 }
00197 
00198 KateSmartRange * KateSmartManager::newSmartRange( const Range & range, SmartRange * parent, SmartRange::InsertBehaviors insertBehavior, bool internal )
00199 {
00200   QMutexLocker l(internal ? doc()->smartMutex() : 0);
00201 
00202   KateSmartRange* newRange;
00203 
00204   if (usingRevision() != -1 && !internal)
00205     newRange = new KateSmartRange(translateFromRevision(range), doc(), parent, insertBehavior);
00206   else
00207     newRange = new KateSmartRange(range, doc(), parent, insertBehavior);
00208 
00209   if (internal)
00210     newRange->setInternal();
00211   if (!parent)
00212     rangeLostParent(newRange);
00213   return newRange;
00214 }
00215 
00216 KateSmartRange * KateSmartManager::newSmartRange( KateSmartCursor * start, KateSmartCursor * end, SmartRange * parent, SmartRange::InsertBehaviors insertBehavior, bool internal )
00217 {
00218   QMutexLocker l(internal ? doc()->smartMutex() : 0);
00219 
00220 //Why translate "smart" cursors? They should translate automatically!
00221 //   if (usingRevision() != -1 && !internal) {
00222 //     KTextEditor::Cursor tempStart = translateFromRevision(*start, (insertBehavior & SmartRange::ExpandLeft) ? SmartCursor::StayOnInsert : SmartCursor::MoveOnInsert);
00223 //     KTextEditor::Cursor tempEnd = translateFromRevision(*end, (insertBehavior & SmartRange::ExpandRight) ? SmartCursor::MoveOnInsert : SmartCursor::StayOnInsert);
00224 //     *start = tempStart;
00225 //     *end = tempEnd;
00226 //   }
00227 
00228   KateSmartRange* newRange = new KateSmartRange(start, end, parent, insertBehavior);
00229   if (internal)
00230     newRange->setInternal();
00231   if (!parent)
00232     rangeLostParent(newRange);
00233   return newRange;
00234 }
00235 
00236 void KateSmartGroup::addCursor( KateSmartCursor * cursor)
00237 {
00238   Q_ASSERT(!m_feedbackCursors.contains(cursor));
00239   Q_ASSERT(!m_normalCursors.contains(cursor));
00240 
00241   if (cursor->feedbackEnabled())
00242     m_feedbackCursors.insert(cursor);
00243   else
00244     m_normalCursors.insert(cursor);
00245 }
00246 
00247 void KateSmartGroup::changeCursorFeedback( KateSmartCursor * cursor )
00248 {
00249   if (!cursor->feedbackEnabled()) {
00250     Q_ASSERT(!m_feedbackCursors.contains(cursor));
00251     Q_ASSERT(m_normalCursors.contains(cursor));
00252     m_normalCursors.remove(cursor);
00253     m_feedbackCursors.insert(cursor);
00254 
00255   } else {
00256     Q_ASSERT(m_feedbackCursors.contains(cursor));
00257     Q_ASSERT(!m_normalCursors.contains(cursor));
00258     m_feedbackCursors.remove(cursor);
00259     m_normalCursors.insert(cursor);
00260   }
00261 }
00262 
00263 void KateSmartGroup::removeCursor( KateSmartCursor * cursor)
00264 {
00265   if (cursor->feedbackEnabled()) {
00266     Q_ASSERT(m_feedbackCursors.contains(cursor));
00267     Q_ASSERT(!m_normalCursors.contains(cursor));
00268     m_feedbackCursors.remove(cursor);
00269 
00270   } else {
00271     Q_ASSERT(!m_feedbackCursors.contains(cursor));
00272     Q_ASSERT(m_normalCursors.contains(cursor));
00273     m_normalCursors.remove(cursor);
00274   }
00275 }
00276 
00277 void KateSmartGroup::joined( KateSmartCursor * cursor )
00278 {
00279   addCursor(cursor);
00280 }
00281 
00282 void KateSmartGroup::leaving( KateSmartCursor * cursor )
00283 {
00284   removeCursor(cursor);
00285 }
00286 
00287 KateSmartGroup * KateSmartManager::groupForLine( int line ) const
00288 {
00289   // Special case
00290   if (line == -1)
00291     return m_invalidGroup;
00292 
00293   // FIXME maybe this should perform a bit better
00294   KateSmartGroup* smartGroup = m_firstGroup;
00295   while (smartGroup && !smartGroup->containsLine(line))
00296     smartGroup = smartGroup->next();
00297 
00298   // If you hit this assert, it is a fundamental bug in katepart.  A cursor's
00299   // position is being set beyond the end of the document, or (perhaps less
00300   // likely), in this class itself.
00301   //
00302   // Please figure out how to reproduce, and report to rodda@kde.org.
00303   Q_ASSERT(smartGroup);
00304   return smartGroup;
00305 }
00306 
00307 void KateSmartManager::slotTextChanged(KateEditInfo* edit)
00308 {
00309   QMutexLocker lock(doc()->smartMutex());
00310 #ifdef DEBUG_TRANSLATION
00311   KateTranslationDebugger KateTranslationDebugger(this, edit);
00312 #endif
00313   KateSmartGroup* firstSmartGroup = groupForLine(edit->oldRange().start().line());
00314   KateSmartGroup* currentGroup = firstSmartGroup;
00315 
00316   // Check to see if we need to split or consolidate
00317   int splitEndLine = edit->translate().line() + firstSmartGroup->endLine();
00318 
00319   if (edit->translate().line() > 0) {
00320     // May need to expand smart groups
00321     KateSmartGroup* endGroup = currentGroup->next();
00322 
00323     int currentCanExpand = endGroup ? s_maximumGroupSize - currentGroup->length() : s_defaultGroupSize - currentGroup->length();
00324     int expanded = 0;
00325 
00326     if (currentCanExpand) {
00327        int expandBy = qMin(edit->translate().line(), currentCanExpand);
00328       // Current group can expand to accommodate the extra lines
00329       currentGroup->setNewEndLine(currentGroup->endLine() + expandBy);
00330 
00331       expanded = expandBy;
00332     }
00333 
00334     if (expanded < edit->translate().line()) {
00335       // Need at least one new group
00336       int newStartLine, newEndLine;
00337 
00338       do {
00339         newStartLine = currentGroup->newEndLine() + 1;
00340         newEndLine = qMin(newStartLine + s_defaultGroupSize - 1, splitEndLine);
00341         currentGroup = new KateSmartGroup(newStartLine, newEndLine, currentGroup, endGroup);
00342 
00343       } while (newEndLine < splitEndLine);
00344     }
00345 
00346 
00347   } else if (edit->translate().line() < 0) {
00348     // Might need to consolitate
00349     // Consolidate groups together while keeping the end result the same
00350     while (currentGroup->next() && currentGroup->length() + edit->translate().line() < s_minimumGroupSize)
00351       currentGroup->merge();
00352 
00353     // Reduce the size of the current group
00354     currentGroup->setNewEndLine(currentGroup->endLine() + edit->translate().line());
00355   }
00356 
00357   // Shift the groups so they have their new start and end lines
00358   if (edit->translate().line())
00359     for (KateSmartGroup* smartGroup = currentGroup->next(); smartGroup; smartGroup = smartGroup->next())
00360       smartGroup->translateShifted(*edit);
00361 
00362   // Translate affected groups
00363   for (KateSmartGroup* smartGroup = firstSmartGroup; smartGroup; smartGroup = smartGroup->next()) {
00364     if (smartGroup->startLine() > edit->oldRange().end().line())
00365       break;
00366 
00367     smartGroup->translateChanged(*edit);
00368   }
00369 
00370   // Cursor feedback
00371   bool groupChanged = true;
00372   for (KateSmartGroup* smartGroup = firstSmartGroup; smartGroup; smartGroup = smartGroup->next()) {
00373     if (groupChanged) {
00374       groupChanged = smartGroup->startLine() <= edit->oldRange().end().line();
00375       // Don't continue iterating if no line translation occurred.
00376       if (!groupChanged && !edit->translate().line())
00377         break;
00378     }
00379 
00380     if (groupChanged)
00381       smartGroup->translatedChanged(*edit);
00382     else
00383       smartGroup->translatedShifted(*edit);
00384   }
00385 
00386   // Allow rebuilding the child-structure of affected ranges
00387   for (KateSmartGroup* smartGroup = firstSmartGroup; smartGroup; smartGroup = smartGroup->next()) {
00388     if (smartGroup->startLine() > edit->oldRange().end().line())
00389       break;
00390 
00391     smartGroup->translatedChanged2(*edit);
00392   }
00393 
00394 #ifdef DEBUG_TRANSLATION
00395   KateTranslationDebugger.verifyAll();
00396 #endif
00397 
00398   // Range feedback
00399   foreach (KateSmartRange* range, m_topRanges) {
00400     KateSmartRange* mostSpecific = feedbackRange(*edit, range);
00401 
00402     if (!mostSpecific)
00403       mostSpecific = range;
00404     range->feedbackMostSpecific(mostSpecific);
00405   }
00406 
00407 #ifdef DEBUG_TRANSLATION
00408   KateTranslationDebugger.verifyAll();
00409 #endif
00410   //debugOutput();
00411 //   verifyCorrect();
00412 }
00413 
00414 KateSmartRange* KateSmartManager::feedbackRange( const KateEditInfo& edit, KateSmartRange * range )
00415 {
00416   KateSmartRange* mostSpecific = 0L;
00417 
00418   // This range precedes the edit... no more to do
00419   if ((range->end() < edit.start()  && range->kEnd().lastPosition() < edit.start()) ||
00420     (range->end() == edit.start() && range->kEnd().lastPosition() == edit.start() && !range->isEmpty())
00421   ) {
00422     //kDebug() << "Not feeding back to " << *range << "as edit start" << edit.start();
00423     return mostSpecific;
00424   }
00425 
00426   foreach (SmartRange* child, range->childRanges())
00427     if (!mostSpecific)
00428       mostSpecific = feedbackRange(edit, static_cast<KateSmartRange*>(child));
00429     else
00430       feedbackRange(edit, static_cast<KateSmartRange*>(child));
00431 
00432   //kDebug() << "edit" << edit.oldRange() << edit.newRange() << "last at" << range->kStart().lastPosition() << range->kEnd().lastPosition() << "now" << *range;
00433 
00434   if (range->start() > edit.newRange().end() ||
00435       (range->start() == edit.newRange().end() && range->kStart().lastPosition() == edit.oldRange().end()))
00436   {
00437     // This range is after the edit... has only been shifted
00438     //kDebug() << "Feeding back shifted to " << *range;
00439     range->shifted();
00440 
00441   } else {
00442     // This range is within the edit.
00443     //kDebug() << "Feeding back translated to " << *range;
00444     if (!mostSpecific)
00445       if (range->start() < edit.oldRange().start() && range->end() > edit.oldRange().end())
00446         mostSpecific = range;
00447 
00448     range->translated(edit);
00449   }
00450 
00451   return mostSpecific;
00452 }
00453 
00454 
00455 void KateSmartGroup::translateChanged( const KateEditInfo& edit)
00456 {
00457   //kDebug() << "Was " << edit.oldRange() << " now " << edit.newRange() << " numcursors feedback " << m_feedbackCursors.count() << " normal " << m_normalCursors.count();
00458 
00459   foreach (KateSmartCursor* cursor, m_feedbackCursors)
00460     cursor->translate(edit);
00461 
00462   foreach (KateSmartCursor* cursor, m_normalCursors)
00463     cursor->translate(edit);
00464 }
00465 
00466 void KateSmartGroup::translateShifted(const KateEditInfo& edit)
00467 {
00468   m_newStartLine = m_startLine + edit.translate().line();
00469   m_newEndLine = m_endLine + edit.translate().line();
00470   //Since shifting only does not change the overlap or order, we don't need to rebuild any child structures here
00471 }
00472 
00473 void KateSmartGroup::translatedChanged(const KateEditInfo& edit)
00474 {
00475   m_startLine = m_newStartLine;
00476   m_endLine = m_newEndLine;
00477 
00478   foreach (KateSmartCursor* cursor, m_feedbackCursors)
00479     cursor->translated(edit);
00480 }
00481 
00482 void KateSmartGroup::translatedChanged2(const KateEditInfo& edit)
00483 {
00484   //Tell the affected parent smart-ranges to rebuild their child-structure, so they stay consistent
00485   QSet<KTextEditor::SmartRange*> rebuilt;
00486 
00487   foreach (KateSmartCursor* cursor, m_normalCursors + m_feedbackCursors) {
00488     KTextEditor::SmartRange* range = cursor->smartRange();
00489     if(range) {
00490         KTextEditor::SmartRange* parent = range->parentRange();
00491         if(parent && !rebuilt.contains(parent)) {
00492             rebuilt.insert(parent);
00493             KateSmartRange* kateSmart = dynamic_cast<KateSmartRange*>(parent);
00494             Q_ASSERT(kateSmart);
00495             kateSmart->rebuildChildStructure();
00496         }
00497     }
00498   }
00499 }
00500 
00501 void KateSmartGroup::translatedShifted(const KateEditInfo& edit)
00502 {
00503   if (m_startLine != m_newStartLine) {
00504     m_startLine = m_newStartLine;
00505     m_endLine = m_newEndLine;
00506   }
00507 
00508   if (edit.translate().line() == 0)
00509     return;
00510 
00511   // Todo: don't need to provide positionChanged to all feedback cursors?
00512   foreach (KateSmartCursor* cursor, m_feedbackCursors)
00513     cursor->shifted();
00514 }
00515 
00516 KateSmartGroup::KateSmartGroup( int startLine, int endLine, KateSmartGroup * previous, KateSmartGroup * next )
00517   : m_startLine(startLine)
00518   , m_newStartLine(startLine)
00519   , m_endLine(endLine)
00520   , m_newEndLine(endLine)
00521   , m_next(next)
00522   , m_previous(previous)
00523 {
00524   if (m_previous)
00525     m_previous->setNext(this);
00526 
00527   if (m_next)
00528     m_next->setPrevious(this);
00529 }
00530 
00531 void KateSmartGroup::merge( )
00532 {
00533   Q_ASSERT(m_next);
00534 
00535   foreach (KateSmartCursor* cursor, next()->feedbackCursors())
00536     cursor->migrate(this);
00537   m_feedbackCursors += next()->feedbackCursors();
00538 
00539   foreach (KateSmartCursor* cursor, next()->normalCursors())
00540     cursor->migrate(this);
00541   m_normalCursors += next()->normalCursors();
00542 
00543   m_newEndLine = m_endLine = next()->endLine();
00544   KateSmartGroup* newNext = next()->next();
00545   delete m_next;
00546   m_next = newNext;
00547   if (m_next)
00548     m_next->setPrevious(this);
00549 }
00550 
00551 const QSet< KateSmartCursor * > & KateSmartGroup::feedbackCursors( ) const
00552 {
00553   return m_feedbackCursors;
00554 }
00555 
00556 const QSet< KateSmartCursor * > & KateSmartGroup::normalCursors( ) const
00557 {
00558   return m_normalCursors;
00559 }
00560 
00561 void KateSmartManager::debugOutput( ) const
00562 {
00563   int groupCount = 1;
00564   KateSmartGroup* currentGroup = m_firstGroup;
00565   while (currentGroup->next()) {
00566     ++groupCount;
00567     currentGroup = currentGroup->next();
00568   }
00569 
00570   kDebug() << "KateSmartManager: SmartGroups " << groupCount << " from " << m_firstGroup->startLine() << " to " << currentGroup->endLine();
00571 
00572   currentGroup = m_firstGroup;
00573   while (currentGroup) {
00574     currentGroup->debugOutput();
00575     currentGroup = currentGroup->next();
00576   }
00577 }
00578 
00579 void KateSmartGroup::debugOutput( ) const
00580 {
00581   kDebug() << " -> KateSmartGroup: from " << startLine() << " to " << endLine() << "; Cursors " << m_normalCursors.count() + m_feedbackCursors.count() << " (" << m_feedbackCursors.count() << " feedback)";
00582 }
00583 
00584 void KateSmartManager::verifyCorrect() const
00585 {
00586   KateSmartGroup* currentGroup = groupForLine(0);
00587   Q_ASSERT(currentGroup);
00588   Q_ASSERT(currentGroup == m_firstGroup);
00589 
00590   forever {
00591     if (!currentGroup->previous())
00592       Q_ASSERT(currentGroup->startLine() == 0);
00593 
00594     foreach (KateSmartCursor* cursor, currentGroup->feedbackCursors()) {
00595       Q_ASSERT(currentGroup->containsLine(cursor->line()));
00596       Q_ASSERT(cursor->smartGroup() == currentGroup);
00597     }
00598 
00599     if (!currentGroup->next())
00600       break;
00601 
00602     Q_ASSERT(currentGroup->endLine() == currentGroup->next()->startLine() - 1);
00603     Q_ASSERT(currentGroup->next()->previous() == currentGroup);
00604 
00605     currentGroup = currentGroup->next();
00606   }
00607 
00608   Q_ASSERT(currentGroup->endLine() == doc()->lines() - 1);
00609 
00610   kDebug() << "Verified correct." << currentGroup->endLine() << doc()->lines() - 1;
00611 }
00612 
00613 void KateSmartManager::rangeGotParent( KateSmartRange * range )
00614 {
00615   Q_ASSERT(m_topRanges.contains(range));
00616   m_topRanges.remove(range);
00617 }
00618 
00619 void KateSmartManager::rangeLostParent( KateSmartRange * range )
00620 {
00621   Q_ASSERT(!m_topRanges.contains(range));
00622   m_topRanges.insert(range);
00623 }
00624 
00625 void KateSmartManager::rangeDeleted( KateSmartRange* range )
00626 {
00627   emit signalRangeDeleted(range);
00628 
00629   if (!range->parentRange())
00630     m_topRanges.remove(range);
00631 }
00632 
00633 void KateSmartManager::unbindSmartRange( SmartRange * range )
00634 {
00635   static_cast<KateSmartRange*>(range)->unbindAndDelete();
00636 }
00637 
00638 void KateSmartManager::deleteCursors(bool includingInternal)
00639 {
00640   m_invalidGroup->deleteCursors(includingInternal);
00641   for (KateSmartGroup* g = m_firstGroup; g; g = g->next())
00642     g->deleteCursors(includingInternal);
00643 }
00644 
00645 void KateSmartGroup::deleteCursors( bool includingInternal )
00646 {
00647   if (includingInternal) {
00648     qDeleteAll(m_feedbackCursors);
00649     m_feedbackCursors.clear();
00650 
00651     qDeleteAll(m_normalCursors);
00652     m_normalCursors.clear();
00653 
00654   } else {
00655     deleteCursorsInternal(m_feedbackCursors);
00656     deleteCursorsInternal(m_normalCursors);
00657   }
00658 }
00659 
00660 void KateSmartGroup::deleteCursorsInternal( QSet< KateSmartCursor * > & set )
00661 {
00662   foreach (KateSmartCursor* c, set.toList()) {
00663     if (!c->range() && !c->isInternal()) {
00664       set.remove(c);
00665       delete c;
00666     }
00667   }
00668 }
00669 
00670 void KateSmartManager::deleteRanges( bool includingInternal )
00671 {
00672   foreach (KateSmartRange* range, m_topRanges.toList()) {
00673     if (includingInternal || !range->isInternal()) {
00674       range->deleteChildRanges();
00675       delete range;
00676 
00677       if (!includingInternal)
00678         m_topRanges.remove(range);
00679     }
00680   }
00681 
00682   if (includingInternal)
00683     m_topRanges.clear();
00684 }
00685 
00686 void KateSmartManager::clear( bool includingInternal )
00687 {
00688   deleteRanges(includingInternal);
00689 
00690   m_clearing = true;
00691   deleteCursors(includingInternal);
00692   m_clearing = false;
00693 }
00694 
00695 void KateSmartManager::useRevision(int revision)
00696 {
00697   if (!m_usingRevision.hasLocalData())
00698     m_usingRevision.setLocalData(new int);
00699 
00700   *m_usingRevision.localData() = revision;
00701 }
00702 
00703 int KateSmartManager::usingRevision() const
00704 {
00705   if (m_usingRevision.hasLocalData())
00706     return *m_usingRevision.localData();
00707 
00708   return -1;
00709 }
00710 
00711 void KateSmartManager::releaseRevision(int revision) const
00712 {
00713   doc()->history()->releaseRevision(revision);
00714 }
00715 
00716 int KateSmartManager::currentRevision() const
00717 {
00718   return doc()->history()->revision();
00719 }
00720 
00721 Cursor KateSmartManager::translateFromRevision(const Cursor& cursor, SmartCursor::InsertBehavior insertBehavior) const
00722 {
00723   Cursor ret = cursor;
00724 
00725   foreach (KateEditInfo* edit, doc()->history()->editsBetweenRevisions(usingRevision()))
00726     translate(edit, ret, insertBehavior);
00727 
00728   return ret;
00729 }
00730 
00731 Range KateSmartManager::translateFromRevision(const Range& range, KTextEditor::SmartRange::InsertBehaviors insertBehavior) const
00732 {
00733   Cursor start = range.start(), end = range.end();
00734 
00735   foreach (KateEditInfo* edit, doc()->history()->editsBetweenRevisions(usingRevision())) {
00736     translate(edit, start, insertBehavior & KTextEditor::SmartRange::ExpandLeft ? SmartCursor::StayOnInsert : SmartCursor::MoveOnInsert);
00737     translate(edit, end, insertBehavior & KTextEditor::SmartRange::ExpandRight ? SmartCursor::MoveOnInsert : SmartCursor::StayOnInsert);
00738   }
00739 
00740   return Range(start, end);
00741 }
00742 
00743 #include "katesmartmanager.moc"

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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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