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

Kate

  • kde-4.14
  • applications
  • kate
  • part
  • buffer
katetextfolding.cpp
Go to the documentation of this file.
1 /* This file is part of the Kate project.
2  *
3  * Copyright (C) 2013 Christoph Cullmann <cullmann@kde.org>
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 as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB. If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "katetextfolding.h"
22 #include "katetextbuffer.h"
23 #include "katetextrange.h"
24 
25 namespace Kate {
26 
27 TextFolding::FoldingRange::FoldingRange (TextBuffer &buffer, const KTextEditor::Range &range, FoldingRangeFlags _flags)
28  : start (new TextCursor (buffer, range.start(), KTextEditor::MovingCursor::MoveOnInsert))
29  , end (new TextCursor (buffer, range.end(), KTextEditor::MovingCursor::MoveOnInsert))
30  , parent (0)
31  , flags (_flags)
32  , id (-1)
33 {
34 }
35 
36 TextFolding::FoldingRange::~FoldingRange ()
37 {
42  delete start;
43  delete end;
44  qDeleteAll (nestedRanges);
45 }
46 
47 TextFolding::TextFolding (TextBuffer &buffer)
48  : QObject ()
49  , m_buffer (buffer)
50  , m_idCounter (-1)
51 {
55  connect (&m_buffer, SIGNAL(cleared()), SLOT(clear()));
56 }
57 
58 TextFolding::~TextFolding ()
59 {
63  qDeleteAll (m_foldingRanges);
64 }
65 
66 void TextFolding::clear ()
67 {
71  m_idCounter = -1;
72 
76  if (m_foldingRanges.isEmpty()) {
80  Q_ASSERT (m_idToFoldingRange.isEmpty());
81  Q_ASSERT (m_foldedFoldingRanges.isEmpty());
82  return;
83  }
84 
88  m_idToFoldingRange.clear();
89  m_foldedFoldingRanges.clear();
90  qDeleteAll (m_foldingRanges);
91  m_foldingRanges.clear ();
92 
96  emit foldingRangesChanged ();
97 }
98 
99 qint64 TextFolding::newFoldingRange (const KTextEditor::Range &range, FoldingRangeFlags flags)
100 {
105  if (!range.isValid() || range.isEmpty())
106  return -1;
107 
112  FoldingRange *newRange = new FoldingRange (m_buffer, range, flags);
113 
119  if ( !newRange->start->isValid()
120  || !newRange->end->isValid()
121  || !insertNewFoldingRange (0 /* no parent here */, m_foldingRanges, newRange)) {
125  delete newRange;
126  return -1;
127  }
128 
132  newRange->id = ++m_idCounter;
133  if (newRange->id < 0)
134  newRange->id = m_idCounter = 0;
135 
139  m_idToFoldingRange.insert (newRange->id, newRange);
140 
144  bool updated = updateFoldedRangesForNewRange (newRange);
145 
150  if (!updated)
151  emit foldingRangesChanged ();
152 
156  return newRange->id;
157 }
158 
159 KTextEditor::Range TextFolding::foldingRange(qint64 id) const
160 {
161  FoldingRange* range = m_idToFoldingRange.value (id);
162  if (!range)
163  return KTextEditor::Range::invalid();
164 
165  return KTextEditor::Range(range->start->toCursor(), range->end->toCursor());
166 }
167 
168 bool TextFolding::foldRange (qint64 id)
169 {
173  FoldingRange *range = m_idToFoldingRange.value (id);
174  if (!range)
175  return false;
176 
180  if (range->flags & Folded)
181  return true;
182 
186  range->flags |= Folded;
187  updateFoldedRangesForNewRange (range);
188  return true;
189 }
190 
191 bool TextFolding::unfoldRange (qint64 id, bool remove)
192 {
196  FoldingRange *range = m_idToFoldingRange.value (id);
197  if (!range)
198  return false;
199 
204  if (!remove && !(range->flags & Folded))
205  return true;
206 
210  const bool deleteRange = remove || !(range->flags & Persistent);
211 
215  if (deleteRange) {
219  m_idToFoldingRange.remove (id);
220 
225  FoldingRange::Vector &parentVector = range->parent ? range->parent->nestedRanges : m_foldingRanges;
226  FoldingRange::Vector newParentVector;
227  Q_FOREACH (FoldingRange *curRange, parentVector) {
231  if (curRange == range) {
232  Q_FOREACH (FoldingRange *newRange, range->nestedRanges) {
233  newRange->parent = range->parent;
234  newParentVector.push_back (newRange);
235  }
236 
237  continue;
238  }
239 
243  newParentVector.push_back (curRange);
244  }
245  parentVector = newParentVector;
246  }
247 
251  bool updated = false;
252  if (range->flags & Folded) {
253  range->flags &= ~Folded;
254  updated = updateFoldedRangesForRemovedRange (range);
255  }
256 
261  if (!updated)
262  emit foldingRangesChanged ();
263 
267  if (deleteRange) {
271  range->nestedRanges.clear ();
272  delete range;
273  }
274 
278  return true;
279 }
280 
281 bool TextFolding::isLineVisible (int line, qint64 *foldedRangeId) const
282 {
286  if (m_foldedFoldingRanges.isEmpty())
287  return true;
288 
292  FoldingRange::Vector::const_iterator upperBound = qUpperBound (m_foldedFoldingRanges.begin(), m_foldedFoldingRanges.end(), line, compareRangeByStartWithLine);
293  if (upperBound != m_foldedFoldingRanges.begin())
294  --upperBound;
295 
299  const bool hidden = (((*upperBound)->end->line() >= line) && (line > (*upperBound)->start->line()));
300 
304  if (foldedRangeId)
305  (*foldedRangeId) = hidden ? (*upperBound)->id : -1;
306 
310  return !hidden;
311 }
312 
313 void TextFolding::ensureLineIsVisible (int line)
314 {
318  if (m_foldedFoldingRanges.isEmpty())
319  return;
320 
324  qint64 foldedRangeId = -1;
325  while (!isLineVisible (line, &foldedRangeId)) {
329  Q_ASSERT (foldedRangeId >= 0);
330 
334  const bool unfolded = unfoldRange (foldedRangeId);
335  (void) unfolded;
336  Q_ASSERT (unfolded);
337  }
338 }
339 
340 int TextFolding::visibleLines () const
341 {
345  int visibleLines = m_buffer.lines();
346 
350  if (m_foldedFoldingRanges.isEmpty())
351  return visibleLines;
352 
356  Q_FOREACH (FoldingRange *range, m_foldedFoldingRanges)
357  visibleLines -= (range->end->line() - range->start->line());
358 
362  Q_ASSERT (visibleLines > 0);
363  return visibleLines;
364 }
365 
366 int TextFolding::lineToVisibleLine (int line) const
367 {
371  Q_ASSERT (line >= 0);
372 
376  int visibleLine = line;
377 
381  if (m_foldedFoldingRanges.isEmpty() || (line == 0))
382  return visibleLine;
383 
388  int seenVisibleLines = 0;
389  int lastLine = 0;
390  Q_FOREACH (FoldingRange *range, m_foldedFoldingRanges) {
394  if (range->start->line() >= line)
395  break;
396 
400  seenVisibleLines += (range->start->line() - lastLine);
401  lastLine = range->end->line();
402 
406  if (line <= range->end->line())
407  return seenVisibleLines;
408 
412  visibleLine -= (range->end->line() - range->start->line());
413  }
414 
418  Q_ASSERT (visibleLine >= 0);
419  return visibleLine;
420 }
421 
422 int TextFolding::visibleLineToLine (int visibleLine) const
423 {
427  Q_ASSERT (visibleLine >= 0);
428 
432  int line = visibleLine;
433 
437  if (m_foldedFoldingRanges.isEmpty() || (visibleLine == 0))
438  return line;
439 
443  int seenVisibleLines = 0;
444  int lastLine = 0;
445  int lastLineVisibleLines = 0;
446  Q_FOREACH (FoldingRange *range, m_foldedFoldingRanges) {
450  lastLineVisibleLines = seenVisibleLines;
451  seenVisibleLines += (range->start->line() - lastLine);
452 
456  if (seenVisibleLines >= visibleLine)
457  break;
458 
459  lastLine = range->end->line();
460  }
461 
465  if (seenVisibleLines < visibleLine)
466  lastLineVisibleLines = seenVisibleLines;
467 
471  line = (lastLine + (visibleLine - lastLineVisibleLines));
472  Q_ASSERT (line >= 0);
473  return line;
474 }
475 
476 QVector<QPair<qint64, TextFolding::FoldingRangeFlags> > TextFolding::foldingRangesStartingOnLine (int line) const
477 {
481  QVector<QPair<qint64, TextFolding::FoldingRangeFlags> > results;
482 
486  foldingRangesStartingOnLine (results, m_foldingRanges, line);
487 
491  return results;
492 }
493 
494 void TextFolding::foldingRangesStartingOnLine (QVector<QPair<qint64, FoldingRangeFlags> > &results, const TextFolding::FoldingRange::Vector &ranges, int line) const
495 {
499  if (ranges.isEmpty())
500  return;
501 
505  FoldingRange::Vector::const_iterator lowerBound = qLowerBound (ranges.begin(), ranges.end(), line, compareRangeByLineWithStart);
506 
510  FoldingRange::Vector::const_iterator upperBound = qUpperBound (ranges.begin(), ranges.end(), line, compareRangeByStartWithLine);
511 
515  if ((lowerBound != ranges.begin()) && ((*(lowerBound-1))->end->line() >= line))
516  --lowerBound;
517 
521  for (FoldingRange::Vector::const_iterator it = lowerBound; it != upperBound; ++it) {
525  if ((*it)->start->line() == line)
526  results.push_back (qMakePair((*it)->id, (*it)->flags));
527 
531  foldingRangesStartingOnLine (results, (*it)->nestedRanges, line);
532  }
533 }
534 
535 QString TextFolding::debugDump () const
536 {
540  return QString ("tree %1 - folded %2").arg (debugDump (m_foldingRanges, true)).arg(debugDump (m_foldedFoldingRanges, false));
541 }
542 
543 void TextFolding::debugPrint (const QString &title) const
544 {
545  // print title + content
546  printf ("%s\n %s\n", qPrintable (title), qPrintable(debugDump()));
547 }
548 
549 QString TextFolding::debugDump (const TextFolding::FoldingRange::Vector &ranges, bool recurse)
550 {
554  QString dump;
555  Q_FOREACH (FoldingRange *range, ranges) {
556  if (!dump.isEmpty())
557  dump += " ";
558 
559  dump += QString ("[%1:%2 %3%4 ").arg (range->start->line()).arg(range->start->column()).arg((range->flags & Persistent) ? "p" : "").arg((range->flags & Folded) ? "f" : "");
560 
564  if (recurse) {
565  QString inner = debugDump (range->nestedRanges, recurse);
566  if (!inner.isEmpty())
567  dump += inner + " ";
568  }
569 
570  dump += QString ("%1:%2]").arg (range->end->line()).arg(range->end->column());
571  }
572  return dump;
573 }
574 
575 bool TextFolding::insertNewFoldingRange (FoldingRange *parent, FoldingRange::Vector &existingRanges, FoldingRange *newRange)
576 {
585  FoldingRange::Vector::iterator lowerBound = qLowerBound (existingRanges.begin(), existingRanges.end(), newRange, compareRangeByStart);
586 
590  FoldingRange::Vector::iterator upperBound = qUpperBound (existingRanges.begin(), existingRanges.end(), newRange, compareRangeByEnd);
591 
595  if ((lowerBound != existingRanges.begin()) && ((*(lowerBound-1))->end->toCursor() > newRange->start->toCursor()))
596  --lowerBound;
597 
601  if (lowerBound == upperBound) {
606  if ((lowerBound == existingRanges.end()) || (newRange->start->toCursor() >= (*lowerBound)->end->toCursor()) || (newRange->end->toCursor() <= (*lowerBound)->start->toCursor())) {
610  existingRanges.insert (lowerBound, newRange);
611  newRange->parent = parent;
612 
616  return true;
617  }
618 
623  if ((newRange->start->toCursor() >= (*lowerBound)->start->toCursor()) && (newRange->end->toCursor() <= (*lowerBound)->end->toCursor()))
624  return insertNewFoldingRange ((*lowerBound), (*lowerBound)->nestedRanges, newRange);
625 
630  }
631 
635  FoldingRange::Vector::iterator it = lowerBound;
636  bool includeUpperBound = false;
637  FoldingRange::Vector nestedRanges;
638  while (it != existingRanges.end()) {
643  if (it == upperBound) {
644  if (newRange->end->toCursor() <= (*upperBound)->start->toCursor())
645  break;
646  else
647  includeUpperBound = true;
648  }
649 
654  if (!((newRange->start->toCursor() <= (*it)->start->toCursor()) && (newRange->end->toCursor() >= (*it)->end->toCursor())))
655  return false;
656 
660  nestedRanges.push_back ((*it));
661 
665  if (it == upperBound)
666  break;
667 
671  ++it;
672  }
673 
678  it = existingRanges.erase (lowerBound, includeUpperBound ? (upperBound+1) : upperBound);
679  existingRanges.insert (it, newRange);
680  newRange->nestedRanges = nestedRanges;
681 
685  newRange->parent = parent;
686  Q_FOREACH (FoldingRange *range, newRange->nestedRanges)
687  range->parent = newRange;
688 
692  return true;
693 }
694 
695 bool TextFolding::compareRangeByStart (FoldingRange *a, FoldingRange *b)
696 {
697  return a->start->toCursor() < b->start->toCursor();
698 }
699 
700 bool TextFolding::compareRangeByEnd (FoldingRange *a, FoldingRange *b)
701 {
702  return a->end->toCursor() < b->end->toCursor();
703 }
704 
705 bool TextFolding::compareRangeByStartWithLine (int line, FoldingRange *range)
706 {
707  return (line < range->start->line());
708 }
709 
710 bool TextFolding::compareRangeByLineWithStart (FoldingRange *range, int line)
711 {
712  return (range->start->line() < line);
713 }
714 
715 bool TextFolding::updateFoldedRangesForNewRange (TextFolding::FoldingRange *newRange)
716 {
720  if (!(newRange->flags & Folded))
721  return false;
722 
726  TextFolding::FoldingRange *parent = newRange->parent;
727  while (parent) {
731  if (parent->flags & Folded)
732  return false;
733 
737  parent = parent->parent;
738  }
739 
745  FoldingRange::Vector newFoldedFoldingRanges;
746  bool newRangeInserted = false;
747  Q_FOREACH (FoldingRange *range, m_foldedFoldingRanges) {
751  if ((newRange->start->toCursor() <= range->start->toCursor()) && (newRange->end->toCursor() >= range->end->toCursor()))
752  continue;
753 
758  if (!newRangeInserted && (range->start->toCursor() >= newRange->end->toCursor())) {
759  newFoldedFoldingRanges.push_back (newRange);
760  newRangeInserted = true;
761  }
762 
766  newFoldedFoldingRanges.push_back (range);
767  }
768 
772  if (!newRangeInserted)
773  newFoldedFoldingRanges.push_back (newRange);
774 
778  m_foldedFoldingRanges = newFoldedFoldingRanges;
779 
783  emit foldingRangesChanged ();
784 
788  return true;
789 }
790 
791 bool TextFolding::updateFoldedRangesForRemovedRange (TextFolding::FoldingRange *oldRange)
792 {
796  if (oldRange->flags & Folded)
797  return false;
798 
802  TextFolding::FoldingRange *parent = oldRange->parent;
803  while (parent) {
807  if (parent->flags & Folded)
808  return false;
809 
813  parent = parent->parent;
814  }
815 
821  FoldingRange::Vector newFoldedFoldingRanges;
822  Q_FOREACH (FoldingRange *range, m_foldedFoldingRanges) {
826  if (range == oldRange) {
827  appendFoldedRanges (newFoldedFoldingRanges, oldRange->nestedRanges);
828  continue;
829  }
830 
834  newFoldedFoldingRanges.push_back (range);
835  }
836 
840  m_foldedFoldingRanges = newFoldedFoldingRanges;
841 
845  emit foldingRangesChanged ();
846 
850  return true;
851 }
852 
853 void TextFolding::appendFoldedRanges (TextFolding::FoldingRange::Vector &newFoldedFoldingRanges, const TextFolding::FoldingRange::Vector &ranges) const
854 {
858  Q_FOREACH (FoldingRange *range, ranges) {
862  if (range->flags & Folded) {
863  newFoldedFoldingRanges.push_back (range);
864  continue;
865  }
866 
870  appendFoldedRanges (newFoldedFoldingRanges, range->nestedRanges);
871  }
872 }
873 
874 QVariantList TextFolding::exportFoldingRanges () const
875 {
876  QVariantList folds;
877  exportFoldingRanges (m_foldingRanges, folds);
878  return folds;
879 }
880 
881 void TextFolding::exportFoldingRanges (const TextFolding::FoldingRange::Vector &ranges, QVariantList &folds)
882 {
886  Q_FOREACH (FoldingRange *range, ranges) {
890  QVariantMap rangeMap;
891  rangeMap["startLine"] = range->start->line();
892  rangeMap["startColumn"] = range->start->column();
893  rangeMap["endLine"] = range->end->line();
894  rangeMap["endColumn"] = range->end->column();
895  rangeMap["flags"] = (int)range->flags;
896  folds.append (rangeMap);
897 
901  exportFoldingRanges (range->nestedRanges, folds);
902  }
903 }
904 
905 void TextFolding::importFoldingRanges (const QVariantList &folds)
906 {
910  Q_FOREACH (QVariant rangeVariant, folds) {
914  QVariantMap rangeMap = rangeVariant.toMap ();
915 
919  KTextEditor::Cursor start (rangeMap["startLine"].toInt(), rangeMap["startColumn"].toInt());
920  KTextEditor::Cursor end (rangeMap["endLine"].toInt(), rangeMap["endColumn"].toInt());
921 
925  int rawFlags = rangeMap["flags"].toInt();
926  FoldingRangeFlags flags;
927  if (rawFlags & Persistent)
928  flags = Persistent;
929  if (rawFlags & Folded)
930  flags = Folded;
931 
935  newFoldingRange (KTextEditor::Range (start, end), flags);
936  }
937 }
938 
939 }
Kate::TextFolding::clear
void clear()
Clear the complete folding.
Definition: katetextfolding.cpp:66
QHash::insert
iterator insert(const Key &key, const T &value)
Kate::TextFolding::TextFolding
TextFolding(TextBuffer &buffer)
Create folding object for given buffer.
Definition: katetextfolding.cpp:47
katetextbuffer.h
QVector::begin
iterator begin()
Kate::TextFolding::~TextFolding
~TextFolding()
Cleanup.
Definition: katetextfolding.cpp:58
Kate::TextFolding::visibleLineToLine
int visibleLineToLine(int visibleLine) const
Convert a visible line number to a line number in the text buffer.
Definition: katetextfolding.cpp:422
katetextfolding.h
katetextrange.h
Kate::TextFolding::foldRange
bool foldRange(qint64 id)
Fold the given range.
Definition: katetextfolding.cpp:168
Kate::TextFolding::unfoldRange
bool unfoldRange(qint64 id, bool remove=false)
Unfold the given range.
Definition: katetextfolding.cpp:191
QVector::clear
void clear()
Kate::TextFolding::foldingRangesStartingOnLine
QVector< QPair< qint64, FoldingRangeFlags > > foldingRangesStartingOnLine(int line) const
Queries which folding ranges start at the given line and returns the id + flags for all of them...
Definition: katetextfolding.cpp:476
QString::insert
QString & insert(int position, QChar ch)
QObject
QString::isEmpty
bool isEmpty() const
Kate::TextFolding::foldingRange
KTextEditor::Range foldingRange(qint64 id) const
Returns the folding range associated with id.
Definition: katetextfolding.cpp:159
Kate::TextFolding::Folded
Range is folded away.
Definition: katetextfolding.h:69
QString
QHash::remove
int remove(const Key &key)
Kate::TextFolding::foldingRangesChanged
void foldingRangesChanged()
If the folding state of existing ranges changes or ranges are added/removed, this signal is emitted...
QPair
Kate::TextFolding::Persistent
Range is persistent, e.g.
Definition: katetextfolding.h:64
QHash::clear
void clear()
Kate::TextFolding::lineToVisibleLine
int lineToVisibleLine(int line) const
Convert a text buffer line to a visible line number.
Definition: katetextfolding.cpp:366
QHash::value
const T value(const Key &key) const
Kate::TextFolding::debugDump
QString debugDump() const
Dump folding state as string, for unit testing and debugging.
Definition: katetextfolding.cpp:535
Kate::TextFolding::isLineVisible
bool isLineVisible(int line, qint64 *foldedRangeId=0) const
Query if a given line is visible.
Definition: katetextfolding.cpp:281
Kate::TextBuffer::lines
int lines() const
Lines currently stored in this buffer.
Definition: katetextbuffer.h:189
QVariant::toMap
QMap< QString, QVariant > toMap() const
QVector< FoldingRange * >
QHash::isEmpty
bool isEmpty() const
QVector::isEmpty
bool isEmpty() const
Kate::TextFolding::ensureLineIsVisible
void ensureLineIsVisible(int line)
Ensure that a given line will be visible.
Definition: katetextfolding.cpp:313
QVector::push_back
void push_back(const T &value)
Kate::TextFolding::newFoldingRange
qint64 newFoldingRange(const KTextEditor::Range &range, FoldingRangeFlags flags=FoldingRangeFlags())
Create a new folding range.
Definition: katetextfolding.cpp:99
Kate::TextFolding::debugPrint
void debugPrint(const QString &title) const
Print state to stdout for testing.
Definition: katetextfolding.cpp:543
Kate::TextBuffer
Class representing a text buffer.
Definition: katetextbuffer.h:48
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject::parent
QObject * parent() const
Kate::TextFolding::importFoldingRanges
void importFoldingRanges(const QVariantList &folds)
Import the folding ranges given as a QVariantList like read from configs.
Definition: katetextfolding.cpp:905
Kate::TextFolding::visibleLines
int visibleLines() const
Query number of visible lines.
Definition: katetextfolding.cpp:340
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
Kate::TextFolding::exportFoldingRanges
QVariantList exportFoldingRanges() const
Return the current known folding ranges a QVariantList to store in configs.
Definition: katetextfolding.cpp:874
QVector::end
iterator end()
QVariant
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat May 9 2020 03:56:58 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • 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