00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "katesmartmanager.h"
00020
00021 #include "katedocument.h"
00022 #include "katesmartcursor.h"
00023 #include "katesmartrange.h"
00024
00025 #include <QThread>
00026 #include <QMutexLocker>
00027
00028 #include <kdebug.h>
00029
00030 static const int s_defaultGroupSize = 40;
00031 static const int s_minimumGroupSize = 20;
00032 static const int s_maximumGroupSize = 60;
00033
00034 using namespace KTextEditor;
00035
00036 KateSmartManager::KateSmartManager(KateDocument* parent)
00037 : QObject(parent)
00038 , m_firstGroup(new KateSmartGroup(0, 0, 0L, 0L))
00039 , m_invalidGroup(new KateSmartGroup(-1, -1, 0L, 0L))
00040 , m_clearing(false)
00041 {
00042 connect(doc()->history(), SIGNAL(editDone(KateEditInfo*)), SLOT(slotTextChanged(KateEditInfo*)));
00043
00044 }
00045
00046 KateSmartManager::~KateSmartManager()
00047 {
00048 clear(true);
00049
00050 KateSmartGroup* smartGroup = m_firstGroup;
00051 while (smartGroup) {
00052 KateSmartGroup* toDelete = smartGroup;
00053 smartGroup = smartGroup->next();
00054 delete toDelete;
00055 }
00056
00057 delete m_invalidGroup;
00058 }
00059
00060 KateDocument * KateSmartManager::doc( ) const
00061 {
00062 return static_cast<KateDocument*>(parent());
00063 }
00064
00065 KateSmartCursor * KateSmartManager::newSmartCursor( const Cursor & position, SmartCursor::InsertBehavior insertBehavior, bool internal )
00066 {
00067 QMutexLocker l(internal ? doc()->smartMutex() : 0);
00068
00069 KateSmartCursor* c;
00070 if (usingRevision() != -1 && !internal)
00071 c = new KateSmartCursor(translateFromRevision(position), doc(), insertBehavior);
00072 else
00073 c = new KateSmartCursor(position, doc(), insertBehavior);
00074
00075 if (internal)
00076 c->setInternal();
00077 return c;
00078 }
00079
00080 KateSmartRange * KateSmartManager::newSmartRange( const Range & range, SmartRange * parent, SmartRange::InsertBehaviors insertBehavior, bool internal )
00081 {
00082 QMutexLocker l(internal ? doc()->smartMutex() : 0);
00083
00084 KateSmartRange* newRange;
00085
00086 if (usingRevision() != -1 && !internal)
00087 newRange = new KateSmartRange(translateFromRevision(range), doc(), parent, insertBehavior);
00088 else
00089 newRange = new KateSmartRange(range, doc(), parent, insertBehavior);
00090
00091 if (internal)
00092 newRange->setInternal();
00093 if (!parent)
00094 rangeLostParent(newRange);
00095 return newRange;
00096 }
00097
00098 KateSmartRange * KateSmartManager::newSmartRange( KateSmartCursor * start, KateSmartCursor * end, SmartRange * parent, SmartRange::InsertBehaviors insertBehavior, bool internal )
00099 {
00100 QMutexLocker l(internal ? doc()->smartMutex() : 0);
00101
00102 if (usingRevision() != -1 && !internal) {
00103 KTextEditor::Cursor tempStart = translateFromRevision(*start, (insertBehavior & SmartRange::ExpandLeft) ? SmartCursor::StayOnInsert : SmartCursor::MoveOnInsert);
00104 KTextEditor::Cursor tempEnd = translateFromRevision(*end, (insertBehavior & SmartRange::ExpandRight) ? SmartCursor::MoveOnInsert : SmartCursor::StayOnInsert);
00105 *start = tempStart;
00106 *end = tempEnd;
00107 }
00108
00109 KateSmartRange* newRange = new KateSmartRange(start, end, parent, insertBehavior);
00110 if (internal)
00111 newRange->setInternal();
00112 if (!parent)
00113 rangeLostParent(newRange);
00114 return newRange;
00115 }
00116
00117 void KateSmartGroup::addCursor( KateSmartCursor * cursor)
00118 {
00119 Q_ASSERT(!m_feedbackCursors.contains(cursor));
00120 Q_ASSERT(!m_normalCursors.contains(cursor));
00121
00122 if (cursor->feedbackEnabled())
00123 m_feedbackCursors.insert(cursor);
00124 else
00125 m_normalCursors.insert(cursor);
00126 }
00127
00128 void KateSmartGroup::changeCursorFeedback( KateSmartCursor * cursor )
00129 {
00130 if (!cursor->feedbackEnabled()) {
00131 Q_ASSERT(!m_feedbackCursors.contains(cursor));
00132 Q_ASSERT(m_normalCursors.contains(cursor));
00133 m_normalCursors.remove(cursor);
00134 m_feedbackCursors.insert(cursor);
00135
00136 } else {
00137 Q_ASSERT(m_feedbackCursors.contains(cursor));
00138 Q_ASSERT(!m_normalCursors.contains(cursor));
00139 m_feedbackCursors.remove(cursor);
00140 m_normalCursors.insert(cursor);
00141 }
00142 }
00143
00144 void KateSmartGroup::removeCursor( KateSmartCursor * cursor)
00145 {
00146 if (cursor->feedbackEnabled()) {
00147 Q_ASSERT(m_feedbackCursors.contains(cursor));
00148 Q_ASSERT(!m_normalCursors.contains(cursor));
00149 m_feedbackCursors.remove(cursor);
00150
00151 } else {
00152 Q_ASSERT(!m_feedbackCursors.contains(cursor));
00153 Q_ASSERT(m_normalCursors.contains(cursor));
00154 m_normalCursors.remove(cursor);
00155 }
00156 }
00157
00158 void KateSmartGroup::joined( KateSmartCursor * cursor )
00159 {
00160 addCursor(cursor);
00161 }
00162
00163 void KateSmartGroup::leaving( KateSmartCursor * cursor )
00164 {
00165 removeCursor(cursor);
00166 }
00167
00168 KateSmartGroup * KateSmartManager::groupForLine( int line ) const
00169 {
00170
00171 if (line == -1)
00172 return m_invalidGroup;
00173
00174
00175 KateSmartGroup* smartGroup = m_firstGroup;
00176 while (smartGroup && !smartGroup->containsLine(line))
00177 smartGroup = smartGroup->next();
00178
00179
00180
00181
00182
00183
00184 Q_ASSERT(smartGroup);
00185 return smartGroup;
00186 }
00187
00188 void KateSmartManager::slotTextChanged(KateEditInfo* edit)
00189 {
00190 QMutexLocker lock(doc()->smartMutex());
00191
00192 KateSmartGroup* firstSmartGroup = groupForLine(edit->oldRange().start().line());
00193 KateSmartGroup* currentGroup = firstSmartGroup;
00194
00195
00196 int splitEndLine = edit->translate().line() + firstSmartGroup->endLine();
00197
00198 if (edit->translate().line() > 0) {
00199
00200 KateSmartGroup* endGroup = currentGroup->next();
00201
00202 int currentCanExpand = endGroup ? s_maximumGroupSize - currentGroup->length() : s_defaultGroupSize - currentGroup->length();
00203 int expanded = 0;
00204
00205 if (currentCanExpand) {
00206 int expandBy = qMin(edit->translate().line(), currentCanExpand);
00207
00208 currentGroup->setNewEndLine(currentGroup->endLine() + expandBy);
00209
00210 expanded = expandBy;
00211 }
00212
00213 if (expanded < edit->translate().line()) {
00214
00215 int newStartLine, newEndLine;
00216
00217 do {
00218 newStartLine = currentGroup->newEndLine() + 1;
00219 newEndLine = qMin(newStartLine + s_defaultGroupSize - 1, splitEndLine);
00220 currentGroup = new KateSmartGroup(newStartLine, newEndLine, currentGroup, endGroup);
00221
00222 } while (newEndLine < splitEndLine);
00223 }
00224
00225
00226 } else if (edit->translate().line() < 0) {
00227
00228
00229 while (currentGroup->next() && currentGroup->length() + edit->translate().line() < s_minimumGroupSize)
00230 currentGroup->merge();
00231
00232
00233 currentGroup->setNewEndLine(currentGroup->endLine() + edit->translate().line());
00234 }
00235
00236
00237 if (edit->translate().line())
00238 for (KateSmartGroup* smartGroup = currentGroup->next(); smartGroup; smartGroup = smartGroup->next())
00239 smartGroup->translateShifted(*edit);
00240
00241
00242 for (KateSmartGroup* smartGroup = firstSmartGroup; smartGroup; smartGroup = smartGroup->next()) {
00243 if (smartGroup->startLine() > edit->oldRange().end().line())
00244 break;
00245
00246 smartGroup->translateChanged(*edit);
00247 }
00248
00249
00250 bool groupChanged = true;
00251 for (KateSmartGroup* smartGroup = firstSmartGroup; smartGroup; smartGroup = smartGroup->next()) {
00252 if (groupChanged) {
00253 groupChanged = smartGroup->startLine() <= edit->oldRange().end().line();
00254
00255 if (!groupChanged && !edit->translate().line())
00256 break;
00257 }
00258
00259 if (groupChanged)
00260 smartGroup->translatedChanged(*edit);
00261 else
00262 smartGroup->translatedShifted(*edit);
00263 }
00264
00265
00266 foreach (KateSmartRange* range, m_topRanges) {
00267 KateSmartRange* mostSpecific = feedbackRange(*edit, range);
00268
00269 if (!mostSpecific)
00270 mostSpecific = range;
00271 range->feedbackMostSpecific(mostSpecific);
00272 }
00273
00274
00275
00276 }
00277
00278 KateSmartRange* KateSmartManager::feedbackRange( const KateEditInfo& edit, KateSmartRange * range )
00279 {
00280 KateSmartRange* mostSpecific = 0L;
00281
00282
00283 if (range->end() < edit.start() || range->end() == edit.start() && !range->isEmpty()) {
00284
00285 return mostSpecific;
00286 }
00287
00288 foreach (SmartRange* child, range->childRanges())
00289 if (!mostSpecific)
00290 mostSpecific = feedbackRange(edit, static_cast<KateSmartRange*>(child));
00291 else
00292 feedbackRange(edit, static_cast<KateSmartRange*>(child));
00293
00294
00295
00296 if (range->start() > edit.newRange().end() ||
00297 (range->start() == edit.newRange().end() && range->kStart().lastPosition() == edit.oldRange().end()))
00298 {
00299
00300
00301 range->shifted();
00302
00303 } else {
00304
00305
00306 if (!mostSpecific)
00307 if (range->start() < edit.oldRange().start() && range->end() > edit.oldRange().end())
00308 mostSpecific = range;
00309
00310 range->translated(edit);
00311 }
00312
00313 return mostSpecific;
00314 }
00315
00316
00317 void KateSmartGroup::translateChanged( const KateEditInfo& edit)
00318 {
00319
00320
00321 foreach (KateSmartCursor* cursor, m_feedbackCursors)
00322 cursor->translate(edit);
00323
00324 foreach (KateSmartCursor* cursor, m_normalCursors)
00325 cursor->translate(edit);
00326 }
00327
00328 void KateSmartGroup::translateShifted(const KateEditInfo& edit)
00329 {
00330 m_newStartLine = m_startLine + edit.translate().line();
00331 m_newEndLine = m_endLine + edit.translate().line();
00332 }
00333
00334 void KateSmartGroup::translatedChanged(const KateEditInfo& edit)
00335 {
00336 m_startLine = m_newStartLine;
00337 m_endLine = m_newEndLine;
00338
00339 foreach (KateSmartCursor* cursor, m_feedbackCursors)
00340 cursor->translated(edit);
00341 }
00342
00343 void KateSmartGroup::translatedShifted(const KateEditInfo& edit)
00344 {
00345 if (m_startLine != m_newStartLine) {
00346 m_startLine = m_newStartLine;
00347 m_endLine = m_newEndLine;
00348 }
00349
00350 if (edit.translate().line() == 0)
00351 return;
00352
00353
00354 foreach (KateSmartCursor* cursor, m_feedbackCursors)
00355 cursor->shifted();
00356 }
00357
00358 KateSmartGroup::KateSmartGroup( int startLine, int endLine, KateSmartGroup * previous, KateSmartGroup * next )
00359 : m_startLine(startLine)
00360 , m_newStartLine(startLine)
00361 , m_endLine(endLine)
00362 , m_newEndLine(endLine)
00363 , m_next(next)
00364 , m_previous(previous)
00365 {
00366 if (m_previous)
00367 m_previous->setNext(this);
00368
00369 if (m_next)
00370 m_next->setPrevious(this);
00371 }
00372
00373 void KateSmartGroup::merge( )
00374 {
00375 Q_ASSERT(m_next);
00376
00377 foreach (KateSmartCursor* cursor, next()->feedbackCursors())
00378 cursor->migrate(this);
00379 m_feedbackCursors += next()->feedbackCursors();
00380
00381 foreach (KateSmartCursor* cursor, next()->normalCursors())
00382 cursor->migrate(this);
00383 m_normalCursors += next()->normalCursors();
00384
00385 m_newEndLine = m_endLine = next()->endLine();
00386 KateSmartGroup* newNext = next()->next();
00387 delete m_next;
00388 m_next = newNext;
00389 if (m_next)
00390 m_next->setPrevious(this);
00391 }
00392
00393 const QSet< KateSmartCursor * > & KateSmartGroup::feedbackCursors( ) const
00394 {
00395 return m_feedbackCursors;
00396 }
00397
00398 const QSet< KateSmartCursor * > & KateSmartGroup::normalCursors( ) const
00399 {
00400 return m_normalCursors;
00401 }
00402
00403 void KateSmartManager::debugOutput( ) const
00404 {
00405 int groupCount = 1;
00406 KateSmartGroup* currentGroup = m_firstGroup;
00407 while (currentGroup->next()) {
00408 ++groupCount;
00409 currentGroup = currentGroup->next();
00410 }
00411
00412 kDebug() << "KateSmartManager: SmartGroups " << groupCount << " from " << m_firstGroup->startLine() << " to " << currentGroup->endLine();
00413
00414 currentGroup = m_firstGroup;
00415 while (currentGroup) {
00416 currentGroup->debugOutput();
00417 currentGroup = currentGroup->next();
00418 }
00419 }
00420
00421 void KateSmartGroup::debugOutput( ) const
00422 {
00423 kDebug() << " -> KateSmartGroup: from " << startLine() << " to " << endLine() << "; Cursors " << m_normalCursors.count() + m_feedbackCursors.count() << " (" << m_feedbackCursors.count() << " feedback)";
00424 }
00425
00426 void KateSmartManager::verifyCorrect() const
00427 {
00428 KateSmartGroup* currentGroup = groupForLine(0);
00429 Q_ASSERT(currentGroup);
00430 Q_ASSERT(currentGroup == m_firstGroup);
00431
00432 forever {
00433 if (!currentGroup->previous())
00434 Q_ASSERT(currentGroup->startLine() == 0);
00435
00436 foreach (KateSmartCursor* cursor, currentGroup->feedbackCursors()) {
00437 Q_ASSERT(currentGroup->containsLine(cursor->line()));
00438 Q_ASSERT(cursor->smartGroup() == currentGroup);
00439 }
00440
00441 if (!currentGroup->next())
00442 break;
00443
00444 Q_ASSERT(currentGroup->endLine() == currentGroup->next()->startLine() - 1);
00445 Q_ASSERT(currentGroup->next()->previous() == currentGroup);
00446
00447 currentGroup = currentGroup->next();
00448 }
00449
00450 Q_ASSERT(currentGroup->endLine() == doc()->lines() - 1);
00451
00452 kDebug() << "Verified correct." << currentGroup->endLine() << doc()->lines() - 1;
00453 }
00454
00455 void KateSmartManager::rangeGotParent( KateSmartRange * range )
00456 {
00457 Q_ASSERT(m_topRanges.contains(range));
00458 m_topRanges.remove(range);
00459 }
00460
00461 void KateSmartManager::rangeLostParent( KateSmartRange * range )
00462 {
00463 Q_ASSERT(!m_topRanges.contains(range));
00464 m_topRanges.insert(range);
00465 }
00466
00467 void KateSmartManager::rangeDeleted( KateSmartRange* range )
00468 {
00469 emit signalRangeDeleted(range);
00470
00471 if (!range->parentRange())
00472 m_topRanges.remove(range);
00473 }
00474
00475 void KateSmartManager::unbindSmartRange( SmartRange * range )
00476 {
00477 static_cast<KateSmartRange*>(range)->unbindAndDelete();
00478 }
00479
00480 void KateSmartManager::deleteCursors(bool includingInternal)
00481 {
00482 m_invalidGroup->deleteCursors(includingInternal);
00483 for (KateSmartGroup* g = m_firstGroup; g; g = g->next())
00484 g->deleteCursors(includingInternal);
00485 }
00486
00487 void KateSmartGroup::deleteCursors( bool includingInternal )
00488 {
00489 if (includingInternal) {
00490 qDeleteAll(m_feedbackCursors);
00491 m_feedbackCursors.clear();
00492
00493 qDeleteAll(m_normalCursors);
00494 m_normalCursors.clear();
00495
00496 } else {
00497 deleteCursorsInternal(m_feedbackCursors);
00498 deleteCursorsInternal(m_normalCursors);
00499 }
00500 }
00501
00502 void KateSmartGroup::deleteCursorsInternal( QSet< KateSmartCursor * > & set )
00503 {
00504 foreach (KateSmartCursor* c, set.toList()) {
00505 if (!c->range() && !c->isInternal()) {
00506 set.remove(c);
00507 delete c;
00508 }
00509 }
00510 }
00511
00512 void KateSmartManager::deleteRanges( bool includingInternal )
00513 {
00514 foreach (KateSmartRange* range, m_topRanges.toList()) {
00515 if (includingInternal || !range->isInternal()) {
00516 range->deleteChildRanges();
00517 delete range;
00518
00519 if (!includingInternal)
00520 m_topRanges.remove(range);
00521 }
00522 }
00523
00524 if (includingInternal)
00525 m_topRanges.clear();
00526 }
00527
00528 void KateSmartManager::clear( bool includingInternal )
00529 {
00530 deleteRanges(includingInternal);
00531
00532 m_clearing = true;
00533 deleteCursors(includingInternal);
00534 m_clearing = false;
00535 }
00536
00537 void KateSmartManager::useRevision(int revision)
00538 {
00539 if (!m_usingRevision.hasLocalData())
00540 m_usingRevision.setLocalData(new int);
00541
00542 *m_usingRevision.localData() = revision;
00543 }
00544
00545 int KateSmartManager::usingRevision() const
00546 {
00547 if (m_usingRevision.hasLocalData())
00548 return *m_usingRevision.localData();
00549
00550 return -1;
00551 }
00552
00553 void KateSmartManager::releaseRevision(int revision) const
00554 {
00555 doc()->history()->releaseRevision(revision);
00556 }
00557
00558 int KateSmartManager::currentRevision() const
00559 {
00560 return doc()->history()->revision();
00561 }
00562
00563 static void translate(KateEditInfo* edit, Cursor& ret, SmartCursor::InsertBehavior insertBehavior)
00564 {
00565
00566
00567 if (ret < edit->start())
00568 return;
00569
00570
00571 if (edit->oldRange().overlapsLine(ret.line())) {
00572
00573 if (ret == edit->start()) {
00574
00575 if (insertBehavior == SmartCursor::StayOnInsert)
00576 return;
00577 }
00578
00579
00580 Cursor newPos;
00581 if (edit->oldRange().contains(ret)) {
00582 if (insertBehavior == SmartCursor::MoveOnInsert)
00583 ret = edit->newRange().end();
00584 else
00585 ret = edit->start();
00586
00587 } else {
00588 ret += edit->translate();
00589 }
00590
00591 return;
00592 }
00593
00594
00595 ret.setLine(ret.line() + edit->translate().line());
00596 }
00597
00598 Cursor KateSmartManager::translateFromRevision(const Cursor& cursor, SmartCursor::InsertBehavior insertBehavior) const
00599 {
00600 Cursor ret = cursor;
00601
00602 foreach (KateEditInfo* edit, doc()->history()->editsBetweenRevisions(usingRevision()))
00603 translate(edit, ret, insertBehavior);
00604
00605 return ret;
00606 }
00607
00608 Range KateSmartManager::translateFromRevision(const Range& range, KTextEditor::SmartRange::InsertBehaviors insertBehavior) const
00609 {
00610 Cursor start = range.start(), end = range.end();
00611
00612 foreach (KateEditInfo* edit, doc()->history()->editsBetweenRevisions(usingRevision())) {
00613 translate(edit, start, insertBehavior & KTextEditor::SmartRange::ExpandLeft ? SmartCursor::StayOnInsert : SmartCursor::MoveOnInsert);
00614 translate(edit, end, insertBehavior & KTextEditor::SmartRange::ExpandRight ? SmartCursor::MoveOnInsert : SmartCursor::StayOnInsert);
00615 }
00616
00617 return Range(start, end);
00618 }
00619
00620 #include "katesmartmanager.moc"