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