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