• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kate
 

kate

  • kate
  • part
katecodefoldinghelpers.cpp
1/* This file is part of the KDE libraries
2 Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17*/
18
19#include "katecodefoldinghelpers.h"
20#include "katecodefoldinghelpers.moc"
21
22#include "katebuffer.h"
23#include "katecursor.h"
24#include <kdebug.h>
25
26#include <tqstring.h>
27
28#define JW_DEBUG 0
29
30bool KateCodeFoldingTree::trueVal = true;
31
32KateCodeFoldingNode::KateCodeFoldingNode() :
33 parentNode(0),
34 startLineRel(0),
35 endLineRel(0),
36 startCol(0),
37 endCol(0),
38 startLineValid(false),
39 endLineValid(false),
40 type(0),
41 visible(true),
42 deleteOpening(false),
43 deleteEnding(false)
44{
45}//the endline fields should be initialised to not valid
46
47KateCodeFoldingNode::KateCodeFoldingNode(KateCodeFoldingNode *par, signed char typ, unsigned int sLRel):
48 parentNode(par),
49 startLineRel(sLRel),
50 endLineRel(10000),
51 startCol(0),
52 endCol(0),
53 startLineValid(true),
54 endLineValid(false),
55 type(typ),
56 visible(true),
57 deleteOpening(false),
58 deleteEnding(false)
59{
60}//the endline fields should be initialised to not valid
61
62KateCodeFoldingNode::~KateCodeFoldingNode()
63{
64 // delete all child nodes
65 clearChildren ();
66}
67
68bool KateCodeFoldingNode::getBegin(KateCodeFoldingTree *tree, KateTextCursor* begin) {
69 if (!startLineValid) return false;
70 unsigned int line=startLineRel;
71 for (KateCodeFoldingNode *n=parentNode;n;n=n->parentNode)
72 line+=n->startLineRel;
73
74 tree->m_buffer->codeFoldingColumnUpdate(line);
75 begin->setLine(line);
76 begin->setCol(startCol);
77
78 return true;
79}
80
81bool KateCodeFoldingNode::getEnd(KateCodeFoldingTree *tree, KateTextCursor *end) {
82 if (!endLineValid) return false;
83 unsigned int line=startLineRel+endLineRel;
84 for (KateCodeFoldingNode *n=parentNode;n;n=n->parentNode)
85 line+=n->startLineRel;
86
87 tree->m_buffer->codeFoldingColumnUpdate(line);
88 end->setLine(line);
89 end->setCol(endCol);
90
91 return true;
92}
93
94int KateCodeFoldingNode::cmpPos(KateCodeFoldingTree *tree, uint line,uint col) {
95 KateTextCursor cur(line,col);
96 KateTextCursor start,end;
97 kdDebug(13000)<<"KateCodeFoldingNode::cmpPos (1)"<<endl;
98 bool startValid=getBegin(tree, &start);
99 kdDebug(13000)<<"KateCodeFoldingNode::cmpPos (2)"<<endl;
100 bool endValid=getEnd(tree, &end);
101 kdDebug(13000)<<"KateCodeFoldingNode::cmpPos (3)"<<endl;
102 if ((!endValid) && startValid) {
103 return ((start>cur)?-1:0);
104 }
105 if ((!startValid) && endValid) {
106 return ((cur>end)?1:0);
107 }
108 //here both have to be valid, both invalid must not happen
109 Q_ASSERT(startValid && endValid);
110 return ( (cur<start)?(-1):( (cur>end) ? 1:0));
111}
112
113void KateCodeFoldingNode::insertChild (uint index, KateCodeFoldingNode *node)
114{
115 uint s = m_children.size ();
116
117 if (index > s)
118 return;
119
120 m_children.resize (++s);
121
122 for (uint i=s-1; i > index; --i)
123 m_children[i] = m_children[i-1];
124
125 m_children[index] = node;
126}
127
128KateCodeFoldingNode *KateCodeFoldingNode::takeChild (uint index)
129{
130 uint s = m_children.size ();
131
132 if (index >= s)
133 return 0;
134
135 KateCodeFoldingNode *n = m_children[index];
136
137 for (uint i=index; (i+1) < s; ++i)
138 m_children[i] = m_children[i+1];
139
140 m_children.resize (s-1);
141
142 return n;
143}
144
145void KateCodeFoldingNode::clearChildren ()
146{
147 for (uint i=0; i < m_children.size(); ++i)
148 delete m_children[i];
149
150 m_children.resize (0);
151}
152
153KateCodeFoldingTree::KateCodeFoldingTree(KateBuffer *buffer): TQObject(buffer), m_buffer (buffer)
154{
155 clear();
156}
157
158void KateCodeFoldingTree::fixRoot(int endLRel)
159{
160 m_root.endLineRel = endLRel;
161}
162
163void KateCodeFoldingTree::clear()
164{
165 m_root.clearChildren();
166
167 // initialize the root "special" node
168 m_root.startLineValid=true;
169 m_root.endLineValid=true; // temporary, should be false;
170 m_root.endLineRel=1; // temporary;
171
172 hiddenLinesCountCacheValid=false;
173 lineMapping.setAutoDelete(true);
174 hiddenLines.clear();
175 lineMapping.clear();
176 nodesForLine.clear();
177 markedForDeleting.clear();
178 dontIgnoreUnchangedLines.clear();
179}
180
181KateCodeFoldingTree::~KateCodeFoldingTree()
182{
183}
184
185bool KateCodeFoldingTree::isTopLevel(unsigned int line)
186{
187 if (m_root.noChildren())
188 return true; // no childs
189
190 // look if a given lines belongs to a sub node
191 for ( uint i=0; i < m_root.childCount(); ++i )
192 {
193 KateCodeFoldingNode *node = m_root.child(i);
194
195 if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
196 return false; // the line is within the range of a subnode -> return toplevel=false
197 }
198
199 return true; // the root node is the only node containing the given line, return toplevel=true
200}
201
202void KateCodeFoldingTree::getLineInfo(KateLineInfo *info, unsigned int line)
203{
204 // Initialze the returned structure, this will also be returned if the root node has no child nodes
205 // or the line is not within a childnode's range.
206 info->topLevel = true;
207 info->startsVisibleBlock = false;
208 info->startsInVisibleBlock = false;
209 info->endsBlock = false;
210 info->invalidBlockEnd = false;
211
212 if (m_root.noChildren())
213 return;
214
215 //let's look for some information
216 for ( uint i=0; i < m_root.childCount(); ++i )
217 {
218 KateCodeFoldingNode *node = m_root.child(i);
219
220 if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel)) // we found a node, which contains the given line -> do a complete lookup
221 {
222 info->topLevel = false; //we are definitly not toplevel
223 findAllNodesOpenedOrClosedAt(line); //lookup all nodes, which start or and at the given line
224
225 for ( KateCodeFoldingNode *node = nodesForLine.first(); node; node = nodesForLine.next() )
226 {
227 uint startLine = getStartLine(node);
228
229 // type<0 means, that a region has been closed, but not opened
230 // eg. parantheses missmatch
231 if (node->type < 0)
232 info->invalidBlockEnd=true;
233 else
234 {
235 if (startLine != line) // does the region we look at not start at the given line
236 info->endsBlock = true; // than it has to be an ending
237 else
238 {
239 // The line starts a new region, now determine, if it's a visible or a hidden region
240 if (node->visible)
241 info->startsVisibleBlock=true;
242 else
243 info->startsInVisibleBlock=true;
244 }
245 }
246 }
247
248 return;
249 }
250 }
251
252 return;
253}
254
255
256KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLine(unsigned int line)
257{
258 if (m_root.noChildren()) // does we have child list + nodes ?
259 return &m_root;
260
261 // lets look, if given line is within a subnode range, and then return the deepest one.
262 for ( uint i=0; i < m_root.childCount(); ++i )
263 {
264 KateCodeFoldingNode *node = m_root.child(i);
265
266 if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
267 {
268 // a region surounds the line, look in the next deeper hierarchy step
269 return findNodeForLineDescending(node,line,0);
270 }
271 }
272
273 return &m_root;
274}
275
276
277KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLineDescending ( KateCodeFoldingNode *node,
278 unsigned int line, unsigned int offset, bool oneStepOnly )
279{
280 if (node->noChildren())
281 return node;
282
283 // calculate the offset, between a subnodes real start line and its relative start
284 offset += node->startLineRel;
285
286 for ( uint i=0; i < node->childCount(); ++i )
287 {
288 KateCodeFoldingNode *subNode = node->child(i);
289
290 if ((subNode->startLineRel+offset<=line) && (line<=subNode->endLineRel+subNode->startLineRel+offset)) //warning fix me for invalid ends
291 {
292 // a subnode contains the line.
293 // if oneStepOnly is true, we don't want to search for the deepest node, just return the found one
294
295 if (oneStepOnly)
296 return subNode;
297 else
298 return findNodeForLineDescending (subNode,line,offset); // look into the next deeper hierarchy step
299 }
300 }
301
302 return node; // the current node has no sub nodes, or the line couldn'te be found within a subregion
303}
304
305KateCodeFoldingNode *KateCodeFoldingTree::findNodeForPosition(unsigned int line, unsigned int column)
306{
307 KateCodeFoldingNode *node=findNodeForLine(line);
308
309 if (node==&m_root) return &m_root;
310
311 kdDebug(13000)<<"initial cmpPos"<<endl;
312
313 KateCodeFoldingNode *tmp;
314 int leq=node->cmpPos(this, line,column);
315 while (true) {
316 switch (leq) {
317 case 0: {
318 if (node->noChildren())
319 return node;
320 else
321 {
322 tmp=node;
323 for ( uint i=0; i < node->childCount(); ++i )
324 {
325 KateCodeFoldingNode *subNode = node->child(i);
326 kdDebug(13000)<<"cmdPos(case0):calling"<<endl;
327 leq=subNode->cmpPos(this, line,column);
328 kdDebug(13000)<<"cmdPos(case0):returned"<<endl;
329 if (leq==0) {
330 tmp=subNode;
331 break;
332 } else if (leq==-1) break;
333 }
334 if (tmp!=node) node=tmp; else return node;
335 }
336 break;
337 }
338 //this could be optimized a littlebit
339 case -1:
340 case 1: {
341 if (!(node->parentNode)) return &m_root;
342 kdDebug(13000)<<"current node type"<<node->type<<endl;
343 node=node->parentNode;
344 kdDebug(13000)<<"cmdPos(case-1/1):calling:"<<node<<endl;
345 leq=node->cmpPos(this, line,column);
346 kdDebug(13000)<<"cmdPos(case-1/1):returned"<<endl;
347 break;
348 }
349 }
350
351 }
352 Q_ASSERT(false);
353 return &m_root;
354}
355
356void KateCodeFoldingTree::debugDump()
357{
358 //dump all nodes for debugging
359 kdDebug(13000)<<"The parsed region/block tree for code folding"<<endl;
360 dumpNode(&m_root, "");
361}
362
363void KateCodeFoldingTree::dumpNode(KateCodeFoldingNode *node, const TQString &prefix)
364{
365 //output node properties
366 kdDebug(13000)<<prefix<<TQString(TQString("Type: %1, startLineValid %2, startLineRel %3, endLineValid %4, endLineRel %5, visible %6").
367 arg(node->type).arg(node->startLineValid).arg(node->startLineRel).arg(node->endLineValid).
368 arg(node->endLineRel).arg(node->visible))<<endl;
369
370 //output child node properties recursive
371 if (node->noChildren())
372 return;
373
374 TQString newprefix(prefix + " ");
375 for ( uint i=0; i < node->childCount(); ++i )
376 dumpNode (node->child(i),newprefix);
377}
378
379/*
380 That's one of the most important functions ;)
381*/
382void KateCodeFoldingTree::updateLine(unsigned int line,
383 TQMemArray<uint> *regionChanges, bool *updated,bool changed,bool colsChanged)
384{
385 if ( (!changed) || colsChanged)
386 {
387 if (dontIgnoreUnchangedLines.isEmpty())
388 return;
389
390 if (dontIgnoreUnchangedLines[line])
391 dontIgnoreUnchangedLines.remove(line);
392 else
393 return;
394 }
395
396 something_changed = false;
397
398 findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
399
400 if (regionChanges->isEmpty())
401 {
402 // KateCodeFoldingNode *node=findNodeForLine(line);
403 // if (node->type!=0)
404 // if (getStartLine(node)+node->endLineRel==line) removeEnding(node,line);
405 }
406 else
407 {
408 for (unsigned int i=0;i<regionChanges->size() / 4;i++)
409 {
410 signed char tmp=(*regionChanges)[regionChanges->size()-2-i*2];
411 uint tmppos=(*regionChanges)[regionChanges->size()-1-i*2];
412 (*regionChanges)[regionChanges->size()-2-i*2]=(*regionChanges)[i*2];
413 (*regionChanges)[regionChanges->size()-1-i*2]=(*regionChanges)[i*2+1];
414 (*regionChanges)[i*2]=tmp;
415 (*regionChanges)[i*2+1]=tmppos;
416 }
417
418
419 signed char data= (*regionChanges)[regionChanges->size()-2];
420 uint charPos=(*regionChanges)[regionChanges->size()-1];
421 regionChanges->resize (regionChanges->size()-2);
422
423 int insertPos=-1;
424 KateCodeFoldingNode *node = findNodeForLine(line);
425
426 if (data<0)
427 {
428 // if (insertPos==-1)
429 {
430 unsigned int tmpLine=line-getStartLine(node);
431
432 for ( uint i=0; i < node->childCount(); ++i )
433 {
434 if (node->child(i)->startLineRel >= tmpLine)
435 {
436 insertPos=i;
437 break;
438 }
439 }
440 }
441 }
442 else
443 {
444 for (; (node->parentNode) && (getStartLine(node->parentNode)==line) && (node->parentNode->type!=0); node=node->parentNode);
445
446 if ((getStartLine(node)==line) && (node->type!=0))
447 {
448 insertPos=node->parentNode->findChild(node);
449 node = node->parentNode;
450 }
451 else
452 {
453 for ( uint i=0; i < node->childCount(); ++i )
454 {
455 if (getStartLine(node->child(i))>=line)
456 {
457 insertPos=i;
458 break;
459 }
460 }
461 }
462 }
463
464 do
465 {
466 if (data<0)
467 {
468 if (correctEndings(data,node,line,charPos,insertPos))
469 {
470 insertPos=node->parentNode->findChild(node)+1;
471 node=node->parentNode;
472 }
473 else
474 {
475 if (insertPos!=-1) insertPos++;
476 }
477 }
478 else
479 {
480 int startLine=getStartLine(node);
481 if ((insertPos==-1) || (insertPos>=(int)node->childCount()))
482 {
483 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
484 something_changed = true;
485 node->appendChild(newNode);
486 addOpening(newNode, data, regionChanges, line,charPos);
487 insertPos = node->findChild(newNode)+1;
488 }
489 else
490 {
491 if (node->child(insertPos)->startLineRel == line-startLine)
492 {
493 addOpening(node->child(insertPos), data, regionChanges, line,charPos);
494 insertPos++;
495 }
496 else
497 {
498// kdDebug(13000)<<"ADDING NODE "<<endl;
499 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
500 something_changed = true;
501 node->insertChild(insertPos, newNode);
502 addOpening(newNode, data, regionChanges, line,charPos);
503 insertPos++;
504 }
505 }
506 }
507
508 if (regionChanges->isEmpty())
509 data = 0;
510 else
511 {
512 data = (*regionChanges)[regionChanges->size()-2];
513 charPos=(*regionChanges)[regionChanges->size()-1];
514 regionChanges->resize (regionChanges->size()-2);
515 }
516 } while (data!=0);
517 }
518
519 cleanupUnneededNodes(line);
520// if (something_changed) emit regionBeginEndAddedRemoved(line);
521 (*updated) = something_changed;
522}
523
524
525bool KateCodeFoldingTree::removeOpening(KateCodeFoldingNode *node,unsigned int line)
526{
527 signed char type;
528 if ((type=node->type) == 0)
529 {
530 dontDeleteOpening(node);
531 dontDeleteEnding(node);
532 return false;
533 }
534
535 if (!node->visible)
536 {
537 toggleRegionVisibility(getStartLine(node));
538 }
539
540 KateCodeFoldingNode *parent = node->parentNode;
541 int mypos = parent->findChild(node);
542
543 if (mypos > -1)
544 {
545 //move childnodes() up
546 for(; node->childCount()>0 ;)
547 {
548 KateCodeFoldingNode *tmp;
549 parent->insertChild(mypos, tmp=node->takeChild(0));
550 tmp->parentNode = parent;
551 tmp->startLineRel += node->startLineRel;
552 mypos++;
553 }
554
555 // remove the node
556 //mypos = parent->findChild(node);
557 bool endLineValid = node->endLineValid;
558 int endLineRel = node->endLineRel;
559 uint endCol=node->endCol;
560
561 // removes + deletes
562 KateCodeFoldingNode *child = parent->takeChild(mypos);
563 markedForDeleting.removeRef(child);
564 delete child;
565
566 if ((type>0) && (endLineValid))
567 correctEndings(-type, parent, line+endLineRel/*+1*/,endCol, mypos); // why the hell did I add a +1 here ?
568 }
569
570 return true;
571}
572
573bool KateCodeFoldingTree::removeEnding(KateCodeFoldingNode *node,unsigned int /* line */)
574{
575 KateCodeFoldingNode *parent = node->parentNode;
576
577 if (!parent)
578 return false;
579
580 if (node->type == 0)
581 return false;
582
583 if (node->type < 0)
584 {
585 // removes + deletes
586 int i = parent->findChild (node);
587 if (i >= 0)
588 {
589 KateCodeFoldingNode *child = parent->takeChild(i);
590 markedForDeleting.removeRef(child);
591 delete child;
592 }
593
594 return true;
595 }
596
597 int mypos = parent->findChild(node);
598 int count = parent->childCount();
599
600 for (int i=mypos+1; i<count; i++)
601 {
602 if (parent->child(i)->type == -node->type)
603 {
604 node->endLineValid = true;
605 node->endLineRel = parent->child(i)->startLineRel - node->startLineRel;
606
607 KateCodeFoldingNode *child = parent->takeChild(i);
608 markedForDeleting.removeRef(child);
609 delete child;
610
611 count = i-mypos-1;
612 if (count > 0)
613 {
614 for (int i=0; i<count; i++)
615 {
616 KateCodeFoldingNode *tmp = parent->takeChild(mypos+1);
617 tmp->startLineRel -= node->startLineRel;
618 tmp->parentNode = node; //should help 16.04.2002
619 node->appendChild(tmp);
620 }
621 }
622 return false;
623 }
624 }
625
626 if ( (parent->type == node->type) || /*temporary fix */ (!parent->parentNode))
627 {
628 for (int i=mypos+1; i<(int)parent->childCount(); i++)
629 {
630 KateCodeFoldingNode *tmp = parent->takeChild(mypos+1);
631 tmp->startLineRel -= node->startLineRel;
632 tmp->parentNode = node; // SHOULD HELP 16.04.2002
633 node->appendChild(tmp);
634 }
635
636 // this should fix the bug of wrongly closed nodes
637 if (!parent->parentNode)
638 node->endLineValid=false;
639 else
640 node->endLineValid = parent->endLineValid;
641
642 node->endLineRel = parent->endLineRel-node->startLineRel;
643
644 if (node->endLineValid)
645 return removeEnding(parent, getStartLine(parent)+parent->endLineRel);
646
647 return false;
648 }
649
650 node->endLineValid = false;
651 node->endLineRel = parent->endLineRel - node->startLineRel;
652
653 return false;
654}
655
656
657bool KateCodeFoldingTree::correctEndings(signed char data, KateCodeFoldingNode *node,unsigned int line,unsigned int endCol,int insertPos)
658{
659// if (node->type==0) {kdError()<<"correct Ending should never be called with the root node"<<endl; return true;}
660 uint startLine = getStartLine(node);
661 if (data != -node->type)
662 {
663#if JW_DEBUG
664 kdDebug(13000)<<"data!=-node->type (correctEndings)"<<endl;
665#endif
666 //invalid close -> add to unopend list
667 dontDeleteEnding(node);
668 if (data == node->type) {
669 node->endCol=endCol;
670 return false;
671 }
672 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
673 something_changed = true;
674 newNode->startLineValid = false;
675 newNode->endLineValid = true;
676 newNode->endLineRel = 0;
677 newNode->endCol=endCol;
678
679 if ((insertPos==-1) || (insertPos==(int)node->childCount()))
680 node->appendChild(newNode);
681 else
682 node->insertChild(insertPos,newNode);
683
684 // find correct position
685 return false;
686 }
687 else
688 {
689 something_changed = true;
690 dontDeleteEnding(node);
691
692 // valid closing region
693 if (!node->endLineValid)
694 {
695 node->endLineValid = true;
696 node->endLineRel = line - startLine;
697 node->endCol=endCol;
698 //moving
699
700 moveSubNodesUp(node);
701 }
702 else
703 {
704#if JW_DEBUG
705 kdDebug(13000)<<"Closing a node which had already a valid end"<<endl;
706#endif
707 // block has already an ending
708 if (startLine+node->endLineRel == line)
709 {
710 node->endCol=endCol;
711 // we won, just skip
712#if JW_DEBUG
713 kdDebug(13000)<< "We won, just skipping (correctEndings)"<<endl;
714#endif
715 }
716 else
717 {
718 int bakEndLine = node->endLineRel+startLine;
719 uint bakEndCol = node->endCol;
720 node->endLineRel = line-startLine;
721 node->endCol=endCol;
722
723#if JW_DEBUG
724 kdDebug(13000)<< "reclosed node had childnodes()"<<endl;
725 kdDebug(13000)<<"It could be, that childnodes() need to be moved up"<<endl;
726#endif
727 moveSubNodesUp(node);
728
729 if (node->parentNode)
730 {
731 correctEndings(data,node->parentNode,bakEndLine, bakEndCol,node->parentNode->findChild(node)+1); // ????
732 }
733 else
734 {
735 //add to unopened list (bakEndLine)
736 }
737 }
738 }
739 }
740 return true;
741}
742
743void KateCodeFoldingTree::moveSubNodesUp(KateCodeFoldingNode *node)
744{
745 int mypos = node->parentNode->findChild(node);
746 int removepos=-1;
747 int count = node->childCount();
748 for (int i=0; i<count; i++)
749 if (node->child(i)->startLineRel >= node->endLineRel)
750 {
751 removepos=i;
752 break;
753 }
754#if JW_DEBUG
755 kdDebug(13000)<<TQString("remove pos: %1").arg(removepos)<<endl;
756#endif
757 if (removepos>-1)
758 {
759#if JW_DEBUG
760 kdDebug(13000)<<"Children need to be moved"<<endl;
761#endif
762 KateCodeFoldingNode *moveNode;
763 if (mypos == (int)node->parentNode->childCount()-1)
764 {
765 while (removepos<(int)node->childCount())
766 {
767 node->parentNode->appendChild(moveNode=node->takeChild(removepos));
768 moveNode->parentNode = node->parentNode;
769 moveNode->startLineRel += node->startLineRel;
770 }
771 }
772 else
773 {
774 int insertPos=mypos;
775 while (removepos < (int)node->childCount())
776 {
777 insertPos++;
778 node->parentNode->insertChild(insertPos, moveNode=node->takeChild(removepos));
779 moveNode->parentNode = node->parentNode; // That should solve a crash
780 moveNode->startLineRel += node->startLineRel;
781 }
782 }
783 }
784
785}
786
787
788
789void KateCodeFoldingTree::addOpening(KateCodeFoldingNode *node,signed char nType, TQMemArray<uint>* list,unsigned int line,unsigned int charPos)
790{
791 uint startLine = getStartLine(node);
792 if ((startLine==line) && (node->type!=0))
793 {
794#if JW_DEBUG
795 kdDebug(13000)<<"startLine equals line"<<endl;
796#endif
797 if (nType == node->type)
798 {
799#if JW_DEBUG
800 kdDebug(13000)<<"Node exists"<<endl;
801#endif
802 node->deleteOpening = false;
803 node->startCol=charPos;
804 KateCodeFoldingNode *parent = node->parentNode;
805
806 if (!node->endLineValid)
807 {
808 int current = parent->findChild(node);
809 int count = parent->childCount()-(current+1);
810 node->endLineRel = parent->endLineRel - node->startLineRel;
811
812// EXPERIMENTAL TEST BEGIN
813// move this afte the test for unopened, but closed regions within the parent node, or if there are no siblings, bubble up
814 if (parent)
815 if (parent->type == node->type)
816 {
817 if (parent->endLineValid)
818 {
819 removeEnding(parent, line);
820 node->endLineValid = true;
821 }
822 }
823
824// EXPERIMENTAL TEST BEGIN
825
826 if (current != (int)parent->childCount()-1)
827 {
828 //search for an unopened but closed region, even if the parent is of the same type
829#ifdef __GNUC__
830#warning "FIXME: why does this seem to work?"
831#endif
832// if (node->type != parent->type)
833 {
834 for (int i=current+1; i<(int)parent->childCount(); i++)
835 {
836 if (parent->child(i)->type == -node->type)
837 {
838 count = (i-current-1);
839 node->endLineValid = true;
840 node->endLineRel = getStartLine(parent->child(i))-line;
841 node->endCol = parent->child(i)->endCol;
842 KateCodeFoldingNode *child = parent->takeChild(i);
843 markedForDeleting.removeRef( child );
844 delete child;
845 break;
846 }
847 }
848 }
849// else
850// {
851// parent->endLineValid = false;
852// parent->endLineRel = 20000;
853// }
854
855 if (count>0)
856 {
857 for (int i=0;i<count;i++)
858 {
859 KateCodeFoldingNode *tmp;
860 node->appendChild(tmp=parent->takeChild(current+1));
861 tmp->startLineRel -= node->startLineRel;
862 tmp->parentNode = node;
863 }
864 }
865 }
866
867 }
868
869 addOpening_further_iterations(node, nType, list, line, 0, startLine,node->startCol);
870
871 } //else ohoh, much work to do same line, but other region type
872 }
873 else
874 { // create a new region
875 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,nType,line-startLine);
876 something_changed = true;
877
878 int insert_position=-1;
879 for (int i=0; i<(int)node->childCount(); i++)
880 {
881 if (startLine+node->child(i)->startLineRel > line)
882 {
883 insert_position=i;
884 break;
885 }
886 }
887
888 int current;
889 if (insert_position==-1)
890 {
891 node->appendChild(newNode);
892 current = node->childCount()-1;
893 }
894 else
895 {
896 node->insertChild(insert_position, newNode);
897 current = insert_position;
898 }
899
900// if (node->type==newNode->type)
901// {
902// newNode->endLineValid=true;
903// node->endLineValid=false;
904// newNode->endLineRel=node->endLineRel-newNode->startLineRel;
905// node->endLineRel=20000; //FIXME
906
907 int count = node->childCount() - (current+1);
908 newNode->endLineRel -= newNode->startLineRel;
909 if (current != (int)node->childCount()-1)
910 {
911 if (node->type != newNode->type)
912 {
913 for (int i=current+1; i<(int)node->childCount(); i++)
914 {
915 if (node->child(i)->type == -newNode->type)
916 {
917 count = node->childCount() - i - 1;
918 newNode->endLineValid = true;
919 newNode->endLineRel = line - getStartLine(node->child(i));
920 KateCodeFoldingNode *child = node->takeChild(i);
921 markedForDeleting.removeRef( child );
922 delete child;
923 break;
924 }
925 }
926 }
927 else
928 {
929 node->endLineValid = false;
930 node->endLineRel = 10000;
931 }
932 if (count > 0)
933 {
934 for (int i=0;i<count;i++)
935 {
936 KateCodeFoldingNode *tmp;
937 newNode->appendChild(tmp=node->takeChild(current+1));
938 tmp->parentNode=newNode;
939 }
940 }
941// }
942 }
943
944 addOpening(newNode, nType, list, line,charPos);
945
946 addOpening_further_iterations(node, node->type, list, line, current, startLine,node->startCol);
947 }
948}
949
950
951void KateCodeFoldingTree::addOpening_further_iterations(KateCodeFoldingNode *node,signed char /* nType */, TQMemArray<uint>*
952 list,unsigned int line,int current, unsigned int startLine,unsigned int charPos)
953{
954 while (!(list->isEmpty()))
955 {
956 if (list->isEmpty())
957 return;
958 else
959 {
960 signed char data = (*list)[list->size()-2];
961 uint charPos=(*list)[list->size()-1];
962 list->resize (list->size()-2);
963
964 if (data<0)
965 {
966#if JW_DEBUG
967 kdDebug(13000)<<"An ending was found"<<endl;
968#endif
969
970 if (correctEndings(data,node,line,charPos,-1))
971 return; // -1 ?
972
973#if 0
974 if(data == -nType)
975 {
976 if (node->endLineValid)
977 {
978 if (node->endLineRel+startLine==line) // We've won again
979 {
980 //handle next node;
981 }
982 else
983 { // much moving
984 node->endLineRel=line-startLine;
985 node->endLineValid=true;
986 }
987 return; // next higher level should do the rest
988 }
989 else
990 {
991 node->endLineRel=line-startLine;
992 node->endLineValid=true;
993 //much moving
994 }
995 } //else add to unopened list
996#endif
997 }
998 else
999 {
1000 bool needNew = true;
1001 if (current < (int)node->childCount())
1002 {
1003 if (getStartLine(node->child(current)) == line)
1004 needNew=false;
1005 }
1006 if (needNew)
1007 {
1008 something_changed = true;
1009 KateCodeFoldingNode *newNode = new KateCodeFoldingNode(node, data, line-startLine);
1010 node->insertChild(current, newNode); //find the correct position later
1011 }
1012
1013 addOpening(node->child(current), data, list, line,charPos);
1014 current++;
1015 //lookup node or create subnode
1016 }
1017 }
1018 } // end while
1019}
1020
1021unsigned int KateCodeFoldingTree::getStartLine(KateCodeFoldingNode *node)
1022{
1023 unsigned int lineStart=0;
1024 for (KateCodeFoldingNode *iter=node; iter->type != 0; iter=iter->parentNode)
1025 lineStart += iter->startLineRel;
1026
1027 return lineStart;
1028}
1029
1030
1031void KateCodeFoldingTree::lineHasBeenRemoved(unsigned int line)
1032{
1033 lineMapping.clear();
1034 dontIgnoreUnchangedLines.insert(line, &trueVal);
1035 dontIgnoreUnchangedLines.insert(line-1, &trueVal);
1036 dontIgnoreUnchangedLines.insert(line+1, &trueVal);
1037 hiddenLinesCountCacheValid = false;
1038#if JW_DEBUG
1039 kdDebug(13000)<<TQString("KateCodeFoldingTree::lineHasBeenRemoved: %1").arg(line)<<endl;
1040#endif
1041
1042//line ++;
1043 findAndMarkAllNodesforRemovalOpenedOrClosedAt(line); //It's an ugly solution
1044 cleanupUnneededNodes(line); //It's an ugly solution
1045
1046 KateCodeFoldingNode *node = findNodeForLine(line);
1047//????? if (node->endLineValid)
1048 {
1049 int startLine = getStartLine(node);
1050 if (startLine == (int)line)
1051 node->startLineRel--;
1052 else
1053 {
1054 if (node->endLineRel == 0)
1055 node->endLineValid = false;
1056 node->endLineRel--;
1057 }
1058
1059 int count = node->childCount();
1060 for (int i=0; i<count; i++)
1061 {
1062 if (node->child(i)->startLineRel+startLine >= line)
1063 node->child(i)->startLineRel--;
1064 }
1065 }
1066
1067 if (node->parentNode)
1068 decrementBy1(node->parentNode, node);
1069
1070 for (TQValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
1071 {
1072 if ((*it).start > line)
1073 (*it).start--;
1074 else if ((*it).start+(*it).length > line)
1075 (*it).length--;
1076 }
1077}
1078
1079
1080void KateCodeFoldingTree::decrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after)
1081{
1082 if (node->endLineRel == 0)
1083 node->endLineValid = false;
1084 node->endLineRel--;
1085
1086 for (uint i=node->findChild(after)+1; i < node->childCount(); ++i)
1087 node->child(i)->startLineRel--;
1088
1089 if (node->parentNode)
1090 decrementBy1(node->parentNode,node);
1091}
1092
1093
1094void KateCodeFoldingTree::lineHasBeenInserted(unsigned int line)
1095{
1096 lineMapping.clear();
1097 dontIgnoreUnchangedLines.insert(line, &trueVal);
1098 dontIgnoreUnchangedLines.insert(line-1, &trueVal);
1099 dontIgnoreUnchangedLines.insert(line+1, &trueVal);
1100 hiddenLinesCountCacheValid = false;
1101//return;
1102#if JW_DEBUG
1103 kdDebug(13000)<<TQString("KateCodeFoldingTree::lineHasBeenInserted: %1").arg(line)<<endl;
1104#endif
1105
1106// findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
1107// cleanupUnneededNodes(line);
1108
1109 KateCodeFoldingNode *node = findNodeForLine(line);
1110// ???????? if (node->endLineValid)
1111 {
1112 int startLine=getStartLine(node);
1113 if (node->type < 0)
1114 node->startLineRel++;
1115 else
1116 node->endLineRel++;
1117
1118 for (uint i=0; i < node->childCount(); ++i)
1119 {
1120 KateCodeFoldingNode *iter = node->child(i);
1121
1122 if (iter->startLineRel+startLine >= line)
1123 iter->startLineRel++;
1124 }
1125 }
1126
1127 if (node->parentNode)
1128 incrementBy1(node->parentNode, node);
1129
1130 for (TQValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
1131 {
1132 if ((*it).start > line)
1133 (*it).start++;
1134 else if ((*it).start+(*it).length > line)
1135 (*it).length++;
1136 }
1137}
1138
1139void KateCodeFoldingTree::incrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after)
1140{
1141 node->endLineRel++;
1142
1143 for (uint i=node->findChild(after)+1; i < node->childCount(); ++i)
1144 node->child(i)->startLineRel++;
1145
1146 if (node->parentNode)
1147 incrementBy1(node->parentNode,node);
1148}
1149
1150
1151void KateCodeFoldingTree::findAndMarkAllNodesforRemovalOpenedOrClosedAt(unsigned int line)
1152{
1153#ifdef __GNUC__
1154#warning "FIXME: make this multiple region changes per line save";
1155#endif
1156// return;
1157 markedForDeleting.clear();
1158 KateCodeFoldingNode *node = findNodeForLine(line);
1159 if (node->type == 0)
1160 return;
1161
1162 addNodeToRemoveList(node, line);
1163
1164 while (((node->parentNode) && (node->parentNode->type!=0)) && (getStartLine(node->parentNode)==line))
1165 {
1166 node = node->parentNode;
1167 addNodeToRemoveList(node, line);
1168 }
1169#if JW_DEBUG
1170 kdDebug(13000)<<" added line to markedForDeleting list"<<endl;
1171#endif
1172}
1173
1174
1175void KateCodeFoldingTree::addNodeToRemoveList(KateCodeFoldingNode *node,unsigned int line)
1176{
1177 bool add=false;
1178#ifdef __GNUC__
1179#warning "FIXME: make this multiple region changes per line save";
1180#endif
1181 unsigned int startLine=getStartLine(node);
1182 if ((startLine==line) && (node->startLineValid))
1183 {
1184 add=true;
1185 node->deleteOpening = true;
1186 }
1187 if ((startLine+node->endLineRel==line) || ((node->endLineValid==false) && (node->deleteOpening)))
1188 {
1189 int myPos=node->parentNode->findChild(node); // this has to be implemented nicely
1190 if ((int)node->parentNode->childCount()>myPos+1)
1191 addNodeToRemoveList(node->parentNode->child(myPos+1),line);
1192 add=true;
1193 node->deleteEnding = true;
1194 }
1195
1196 if(add)
1197 markedForDeleting.append(node);
1198
1199}
1200
1201
1202void KateCodeFoldingTree::findAllNodesOpenedOrClosedAt(unsigned int line)
1203{
1204 nodesForLine.clear();
1205 KateCodeFoldingNode *node = findNodeForLine(line);
1206 if (node->type == 0)
1207 return;
1208
1209 unsigned int startLine = getStartLine(node);
1210 if (startLine == line)
1211 nodesForLine.append(node);
1212 else if ((startLine+node->endLineRel == line))
1213 nodesForLine.append(node);
1214
1215 while (node->parentNode)
1216 {
1217 addNodeToFoundList(node->parentNode, line, node->parentNode->findChild(node));
1218 node = node->parentNode;
1219 }
1220#if JW_DEBUG
1221 kdDebug(13000)<<" added line to nodesForLine list"<<endl;
1222#endif
1223}
1224
1225
1226void KateCodeFoldingTree::addNodeToFoundList(KateCodeFoldingNode *node,unsigned int line,int childpos)
1227{
1228 unsigned int startLine = getStartLine(node);
1229
1230 if ((startLine==line) && (node->type!=0))
1231 nodesForLine.append(node);
1232 else if ((startLine+node->endLineRel==line) && (node->type!=0))
1233 nodesForLine.append(node);
1234
1235 for (int i=childpos+1; i<(int)node->childCount(); i++)
1236 {
1237 KateCodeFoldingNode *child = node->child(i);
1238
1239 if (startLine+child->startLineRel == line)
1240 {
1241 nodesForLine.append(child);
1242 addNodeToFoundList(child, line, 0);
1243 }
1244 else
1245 break;
1246 }
1247}
1248
1249
1250void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line)
1251{
1252#if JW_DEBUG
1253 kdDebug(13000)<<"void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line)"<<endl;
1254#endif
1255
1256// return;
1257 if (markedForDeleting.isEmpty())
1258 return;
1259
1260 for (int i=0; i<(int)markedForDeleting.count(); i++)
1261 {
1262 KateCodeFoldingNode *node = markedForDeleting.at(i);
1263 if (node->deleteOpening)
1264 kdDebug(13000)<<"DELETE OPENING SET"<<endl;
1265 if (node->deleteEnding)
1266 kdDebug(13000)<<"DELETE ENDING SET"<<endl;
1267
1268 if ((node->deleteOpening) && (node->deleteEnding))
1269 {
1270#if JW_DEBUG
1271 kdDebug(13000)<<"Deleting complete node"<<endl;
1272#endif
1273 if (node->endLineValid) // just delete it, it has been opened and closed on this line
1274 {
1275 int f = node->parentNode->findChild (node);
1276
1277 if (f >= 0)
1278 delete node->parentNode->takeChild(f);
1279 }
1280 else
1281 {
1282 removeOpening(node, line);
1283 // the node has subnodes which need to be moved up and this one has to be deleted
1284 }
1285 something_changed = true;
1286 }
1287 else
1288 {
1289 if ((node->deleteOpening) && (node->startLineValid))
1290 {
1291#if JW_DEBUG
1292 kdDebug(13000)<<"calling removeOpening"<<endl;
1293#endif
1294 removeOpening(node, line);
1295 something_changed = true;
1296 }
1297 else
1298 {
1299 dontDeleteOpening(node);
1300
1301 if ((node->deleteEnding) && (node->endLineValid))
1302 {
1303 dontDeleteEnding(node);
1304 removeEnding(node, line);
1305 something_changed = true;
1306 }
1307 else
1308 dontDeleteEnding(node);
1309 }
1310 }
1311 }
1312}
1313
1314void KateCodeFoldingTree::dontDeleteEnding(KateCodeFoldingNode* node)
1315{
1316 node->deleteEnding = false;
1317}
1318
1319
1320void KateCodeFoldingTree::dontDeleteOpening(KateCodeFoldingNode* node)
1321{
1322 node->deleteOpening = false;
1323}
1324
1325
1326void KateCodeFoldingTree::toggleRegionVisibility(unsigned int line)
1327{
1328 // hl whole file
1329 m_buffer->line (m_buffer->count()-1);
1330
1331 lineMapping.clear();
1332 hiddenLinesCountCacheValid = false;
1333 kdDebug(13000)<<TQString(TQString("KateCodeFoldingTree::toggleRegionVisibility() %1").arg(line))<<endl;
1334
1335 findAllNodesOpenedOrClosedAt(line);
1336 for (int i=0; i<(int)nodesForLine.count(); i++)
1337 {
1338 KateCodeFoldingNode *node=nodesForLine.at(i);
1339 if ( (!node->startLineValid) || (getStartLine(node) != line) )
1340 {
1341 nodesForLine.remove(i);
1342 i--;
1343 }
1344 }
1345
1346 if (nodesForLine.isEmpty())
1347 return;
1348
1349 nodesForLine.at(0)->visible = !nodesForLine.at(0)->visible;
1350
1351 if (!nodesForLine.at(0)->visible)
1352 addHiddenLineBlock(nodesForLine.at(0),line);
1353 else
1354 {
1355 for (TQValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end();++it)
1356 if ((*it).start == line+1)
1357 {
1358 hiddenLines.remove(it);
1359 break;
1360 }
1361
1362 updateHiddenSubNodes(nodesForLine.at(0));
1363 }
1364
1365 emit regionVisibilityChangedAt(line);
1366}
1367
1368void KateCodeFoldingTree::updateHiddenSubNodes(KateCodeFoldingNode *node)
1369{
1370 for (uint i=0; i < node->childCount(); ++i)
1371 {
1372 KateCodeFoldingNode *iter = node->child(i);
1373
1374 if (!iter->visible)
1375 addHiddenLineBlock(iter, getStartLine(iter));
1376 else
1377 updateHiddenSubNodes(iter);
1378 }
1379}
1380
1381void KateCodeFoldingTree::addHiddenLineBlock(KateCodeFoldingNode *node,unsigned int line)
1382{
1383 KateHiddenLineBlock data;
1384 data.start = line+1;
1385 data.length = node->endLineRel-(existsOpeningAtLineAfter(line+node->endLineRel,node)?1:0); // without -1;
1386 bool inserted = false;
1387
1388 for (TQValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
1389 {
1390 if (((*it).start>=data.start) && ((*it).start<=data.start+data.length-1)) // another hidden block starting at the within this block already exits -> adapt new block
1391 {
1392 // the existing block can't have lines behind the new one, because a newly hidden
1393 // block has to encapsulate already hidden ones
1394 it=hiddenLines.remove(it);
1395 --it;
1396 }
1397 else
1398 {
1399 if ((*it).start > line)
1400 {
1401 hiddenLines.insert(it, data);
1402 inserted = true;
1403
1404 break;
1405 }
1406 }
1407 }
1408
1409 if (!inserted)
1410 hiddenLines.append(data);
1411}
1412
1413bool KateCodeFoldingTree::existsOpeningAtLineAfter(unsigned int line, KateCodeFoldingNode *node)
1414{
1415 for(KateCodeFoldingNode *tmp = node->parentNode; tmp; tmp=tmp->parentNode)
1416 {
1417 KateCodeFoldingNode *tmp2;
1418 unsigned int startLine=getStartLine(tmp);
1419
1420 if ((tmp2 = tmp->child(tmp->findChild(node) + 1))
1421 && ((tmp2->startLineRel + startLine) == line))
1422 return true;
1423
1424 if ((startLine + tmp->endLineRel) > line)
1425 return false;
1426 }
1427
1428 return false;
1429}
1430
1431
1432//
1433// get the real line number for a virtual line
1434//
1435unsigned int KateCodeFoldingTree::getRealLine(unsigned int virtualLine)
1436{
1437 // he, if nothing is hidden, why look at it ;)
1438 if (hiddenLines.isEmpty())
1439 return virtualLine;
1440
1441 // kdDebug(13000)<<TQString("VirtualLine %1").arg(virtualLine)<<endl;
1442
1443 unsigned int *real=lineMapping[virtualLine];
1444 if (real)
1445 return (*real);
1446
1447 unsigned int tmp = virtualLine;
1448 for (TQValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.begin();it!=hiddenLines.end();++it)
1449 {
1450 if ((*it).start<=virtualLine)
1451 virtualLine += (*it).length;
1452 else
1453 break;
1454 }
1455
1456 // kdDebug(13000)<<TQString("Real Line %1").arg(virtualLine)<<endl;
1457
1458 lineMapping.insert(tmp, new unsigned int(virtualLine));
1459 return virtualLine;
1460}
1461
1462//
1463// get the virtual line number for a real line
1464//
1465unsigned int KateCodeFoldingTree::getVirtualLine(unsigned int realLine)
1466{
1467 // he, if nothing is hidden, why look at it ;)
1468 if (hiddenLines.isEmpty())
1469 return realLine;
1470
1471 // kdDebug(13000)<<TQString("RealLine--> %1").arg(realLine)<<endl;
1472
1473 for (TQValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.fromLast(); it!=hiddenLines.end(); --it)
1474 {
1475 if ((*it).start <= realLine)
1476 realLine -= (*it).length;
1477 // else
1478 // break;
1479 }
1480
1481 // kdDebug(13000)<<TQString("-->virtual Line %1").arg(realLine)<<endl;
1482
1483 return realLine;
1484}
1485
1486//
1487// get the number of hidden lines
1488//
1489unsigned int KateCodeFoldingTree::getHiddenLinesCount(unsigned int doclen)
1490{
1491 // he, if nothing is hidden, why look at it ;)
1492 if (hiddenLines.isEmpty())
1493 return 0;
1494
1495 if (hiddenLinesCountCacheValid)
1496 return hiddenLinesCountCache;
1497
1498 hiddenLinesCountCacheValid = true;
1499 hiddenLinesCountCache = 0;
1500
1501 for (TQValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
1502 {
1503 if ((*it).start+(*it).length<=doclen)
1504 hiddenLinesCountCache += (*it).length;
1505 else
1506 {
1507 hiddenLinesCountCache += ((*it).length- ((*it).length + (*it).start - doclen));
1508 break;
1509 }
1510 }
1511
1512 return hiddenLinesCountCache;
1513}
1514
1515void KateCodeFoldingTree::collapseToplevelNodes()
1516{
1517 // hl whole file
1518 m_buffer->line (m_buffer->count()-1);
1519
1520 if (m_root.noChildren ())
1521 return;
1522
1523 for ( uint i=0; i < m_root.childCount(); ++i )
1524 {
1525 KateCodeFoldingNode *node = m_root.child(i);
1526
1527 if (node->visible && node->startLineValid && node->endLineValid)
1528 {
1529 node->visible=false;
1530 lineMapping.clear();
1531 hiddenLinesCountCacheValid = false;
1532 addHiddenLineBlock(node,node->startLineRel);
1533 emit regionVisibilityChangedAt(node->startLineRel);
1534 }
1535 }
1536}
1537
1538void KateCodeFoldingTree::expandToplevelNodes(int numLines)
1539{
1540 // hl whole file
1541 m_buffer->line (m_buffer->count()-1);
1542
1543 KateLineInfo line;
1544 for (int i = 0; i < numLines; i++) {
1545 getLineInfo(&line, i);
1546
1547 if (line.startsInVisibleBlock)
1548 toggleRegionVisibility(i);
1549 }
1550}
1551
1552int KateCodeFoldingTree::collapseOne(int realLine)
1553{
1554 // hl whole file
1555 m_buffer->line (m_buffer->count()-1);
1556
1557 KateLineInfo line;
1558 int unrelatedBlocks = 0;
1559 for (int i = realLine; i >= 0; i--) {
1560 getLineInfo(&line, i);
1561
1562 if (line.topLevel && !line.endsBlock)
1563 // optimisation
1564 break;
1565
1566 if (line.endsBlock && ( line.invalidBlockEnd ) && (i != realLine)) {
1567 unrelatedBlocks++;
1568 }
1569
1570 if (line.startsVisibleBlock) {
1571 unrelatedBlocks--;
1572 if (unrelatedBlocks == -1) {
1573 toggleRegionVisibility(i);
1574 return i;
1575 }
1576 }
1577 }
1578 return -1;
1579}
1580
1581void KateCodeFoldingTree::expandOne(int realLine, int numLines)
1582{
1583 // hl whole file
1584 m_buffer->line (m_buffer->count()-1);
1585
1586 KateLineInfo line;
1587 int blockTrack = 0;
1588 for (int i = realLine; i >= 0; i--) {
1589 getLineInfo(&line, i);
1590
1591 if (line.topLevel)
1592 // done
1593 break;
1594
1595 if (line.startsInVisibleBlock && i != realLine) {
1596 if (blockTrack == 0)
1597 toggleRegionVisibility(i);
1598
1599 blockTrack--;
1600 }
1601
1602 if (line.endsBlock)
1603 blockTrack++;
1604
1605 if (blockTrack < 0)
1606 // too shallow
1607 break;
1608 }
1609
1610 blockTrack = 0;
1611 for (int i = realLine; i < numLines; i++) {
1612 getLineInfo(&line, i);
1613
1614 if (line.topLevel)
1615 // done
1616 break;
1617
1618 if (line.startsInVisibleBlock) {
1619 if (blockTrack == 0)
1620 toggleRegionVisibility(i);
1621
1622 blockTrack++;
1623 }
1624
1625 if (line.endsBlock)
1626 blockTrack--;
1627
1628 if (blockTrack < 0)
1629 // too shallow
1630 break;
1631 }
1632}
1633
1634void KateCodeFoldingTree::ensureVisible( uint line )
1635{
1636 // first have a look, if the line is really hidden
1637 bool found=false;
1638 for (TQValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.begin();it!=hiddenLines.end();++it)
1639 {
1640 if ( ((*it).start<=line) && ((*it).start+(*it).length>line) )
1641 {
1642 found=true;
1643 break;
1644 }
1645 }
1646
1647
1648 if (!found) return;
1649
1650 kdDebug(13000)<<"line "<<line<<" is really hidden ->show block"<<endl;
1651
1652 // it looks like we really have to ensure visibility
1653 KateCodeFoldingNode *n = findNodeForLine( line );
1654 do {
1655 if ( ! n->visible )
1656 toggleRegionVisibility( getStartLine( n ) );
1657 n = n->parentNode;
1658 } while( n );
1659
1660}
KateBuffer
The KateBuffer class maintains a collections of lines.
Definition: katebuffer.h:342
KateTextCursor
Simple cursor class with no document pointer.
Definition: katecursor.h:34
endl
kndbgstream & endl(kndbgstream &s)
kdDebug
kdbgstream kdDebug(int area=0)
KStdAction::clear
TDEAction * clear(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
TDEStdAccel::end
const TDEShortcut & end()

kate

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

kate

Skip menu "kate"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kate by doxygen 1.9.4
This website is maintained by Timothy Pearson.