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