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