00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
#include "katecodefoldinghelpers.h"
00020
#include "katecodefoldinghelpers.moc"
00021
00022
#include <kdebug.h>
00023
00024
#include <qstring.h>
00025
00026
#define JW_DEBUG 0
00027
00028
bool KateCodeFoldingTree::trueVal =
true;
00029
00030 KateCodeFoldingNode::KateCodeFoldingNode() :
00031 parentNode(0),
00032 startLineRel(0),
00033 endLineRel(0),
00034 startLineValid(false),
00035 endLineValid(false),
00036 type(0),
00037 visible(true),
00038 deleteOpening(false),
00039 deleteEnding(false),
00040 m_childnodes(0)
00041 {
00042 }
00043
00044 KateCodeFoldingNode::KateCodeFoldingNode(KateCodeFoldingNode *par,
signed char typ,
unsigned int sLRel):
00045 parentNode(par),
00046 startLineRel(sLRel),
00047 endLineRel(10000),
00048 startLineValid(true),
00049 endLineValid(false),
00050 type(typ),
00051 visible(true),
00052 deleteOpening(false),
00053 deleteEnding(false),
00054 m_childnodes(0)
00055 {
00056 }
00057
00058 KateCodeFoldingNode::~KateCodeFoldingNode()
00059 {
00060
00061
if (m_childnodes)
00062
delete m_childnodes;
00063 }
00064
00065
00066 KateCodeFoldingTree::KateCodeFoldingTree(
QObject *par):
QObject(par), KateCodeFoldingNode()
00067 {
00068
clear();
00069 }
00070
00071
void KateCodeFoldingTree::fixRoot(
int endLRel)
00072 {
00073 endLineRel = endLRel;
00074 }
00075
00076
void KateCodeFoldingTree::clear()
00077 {
00078
if (m_childnodes)
00079 m_childnodes->clear();
00080
00081
00082 startLineValid=
true;
00083 endLineValid=
true;
00084 endLineRel=1;
00085
00086 hiddenLinesCountCacheValid=
false;
00087 lineMapping.setAutoDelete(
true);
00088 hiddenLines.clear();
00089 lineMapping.clear();
00090 nodesForLine.clear();
00091 markedForDeleting.clear();
00092 dontIgnoreUnchangedLines.clear();
00093 }
00094
00095 KateCodeFoldingTree::~KateCodeFoldingTree()
00096 {
00097 }
00098
00099
bool KateCodeFoldingTree::isTopLevel(
unsigned int line)
00100 {
00101
if (!hasChildNodes())
00102
return true;
00103
00104
00105
for ( KateCodeFoldingNode *node = m_childnodes->first(); node; node = m_childnodes->next() )
00106 {
00107
if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
00108
return false;
00109 }
00110
00111
return true;
00112 }
00113
00114
void KateCodeFoldingTree::getLineInfo(KateLineInfo *info,
unsigned int line)
00115 {
00116
00117
00118 info->topLevel =
true;
00119 info->startsVisibleBlock =
false;
00120 info->startsInVisibleBlock =
false;
00121 info->endsBlock =
false;
00122 info->invalidBlockEnd =
false;
00123
00124
if (!hasChildNodes())
00125
return;
00126
00127
00128
for ( KateCodeFoldingNode *node = m_childnodes->first(); node; node = m_childnodes->next() )
00129 {
00130
if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
00131 {
00132 info->topLevel =
false;
00133 findAllNodesOpenedOrClosedAt(line);
00134
00135
for ( KateCodeFoldingNode *node = nodesForLine.first(); node; node = nodesForLine.next() )
00136 {
00137 uint startLine = getStartLine(node);
00138
00139
00140
00141
if (node->type < 0)
00142 info->invalidBlockEnd=
true;
00143
else
00144 {
00145
if (startLine != line)
00146 info->endsBlock =
true;
00147
else
00148 {
00149
00150
if (node->visible)
00151 info->startsVisibleBlock=
true;
00152
else
00153 info->startsInVisibleBlock=
true;
00154 }
00155 }
00156 }
00157
00158
return;
00159 }
00160 }
00161
00162
return;
00163 }
00164
00165 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLine(
unsigned int line)
00166 {
00167
if (hasChildNodes())
00168 {
00169
00170
for (KateCodeFoldingNode *node=m_childnodes->first(); node; node=m_childnodes->next())
00171 {
00172
if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
00173 {
00174
00175
return findNodeForLineDescending(node,line,0);
00176 }
00177 }
00178 }
00179
00180
return this;
00181 }
00182
00183 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLineDescending ( KateCodeFoldingNode *node,
00184
unsigned int line,
unsigned int offset,
bool oneStepOnly )
00185 {
00186
if (hasChildNodes())
00187 {
00188
00189 offset += node->startLineRel;
00190
for ( KateCodeFoldingNode *subNode = node->childnodes()->first(); subNode; subNode=node->childnodes()->next() )
00191 {
00192
if ((subNode->startLineRel+offset<=line) && (line<=subNode->endLineRel+subNode->startLineRel+offset))
00193 {
00194
00195
00196
00197
if (oneStepOnly)
00198
return subNode;
00199
else
00200
return findNodeForLineDescending (subNode,line,offset);
00201 }
00202 }
00203 }
00204
00205
return node;
00206 }
00207
00208
00209
void KateCodeFoldingTree::debugDump()
00210 {
00211
00212
kdDebug(13000)<<
"The parsed region/block tree for code folding"<<
endl;
00213 dumpNode(
this,
"");
00214 }
00215
00216
void KateCodeFoldingTree::dumpNode(KateCodeFoldingNode *node,
QString prefix)
00217 {
00218
00219
kdDebug(13000)<<prefix<<
QString(
"Type: %1, startLineValid %2, startLineRel %3, endLineValid %4, endLineRel %5").
00220 arg(node->type).arg(node->startLineValid).arg(node->startLineRel).arg(node->endLineValid).
00221 arg(node->endLineRel)<<
endl;
00222
00223
00224
if (node->hasChildNodes())
00225 {
00226 prefix=prefix+
" ";
00227
for ( KateCodeFoldingNode *subNode = node->childnodes()->first(); subNode; subNode=node->childnodes()->next() )
00228 dumpNode (subNode,prefix);
00229 }
00230 }
00231
00232
00233
00234
00235
void KateCodeFoldingTree::updateLine(
unsigned int line,
00236
QMemArray<signed char> *regionChanges,
bool *updated,
bool changed)
00237 {
00238
if (!changed)
00239 {
00240
if (dontIgnoreUnchangedLines.isEmpty())
00241
return;
00242
00243
if (dontIgnoreUnchangedLines[line])
00244 dontIgnoreUnchangedLines.remove(line);
00245
else
00246
return;
00247 }
00248
00249 something_changed =
false;
00250
00251 findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
00252
00253
if (regionChanges->isEmpty())
00254 {
00255
00256
00257
00258 }
00259
else
00260 {
00261
for (
unsigned int i=0;i<regionChanges->size() / 2;i++) {
00262
signed char tmp=(*regionChanges)[regionChanges->size()-1-i];
00263 (*regionChanges)[regionChanges->size()-1-i]=(*regionChanges)[i];
00264 (*regionChanges)[i]=tmp;
00265 }
00266
00267
00268
signed char data= (*regionChanges)[regionChanges->size()-1];
00269 regionChanges->resize (regionChanges->size()-1);
00270
00271
int insertPos=-1;
00272 KateCodeFoldingNode *node = findNodeForLine(line);
00273
00274
if (data<0)
00275 {
00276
00277 {
00278
unsigned int tmpLine=line-getStartLine(node);
00279
00280
for (
int i=0; i<(
int)node->childnodes()->count(); i++)
00281 {
00282
if (node->childnodes()->at(i)->startLineRel >= tmpLine)
00283 {
00284 insertPos=i;
00285
break;
00286 }
00287 }
00288 }
00289 }
00290
else
00291 {
00292
for (; (node->parentNode) && (getStartLine(node->parentNode)==line) && (node->parentNode->type!=0); node=node->parentNode);
00293
00294
if ((getStartLine(node)==line) && (node->type!=0))
00295 {
00296 insertPos=node->parentNode->childnodes()->find(node);
00297 node = node->parentNode;
00298 }
00299
else
00300 {
00301
for (
int i=0;i<(
int)node->childnodes()->count();i++)
00302 {
00303
if (getStartLine(node->childnodes()->at(i))>=line)
00304 {
00305 insertPos=i;
00306
break;
00307 }
00308 }
00309 }
00310 }
00311
00312
do
00313 {
00314
if (data<0)
00315 {
00316
if (correctEndings(data,node,line,insertPos))
00317 {
00318 insertPos=node->parentNode->childnodes()->find(node)+1;
00319 node=node->parentNode;
00320 }
00321
else
00322 {
00323
if (insertPos!=-1) insertPos++;
00324 }
00325 }
00326
else
00327 {
00328
int startLine=getStartLine(node);
00329
if ((insertPos==-1) || (insertPos>=(
int)node->childnodes()->count()))
00330 {
00331 KateCodeFoldingNode *newNode =
new KateCodeFoldingNode (node,data,line-startLine);
00332 something_changed =
true;
00333 node->childnodes()->append(newNode);
00334 addOpening(newNode, data, regionChanges, line);
00335 insertPos = node->childnodes()->find(newNode)+1;
00336 }
00337
else
00338 {
00339
if (node->childnodes()->at(insertPos)->startLineRel == line-startLine)
00340 {
00341 addOpening(node->childnodes()->at(insertPos), data, regionChanges, line);
00342 insertPos++;
00343 }
00344
else
00345 {
00346
00347 KateCodeFoldingNode *newNode =
new KateCodeFoldingNode (node,data,line-startLine);
00348 something_changed =
true;
00349 node->childnodes()->insert(insertPos, newNode);
00350 addOpening(newNode, data, regionChanges, line);
00351 insertPos++;
00352 }
00353 }
00354 }
00355
00356
if (regionChanges->isEmpty())
00357 data = 0;
00358
else
00359 {
00360 data = (*regionChanges)[regionChanges->size()-1];
00361 regionChanges->resize (regionChanges->size()-1);
00362 }
00363 }
while (data!=0);
00364 }
00365
00366 cleanupUnneededNodes(line);
00367
00368 (*updated) = something_changed;
00369 }
00370
00371
00372
bool KateCodeFoldingTree::removeOpening(KateCodeFoldingNode *node,
unsigned int line)
00373 {
00374
signed char type;
00375
if ((type=node->type) == 0)
00376 {
00377 dontDeleteOpening(node);
00378 dontDeleteEnding(node);
00379
return false;
00380 }
00381
00382
if (!node->visible)
00383 {
00384 toggleRegionVisibility(getStartLine(node));
00385 }
00386
00387 KateCodeFoldingNode *parent = node->parentNode;
00388
int mypos = parent->childnodes()->find(node);
00389
00390
if (mypos > -1)
00391 {
00392
00393
for(; node->childnodes()->count()>0 ;)
00394 {
00395 KateCodeFoldingNode *tmp;
00396 parent->childnodes()->insert(mypos, tmp=node->childnodes()->take(0));
00397 tmp->parentNode = parent;
00398 tmp->startLineRel += node->startLineRel;
00399 mypos++;
00400 }
00401
00402
00403
00404
bool endLineValid = node->endLineValid;
00405
int endLineRel = node->endLineRel;
00406
00407
00408 parent->childnodes()->remove(mypos);
00409
00410
if ((type>0) && (endLineValid))
00411 correctEndings(-type, parent, line+endLineRel, mypos);
00412 }
00413
00414
return true;
00415 }
00416
00417
bool KateCodeFoldingTree::removeEnding(KateCodeFoldingNode *node,
unsigned int )
00418 {
00419 KateCodeFoldingNode *parent = node->parentNode;
00420
00421
if (!parent)
00422
return false;
00423
00424
if (node->type == 0)
00425
return false;
00426
00427
if (node->type < 0)
00428 {
00429
00430 parent->childnodes()->remove (node);
00431
return true;
00432 }
00433
00434
int mypos = parent->childnodes()->find(node);
00435
int count = parent->childnodes()->count();
00436
00437
for (
int i=mypos+1; i<count; i++)
00438 {
00439
if (parent->childnodes()->at(i)->type == -node->type)
00440 {
00441 node->endLineValid =
true;
00442 node->endLineRel = parent->childnodes()->at(i)->startLineRel - node->startLineRel;
00443 parent->childnodes()->remove(i);
00444 count = i-mypos-1;
00445
if (count > 0)
00446 {
00447
for (
int i=0; i<count; i++)
00448 {
00449 KateCodeFoldingNode *tmp = parent->childnodes()->take(mypos+1);
00450 tmp->startLineRel -= node->startLineRel;
00451 tmp->parentNode = node;
00452 node->childnodes()->append(tmp);
00453 }
00454 }
00455
return false;
00456 }
00457 }
00458
00459
if ( (parent->type == node->type) || (!parent->parentNode))
00460 {
00461
for (
int i=mypos+1; i<(
int)parent->childnodes()->count(); i++)
00462 {
00463 KateCodeFoldingNode *tmp = parent->childnodes()->take(mypos+1);
00464 tmp->startLineRel -= node->startLineRel;
00465 tmp->parentNode = node;
00466 node->childnodes()->append(tmp);
00467 }
00468
00469
00470
if (!parent->parentNode)
00471 node->endLineValid=
false;
00472
else
00473 node->endLineValid = parent->endLineValid;
00474
00475 node->endLineRel = parent->endLineRel-node->startLineRel;
00476
00477
if (node->endLineValid)
00478
return removeEnding(parent, getStartLine(parent)+parent->endLineRel);
00479
00480
return false;
00481 }
00482
00483 node->endLineValid =
false;
00484 node->endLineRel = parent->endLineRel - node->startLineRel;
00485
00486
return false;
00487 }
00488
00489
00490
bool KateCodeFoldingTree::correctEndings(
signed char data, KateCodeFoldingNode *node,
unsigned int line,
int insertPos)
00491 {
00492
00493 uint startLine = getStartLine(node);
00494
if (data != -node->type)
00495 {
00496
#if JW_DEBUG
00497
kdDebug(13000)<<
"data!=-node->type (correctEndings)"<<
endl;
00498
#endif
00499
00500 dontDeleteEnding(node);
00501
if (data == node->type)
00502
return false;
00503 KateCodeFoldingNode *newNode =
new KateCodeFoldingNode (node,data,line-startLine);
00504 something_changed =
true;
00505 newNode->startLineValid =
false;
00506 newNode->endLineValid =
true;
00507 newNode->endLineRel = 0;
00508
00509
if ((insertPos==-1) || (insertPos==(
int)node->childnodes()->count()))
00510 node->childnodes()->append(newNode);
00511
else
00512 node->childnodes()->insert(insertPos,newNode);
00513
00514
00515
return false;
00516 }
00517
else
00518 {
00519 something_changed =
true;
00520 dontDeleteEnding(node);
00521
00522
00523
if (!node->endLineValid)
00524 {
00525 node->endLineValid =
true;
00526 node->endLineRel = line - startLine;
00527
00528
00529 moveSubNodesUp(node);
00530 }
00531
else
00532 {
00533
#if JW_DEBUG
00534
kdDebug(13000)<<
"Closing a node which had already a valid end"<<
endl;
00535
#endif
00536
00537
if (startLine+node->endLineRel == line)
00538 {
00539
00540
#if JW_DEBUG
00541
kdDebug(13000)<<
"We won, just skipping (correctEndings)"<<
endl;
00542
#endif
00543
}
00544
else
00545 {
00546
int bakEndLine = node->endLineRel+startLine;
00547 node->endLineRel = line-startLine;
00548
00549
00550
#if JW_DEBUG
00551
kdDebug(13000)<<
"reclosed node had childnodes()"<<
endl;
00552
kdDebug(13000)<<
"It could be, that childnodes() need to be moved up"<<
endl;
00553
#endif
00554
moveSubNodesUp(node);
00555
00556
if (node->parentNode)
00557 {
00558 correctEndings(data,node->parentNode,bakEndLine, node->parentNode->childnodes()->find(node)+1);
00559 }
00560
else
00561 {
00562
00563 }
00564 }
00565 }
00566 }
00567
return true;
00568 }
00569
00570
void KateCodeFoldingTree::moveSubNodesUp(KateCodeFoldingNode *node)
00571 {
00572
int mypos = node->parentNode->childnodes()->find(node);
00573
int removepos=-1;
00574
int count = node->childnodes()->count();
00575
for (
int i=0; i<count; i++)
00576
if (node->childnodes()->at(i)->startLineRel >= node->endLineRel)
00577 {
00578 removepos=i;
00579
break;
00580 }
00581
#if JW_DEBUG
00582
kdDebug(13000)<<
QString(
"remove pos: %1").arg(removepos)<<
endl;
00583
#endif
00584
if (removepos>-1)
00585 {
00586
#if JW_DEBUG
00587
kdDebug(13000)<<
"Children need to be moved"<<
endl;
00588
#endif
00589
KateCodeFoldingNode *moveNode;
00590
if (mypos == (
int)node->parentNode->childnodes()->count()-1)
00591 {
00592
while (removepos<(
int)node->childnodes()->count())
00593 {
00594 node->parentNode->childnodes()->append(moveNode=node->childnodes()->take(removepos));
00595 moveNode->parentNode = node->parentNode;
00596 moveNode->startLineRel += node->startLineRel;
00597 }
00598 }
00599
else
00600 {
00601
int insertPos=mypos;
00602
while (removepos < (
int)node->childnodes()->count())
00603 {
00604 insertPos++;
00605 node->parentNode->childnodes()->insert(insertPos, moveNode=node->childnodes()->take(removepos));
00606 moveNode->parentNode = node->parentNode;
00607 moveNode->startLineRel += node->startLineRel;
00608 }
00609 }
00610 }
00611
00612 }
00613
00614
00615
00616
void KateCodeFoldingTree::addOpening(KateCodeFoldingNode *node,
signed char nType,
QMemArray<signed char>* list,
unsigned int line)
00617 {
00618 uint startLine = getStartLine(node);
00619
if ((startLine==line) && (node->type!=0))
00620 {
00621
#if JW_DEBUG
00622
kdDebug(13000)<<
"startLine equals line"<<
endl;
00623
#endif
00624
if (nType == node->type)
00625 {
00626
#if JW_DEBUG
00627
kdDebug(13000)<<
"Node exists"<<
endl;
00628
#endif
00629
node->deleteOpening =
false;
00630 KateCodeFoldingNode *parent = node->parentNode;
00631
00632
if (!node->endLineValid)
00633 {
00634
int current = parent->childnodes()->find(node);
00635
int count = parent->childnodes()->count()-(current+1);
00636 node->endLineRel = parent->endLineRel - node->startLineRel;
00637
00638
00639
00640
if (parent)
00641
if (parent->type == node->type)
00642 {
00643
if (parent->endLineValid)
00644 {
00645 removeEnding(parent, line);
00646 node->endLineValid =
true;
00647 }
00648 }
00649
00650
00651
00652
if (current != (
int)parent->childnodes()->count()-1)
00653 {
00654
00655
#ifdef __GNUC__
00656
#warning "FIXME: why does this seem to work?"
00657
#endif
00658
00659 {
00660
for (
int i=current+1; i<(
int)parent->childnodes()->count(); i++)
00661 {
00662
if (parent->childnodes()->at(i)->type == -node->type)
00663 {
00664 count = (i-current-1);
00665 node->endLineValid =
true;
00666 node->endLineRel = getStartLine(parent->childnodes()->at(i))-line;
00667 parent->childnodes()->remove(i);
00668
break;
00669 }
00670 }
00671 }
00672
00673
00674
00675
00676
00677
00678
if (count>0)
00679 {
00680
for (
int i=0;i<count;i++)
00681 {
00682 KateCodeFoldingNode *tmp;
00683 node->childnodes()->append(tmp=parent->childnodes()->take(current+1));
00684 tmp->startLineRel -= node->startLineRel;
00685 tmp->parentNode = node;
00686 }
00687 }
00688 }
00689
00690 }
00691
00692 addOpening_further_iterations(node, nType, list, line, 0, startLine);
00693
00694 }
00695 }
00696
else
00697 {
00698 KateCodeFoldingNode *newNode =
new KateCodeFoldingNode (node,nType,line-startLine);
00699 something_changed =
true;
00700
00701
int insert_position=-1;
00702
for (
int i=0; i<(
int)node->childnodes()->count(); i++)
00703 {
00704
if (startLine+node->childnodes()->at(i)->startLineRel > line)
00705 {
00706 insert_position=i;
00707
break;
00708 }
00709 }
00710
00711
int current;
00712
if (insert_position==-1)
00713 {
00714 node->childnodes()->append(newNode);
00715 current = node->childnodes()->count()-1;
00716 }
00717
else
00718 {
00719 node->childnodes()->insert(insert_position, newNode);
00720 current = insert_position;
00721 }
00722
00723
00724
00725
00726
00727
00728
00729
00730
int count = node->childnodes()->count() - (current+1);
00731 newNode->endLineRel -= newNode->startLineRel;
00732
if (current != (
int)node->childnodes()->count()-1)
00733 {
00734
if (node->type != newNode->type)
00735 {
00736
for (
int i=current+1; i<(
int)node->childnodes()->count(); i++)
00737 {
00738
if (node->childnodes()->at(i)->type == -newNode->type)
00739 {
00740 count = node->childnodes()->count() - i - 1;
00741 newNode->endLineValid =
true;
00742 newNode->endLineRel = line - getStartLine(node->childnodes()->at(i));
00743 node->childnodes()->remove(i);
00744
break;
00745 }
00746 }
00747 }
00748
else
00749 {
00750 node->endLineValid =
false;
00751 node->endLineRel = 10000;
00752 }
00753
if (count > 0)
00754 {
00755
for (
int i=0;i<count;i++)
00756 {
00757 KateCodeFoldingNode *tmp;
00758 newNode->childnodes()->append(tmp=node->childnodes()->take(current+1));
00759 tmp->parentNode=newNode;
00760 }
00761 }
00762
00763 }
00764
00765 addOpening(newNode, nType, list, line);
00766
00767 addOpening_further_iterations(node, node->type, list, line, current, startLine);
00768 }
00769 }
00770
00771
00772
void KateCodeFoldingTree::addOpening_further_iterations(KateCodeFoldingNode *node,
signed char ,
QMemArray<signed char>*
00773 list,
unsigned int line,
int current,
unsigned int startLine)
00774 {
00775
while (!(list->isEmpty()))
00776 {
00777
if (list->isEmpty())
00778
return;
00779
else
00780 {
00781
signed char data = (*list)[list->size()-1];
00782 list->resize (list->size()-1);
00783
00784
if (data<0)
00785 {
00786
#if JW_DEBUG
00787
kdDebug(13000)<<
"An ending was found"<<
endl;
00788
#endif
00789
00790
if (correctEndings(data,node,line,-1))
00791
return;
00792
00793
#if 0
00794
if(data == -nType)
00795 {
00796
if (node->endLineValid)
00797 {
00798
if (node->endLineRel+startLine==line)
00799 {
00800
00801 }
00802
else
00803 {
00804 node->endLineRel=line-startLine;
00805 node->endLineValid=
true;
00806 }
00807
return;
00808 }
00809
else
00810 {
00811 node->endLineRel=line-startLine;
00812 node->endLineValid=
true;
00813
00814 }
00815 }
00816
#endif
00817
}
00818
else
00819 {
00820
bool needNew =
true;
00821
if (current < (
int)node->childnodes()->count())
00822 {
00823
if (getStartLine(node->childnodes()->at(current)) == line)
00824 needNew=
false;
00825 }
00826
if (needNew)
00827 {
00828 something_changed =
true;
00829 KateCodeFoldingNode *newNode =
new KateCodeFoldingNode(node, data, line-startLine);
00830 node->childnodes()->insert(current, newNode);
00831 }
00832
00833 addOpening(node->childnodes()->at(current), data, list, line);
00834 current++;
00835
00836 }
00837 }
00838 }
00839 }
00840
00841
unsigned int KateCodeFoldingTree::getStartLine(KateCodeFoldingNode *node)
00842 {
00843
unsigned int lineStart=0;
00844
for (KateCodeFoldingNode *iter=node; iter->type != 0; iter=iter->parentNode)
00845 lineStart += iter->startLineRel;
00846
00847
return lineStart;
00848 }
00849
00850
00851
void KateCodeFoldingTree::lineHasBeenRemoved(
unsigned int line)
00852 {
00853 lineMapping.clear();
00854 dontIgnoreUnchangedLines.insert(line, &trueVal);
00855 dontIgnoreUnchangedLines.insert(line-1, &trueVal);
00856 dontIgnoreUnchangedLines.insert(line+1, &trueVal);
00857 hiddenLinesCountCacheValid =
false;
00858
#if JW_DEBUG
00859
kdDebug(13000)<<
QString(
"KateCodeFoldingTree::lineHasBeenRemoved: %1").arg(line)<<
endl;
00860
#endif
00861
00862
00863 findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
00864 cleanupUnneededNodes(line);
00865
00866 KateCodeFoldingNode *node = findNodeForLine(line);
00867
00868 {
00869
int startLine = getStartLine(node);
00870
if (startLine == (
int)line)
00871 node->startLineRel--;
00872
else
00873 {
00874
if (node->endLineRel == 0)
00875 node->endLineValid =
false;
00876 node->endLineRel--;
00877 }
00878
00879
int count = node->childnodes()->count();
00880
for (
int i=0; i<count; i++)
00881 {
00882
if (node->childnodes()->at(i)->startLineRel+startLine >= line)
00883 node->childnodes()->at(i)->startLineRel--;
00884 }
00885 }
00886
00887
if (node->parentNode)
00888 decrementBy1(node->parentNode, node);
00889
00890
for (
QValueList<hiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
00891 {
00892
if ((*it).start > line)
00893 (*it).start--;
00894
else if ((*it).start+(*it).length > line)
00895 (*it).length--;
00896 }
00897 }
00898
00899
00900
void KateCodeFoldingTree::decrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after)
00901 {
00902
if (node->endLineRel == 0)
00903 node->endLineValid =
false;
00904 node->endLineRel--;
00905
00906 node->childnodes()->find(after);
00907 KateCodeFoldingNode *iter;
00908
while ((iter=node->childnodes()->next()))
00909 iter->startLineRel--;
00910
00911
if (node->parentNode)
00912 decrementBy1(node->parentNode,node);
00913 }
00914
00915
00916
void KateCodeFoldingTree::lineHasBeenInserted(
unsigned int line)
00917 {
00918 lineMapping.clear();
00919 dontIgnoreUnchangedLines.insert(line, &trueVal);
00920 dontIgnoreUnchangedLines.insert(line-1, &trueVal);
00921 dontIgnoreUnchangedLines.insert(line+1, &trueVal);
00922 hiddenLinesCountCacheValid =
false;
00923
00924
#if JW_DEBUG
00925
kdDebug(13000)<<
QString(
"KateCodeFoldingTree::lineHasBeenInserted: %1").arg(line)<<
endl;
00926
#endif
00927
00928
00929
00930
00931 KateCodeFoldingNode *node = findNodeForLine(line);
00932
00933 {
00934
int startLine=getStartLine(node);
00935
if (node->type < 0)
00936 node->startLineRel++;
00937
else
00938 node->endLineRel++;
00939
00940
for (KateCodeFoldingNode *iter=node->childnodes()->first(); iter; iter=node->childnodes()->next())
00941 {
00942
if (iter->startLineRel+startLine >= line)
00943 iter->startLineRel++;
00944 }
00945 }
00946
00947
if (node->parentNode)
00948 incrementBy1(node->parentNode, node);
00949
00950
for (
QValueList<hiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
00951 {
00952
if ((*it).start > line)
00953 (*it).start++;
00954
else if ((*it).start+(*it).length > line)
00955 (*it).length++;
00956 }
00957 }
00958
00959
void KateCodeFoldingTree::incrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after)
00960 {
00961 node->endLineRel++;
00962
00963 node->childnodes()->find(after);
00964 KateCodeFoldingNode *iter;
00965
while ((iter=node->childnodes()->next()))
00966 iter->startLineRel++;
00967
00968
if (node->parentNode)
00969 incrementBy1(node->parentNode,node);
00970 }
00971
00972
00973
void KateCodeFoldingTree::findAndMarkAllNodesforRemovalOpenedOrClosedAt(
unsigned int line)
00974 {
00975
#ifdef __GNUC__
00976
#warning "FIXME: make this multiple region changes per line save";
00977
#endif
00978
00979 markedForDeleting.clear();
00980 KateCodeFoldingNode *node = findNodeForLine(line);
00981
if (node->type == 0)
00982
return;
00983
00984 addNodeToRemoveList(node, line);
00985
00986
while (((node->parentNode) && (node->parentNode->type!=0)) && (getStartLine(node->parentNode)==line))
00987 {
00988 node = node->parentNode;
00989 addNodeToRemoveList(node, line);
00990 }
00991
#if JW_DEBUG
00992
kdDebug(13000)<<
" added line to markedForDeleting list"<<
endl;
00993
#endif
00994
}
00995
00996
00997
void KateCodeFoldingTree::addNodeToRemoveList(KateCodeFoldingNode *node,
unsigned int line)
00998 {
00999
bool add=
false;
01000
#ifdef __GNUC__
01001
#warning "FIXME: make this multiple region changes per line save";
01002
#endif
01003
unsigned int startLine=getStartLine(node);
01004
if ((startLine==line) && (node->startLineValid))
01005 {
01006 add=
true;
01007 node->deleteOpening =
true;
01008 }
01009
if ((startLine+node->endLineRel==line) || ((node->endLineValid==
false) && (node->deleteOpening)))
01010 {
01011
int myPos=node->parentNode->childnodes()->find(node);
01012
if ((
int)node->parentNode->childnodes()->count()>myPos+1)
01013 addNodeToRemoveList(node->parentNode->childnodes()->at(myPos+1),line);
01014 add=
true;
01015 node->deleteEnding =
true;
01016 }
01017
01018
if(add)
01019 markedForDeleting.append(node);
01020
01021 }
01022
01023
01024
void KateCodeFoldingTree::findAllNodesOpenedOrClosedAt(
unsigned int line)
01025 {
01026 nodesForLine.clear();
01027 KateCodeFoldingNode *node = findNodeForLine(line);
01028
if (node->type == 0)
01029
return;
01030
01031
unsigned int startLine = getStartLine(node);
01032
if (startLine == line)
01033 nodesForLine.append(node);
01034
else if ((startLine+node->endLineRel == line))
01035 nodesForLine.append(node);
01036
01037
while (node->parentNode)
01038 {
01039 addNodeToFoundList(node->parentNode, line, node->parentNode->childnodes()->find(node));
01040 node = node->parentNode;
01041 }
01042
#if JW_DEBUG
01043
kdDebug(13000)<<
" added line to nodesForLine list"<<
endl;
01044
#endif
01045
}
01046
01047
01048
void KateCodeFoldingTree::addNodeToFoundList(KateCodeFoldingNode *node,
unsigned int line,
int childpos)
01049 {
01050
unsigned int startLine = getStartLine(node);
01051
01052
if ((startLine==line) && (node->type!=0))
01053 nodesForLine.append(node);
01054
else if ((startLine+node->endLineRel==line) && (node->type!=0))
01055 nodesForLine.append(node);
01056
01057
for (
int i=childpos+1; i<(
int)node->childnodes()->count(); i++)
01058 {
01059 KateCodeFoldingNode *child = node->childnodes()->at(i);
01060
01061
if (startLine+child->startLineRel == line)
01062 {
01063 nodesForLine.append(child);
01064 addNodeToFoundList(child, line, 0);
01065 }
01066
else
01067
break;
01068 }
01069 }
01070
01071
01072
void KateCodeFoldingTree::cleanupUnneededNodes(
unsigned int line)
01073 {
01074
#if JW_DEBUG
01075
kdDebug(13000)<<
"void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line)"<<
endl;
01076
#endif
01077
01078
01079
if (markedForDeleting.isEmpty())
01080
return;
01081
01082
for (
int i=0; i<(
int)markedForDeleting.count(); i++)
01083 {
01084 KateCodeFoldingNode *node = markedForDeleting.at(i);
01085
if (node->deleteOpening)
01086
kdDebug(13000)<<
"DELETE OPENING SET"<<
endl;
01087
if (node->deleteEnding)
01088
kdDebug(13000)<<
"DELETE ENDING SET"<<
endl;
01089
01090
if ((node->deleteOpening) && (node->deleteEnding))
01091 {
01092
#if JW_DEBUG
01093
kdDebug(13000)<<
"Deleting complete node"<<
endl;
01094
#endif
01095
if (node->endLineValid)
01096 {
01097 node->parentNode->childnodes()->remove(node);
01098 }
01099
else
01100 {
01101 removeOpening(node, line);
01102
01103 }
01104 something_changed =
true;
01105 }
01106
else
01107 {
01108
if ((node->deleteOpening) && (node->startLineValid))
01109 {
01110
#if JW_DEBUG
01111
kdDebug(13000)<<
"calling removeOpening"<<
endl;
01112
#endif
01113
removeOpening(node, line);
01114 something_changed =
true;
01115 }
01116
else
01117 {
01118 dontDeleteOpening(node);
01119
01120
if ((node->deleteEnding) && (node->endLineValid))
01121 {
01122 dontDeleteEnding(node);
01123 removeEnding(node, line);
01124 something_changed =
true;
01125 }
01126
else
01127 dontDeleteEnding(node);
01128 }
01129 }
01130 }
01131 }
01132
01133
void KateCodeFoldingTree::dontDeleteEnding(KateCodeFoldingNode* node)
01134 {
01135 node->deleteEnding =
false;
01136 }
01137
01138
01139
void KateCodeFoldingTree::dontDeleteOpening(KateCodeFoldingNode* node)
01140 {
01141 node->deleteOpening =
false;
01142 }
01143
01144
01145
void KateCodeFoldingTree::toggleRegionVisibility(
unsigned int line)
01146 {
01147 lineMapping.clear();
01148 hiddenLinesCountCacheValid =
false;
01149
kdDebug(13000)<<
QString(
"KateCodeFoldingTree::toggleRegionVisibility() %1").arg(line)<<
endl;
01150
01151 findAllNodesOpenedOrClosedAt(line);
01152
for (
int i=0; i<(
int)nodesForLine.count(); i++)
01153 {
01154
if (getStartLine(nodesForLine.at(i)) != line)
01155 {
01156 nodesForLine.remove(i);
01157 i--;
01158 }
01159 }
01160
01161
if (nodesForLine.isEmpty())
01162
return;
01163
01164 nodesForLine.at(0)->visible = !nodesForLine.at(0)->visible;
01165
01166
01167
#if 0
01168
for (
unsigned int i=line+1;i<=nodesForLine.at(0)->endLineRel+line;i++)
01169 {
01170
01171 emit(setLineVisible(i,nodesForLine.at(0)->visible));
01172 }
01173
#endif
01174
01175
if (!nodesForLine.at(0)->visible)
01176 addHiddenLineBlock(nodesForLine.at(0),line);
01177
else
01178 {
01179
for (
QValueList<hiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end();++it)
01180
if ((*it).start == line+1)
01181 {
01182 hiddenLines.remove(it);
01183
break;
01184 }
01185
01186
for (
unsigned int i=line+1; i<=nodesForLine.at(0)->endLineRel+line; i++)
01187 emit(setLineVisible(i,
true));
01188
01189 updateHiddenSubNodes(nodesForLine.at(0));
01190 }
01191
01192 emit regionVisibilityChangedAt(line);
01193 }
01194
01195
void KateCodeFoldingTree::updateHiddenSubNodes(KateCodeFoldingNode *node)
01196 {
01197
for (KateCodeFoldingNode *iter=node->childnodes()->first(); iter; iter=node->childnodes()->next())
01198 {
01199
if (!iter->visible)
01200 addHiddenLineBlock(iter, getStartLine(iter));
01201
else
01202 updateHiddenSubNodes(iter);
01203 }
01204 }
01205
01206
void KateCodeFoldingTree::addHiddenLineBlock(KateCodeFoldingNode *node,
unsigned int line)
01207 {
01208
struct hiddenLineBlock data;
01209 data.start = line+1;
01210 data.length = node->endLineRel-(existsOpeningAtLineAfter(line+node->endLineRel,node)?1:0);
01211
bool inserted =
false;
01212
01213
for (
QValueList<hiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
01214 {
01215
if (((*it).start>=data.start) && ((*it).start<=data.start+data.length-1))
01216 {
01217
01218
01219 it=hiddenLines.remove(it);
01220 --it;
01221 }
01222
else
01223 {
01224
if ((*it).start > line)
01225 {
01226 hiddenLines.insert(it, data);
01227 inserted =
true;
01228
01229
break;
01230 }
01231 }
01232 }
01233
01234
if (!inserted)
01235 hiddenLines.append(data);
01236
01237
for (
unsigned int i = line+1; i <= (node->endLineRel+line); i++)
01238 emit(setLineVisible(i,
false));
01239 }
01240
01241
bool KateCodeFoldingTree::existsOpeningAtLineAfter(
unsigned int line, KateCodeFoldingNode *node)
01242 {
01243
for(KateCodeFoldingNode *tmp = node->parentNode; tmp; tmp=tmp->parentNode)
01244 {
01245 KateCodeFoldingNode *tmp2;
01246
unsigned int startLine=getStartLine(tmp);
01247
01248
if ((tmp2 = tmp->childnodes()->at(tmp->childnodes()->find(node) + 1))
01249 && ((tmp2->startLineRel + startLine) == line))
01250
return true;
01251
01252
if ((startLine + tmp->endLineRel) > line)
01253
return false;
01254 }
01255
01256
return false;
01257 }
01258
01259
01260
01261
01262
01263
unsigned int KateCodeFoldingTree::getRealLine(
unsigned int virtualLine)
01264 {
01265
01266
if (hiddenLines.isEmpty())
01267
return virtualLine;
01268
01269
01270
01271
unsigned int *real=lineMapping[virtualLine];
01272
if (real)
01273
return (*real);
01274
01275
unsigned int tmp = virtualLine;
01276
for (
QValueList<hiddenLineBlock>::ConstIterator it=hiddenLines.begin();it!=hiddenLines.end();++it)
01277 {
01278
if ((*it).start<=virtualLine)
01279 virtualLine += (*it).length;
01280
else
01281
break;
01282 }
01283
01284
01285
01286 lineMapping.insert(tmp,
new unsigned int(virtualLine));
01287
return virtualLine;
01288 }
01289
01290
01291
01292
01293
unsigned int KateCodeFoldingTree::getVirtualLine(
unsigned int realLine)
01294 {
01295
01296
if (hiddenLines.isEmpty())
01297
return realLine;
01298
01299
01300
01301
for (
QValueList<hiddenLineBlock>::ConstIterator it=hiddenLines.fromLast(); it!=hiddenLines.end(); --it)
01302 {
01303
if ((*it).start <= realLine)
01304 realLine -= (*it).length;
01305
01306
01307 }
01308
01309
01310
01311
return realLine;
01312 }
01313
01314
01315
01316
01317
unsigned int KateCodeFoldingTree::getHiddenLinesCount(
unsigned int doclen)
01318 {
01319
01320
if (hiddenLines.isEmpty())
01321
return 0;
01322
01323
if (hiddenLinesCountCacheValid)
01324
return hiddenLinesCountCache;
01325
01326 hiddenLinesCountCacheValid =
true;
01327 hiddenLinesCountCache = 0;
01328
01329
for (
QValueList<hiddenLineBlock>::ConstIterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
01330 {
01331
if ((*it).start+(*it).length<=doclen)
01332 hiddenLinesCountCache += (*it).length;
01333
else
01334 {
01335 hiddenLinesCountCache += ((*it).length- ((*it).length + (*it).start - doclen));
01336
break;
01337 }
01338 }
01339
01340
return hiddenLinesCountCache;
01341 }
01342
01343
01344
void KateCodeFoldingTree::collapseToplevelNodes()
01345 {
01346
if( !hasChildNodes ())
01347
return;
01348
01349
for (uint i=0; i<m_childnodes->count(); i++)
01350 {
01351 KateCodeFoldingNode *node = m_childnodes->at(i);
01352
if (node->visible && node->startLineValid && node->endLineValid)
01353 {
01354 node->visible=
false;
01355 lineMapping.clear();
01356 hiddenLinesCountCacheValid =
false;
01357 addHiddenLineBlock(node,node->startLineRel);
01358 emit regionVisibilityChangedAt(node->startLineRel);
01359 }
01360 }
01361 }
01362
01363
void KateCodeFoldingTree::expandToplevelNodes(
int numLines)
01364 {
01365 KateLineInfo line;
01366
for (
int i = 0; i < numLines; i++) {
01367 getLineInfo(&line, i);
01368
01369
if (line.startsInVisibleBlock)
01370 toggleRegionVisibility(i);
01371 }
01372 }
01373
01374
int KateCodeFoldingTree::collapseOne(
int realLine)
01375 {
01376 KateLineInfo line;
01377
int unrelatedBlocks = 0;
01378
for (
int i = realLine; i >= 0; i--) {
01379 getLineInfo(&line, i);
01380
01381
if (line.topLevel && !line.endsBlock)
01382
01383
break;
01384
01385
if (line.endsBlock && i != realLine) {
01386 unrelatedBlocks++;
01387 }
01388
01389
if (line.startsVisibleBlock) {
01390 unrelatedBlocks--;
01391
if (unrelatedBlocks == -1) {
01392 toggleRegionVisibility(i);
01393
return i;
01394 }
01395 }
01396 }
01397
return -1;
01398 }
01399
01400
void KateCodeFoldingTree::expandOne(
int realLine,
int numLines)
01401 {
01402 KateLineInfo line;
01403
int blockTrack = 0;
01404
for (
int i = realLine; i >= 0; i--) {
01405 getLineInfo(&line, i);
01406
01407
if (line.topLevel)
01408
01409
break;
01410
01411
if (line.startsInVisibleBlock && i != realLine) {
01412
if (blockTrack == 0)
01413 toggleRegionVisibility(i);
01414
01415 blockTrack--;
01416 }
01417
01418
if (line.endsBlock)
01419 blockTrack++;
01420
01421
if (blockTrack < 0)
01422
01423
break;
01424 }
01425
01426 blockTrack = 0;
01427
for (
int i = realLine; i < numLines; i++) {
01428 getLineInfo(&line, i);
01429
01430
if (line.topLevel)
01431
01432
break;
01433
01434
if (line.startsInVisibleBlock) {
01435
if (blockTrack == 0)
01436 toggleRegionVisibility(i);
01437
01438 blockTrack++;
01439 }
01440
01441
if (line.endsBlock)
01442 blockTrack--;
01443
01444
if (blockTrack < 0)
01445
01446
break;
01447 }
01448 }
01449
01450
void KateCodeFoldingTree::ensureVisible( uint line )
01451 {
01452
01453
bool found=
false;
01454
for (
QValueList<hiddenLineBlock>::ConstIterator it=hiddenLines.begin();it!=hiddenLines.end();++it)
01455 {
01456
if ( ((*it).start<=line) && ((*it).start+(*it).length>line) )
01457 {
01458 found=
true;
01459
break;
01460 }
01461 }
01462
01463
01464
if (!found)
return;
01465
01466
kdDebug()<<
"line "<<line<<
" is really hidden ->show block"<<
endl;
01467
01468
01469 KateCodeFoldingNode *n = findNodeForLine( line );
01470
do {
01471
if ( ! n->visible )
01472 toggleRegionVisibility( getStartLine( n ) );
01473 n = n->parentNode;
01474 }
while( n );
01475
01476 }
01477
01478