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

KTextEditor

smartrange.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2003-2005 Hamish Rodda <rodda@kde.org>
00003    Copyright (C) 2008 David Nolden <david.nolden.kdevelop@art-master.de>
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 version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "smartrange.h"
00021 
00022 #include <QtCore/QStack>
00023 
00024 #include "document.h"
00025 #include "view.h"
00026 #include "attribute.h"
00027 #include "rangefeedback.h"
00028 
00029 #include <kaction.h>
00030 #include <kdebug.h>
00031 
00032 using namespace KTextEditor;
00033 
00034 //Uncomment this to enable debugging of the child-order. If it is enabled, an assertion will
00035 //be triggered when the order is violated.
00036 //This is slow.
00037 //    #define SHOULD_DEBUG_CHILD_ORDER
00038 
00039 //Uncomment this to debug the m_overlapCount values. When it is enabled,
00040 //extensive tests will be done to verify that the values are true,
00041 //and an assertion is triggered when not.
00042 //This is very slow, especially with many child-ranges.
00043 //    #define SHOULD_DEBUG_OVERLAP
00044 
00045 #ifdef SHOULD_DEBUG_CHILD_ORDER
00046 #define DEBUG_CHILD_ORDER \
00047   {\
00048   KTextEditor::Cursor lastEnd = KTextEditor::Cursor(-1,-1);\
00049   for(int a = 0; a < m_childRanges.size(); ++a) {\
00050     Q_ASSERT(m_childRanges[a]->end() >= lastEnd);\
00051     Q_ASSERT(m_childRanges[a]->start() >= start());\
00052     Q_ASSERT(m_childRanges[a]->end() <= end());\
00053     lastEnd = m_childRanges[a]->end();\
00054   }\
00055   }\
00056   
00057 #else
00058 #define DEBUG_CHILD_ORDER
00059 #endif
00060 
00061 #ifdef SHOULD_DEBUG_OVERLAP
00062 #define DEBUG_CHILD_OVERLAP  \
00063 {\
00064   QVector<int> counter(m_childRanges.size(), 0);\
00065 \
00066   for(int a = 0; a < m_childRanges.size(); ++a) {\
00067     const SmartRange& overlapper(*m_childRanges[a]);\
00068     for(int b = 0; b < a; ++b) {\
00069       const SmartRange& overlapped(*m_childRanges[b]);\
00070       Q_ASSERT(overlapped.end() <= overlapper.end());\
00071       if(overlapped.end() > overlapper.start()) {\
00072         ++counter[b];\
00073       }\
00074     }\
00075   }\
00076   for(int a = 0; a < m_childRanges.size(); ++a) {\
00077     Q_ASSERT(m_childRanges[a]->m_overlapCount == counter[a]);\
00078   }\
00079 }\
00080 
00081 #define DEBUG_PARENT_OVERLAP  \
00082 if(m_parentRange) {\
00083   QVector<int> counter(m_parentRange->m_childRanges.size(), 0);\
00084 \
00085   for(int a = 0; a < m_parentRange->m_childRanges.size(); ++a) {\
00086     const SmartRange& overlapper(*m_parentRange->m_childRanges[a]);\
00087     for(int b = 0; b < a; ++b) {\
00088       const SmartRange& overlapped(*m_parentRange->m_childRanges[b]);\
00089       Q_ASSERT(overlapped.end() <= overlapper.end());\
00090       if(overlapped.end() > overlapper.start()) {\
00091         ++counter[b];\
00092       }\
00093     }\
00094   }\
00095   for(int a = 0; a < m_parentRange->m_childRanges.size(); ++a) {\
00096     Q_ASSERT(m_parentRange->m_childRanges[a]->m_overlapCount == counter[a]);\
00097   }\
00098 }\
00099 
00100 #else
00101 #define DEBUG_CHILD_OVERLAP
00102 #define DEBUG_PARENT_OVERLAP
00103 #endif
00104 
00107 static int lowerBound(const QList<SmartRange*>& ranges, const Cursor& pos)
00108 {
00109     int begin = 0;
00110     int n = ranges.count();
00111 
00112     int half;
00113     int middle;
00114 
00115     while (n > 0) {
00116         half = n >> 1;
00117         middle = begin + half;
00118         if(ranges[middle]->end() > pos) {
00119           n = half;
00120         }else{
00121           begin = middle + 1;
00122           n -= half + 1;
00123         }
00124     }
00125     return begin;
00126 }
00127 
00130 static int lowerBoundRange(const QList<SmartRange*>& ranges, const Cursor& pos, const SmartRange* range)
00131 {
00132     int begin = 0;
00133     int n = ranges.count();
00134 
00135     int half;
00136     int middle;
00137 
00138     while (n > 0) {
00139         half = n >> 1;
00140         middle = begin + half;
00141         if(ranges[begin] == range)
00142           return begin;
00143         if(ranges[middle] == range)
00144           return middle;
00145         
00146         if(ranges[middle]->end() > pos) {
00147           n = half;
00148         }else{
00149           begin = middle + 1;
00150           n -= half + 1;
00151         }
00152     }
00153     return begin;
00154 }
00155 
00157 static int findIndex(const QList<SmartRange*>& ranges, const SmartRange* smartRange, const Range* range) {
00158   int index = lowerBoundRange(ranges, range->start(), smartRange);
00159   int childCount = ranges.count();
00160   
00161   //In case of degenerated ranges, we may have found the wrong index.
00162   while(index < childCount && ranges[index] != smartRange)
00163     ++index;
00164 
00165   if(index == childCount) {
00166     //During rangeChanged the order may temporarily be inconsistent, so we use indexOf as fallback
00167     return ranges.indexOf(const_cast<SmartRange*>(smartRange));
00168 /*    if(smartRange != range) //Try again finding the range, using the smart-range only
00169       return findIndex(ranges, smartRange, smartRange);*/
00170     
00171 //     Q_ASSERT(ranges.indexOf(const_cast<SmartRange*>(smartRange)) == -1);
00172     return -1;
00173   }
00174   
00175   return index;
00176 }
00177 
00178 SmartRange::SmartRange(SmartCursor* start, SmartCursor* end, SmartRange * parent, InsertBehaviors insertBehavior )
00179   : Range(start, end)
00180   , m_attribute(0L)
00181   , m_parentRange(parent)
00182   , m_ownsAttribute(false)
00183   , m_overlapCount(0)
00184 {
00185   setInsertBehavior(insertBehavior);
00186 
00187   // Not calling setParentRange here...:
00188   // 1) subclasses are not yet constructed
00189   // 2) it would otherwise give the wrong impression
00190   if (m_parentRange)
00191     m_parentRange->insertChildRange(this);
00192 }
00193 
00194 SmartRange::~SmartRange( )
00195 {
00196   deleteChildRanges();
00197 
00198   setParentRange(0L);
00199 
00200   /*if (!m_deleteCursors)
00201   {
00202     // Save from deletion in the parent
00203     m_start = 0L;
00204     m_end = 0L;
00205   }*/
00206 }
00207 
00208 bool SmartRange::confineToRange(const Range& range)
00209 {
00210   if (!Range::confineToRange(range))
00211     // Don't need to check if children should be confined, they already are
00212     return false;
00213 
00214   foreach (SmartRange* child, m_childRanges)
00215     child->confineToRange(*this);
00216 
00217   return true;
00218 }
00219 
00220 bool SmartRange::expandToRange(const Range& range)
00221 {
00222   if (!Range::expandToRange(range))
00223     // Don't need to check if parents should be expanded, they already are
00224     return false;
00225 
00226   if (parentRange())
00227     parentRange()->expandToRange(*this);
00228   
00229   return true;
00230 }
00231 
00232 void SmartRange::setRange(const Range& range)
00233 {
00234   if (range == *this)
00235     return;
00236 
00237   Range old = *this;
00238 
00239   Range::setRange(range);
00240   
00241   DEBUG_CHILD_OVERLAP
00242 }
00243 
00244 const QList<SmartRange*>& SmartRange::childRanges() const
00245 {
00246   return m_childRanges;
00247 }
00248 
00249 SmartRange * SmartRange::childBefore( const SmartRange * range ) const
00250 {
00251   int index = findIndex(m_childRanges, range, range);
00252   
00253   if (--index >= 0)
00254     return m_childRanges[index];
00255   
00256   return 0L;
00257 }
00258 
00259 SmartRange * SmartRange::childAfter( const SmartRange * range ) const
00260 {
00261   int index = findIndex(m_childRanges, range, range);
00262   if (index != -1 && ++index < m_childRanges.count())
00263     return m_childRanges[index];
00264   return 0L;
00265 }
00266 
00267 void SmartRange::insertChildRange( SmartRange * newChild )
00268 {
00269   DEBUG_CHILD_OVERLAP
00270 
00271   Q_ASSERT(newChild->parentRange() == this);
00272 
00273   // A new child has been added, so expand this range if required.
00274   expandToRange(*newChild);
00275   
00276   DEBUG_CHILD_ORDER
00277 
00278   int insertAt = lowerBound(m_childRanges, newChild->end());
00279   m_childRanges.insert(insertAt, newChild);
00280   
00281   //Increase the overlap of previous ranges
00282   for(int current = insertAt-1; current >= 0; --current) {
00283     SmartRange& range(*m_childRanges[current]);
00284     Q_ASSERT(range.end() <= newChild->end());
00285     
00286     if(range.end() > newChild->start()) {
00287       ++range.m_overlapCount;
00288     }else{
00289       //range.end() <= start(), The range does not overlap, and the same applies for all earlier ranges
00290       break;
00291     }
00292   }
00293 
00294   //Increase this ranges overlap from already existing ranges
00295   for(int current = insertAt+1; current < m_childRanges.size(); ++current) {
00296     SmartRange& range(*m_childRanges[current]);
00297     Q_ASSERT(range.end() >= newChild->end());
00298     
00299     if(range.start() < newChild->end())
00300       ++newChild->m_overlapCount; //The range overlaps newChild
00301     
00302     if(!range.m_overlapCount)
00303       break; //If this follower-range isn't overlapped by any other ranges, we can break here.
00304   }
00305 
00306   DEBUG_CHILD_OVERLAP
00307 
00308   DEBUG_CHILD_ORDER
00309   
00310   QMutableListIterator<SmartRange*> it = m_childRanges;
00311   it.toBack();
00312 
00313   foreach (SmartRangeNotifier* n, m_notifiers)
00314     emit n->childRangeInserted(this, newChild);
00315 
00316   foreach (SmartRangeWatcher* w, m_watchers)
00317     w->childRangeInserted(this, newChild);
00318   
00319   DEBUG_CHILD_OVERLAP
00320   DEBUG_CHILD_ORDER
00321 }
00322 
00323 void SmartRange::removeChildRange(SmartRange* child)
00324 {
00325   DEBUG_CHILD_OVERLAP
00326   
00327   int index = findIndex(m_childRanges, child, child);
00328   if (index != -1) {
00329     m_childRanges.removeAt(index);
00330 
00331     //Reduce the overlap with all previously overlapping ranges(parentChildren is still sorted by the old end-position)
00332     for(int current = index-1; current >= 0; --current) {
00333       SmartRange& range(*m_childRanges[current]);
00334       Q_ASSERT(range.end() <= child->end());
00335       if(range.end() <= child->start()) {
00336         break; //This range did not overlap before, the same applies for all earlier ranges because of the order
00337       }else{
00338         if(range.m_overlapCount) {
00339           --range.m_overlapCount;
00340         } else {
00341           //May happen with more than 64 overlaps
00342 #ifdef SHOULD_DEBUG_OVERLAP
00343           Q_ASSERT(0);
00344 #endif
00345         }
00346       }
00347     }
00348     
00349     DEBUG_CHILD_OVERLAP
00350     
00351     child->m_overlapCount = 0; //It has no neighbors any more, so no overlap
00352     
00353     foreach (SmartRangeNotifier* n, m_notifiers)
00354       emit n->childRangeInserted(this, child);
00355 
00356     foreach (SmartRangeWatcher* w, m_watchers)
00357       w->childRangeInserted(this, child);
00358   }
00359 
00360   DEBUG_CHILD_OVERLAP
00361 }
00362 
00363 SmartRange * SmartRange::mostSpecificRange( const Range & input ) const
00364 {
00365   if (!input.isValid())
00366     return 0L;
00367 
00368   if (contains(input)) {
00369     int child = lowerBound(m_childRanges, input.start());
00370 
00371     SmartRange* mostSpecific = 0;
00372     
00373     while(child != m_childRanges.size()) {
00374       SmartRange* r = m_childRanges[child];
00375       if(r->contains(input)) {
00376         SmartRange* candidate = r->mostSpecificRange(input);
00377         if(mostSpecific == 0 ||
00378           ((candidate->end() - candidate->start()) < (mostSpecific->end() - mostSpecific->start())) ||
00379           (candidate->end() < mostSpecific->end()))
00380           mostSpecific = candidate;
00381       }
00382       
00383       if(r->m_overlapCount == 0)
00384         break;
00385       
00386       ++child; //We have to iterate as long as there is overlapping ranges
00387     }
00388 
00389     if(mostSpecific)
00390       return mostSpecific;
00391     else
00392       return const_cast<SmartRange*>(this);
00393 
00394   } else if (parentRange()) {
00395     return parentRange()->mostSpecificRange(input);
00396 
00397   } else {
00398     return 0L;
00399   }
00400 }
00401 
00402 SmartRange * SmartRange::firstRangeContaining( const Cursor & pos ) const
00403 {
00404   if (!pos.isValid())
00405     return 0L;
00406 
00407   if (contains(pos)) {
00408     if (parentRange() && parentRange()->contains(pos))
00409       return parentRange()->firstRangeContaining(pos);
00410 
00411     return const_cast<SmartRange*>(this);
00412 
00413   } else {
00414     if (!parentRange())
00415       return 0L;
00416 
00417     return parentRange()->firstRangeContaining(pos);
00418   }
00419 }
00420 
00421 int SmartRange::overlapCount() const
00422 {
00423   return m_overlapCount;
00424 }
00425 
00426 QList<SmartRange*> SmartRange::deepestRangesContaining(const Cursor& pos) const
00427 {
00428   QList<SmartRange*> ret;
00429   
00430   if(!contains(pos))
00431     return ret;
00432   
00433   int child = lowerBound(m_childRanges, pos);
00434   
00435   while(child != m_childRanges.size()) {
00436     SmartRange* r = m_childRanges[child];
00437     //The list will be unchanged if the range doesn't contain the position
00438     ret += r->deepestRangesContaining(pos);
00439     
00440     if(r->m_overlapCount == 0)
00441       break;
00442     
00443     ++child; //We have to iterate as long as there is overlapping ranges
00444   }
00445   
00446   if(!ret.isEmpty())
00447     return ret;
00448   else
00449     return ret << const_cast<SmartRange*>(this);
00450 }
00451 
00452 SmartRange * SmartRange::deepestRangeContaining( const Cursor & pos, QStack<SmartRange*>* rangesEntered, QStack<SmartRange*>* rangesExited ) const
00453 {
00454   if (!pos.isValid()) {
00455     // Just leave all ranges
00456     if (rangesExited) {
00457       SmartRange* range = const_cast<SmartRange*>(this);
00458       while (range) {
00459         rangesExited->append(range);
00460         range = range->parentRange();
00461       }
00462     }
00463     return 0L;
00464   }
00465 
00466   return deepestRangeContainingInternal(pos, rangesEntered, rangesExited, true);
00467 }
00468 
00469 SmartRange * SmartRange::deepestRangeContainingInternal( const Cursor & pos, QStack<SmartRange*>* rangesEntered, QStack<SmartRange*>* rangesExited, bool first ) const
00470 {
00471   if (contains(pos)) {
00472     if (!first && rangesEntered)
00473       rangesEntered->push(const_cast<SmartRange*>(this));
00474 
00475     int child = lowerBound(m_childRanges, pos);
00476 
00477     QStack<SmartRange*> mostSpecificStack;
00478     SmartRange* mostSpecific = 0;
00479     
00480     while(child != m_childRanges.size()) {
00481       SmartRange* r = m_childRanges[child];
00482       if(r->contains(pos)) {
00483         QStack<SmartRange*> candidateStack;
00484         SmartRange* candidateRange = r->deepestRangeContainingInternal(pos, rangesEntered ? &candidateStack : 0, 0);
00485         
00486         Q_ASSERT(!rangesEntered || !candidateStack.isEmpty());
00487         Q_ASSERT(candidateRange);
00488         
00489         if(!mostSpecific ||
00490           ((candidateRange->end() - candidateRange->start()) < (mostSpecific->end() - mostSpecific->start())) ||
00491           (candidateRange->end() < mostSpecific->end())) {
00492           mostSpecific = candidateRange;
00493           mostSpecificStack = candidateStack;
00494         }
00495       }
00496       
00497       if(r->m_overlapCount == 0)
00498         break;
00499       
00500       ++child; //We have to iterate as long as there is overlapping ranges
00501     }
00502     
00503     if(mostSpecific) {
00504       if(rangesEntered)
00505         *rangesEntered += mostSpecificStack;
00506       return mostSpecific;
00507     }
00508     
00509     return const_cast<SmartRange*>(this);
00510 
00511   } else {
00512     if (rangesExited)
00513       rangesExited->push(const_cast<SmartRange*>(this));
00514 
00515     if (!parentRange())
00516       return 0L;
00517 
00518     // first is true, because the parentRange won't be "entered" on first descent
00519     return parentRange()->deepestRangeContainingInternal(pos, rangesEntered, rangesExited, true);
00520   }
00521 }
00522 
00523 Document* SmartRange::document( ) const
00524 {
00525   return smartStart().document();
00526 }
00527 
00528 void SmartRange::associateAction( KAction * action )
00529 {
00530   m_associatedActions.append(action);
00531 
00532   bool enable = false;
00533   if (View* v = document()->activeView())
00534     if (contains(v->cursorPosition()))
00535       enable = true;
00536 
00537   action->setEnabled(enable);
00538 
00539   if (m_associatedActions.count() == 1)
00540     checkFeedback();
00541 }
00542 
00543 void SmartRange::dissociateAction( KAction * action )
00544 {
00545   m_associatedActions.removeAll(action);
00546   if (!m_associatedActions.count())
00547     checkFeedback();
00548 }
00549 
00550 void SmartRange::clearAssociatedActions( )
00551 {
00552   m_associatedActions.clear();
00553   checkFeedback();
00554 }
00555 
00556 SmartRange::InsertBehaviors SmartRange::insertBehavior( ) const
00557 {
00558   return ((smartStart().insertBehavior() == SmartCursor::MoveOnInsert) ? DoNotExpand : ExpandLeft) | ((smartEnd().insertBehavior() == SmartCursor::MoveOnInsert) ? ExpandRight : DoNotExpand);
00559 }
00560 
00561 void SmartRange::setInsertBehavior(SmartRange::InsertBehaviors behavior)
00562 {
00563   static_cast<SmartCursor*>(m_start)->setInsertBehavior((behavior & ExpandLeft) ? SmartCursor::StayOnInsert : SmartCursor::MoveOnInsert);
00564   static_cast<SmartCursor*>(m_end)->setInsertBehavior((behavior & ExpandRight) ? SmartCursor::MoveOnInsert : SmartCursor::StayOnInsert);
00565 }
00566 
00567 void SmartRange::clearChildRanges()
00568 {
00569   foreach (SmartRange* r, m_childRanges)
00570     r->removeText();
00571 }
00572 
00573 void SmartRange::deleteChildRanges()
00574 {
00575   // FIXME: Probably more efficient to prevent them from unlinking themselves?
00576   qDeleteAll(m_childRanges);
00577 
00578   // i.e. this is probably already clear
00579   m_childRanges.clear();
00580 }
00581 
00582 void SmartRange::clearAndDeleteChildRanges( )
00583 {
00584   // FIXME: Probably more efficient to prevent them from unlinking themselves?
00585   foreach (SmartRange* r, m_childRanges)
00586     r->removeText();
00587 
00588   qDeleteAll(m_childRanges);
00589 
00590   // i.e. this is probably already clear
00591   m_childRanges.clear();
00592 }
00593 
00594 void SmartRange::setParentRange( SmartRange * r )
00595 {
00596   if (m_parentRange == r)
00597     return;
00598   
00599   DEBUG_PARENT_OVERLAP
00600 
00601   if (m_parentRange)
00602     m_parentRange->removeChildRange(this);
00603 
00604   SmartRange* oldParent = m_parentRange;
00605 
00606   m_parentRange = r;
00607 
00608   if (m_parentRange)
00609     m_parentRange->insertChildRange(this);
00610 
00611   foreach (SmartRangeNotifier* n, m_notifiers)
00612     emit n->parentRangeChanged(this, m_parentRange, oldParent);
00613 
00614   foreach (SmartRangeWatcher* w, m_watchers)
00615     w->parentRangeChanged(this, m_parentRange, oldParent);
00616   
00617   DEBUG_PARENT_OVERLAP
00618 }
00619 
00620 void SmartRange::setAttribute( Attribute::Ptr attribute )
00621 {
00622   if (attribute == m_attribute)
00623     return;
00624 
00625   Attribute::Ptr prev = m_attribute;
00626 
00627   m_attribute = attribute;
00628 
00629   foreach (SmartRangeNotifier* n, m_notifiers)
00630     emit n->rangeAttributeChanged(this, attribute, prev);
00631 
00632   foreach (SmartRangeWatcher* w, m_watchers)
00633     w->rangeAttributeChanged(this, attribute, prev);
00634 }
00635 
00636 Attribute::Ptr SmartRange::attribute( ) const
00637 {
00638   return m_attribute;
00639 }
00640 
00641 QStringList SmartRange::text( bool block ) const
00642 {
00643   return document()->textLines(*this, block);
00644 }
00645 
00646 bool SmartRange::replaceText( const QStringList & text, bool block )
00647 {
00648   return document()->replaceText(*this, text, block);
00649 }
00650 
00651 bool SmartRange::removeText( bool block )
00652 {
00653   return document()->removeText(*this, block);
00654 }
00655 
00656 static bool rangeEndLessThan(const SmartRange* s1, const SmartRange* s2) {
00657   return s1->end() < s2->end();
00658 }
00659 
00660 void SmartRange::rebuildChildStructure() {
00661   
00663   qStableSort(m_childRanges.begin(), m_childRanges.end(), rangeEndLessThan);
00664   DEBUG_CHILD_ORDER
00666   for(int a = 0; a < m_childRanges.size(); ++a) {
00667     SmartRange& overlapper(*m_childRanges[a]);
00668     overlapper.m_overlapCount = 0;
00669     
00670     //Increase the overlap of overlapped ranegs
00671     for(int current = a-1; current >= 0; --current) {
00672       SmartRange& range(*m_childRanges[current]);
00673       Q_ASSERT(range.end() <= overlapper.end());
00674       
00675       if(range.end() > overlapper.start()) {
00676         ++range.m_overlapCount;
00677       }else{
00678         //range.end() <= start(), The range does not overlap, and the same applies for all earlier ranges
00679         break;
00680       }
00681     }
00682   }
00683   
00684   DEBUG_CHILD_OVERLAP
00685 }
00686 
00687 void SmartRange::rangeChanged( Cursor* c, const Range& from )
00688 {
00689 #ifdef SHOULD_DEBUG_CHILD_ORDER
00690   if (parentRange() ) {
00691     //Make sure the child-order is correct, in respect to "from"
00692     QList<SmartRange*>& parentChildren(parentRange()->m_childRanges);
00693     
00694     int index = findIndex(parentChildren, this, &from);
00695     Q_ASSERT(index != -1);
00696     Q_ASSERT(parentChildren[index] == this);
00697     const Range* lastRange = 0;
00698     for(int a = 0; a < index; ++a) {
00699       if(lastRange) {
00700         Q_ASSERT(lastRange->end() <= parentChildren[a]->end());
00701       }
00702       lastRange = parentChildren[a];
00703     }
00704     
00705     if(lastRange) {
00706       Q_ASSERT(lastRange->end() <= from.end());
00707     }
00708     
00709     if(index+1 < parentChildren.size()) {
00710       Q_ASSERT(from.end() <= parentChildren[index+1]->end());
00711     }
00712     lastRange = &from;
00713     
00714     for(int a = index+1; a < parentChildren.size(); ++a) {
00715       if(lastRange) {
00716         Q_ASSERT(lastRange->end() <= parentChildren[a]->end());
00717       }
00718       lastRange = parentChildren[a];
00719     }
00720   }
00721 #endif
00722   Range::rangeChanged(c, from);
00723 
00724   // Decide whether the parent range has expanded or contracted, if there is one
00725   if (parentRange() ) {
00726     QList<SmartRange*>& parentChildren(parentRange()->m_childRanges);
00727     
00728     int index = findIndex(parentChildren, this, &from);
00729     Q_ASSERT(index != -1);
00730     Q_ASSERT(parentChildren[index] == this);
00731     
00732     //Reduce the overlap with all previously overlapping ranges(parentChildren is still sorted by the old end-position)
00733     for(int current = index-1; current >= 0; --current) {
00734       SmartRange& range(*parentChildren[current]);
00735       Q_ASSERT(range.end() <= from.end());
00736       if(range.end() <= from.start()) {
00737 //         break; //This range did not overlap before, the same applies for all earlier ranges because of the order
00738       }else{
00739         if(range.m_overlapCount) {
00740           --range.m_overlapCount;
00741         }else{
00742 #ifdef SHOULD_DEBUG_OVERLAP
00743           Q_ASSERT(0);
00744 #endif
00745         }
00746       }
00747     }
00748     
00749   //Decrease this ranges overlap from existing ranges behind, since it may be moved so it isn't overlapped any more
00750   for(int current = index+1; current < parentChildren.size(); ++current) {
00751     SmartRange& range(*parentChildren[current]);
00752     Q_ASSERT(range.end() >= from.end());
00753     
00754     if(range.start() < from.end())
00755       --m_overlapCount; //The range overlaps newChild
00756     
00757     if(!range.m_overlapCount)
00758       break; //If this follower-range isn't overlapped by any other ranges, we can break here.
00759   }
00760     
00761     if(from.end() != end()) {
00762       //Update the order in the parent, the ranges must be strictly sorted
00763       if(from.end() > end()) {
00764         //Bubble backwards, the position has been reduced
00765         while(index > 0 && parentChildren[index-1]->end() > end()) {
00766           parentChildren[index] = parentChildren[index-1];
00767           parentChildren[index-1] = this;
00768           --index;
00769         }
00770       }else{
00771         //Bubble forwards, the position has moved forwards
00772         while( index+1 < parentChildren.size() && (parentChildren[index+1]->end() < end()) ) {
00773           parentChildren[index] = parentChildren[index+1];
00774           parentChildren[index+1] = this;
00775           ++index;
00776         }
00777       }
00778     }
00779     Q_ASSERT(parentChildren[index] == this);
00780     
00781     //Increase the overlap
00782     for(int current = index-1; current >= 0; --current) {
00783       SmartRange& range(*parentChildren[current]);
00784       Q_ASSERT(range.end() <= end());
00785       
00786       if(range.end() > start()) {
00787         ++range.m_overlapCount;
00788       }else{
00789         //range.end() <= start(), The range does not overlap, and the same applies for all earlier ranges
00790         break;
00791       }
00792     }
00793     
00794   //Increase this ranges overlap from existing ranges behind, since it may have been moved
00795   for(int current = index+1; current < parentChildren.size(); ++current) {
00796     SmartRange& range(*parentChildren[current]);
00797     Q_ASSERT(range.end() >= end());
00798     
00799     if(range.start() < end())
00800       ++m_overlapCount; //The range overlaps newChild
00801     
00802     if(!range.m_overlapCount)
00803       break; //If this follower-range isn't overlapped by any other ranges, we can break here.
00804   }
00805     
00806   DEBUG_CHILD_ORDER
00807   DEBUG_PARENT_OVERLAP
00808   
00809   //Expand the parent in the end, so the overlap is consistent when the parent gets control
00810   if ((start() < from.start() || end() > from.end()))
00811     parentRange()->expandToRange(*this);
00812   }
00813   
00814   DEBUG_CHILD_OVERLAP
00815 
00816   
00817   // Contract child ranges if required
00818   if(!m_childRanges.isEmpty()) {
00819     if (start() > from.start()) {
00820       foreach(SmartRange* child, m_childRanges) {
00821         if(child->start() < start())
00822           child->start() = start();
00823         else if(!child->m_overlapCount)
00824           break; //We can safely break here, because the child is not overlapped
00825       }
00826     }
00827 
00828     if (end() < from.end()) {
00829       
00830       //We have to create a copy of the child-ranges, because their order may change
00831       QList<SmartRange*> oldChildRanges = m_childRanges;
00832       
00833       for(int a = oldChildRanges.size()-1; a >= 0; --a) {
00834         if(oldChildRanges[a]->end() <= end())
00835           break; //Child-ranges are sorted by the end-cursor, so we can just break here.
00836         oldChildRanges[a]->end() = end();
00837       }
00838     }
00839   }
00840 
00841   DEBUG_CHILD_ORDER
00842   DEBUG_CHILD_OVERLAP
00843   
00844   // SmartCursor and its subclasses take care of adjusting ranges if the tree
00845   // structure is being used.
00846   foreach (SmartRangeNotifier* n, m_notifiers)
00847     if (n->wantsDirectChanges()) {
00848       emit n->rangePositionChanged(this);
00849       emit n->rangeContentsChanged(this);
00850 
00851       if (start() == end())
00852         emit n->rangeEliminated(this);
00853     }
00854 
00855   foreach (SmartRangeWatcher* w, m_watchers)
00856     if (w->wantsDirectChanges()) {
00857       w->rangePositionChanged(this);
00858       w->rangeContentsChanged(this);
00859 
00860       if (start() == end())
00861         w->rangeEliminated(this);
00862     }
00863 }
00864 
00865 bool SmartRange::isSmartRange( ) const
00866 {
00867   return true;
00868 }
00869 
00870 SmartRange* SmartRange::toSmartRange( ) const
00871 {
00872   return const_cast<SmartRange*>(this);
00873 }
00874 
00875 bool SmartRange::hasParent( SmartRange * parent ) const
00876 {
00877   if (parentRange() == parent)
00878     return true;
00879 
00880   if (parentRange())
00881     return parentRange()->hasParent(parent);
00882 
00883   return false;
00884 }
00885 
00886 const QList< SmartRangeWatcher * > & SmartRange::watchers( ) const
00887 {
00888   return m_watchers;
00889 }
00890 
00891 void SmartRange::addWatcher( SmartRangeWatcher * watcher )
00892 {
00893   if (!m_watchers.contains(watcher))
00894     m_watchers.append(watcher);
00895 
00896   checkFeedback();
00897 }
00898 
00899 void SmartRange::removeWatcher( SmartRangeWatcher * watcher )
00900 {
00901   m_watchers.removeAll(watcher);
00902   checkFeedback();
00903 }
00904 
00905 SmartRangeNotifier * SmartRange::primaryNotifier( )
00906 {
00907   if (m_notifiers.isEmpty())
00908     m_notifiers.append(createNotifier());
00909 
00910   return m_notifiers.first();
00911 }
00912 
00913 const QList< SmartRangeNotifier * > SmartRange::notifiers( ) const
00914 {
00915   return m_notifiers;
00916 }
00917 
00918 void SmartRange::addNotifier( SmartRangeNotifier * notifier )
00919 {
00920   if (!m_notifiers.contains(notifier))
00921     m_notifiers.append(notifier);
00922 
00923   checkFeedback();
00924 }
00925 
00926 void SmartRange::removeNotifier( SmartRangeNotifier * notifier )
00927 {
00928   m_notifiers.removeAll(notifier);
00929   checkFeedback();
00930 }
00931 
00932 void SmartRange::deletePrimaryNotifier( )
00933 {
00934   if (m_notifiers.isEmpty())
00935     return;
00936 
00937   SmartRangeNotifier* n = m_notifiers.first();
00938   removeNotifier(n);
00939   delete n;
00940 }
00941 
00942 void SmartRange::checkFeedback( )
00943 {
00944 }
00945 
00946 // kate: space-indent on; indent-width 2; replace-tabs on;

KTextEditor

Skip menu "KTextEditor"
  • Main Page
  • Modules
  • 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