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