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

KTextEditor

  • kde-4.14
  • applications
  • kate
  • ktexteditor
smartrange.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 2003-2005 Hamish Rodda <rodda@kde.org>
3  Copyright (C) 2008 David Nolden <david.nolden.kdevelop@art-master.de>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include "smartrange.h"
21 
22 #include <QtCore/QStack>
23 
24 #include "document.h"
25 #include "view.h"
26 #include "attribute.h"
27 #include "rangefeedback.h"
28 
29 #include <kaction.h>
30 #include <kdebug.h>
31 
32 using namespace KTextEditor;
33 
34 //Uncomment this to enable debugging of the child-order. If it is enabled, an assertion will
35 //be triggered when the order is violated.
36 //This is slow.
37 // #define SHOULD_DEBUG_CHILD_ORDER
38 
39 //Uncomment this to debug the m_overlapCount values. When it is enabled,
40 //extensive tests will be done to verify that the values are true,
41 //and an assertion is triggered when not.
42 //This is very slow, especially with many child-ranges.
43 // #define SHOULD_DEBUG_OVERLAP
44 
45 #ifdef SHOULD_DEBUG_CHILD_ORDER
46 #define DEBUG_CHILD_ORDER \
47  {\
48  KTextEditor::Cursor lastEnd = KTextEditor::Cursor(-1,-1);\
49  for(int a = 0; a < m_childRanges.size(); ++a) {\
50  Q_ASSERT(m_childRanges[a]->end() >= lastEnd);\
51  Q_ASSERT(m_childRanges[a]->start() >= start());\
52  Q_ASSERT(m_childRanges[a]->end() <= end());\
53  lastEnd = m_childRanges[a]->end();\
54  }\
55  }\
56 
57 #else
58 #define DEBUG_CHILD_ORDER
59 #endif
60 
61 #ifdef SHOULD_DEBUG_OVERLAP
62 #define DEBUG_CHILD_OVERLAP \
63 {\
64  QVector<int> counter(m_childRanges.size(), 0);\
65 \
66  for(int a = 0; a < m_childRanges.size(); ++a) {\
67  const SmartRange& overlapper(*m_childRanges[a]);\
68  for(int b = 0; b < a; ++b) {\
69  const SmartRange& overlapped(*m_childRanges[b]);\
70  Q_ASSERT(overlapped.end() <= overlapper.end());\
71  if(overlapped.end() > overlapper.start()) {\
72  ++counter[b];\
73  }\
74  }\
75  }\
76  for(int a = 0; a < m_childRanges.size(); ++a) {\
77  Q_ASSERT(m_childRanges[a]->m_overlapCount == counter[a]);\
78  }\
79 }\
80 
81 #define DEBUG_PARENT_OVERLAP \
82 if(m_parentRange) {\
83  QVector<int> counter(m_parentRange->m_childRanges.size(), 0);\
84 \
85  for(int a = 0; a < m_parentRange->m_childRanges.size(); ++a) {\
86  const SmartRange& overlapper(*m_parentRange->m_childRanges[a]);\
87  for(int b = 0; b < a; ++b) {\
88  const SmartRange& overlapped(*m_parentRange->m_childRanges[b]);\
89  Q_ASSERT(overlapped.end() <= overlapper.end());\
90  if(overlapped.end() > overlapper.start()) {\
91  ++counter[b];\
92  }\
93  }\
94  }\
95  for(int a = 0; a < m_parentRange->m_childRanges.size(); ++a) {\
96  Q_ASSERT(m_parentRange->m_childRanges[a]->m_overlapCount == counter[a]);\
97  }\
98 }\
99 
100 #else
101 #define DEBUG_CHILD_OVERLAP
102 #define DEBUG_PARENT_OVERLAP
103 #endif
104 
107 static int lowerBound(const QList<SmartRange*>& ranges, const Cursor& pos)
108 {
109  int begin = 0;
110  int n = ranges.count();
111 
112  int half;
113  int middle;
114 
115  while (n > 0) {
116  half = n >> 1;
117  middle = begin + half;
118  if(ranges[middle]->end() > pos) {
119  n = half;
120  }else{
121  begin = middle + 1;
122  n -= half + 1;
123  }
124  }
125  return begin;
126 }
127 
130 static int lowerBoundRange(const QList<SmartRange*>& ranges, const Cursor& pos, const SmartRange* range)
131 {
132  int begin = 0;
133  int n = ranges.count();
134 
135  int half;
136  int middle;
137 
138  while (n > 0) {
139  half = n >> 1;
140  middle = begin + half;
141  if(ranges[begin] == range)
142  return begin;
143  if(ranges[middle] == range)
144  return middle;
145 
146  if(ranges[middle]->end() > pos) {
147  n = half;
148  }else{
149  begin = middle + 1;
150  n -= half + 1;
151  }
152  }
153  return begin;
154 }
155 
157 static int findIndex(const QList<SmartRange*>& ranges, const SmartRange* smartRange, const Range* range) {
158  int index = lowerBoundRange(ranges, range->start(), smartRange);
159  int childCount = ranges.count();
160 
161  //In case of degenerated ranges, we may have found the wrong index.
162  while(index < childCount && ranges[index] != smartRange)
163  ++index;
164 
165  if(index == childCount) {
166  //During rangeChanged the order may temporarily be inconsistent, so we use indexOf as fallback
167  return ranges.indexOf(const_cast<SmartRange*>(smartRange));
168 /* if(smartRange != range) //Try again finding the range, using the smart-range only
169  return findIndex(ranges, smartRange, smartRange);*/
170 
171 // Q_ASSERT(ranges.indexOf(const_cast<SmartRange*>(smartRange)) == -1);
172  return -1;
173  }
174 
175  return index;
176 }
177 
178 SmartRange::SmartRange(SmartCursor* start, SmartCursor* end, SmartRange * parent, InsertBehaviors insertBehavior )
179  : Range(start, end)
180  , m_attribute(0L)
181  , m_parentRange(parent)
182  , m_ownsAttribute(false)
183  , m_overlapCount(0)
184 {
185  setInsertBehavior(insertBehavior);
186 
187  // Not calling setParentRange here...:
188  // 1) subclasses are not yet constructed
189  // 2) it would otherwise give the wrong impression
190  if (m_parentRange)
191  m_parentRange->insertChildRange(this);
192 }
193 
194 SmartRange::~SmartRange( )
195 {
196  deleteChildRanges();
197 
198  setParentRange(0L);
199 
200  /*if (!m_deleteCursors)
201  {
202  // Save from deletion in the parent
203  m_start = 0L;
204  m_end = 0L;
205  }*/
206 }
207 
208 bool SmartRange::confineToRange(const Range& range)
209 {
210  if (!Range::confineToRange(range))
211  // Don't need to check if children should be confined, they already are
212  return false;
213 
214  foreach (SmartRange* child, m_childRanges)
215  child->confineToRange(*this);
216 
217  return true;
218 }
219 
220 bool SmartRange::expandToRange(const Range& range)
221 {
222  if (!Range::expandToRange(range))
223  // Don't need to check if parents should be expanded, they already are
224  return false;
225 
226  if (parentRange())
227  parentRange()->expandToRange(*this);
228 
229  return true;
230 }
231 
232 void SmartRange::setRange(const Range& range)
233 {
234  if (range == *this)
235  return;
236 
237  Range old = *this;
238 
239  Range::setRange(range);
240 
241  DEBUG_CHILD_OVERLAP
242 }
243 
244 const QList<SmartRange*>& SmartRange::childRanges() const
245 {
246  return m_childRanges;
247 }
248 
249 SmartRange * SmartRange::childBefore( const SmartRange * range ) const
250 {
251  int index = findIndex(m_childRanges, range, range);
252 
253  if (--index >= 0)
254  return m_childRanges[index];
255 
256  return 0L;
257 }
258 
259 SmartRange * SmartRange::childAfter( const SmartRange * range ) const
260 {
261  int index = findIndex(m_childRanges, range, range);
262  if (index != -1 && ++index < m_childRanges.count())
263  return m_childRanges[index];
264  return 0L;
265 }
266 
267 void SmartRange::insertChildRange( SmartRange * newChild )
268 {
269  DEBUG_CHILD_OVERLAP
270 
271  Q_ASSERT(newChild->parentRange() == this);
272 
273  // A new child has been added, so expand this range if required.
274  expandToRange(*newChild);
275 
276  DEBUG_CHILD_ORDER
277 
278  int insertAt = lowerBound(m_childRanges, newChild->end());
279  m_childRanges.insert(insertAt, newChild);
280 
281  //Increase the overlap of previous ranges
282  for(int current = insertAt-1; current >= 0; --current) {
283  SmartRange& range(*m_childRanges[current]);
284  Q_ASSERT(range.end() <= newChild->end());
285 
286  if(range.end() > newChild->start()) {
287  ++range.m_overlapCount;
288  }else{
289  //range.end() <= start(), The range does not overlap, and the same applies for all earlier ranges
290  break;
291  }
292  }
293 
294  //Increase this ranges overlap from already existing ranges
295  for(int current = insertAt+1; current < m_childRanges.size(); ++current) {
296  SmartRange& range(*m_childRanges[current]);
297  Q_ASSERT(range.end() >= newChild->end());
298 
299  if(range.start() < newChild->end())
300  ++newChild->m_overlapCount; //The range overlaps newChild
301 
302  if(!range.m_overlapCount)
303  break; //If this follower-range isn't overlapped by any other ranges, we can break here.
304  }
305 
306  DEBUG_CHILD_OVERLAP
307 
308  DEBUG_CHILD_ORDER
309 
310  QMutableListIterator<SmartRange*> it = m_childRanges;
311  it.toBack();
312 
313  foreach (SmartRangeNotifier* n, m_notifiers)
314  emit n->childRangeInserted(this, newChild);
315 
316  foreach (SmartRangeWatcher* w, m_watchers)
317  w->childRangeInserted(this, newChild);
318 
319  DEBUG_CHILD_OVERLAP
320  DEBUG_CHILD_ORDER
321 }
322 
323 void SmartRange::removeChildRange(SmartRange* child)
324 {
325  DEBUG_CHILD_OVERLAP
326 
327  int index = findIndex(m_childRanges, child, child);
328  if (index != -1) {
329  m_childRanges.removeAt(index);
330 
331  //Reduce the overlap with all previously overlapping ranges(parentChildren is still sorted by the old end-position)
332  for(int current = index-1; current >= 0; --current) {
333  SmartRange& range(*m_childRanges[current]);
334  Q_ASSERT(range.end() <= child->end());
335  if(range.end() <= child->start()) {
336  break; //This range did not overlap before, the same applies for all earlier ranges because of the order
337  }else{
338  if(range.m_overlapCount) {
339  --range.m_overlapCount;
340  } else {
341  //May happen with more than 64 overlaps
342 #ifdef SHOULD_DEBUG_OVERLAP
343  Q_ASSERT(0);
344 #endif
345  }
346  }
347  }
348 
349  DEBUG_CHILD_OVERLAP
350 
351  child->m_overlapCount = 0; //It has no neighbors any more, so no overlap
352 
353  foreach (SmartRangeNotifier* n, m_notifiers)
354  emit n->childRangeInserted(this, child);
355 
356  foreach (SmartRangeWatcher* w, m_watchers)
357  w->childRangeInserted(this, child);
358  }
359 
360  DEBUG_CHILD_OVERLAP
361 }
362 
363 SmartRange * SmartRange::mostSpecificRange( const Range & input ) const
364 {
365  if (!input.isValid())
366  return 0L;
367 
368  if (contains(input)) {
369  int child = lowerBound(m_childRanges, input.start());
370 
371  SmartRange* mostSpecific = 0;
372 
373  while(child != m_childRanges.size()) {
374  SmartRange* r = m_childRanges[child];
375  if(r->contains(input)) {
376  SmartRange* candidate = r->mostSpecificRange(input);
377  if(mostSpecific == 0 ||
378  ((candidate->end() - candidate->start()) < (mostSpecific->end() - mostSpecific->start())) ||
379  (candidate->end() < mostSpecific->end()))
380  mostSpecific = candidate;
381  }
382 
383  if(r->m_overlapCount == 0)
384  break;
385 
386  ++child; //We have to iterate as long as there is overlapping ranges
387  }
388 
389  if(mostSpecific)
390  return mostSpecific;
391  else
392  return const_cast<SmartRange*>(this);
393 
394  } else if (parentRange()) {
395  return parentRange()->mostSpecificRange(input);
396 
397  } else {
398  return 0L;
399  }
400 }
401 
402 SmartRange * SmartRange::firstRangeContaining( const Cursor & pos ) const
403 {
404  if (!pos.isValid())
405  return 0L;
406 
407  if (contains(pos)) {
408  if (parentRange() && parentRange()->contains(pos))
409  return parentRange()->firstRangeContaining(pos);
410 
411  return const_cast<SmartRange*>(this);
412 
413  } else {
414  if (!parentRange())
415  return 0L;
416 
417  return parentRange()->firstRangeContaining(pos);
418  }
419 }
420 
421 int SmartRange::overlapCount() const
422 {
423  return m_overlapCount;
424 }
425 
426 QList<SmartRange*> SmartRange::deepestRangesContaining(const Cursor& pos) const
427 {
428  QList<SmartRange*> ret;
429 
430  if(!contains(pos))
431  return ret;
432 
433  int child = lowerBound(m_childRanges, pos);
434 
435  while(child != m_childRanges.size()) {
436  SmartRange* r = m_childRanges[child];
437  //The list will be unchanged if the range doesn't contain the position
438  ret += r->deepestRangesContaining(pos);
439 
440  if(r->m_overlapCount == 0)
441  break;
442 
443  ++child; //We have to iterate as long as there is overlapping ranges
444  }
445 
446  if(!ret.isEmpty())
447  return ret;
448  else
449  return ret << const_cast<SmartRange*>(this);
450 }
451 
452 SmartRange * SmartRange::deepestRangeContaining( const Cursor & pos, QStack<SmartRange*>* rangesEntered, QStack<SmartRange*>* rangesExited ) const
453 {
454  if (!pos.isValid()) {
455  // Just leave all ranges
456  if (rangesExited) {
457  SmartRange* range = const_cast<SmartRange*>(this);
458  while (range) {
459  rangesExited->append(range);
460  range = range->parentRange();
461  }
462  }
463  return 0L;
464  }
465 
466  return deepestRangeContainingInternal(pos, rangesEntered, rangesExited, true);
467 }
468 
469 SmartRange * SmartRange::deepestRangeContainingInternal( const Cursor & pos, QStack<SmartRange*>* rangesEntered, QStack<SmartRange*>* rangesExited, bool first ) const
470 {
471  if (contains(pos)) {
472  if (!first && rangesEntered)
473  rangesEntered->push(const_cast<SmartRange*>(this));
474 
475  int child = lowerBound(m_childRanges, pos);
476 
477  QStack<SmartRange*> mostSpecificStack;
478  SmartRange* mostSpecific = 0;
479 
480  while(child != m_childRanges.size()) {
481  SmartRange* r = m_childRanges[child];
482  if(r->contains(pos)) {
483  QStack<SmartRange*> candidateStack;
484  SmartRange* candidateRange = r->deepestRangeContainingInternal(pos, rangesEntered ? &candidateStack : 0, 0);
485 
486  Q_ASSERT(!rangesEntered || !candidateStack.isEmpty());
487  Q_ASSERT(candidateRange);
488 
489  if(!mostSpecific ||
490  ((candidateRange->end() - candidateRange->start()) < (mostSpecific->end() - mostSpecific->start())) ||
491  (candidateRange->end() < mostSpecific->end())) {
492  mostSpecific = candidateRange;
493  mostSpecificStack = candidateStack;
494  }
495  }
496 
497  if(r->m_overlapCount == 0)
498  break;
499 
500  ++child; //We have to iterate as long as there is overlapping ranges
501  }
502 
503  if(mostSpecific) {
504  if(rangesEntered)
505  *rangesEntered += mostSpecificStack;
506  return mostSpecific;
507  }
508 
509  return const_cast<SmartRange*>(this);
510 
511  } else {
512  if (rangesExited)
513  rangesExited->push(const_cast<SmartRange*>(this));
514 
515  if (!parentRange())
516  return 0L;
517 
518  // first is true, because the parentRange won't be "entered" on first descent
519  return parentRange()->deepestRangeContainingInternal(pos, rangesEntered, rangesExited, true);
520  }
521 }
522 
523 Document* SmartRange::document( ) const
524 {
525  return smartStart().document();
526 }
527 
528 void SmartRange::associateAction( KAction * action )
529 {
530  m_associatedActions.append(action);
531 
532  bool enable = false;
533  if (View* v = document()->activeView())
534  if (contains(v->cursorPosition()))
535  enable = true;
536 
537  action->setEnabled(enable);
538 
539  if (m_associatedActions.count() == 1)
540  checkFeedback();
541 }
542 
543 void SmartRange::dissociateAction( KAction * action )
544 {
545  m_associatedActions.removeAll(action);
546  if (!m_associatedActions.count())
547  checkFeedback();
548 }
549 
550 void SmartRange::clearAssociatedActions( )
551 {
552  m_associatedActions.clear();
553  checkFeedback();
554 }
555 
556 SmartRange::InsertBehaviors SmartRange::insertBehavior( ) const
557 {
558  return ((smartStart().insertBehavior() == SmartCursor::MoveOnInsert) ? DoNotExpand : ExpandLeft) | ((smartEnd().insertBehavior() == SmartCursor::MoveOnInsert) ? ExpandRight : DoNotExpand);
559 }
560 
561 void SmartRange::setInsertBehavior(SmartRange::InsertBehaviors behavior)
562 {
563  static_cast<SmartCursor*>(m_start)->setInsertBehavior((behavior & ExpandLeft) ? SmartCursor::StayOnInsert : SmartCursor::MoveOnInsert);
564  static_cast<SmartCursor*>(m_end)->setInsertBehavior((behavior & ExpandRight) ? SmartCursor::MoveOnInsert : SmartCursor::StayOnInsert);
565 }
566 
567 void SmartRange::clearChildRanges()
568 {
569  foreach (SmartRange* r, m_childRanges)
570  r->removeText();
571 }
572 
573 void SmartRange::deleteChildRanges()
574 {
575  // FIXME: Probably more efficient to prevent them from unlinking themselves?
576  qDeleteAll(m_childRanges);
577 
578  // i.e. this is probably already clear
579  m_childRanges.clear();
580 }
581 
582 void SmartRange::clearAndDeleteChildRanges( )
583 {
584  // FIXME: Probably more efficient to prevent them from unlinking themselves?
585  foreach (SmartRange* r, m_childRanges)
586  r->removeText();
587 
588  qDeleteAll(m_childRanges);
589 
590  // i.e. this is probably already clear
591  m_childRanges.clear();
592 }
593 
594 void SmartRange::setParentRange( SmartRange * r )
595 {
596  if (m_parentRange == r)
597  return;
598 
599  DEBUG_PARENT_OVERLAP
600 
601  if (m_parentRange)
602  m_parentRange->removeChildRange(this);
603 
604  SmartRange* oldParent = m_parentRange;
605 
606  m_parentRange = r;
607 
608  if (m_parentRange)
609  m_parentRange->insertChildRange(this);
610 
611  foreach (SmartRangeNotifier* n, m_notifiers)
612  emit n->parentRangeChanged(this, m_parentRange, oldParent);
613 
614  foreach (SmartRangeWatcher* w, m_watchers)
615  w->parentRangeChanged(this, m_parentRange, oldParent);
616 
617  DEBUG_PARENT_OVERLAP
618 }
619 
620 void SmartRange::setAttribute( Attribute::Ptr attribute )
621 {
622  if (attribute == m_attribute)
623  return;
624 
625  Attribute::Ptr prev = m_attribute;
626 
627  m_attribute = attribute;
628 
629  foreach (SmartRangeNotifier* n, m_notifiers)
630  emit n->rangeAttributeChanged(this, attribute, prev);
631 
632  foreach (SmartRangeWatcher* w, m_watchers)
633  w->rangeAttributeChanged(this, attribute, prev);
634 }
635 
636 Attribute::Ptr SmartRange::attribute( ) const
637 {
638  return m_attribute;
639 }
640 
641 QStringList SmartRange::text( bool block ) const
642 {
643  return document()->textLines(*this, block);
644 }
645 
646 bool SmartRange::replaceText( const QStringList & text, bool block )
647 {
648  return document()->replaceText(*this, text, block);
649 }
650 
651 bool SmartRange::removeText( bool block )
652 {
653  return document()->removeText(*this, block);
654 }
655 
656 static bool rangeEndLessThan(const SmartRange* s1, const SmartRange* s2) {
657  return s1->end() < s2->end();
658 }
659 
660 void SmartRange::rebuildChildStructure() {
661 
663  qStableSort(m_childRanges.begin(), m_childRanges.end(), rangeEndLessThan);
664  DEBUG_CHILD_ORDER
666  for(int a = 0; a < m_childRanges.size(); ++a) {
667  SmartRange& overlapper(*m_childRanges[a]);
668  overlapper.m_overlapCount = 0;
669 
670  //Increase the overlap of overlapped ranegs
671  for(int current = a-1; current >= 0; --current) {
672  SmartRange& range(*m_childRanges[current]);
673  Q_ASSERT(range.end() <= overlapper.end());
674 
675  if(range.end() > overlapper.start()) {
676  ++range.m_overlapCount;
677  }else{
678  //range.end() <= start(), The range does not overlap, and the same applies for all earlier ranges
679  break;
680  }
681  }
682  }
683 
684  DEBUG_CHILD_OVERLAP
685 }
686 
687 void SmartRange::rangeChanged( Cursor* c, const Range& from )
688 {
689 #ifdef SHOULD_DEBUG_CHILD_ORDER
690  if (parentRange() ) {
691  //Make sure the child-order is correct, in respect to "from"
692  QList<SmartRange*>& parentChildren(parentRange()->m_childRanges);
693 
694  int index = findIndex(parentChildren, this, &from);
695  Q_ASSERT(index != -1);
696  Q_ASSERT(parentChildren[index] == this);
697  const Range* lastRange = 0;
698  for(int a = 0; a < index; ++a) {
699  if(lastRange) {
700  Q_ASSERT(lastRange->end() <= parentChildren[a]->end());
701  }
702  lastRange = parentChildren[a];
703  }
704 
705  if(lastRange) {
706  Q_ASSERT(lastRange->end() <= from.end());
707  }
708 
709  if(index+1 < parentChildren.size()) {
710  Q_ASSERT(from.end() <= parentChildren[index+1]->end());
711  }
712  lastRange = &from;
713 
714  for(int a = index+1; a < parentChildren.size(); ++a) {
715  if(lastRange) {
716  Q_ASSERT(lastRange->end() <= parentChildren[a]->end());
717  }
718  lastRange = parentChildren[a];
719  }
720  }
721 #endif
722  Range::rangeChanged(c, from);
723 
724  // Decide whether the parent range has expanded or contracted, if there is one
725  if (parentRange() ) {
726  QList<SmartRange*>& parentChildren(parentRange()->m_childRanges);
727 
728  int index = findIndex(parentChildren, this, &from);
729  Q_ASSERT(index != -1);
730  Q_ASSERT(parentChildren[index] == this);
731 
732  //Reduce the overlap with all previously overlapping ranges(parentChildren is still sorted by the old end-position)
733  for(int current = index-1; current >= 0; --current) {
734  SmartRange& range(*parentChildren[current]);
735  Q_ASSERT(range.end() <= from.end());
736  if(range.end() <= from.start()) {
737 // break; //This range did not overlap before, the same applies for all earlier ranges because of the order
738  }else{
739  if(range.m_overlapCount) {
740  --range.m_overlapCount;
741  }else{
742 #ifdef SHOULD_DEBUG_OVERLAP
743  Q_ASSERT(0);
744 #endif
745  }
746  }
747  }
748 
749  //Decrease this ranges overlap from existing ranges behind, since it may be moved so it isn't overlapped any more
750  for(int current = index+1; current < parentChildren.size(); ++current) {
751  SmartRange& range(*parentChildren[current]);
752  Q_ASSERT(range.end() >= from.end());
753 
754  if(range.start() < from.end())
755  --m_overlapCount; //The range overlaps newChild
756 
757  if(!range.m_overlapCount)
758  break; //If this follower-range isn't overlapped by any other ranges, we can break here.
759  }
760 
761  if(from.end() != end()) {
762  //Update the order in the parent, the ranges must be strictly sorted
763  if(from.end() > end()) {
764  //Bubble backwards, the position has been reduced
765  while(index > 0 && parentChildren[index-1]->end() > end()) {
766  parentChildren[index] = parentChildren[index-1];
767  parentChildren[index-1] = this;
768  --index;
769  }
770  }else{
771  //Bubble forwards, the position has moved forwards
772  while( index+1 < parentChildren.size() && (parentChildren[index+1]->end() < end()) ) {
773  parentChildren[index] = parentChildren[index+1];
774  parentChildren[index+1] = this;
775  ++index;
776  }
777  }
778  }
779  Q_ASSERT(parentChildren[index] == this);
780 
781  //Increase the overlap
782  for(int current = index-1; current >= 0; --current) {
783  SmartRange& range(*parentChildren[current]);
784  Q_ASSERT(range.end() <= end());
785 
786  if(range.end() > start()) {
787  ++range.m_overlapCount;
788  }else{
789  //range.end() <= start(), The range does not overlap, and the same applies for all earlier ranges
790  break;
791  }
792  }
793 
794  //Increase this ranges overlap from existing ranges behind, since it may have been moved
795  for(int current = index+1; current < parentChildren.size(); ++current) {
796  SmartRange& range(*parentChildren[current]);
797  Q_ASSERT(range.end() >= end());
798 
799  if(range.start() < end())
800  ++m_overlapCount; //The range overlaps newChild
801 
802  if(!range.m_overlapCount)
803  break; //If this follower-range isn't overlapped by any other ranges, we can break here.
804  }
805 
806  DEBUG_CHILD_ORDER
807  DEBUG_PARENT_OVERLAP
808 
809  //Expand the parent in the end, so the overlap is consistent when the parent gets control
810  if ((start() < from.start() || end() > from.end()))
811  parentRange()->expandToRange(*this);
812  }
813 
814  DEBUG_CHILD_OVERLAP
815 
816 
817  // Contract child ranges if required
818  if(!m_childRanges.isEmpty()) {
819  if (start() > from.start()) {
820  foreach(SmartRange* child, m_childRanges) {
821  if(child->start() < start())
822  child->start() = start();
823  else if(!child->m_overlapCount)
824  break; //We can safely break here, because the child is not overlapped
825  }
826  }
827 
828  if (end() < from.end()) {
829 
830  //We have to create a copy of the child-ranges, because their order may change
831  QList<SmartRange*> oldChildRanges = m_childRanges;
832 
833  for(int a = oldChildRanges.size()-1; a >= 0; --a) {
834  if(oldChildRanges[a]->end() <= end())
835  break; //Child-ranges are sorted by the end-cursor, so we can just break here.
836  oldChildRanges[a]->end() = end();
837  }
838  }
839  }
840 
841  DEBUG_CHILD_ORDER
842  DEBUG_CHILD_OVERLAP
843 
844  // SmartCursor and its subclasses take care of adjusting ranges if the tree
845  // structure is being used.
846  foreach (SmartRangeNotifier* n, m_notifiers)
847  if (n->wantsDirectChanges()) {
848  emit n->rangePositionChanged(this);
849  emit n->rangeContentsChanged(this);
850 
851  if (start() == end())
852  emit n->rangeEliminated(this);
853  }
854 
855  foreach (SmartRangeWatcher* w, m_watchers)
856  if (w->wantsDirectChanges()) {
857  w->rangePositionChanged(this);
858  w->rangeContentsChanged(this);
859 
860  if (start() == end())
861  w->rangeEliminated(this);
862  }
863 }
864 
865 bool SmartRange::isSmartRange( ) const
866 {
867  return true;
868 }
869 
870 SmartRange* SmartRange::toSmartRange( ) const
871 {
872  return const_cast<SmartRange*>(this);
873 }
874 
875 bool SmartRange::hasParent( SmartRange * parent ) const
876 {
877  if (parentRange() == parent)
878  return true;
879 
880  if (parentRange())
881  return parentRange()->hasParent(parent);
882 
883  return false;
884 }
885 
886 const QList< SmartRangeWatcher * > & SmartRange::watchers( ) const
887 {
888  return m_watchers;
889 }
890 
891 void SmartRange::addWatcher( SmartRangeWatcher * watcher )
892 {
893  if (!m_watchers.contains(watcher))
894  m_watchers.append(watcher);
895 
896  checkFeedback();
897 }
898 
899 void SmartRange::removeWatcher( SmartRangeWatcher * watcher )
900 {
901  m_watchers.removeAll(watcher);
902  checkFeedback();
903 }
904 
905 SmartRangeNotifier * SmartRange::primaryNotifier( )
906 {
907  if (m_notifiers.isEmpty())
908  m_notifiers.append(createNotifier());
909 
910  return m_notifiers.first();
911 }
912 
913 const QList< SmartRangeNotifier * > SmartRange::notifiers( ) const
914 {
915  return m_notifiers;
916 }
917 
918 void SmartRange::addNotifier( SmartRangeNotifier * notifier )
919 {
920  if (!m_notifiers.contains(notifier))
921  m_notifiers.append(notifier);
922 
923  checkFeedback();
924 }
925 
926 void SmartRange::removeNotifier( SmartRangeNotifier * notifier )
927 {
928  m_notifiers.removeAll(notifier);
929  checkFeedback();
930 }
931 
932 void SmartRange::deletePrimaryNotifier( )
933 {
934  if (m_notifiers.isEmpty())
935  return;
936 
937  SmartRangeNotifier* n = m_notifiers.first();
938  removeNotifier(n);
939  delete n;
940 }
941 
942 void SmartRange::checkFeedback( )
943 {
944 }
945 
946 // kate: space-indent on; indent-width 2; replace-tabs on;
KTextEditor::SmartCursor::StayOnInsert
Definition: smartcursor.h:188
QList::clear
void clear()
KTextEditor::Range::start
Cursor & start()
Get the start position of this range.
Definition: range.cpp:296
lowerBound
static int lowerBound(const QList< SmartRange * > &ranges, const Cursor &pos)
Returns the index of the first range that ends behind pos The list must be sorted by the ranges end-p...
Definition: smartrange.cpp:107
KTextEditor::SmartRange::childAfter
SmartRange * childAfter(const SmartRange *range) const
Find the child after range, if any.
Definition: smartrange.cpp:259
KTextEditor::SmartRange::hasParent
bool hasParent(SmartRange *parent) const
Determine whether parent is a parent of this range.
Definition: smartrange.cpp:875
KTextEditor::SmartRangeWatcher::parentRangeChanged
virtual void parentRangeChanged(SmartRange *range, SmartRange *newParent, SmartRange *oldParent)
The range's parent was changed.
Definition: rangefeedback.cpp:106
KTextEditor::SmartRangeNotifier::parentRangeChanged
void parentRangeChanged(KTextEditor::SmartRange *range, KTextEditor::SmartRange *newParent, KTextEditor::SmartRange *oldParent)
The range's parent was changed.
KTextEditor::Range::m_start
Cursor * m_start
This range's start cursor pointer.
Definition: range.h:654
KTextEditor::SmartRange::deepestRangeContaining
SmartRange * deepestRangeContaining(const Cursor &pos, QStack< SmartRange * > *rangesEntered=0L, QStack< SmartRange * > *rangesExited=0L) const
Finds the deepest range in the heirachy which contains position pos.
Definition: smartrange.cpp:452
KTextEditor::SmartRange::setParentRange
virtual void setParentRange(SmartRange *r)
Set this range's parent range.
Definition: smartrange.cpp:594
QVector::append
void append(const T &value)
KTextEditor::SmartCursor::insertBehavior
InsertBehavior insertBehavior() const
Returns how this cursor behaves when text is inserted at the cursor.
Definition: smartcursor.cpp:78
KTextEditor::Range::isValid
virtual bool isValid() const
Validity check.
Definition: range.cpp:116
KTextEditor::SmartRange::~SmartRange
virtual ~SmartRange()
Definition: smartrange.cpp:194
KTextEditor::SmartRange::confineToRange
virtual bool confineToRange(const Range &range)
Definition: smartrange.cpp:208
QStack::push
void push(const T &t)
KTextEditor::SmartRange::overlapCount
int overlapCount() const
Returns the count of ranges within the parent-range that end behind this range, and that overlap this...
Definition: smartrange.cpp:421
KTextEditor::SmartRangeNotifier::childRangeInserted
void childRangeInserted(KTextEditor::SmartRange *range, KTextEditor::SmartRange *child)
The range child was inserted as a child range into the current range.
KTextEditor::SmartRange::rebuildChildStructure
void rebuildChildStructure()
Is called after child-ranges have changed internally without the rangeChanged() notification, for example after translations.
Definition: smartrange.cpp:660
KTextEditor::SmartRange
A Range which is bound to a specific Document, and maintains its position.
Definition: smartrange.h:94
DEBUG_CHILD_ORDER
#define DEBUG_CHILD_ORDER
Definition: smartrange.cpp:58
DEBUG_PARENT_OVERLAP
#define DEBUG_PARENT_OVERLAP
Definition: smartrange.cpp:102
KTextEditor::SmartRangeNotifier::rangeAttributeChanged
void rangeAttributeChanged(KTextEditor::SmartRange *range, KTextEditor::Attribute::Ptr currentAttribute, KTextEditor::Attribute::Ptr previousAttribute)
The highlighting attribute of range was changed from previousAttribute to currentAttribute.
KTextEditor::Range::setRange
virtual void setRange(const Range &range)
Set the start and end cursors to range.start() and range.end() respectively.
Definition: range.cpp:126
smartrange.h
KTextEditor::Cursor
An object which represents a position in a Document.
Definition: cursor.h:55
DEBUG_CHILD_OVERLAP
#define DEBUG_CHILD_OVERLAP
Definition: smartrange.cpp:101
KTextEditor::Range::confineToRange
virtual bool confineToRange(const Range &range)
Confine this range if necessary to fit within range.
Definition: range.cpp:192
rangefeedback.h
KTextEditor::Range::rangeChanged
virtual void rangeChanged(Cursor *cursor, const Range &from)
Notify this range that one or both of the cursors' position has changed directly. ...
Definition: range.cpp:222
QList::size
int size() const
KTextEditor::SmartRange::ExpandRight
Expand to encapsulate new characters to the right of the range.
Definition: smartrange.h:106
KTextEditor::SmartRange::deletePrimaryNotifier
void deletePrimaryNotifier()
When finished with the primaryNotifier(), call this method to save memory by having the SmartRangeNot...
Definition: smartrange.cpp:932
KTextEditor::SmartRange::dissociateAction
void dissociateAction(KAction *action)
Remove the association with an action from this range; it will no longer be managed.
Definition: smartrange.cpp:543
QList::indexOf
int indexOf(const T &value, int from) const
KTextEditor::SmartRange::associateAction
void associateAction(KAction *action)
Associate an action with this range.
Definition: smartrange.cpp:528
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
KTextEditor::SmartRangeNotifier::rangeContentsChanged
void rangeContentsChanged(KTextEditor::SmartRange *range)
The contents of the range changed.
KTextEditor::SmartRange::attribute
Attribute::Ptr attribute() const
Gets the active Attribute for this range.
Definition: smartrange.cpp:636
KTextEditor::Cursor::isValid
virtual bool isValid() const
Returns whether the current position of this cursor is a valid position (line + column must both be >...
Definition: cursor.cpp:47
KTextEditor::SmartRange::expandToRange
virtual bool expandToRange(const Range &range)
Definition: smartrange.cpp:220
KTextEditor::SmartRange::setRange
virtual void setRange(const Range &range)
Set the start and end cursors to range.start() and range.end() respectively.
Definition: smartrange.cpp:232
KTextEditor::Range::m_end
Cursor * m_end
This range's end cursor pointer.
Definition: range.h:661
attribute.h
view.h
KTextEditor::Document::removeText
virtual bool removeText(const Range &range, bool block=false)=0
Remove the text specified in range.
KTextEditor::SmartRange::rangeChanged
virtual void rangeChanged(Cursor *cursor, const Range &from)
Definition: smartrange.cpp:687
KTextEditor::Document
A KParts derived class representing a text document.
Definition: document.h:111
KTextEditor::Attribute::Ptr
KSharedPtr< Attribute > Ptr
Definition: attribute.h:61
KTextEditor::SmartRange::setAttribute
void setAttribute(Attribute::Ptr attribute)
Sets the currently active attribute for this range.
Definition: smartrange.cpp:620
KTextEditor::SmartRange::notifiers
const QList< SmartRangeNotifier * > notifiers() const
Returns a list of notifiers which are receiving signals indicating change of state of this range...
Definition: smartrange.cpp:913
KTextEditor::SmartRange::checkFeedback
virtual void checkFeedback()
Definition: smartrange.cpp:942
KTextEditor::SmartRange::watchers
const QList< SmartRangeWatcher * > & watchers() const
Returns a list of registered SmartRangeWatchers.
Definition: smartrange.cpp:886
QList::isEmpty
bool isEmpty() const
QList::removeAll
int removeAll(const T &value)
KTextEditor::SmartRangeWatcher::childRangeInserted
virtual void childRangeInserted(SmartRange *range, SmartRange *child)
The range child was inserted as a child range into the current range.
Definition: rangefeedback.cpp:94
KTextEditor::SmartCursor
A Cursor which is bound to a specific Document, and maintains its position.
Definition: smartcursor.h:65
KTextEditor::SmartRange::replaceText
virtual bool replaceText(const QStringList &text, bool block=false)
Replace text in this range with text.
Definition: smartrange.cpp:646
KTextEditor::SmartRange::createNotifier
virtual SmartRangeNotifier * createNotifier()=0
KTextEditor::SmartRange::isSmartRange
virtual bool isSmartRange() const
Returns that this range is a SmartRange.
Definition: smartrange.cpp:865
KTextEditor::SmartRange::removeWatcher
void removeWatcher(SmartRangeWatcher *watcher)
Stop delivery of notifications to a SmartRangeWatcher.
Definition: smartrange.cpp:899
KTextEditor::SmartRange::smartEnd
SmartCursor & smartEnd()
Get the end point of this range.
Definition: smartrange.h:163
KTextEditor::SmartRange::smartStart
SmartCursor & smartStart()
Get the start point of this range.
Definition: smartrange.h:143
KTextEditor::SmartRange::childBefore
SmartRange * childBefore(const SmartRange *range) const
Find the child before range, if any.
Definition: smartrange.cpp:249
rangeEndLessThan
static bool rangeEndLessThan(const SmartRange *s1, const SmartRange *s2)
Definition: smartrange.cpp:656
document.h
KTextEditor::SmartRange::ExpandLeft
Expand to encapsulate new characters to the left of the range.
Definition: smartrange.h:104
QList
KTextEditor::SmartRange::text
virtual QStringList text(bool block=false) const
Retrieve the text which is contained within this range.
Definition: smartrange.cpp:641
QStringList
KTextEditor::SmartRangeWatcher::rangeEliminated
virtual void rangeEliminated(SmartRange *range)
The range now contains no characters (ie.
Definition: rangefeedback.cpp:86
KTextEditor::Range
An object representing a section of text, from one Cursor to another.
Definition: range.h:54
KTextEditor::SmartRange::insertBehavior
InsertBehaviors insertBehavior() const
Returns how this range reacts to characters inserted immediately outside the range.
Definition: smartrange.cpp:556
KTextEditor::SmartRange::deepestRangesContaining
QList< SmartRange * > deepestRangesContaining(const Cursor &pos) const
Definition: smartrange.cpp:426
QList::end
iterator end()
KTextEditor::SmartRange::SmartRange
SmartRange(SmartCursor *start, SmartCursor *end, SmartRange *parent=0L, InsertBehaviors insertBehavior=DoNotExpand)
Constructor for subclasses to utilise.
Definition: smartrange.cpp:178
KTextEditor::Range::expandToRange
virtual bool expandToRange(const Range &range)
Expand this range if necessary to contain range.
Definition: range.cpp:207
KTextEditor::SmartRangeWatcher::wantsDirectChanges
bool wantsDirectChanges() const
Returns whether this watcher will be notified of changes that happen directly to the range...
Definition: rangefeedback.cpp:48
KTextEditor::SmartRangeWatcher
A class which provides notifications of state changes to a SmartRange via virtual inheritance...
Definition: smartrangewatcher.h:50
KTextEditor::SmartRangeNotifier
A class which provides notifications of state changes to a SmartRange via QObject signals...
Definition: smartrangenotifier.h:48
KTextEditor::SmartRange::primaryNotifier
SmartRangeNotifier * primaryNotifier()
Connect to a notifier to receive signals indicating change of state of this range.
Definition: smartrange.cpp:905
QVector::isEmpty
bool isEmpty() const
KTextEditor::SmartRangeWatcher::rangeContentsChanged
virtual void rangeContentsChanged(SmartRange *range)
The contents of the range changed.
Definition: rangefeedback.cpp:62
QMutableListIterator
KTextEditor::SmartRangeNotifier::wantsDirectChanges
bool wantsDirectChanges() const
Returns whether this notifier will notify of changes that happen directly to the range, e.g.
Definition: rangefeedback.cpp:33
KTextEditor::Range::end
Cursor & end()
Get the end position of this range.
Definition: range.cpp:306
KTextEditor::SmartRangeNotifier::rangeEliminated
void rangeEliminated(KTextEditor::SmartRange *range)
The range now contains no characters (ie.
KTextEditor::SmartRange::childRanges
const QList< SmartRange * > & childRanges() const
Get the ordered list of child ranges.
Definition: smartrange.cpp:244
KTextEditor::SmartRangeNotifier::rangePositionChanged
void rangePositionChanged(KTextEditor::SmartRange *range)
The range's position changed.
KTextEditor::SmartRange::mostSpecificRange
SmartRange * mostSpecificRange(const Range &input) const
Finds the most specific range in a heirachy for the given input range (ie.
Definition: smartrange.cpp:363
KTextEditor::SmartCursor::MoveOnInsert
Definition: smartcursor.h:189
KTextEditor::SmartRange::toSmartRange
virtual SmartRange * toSmartRange() const
Returns this range as a SmartRange, if it is one.
Definition: smartrange.cpp:870
KTextEditor::SmartRange::addWatcher
void addWatcher(SmartRangeWatcher *watcher)
Register a SmartRangeWatcher to receive calls indicating change of state of this range.
Definition: smartrange.cpp:891
KTextEditor::SmartRange::deleteChildRanges
void deleteChildRanges()
Deletes child ranges - i.e., deletes the SmartRange objects only.
Definition: smartrange.cpp:573
KTextEditor::SmartRange::addNotifier
void addNotifier(SmartRangeNotifier *notifier)
Register a notifier to receive signals indicating change of state of this range.
Definition: smartrange.cpp:918
KTextEditor::Range::contains
bool contains(const Range &range) const
Check whether the this range wholly encompasses range.
Definition: range.cpp:160
findIndex
static int findIndex(const QList< SmartRange * > &ranges, const SmartRange *smartRange, const Range *range)
Finds the index of the given SmartRange in the sorted list using binary search. Uses.
Definition: smartrange.cpp:157
KTextEditor::SmartRange::removeNotifier
void removeNotifier(SmartRangeNotifier *notifier)
Deregister a notifier and no longer deliver signals indicating change of state of this range...
Definition: smartrange.cpp:926
KTextEditor::View
A text widget with KXMLGUIClient that represents a Document.
Definition: view.h:145
KTextEditor::SmartRange::document
Document * document() const
Retrieve the document associated with this SmartRange.
Definition: smartrange.cpp:523
KTextEditor::SmartRange::firstRangeContaining
SmartRange * firstRangeContaining(const Cursor &pos) const
Finds the first child range which contains position pos.
Definition: smartrange.cpp:402
KTextEditor::SmartRange::setInsertBehavior
void setInsertBehavior(InsertBehaviors behavior)
Determine how the range should react to characters inserted immediately outside the range...
Definition: smartrange.cpp:561
KTextEditor::SmartRange::removeText
virtual bool removeText(bool block=false)
Remove text contained within this range.
Definition: smartrange.cpp:651
KTextEditor::Document::textLines
virtual QStringList textLines(const Range &range, bool block=false) const =0
Get the document content within the given range.
KTextEditor::SmartRange::parentRange
SmartRange * parentRange() const
Returns this range's parent range, if one exists.
Definition: smartrange.h:277
KTextEditor::SmartRange::clearAndDeleteChildRanges
void clearAndDeleteChildRanges()
Clears child ranges - i.e., clears the text that is covered by the ranges, and deletes the SmartRange...
Definition: smartrange.cpp:582
KTextEditor::SmartRangeWatcher::rangePositionChanged
virtual void rangePositionChanged(SmartRange *range)
The range's position changed.
Definition: rangefeedback.cpp:58
KTextEditor::Document::replaceText
virtual bool replaceText(const Range &range, const QString &text, bool block=false)
Replace text from range with specified text.
Definition: document.cpp:170
KTextEditor::SmartRange::DoNotExpand
Don't expand to encapsulate new characters in either direction. This is the default.
Definition: smartrange.h:102
KTextEditor::SmartCursor::document
Document * document() const
Returns the document to which this cursor is attached.
Definition: smartcursor.cpp:68
lowerBoundRange
static int lowerBoundRange(const QList< SmartRange * > &ranges, const Cursor &pos, const SmartRange *range)
Searches for the given range, or a lower bound for the given position.
Definition: smartrange.cpp:130
QStack
Definition: smartrange.h:31
KTextEditor::SmartRange::clearChildRanges
void clearChildRanges()
Clears child ranges - i.e., removes the text that is covered by the ranges.
Definition: smartrange.cpp:567
KTextEditor::SmartRangeWatcher::rangeAttributeChanged
virtual void rangeAttributeChanged(SmartRange *range, Attribute::Ptr currentAttribute, Attribute::Ptr previousAttribute)
The highlighting attribute of range was changed from previousAttribute to currentAttribute.
Definition: rangefeedback.cpp:102
KTextEditor::SmartRange::clearAssociatedActions
void clearAssociatedActions()
Clears all associations between KActions and this range.
Definition: smartrange.cpp:550
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat May 9 2020 03:56:48 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KTextEditor

Skip menu "KTextEditor"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

applications API Reference

Skip menu "applications API Reference"
  •   kate
  •       kate
  •   KTextEditor
  •   Kate
  • Konsole

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal