katecodefoldinghelpers.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #include "katecodefoldinghelpers.h" 00020 #include "katecodefoldinghelpers.moc" 00021 00022 #include "katebuffer.h" 00023 #include "katecursor.h" 00024 #include <kdebug.h> 00025 00026 #include <tqstring.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 startCol(0), 00037 endCol(0), 00038 startLineValid(false), 00039 endLineValid(false), 00040 type(0), 00041 visible(true), 00042 deleteOpening(false), 00043 deleteEnding(false) 00044 { 00045 }//the endline fields should be initialised to not valid 00046 00047 KateCodeFoldingNode::KateCodeFoldingNode(KateCodeFoldingNode *par, signed char typ, unsigned int sLRel): 00048 parentNode(par), 00049 startLineRel(sLRel), 00050 endLineRel(10000), 00051 startCol(0), 00052 endCol(0), 00053 startLineValid(true), 00054 endLineValid(false), 00055 type(typ), 00056 visible(true), 00057 deleteOpening(false), 00058 deleteEnding(false) 00059 { 00060 }//the endline fields should be initialised to not valid 00061 00062 KateCodeFoldingNode::~KateCodeFoldingNode() 00063 { 00064 // delete all child nodes 00065 clearChildren (); 00066 } 00067 00068 bool KateCodeFoldingNode::getBegin(KateCodeFoldingTree *tree, KateTextCursor* begin) { 00069 if (!startLineValid) return false; 00070 unsigned int line=startLineRel; 00071 for (KateCodeFoldingNode *n=parentNode;n;n=n->parentNode) 00072 line+=n->startLineRel; 00073 00074 tree->m_buffer->codeFoldingColumnUpdate(line); 00075 begin->setLine(line); 00076 begin->setCol(startCol); 00077 00078 return true; 00079 } 00080 00081 bool KateCodeFoldingNode::getEnd(KateCodeFoldingTree *tree, KateTextCursor *end) { 00082 if (!endLineValid) return false; 00083 unsigned int line=startLineRel+endLineRel; 00084 for (KateCodeFoldingNode *n=parentNode;n;n=n->parentNode) 00085 line+=n->startLineRel; 00086 00087 tree->m_buffer->codeFoldingColumnUpdate(line); 00088 end->setLine(line); 00089 end->setCol(endCol); 00090 00091 return true; 00092 } 00093 00094 int KateCodeFoldingNode::cmpPos(KateCodeFoldingTree *tree, uint line,uint col) { 00095 KateTextCursor cur(line,col); 00096 KateTextCursor start,end; 00097 kdDebug(13000)<<"KateCodeFoldingNode::cmpPos (1)"<<endl; 00098 bool startValid=getBegin(tree, &start); 00099 kdDebug(13000)<<"KateCodeFoldingNode::cmpPos (2)"<<endl; 00100 bool endValid=getEnd(tree, &end); 00101 kdDebug(13000)<<"KateCodeFoldingNode::cmpPos (3)"<<endl; 00102 if ((!endValid) && startValid) { 00103 return ((start>cur)?-1:0); 00104 } 00105 if ((!startValid) && endValid) { 00106 return ((cur>end)?1:0); 00107 } 00108 //here both have to be valid, both invalid must not happen 00109 Q_ASSERT(startValid && endValid); 00110 return ( (cur<start)?(-1):( (cur>end) ? 1:0)); 00111 } 00112 00113 void KateCodeFoldingNode::insertChild (uint index, KateCodeFoldingNode *node) 00114 { 00115 uint s = m_children.size (); 00116 00117 if (index > s) 00118 return; 00119 00120 m_children.resize (++s); 00121 00122 for (uint i=s-1; i > index; --i) 00123 m_children[i] = m_children[i-1]; 00124 00125 m_children[index] = node; 00126 } 00127 00128 KateCodeFoldingNode *KateCodeFoldingNode::takeChild (uint index) 00129 { 00130 uint s = m_children.size (); 00131 00132 if (index >= s) 00133 return 0; 00134 00135 KateCodeFoldingNode *n = m_children[index]; 00136 00137 for (uint i=index; (i+1) < s; ++i) 00138 m_children[i] = m_children[i+1]; 00139 00140 m_children.resize (s-1); 00141 00142 return n; 00143 } 00144 00145 void KateCodeFoldingNode::clearChildren () 00146 { 00147 for (uint i=0; i < m_children.size(); ++i) 00148 delete m_children[i]; 00149 00150 m_children.resize (0); 00151 } 00152 00153 KateCodeFoldingTree::KateCodeFoldingTree(KateBuffer *buffer): TQObject(buffer), m_buffer (buffer) 00154 { 00155 clear(); 00156 } 00157 00158 void KateCodeFoldingTree::fixRoot(int endLRel) 00159 { 00160 m_root.endLineRel = endLRel; 00161 } 00162 00163 void KateCodeFoldingTree::clear() 00164 { 00165 m_root.clearChildren(); 00166 00167 // initialize the root "special" node 00168 m_root.startLineValid=true; 00169 m_root.endLineValid=true; // temporary, should be false; 00170 m_root.endLineRel=1; // temporary; 00171 00172 hiddenLinesCountCacheValid=false; 00173 lineMapping.setAutoDelete(true); 00174 hiddenLines.clear(); 00175 lineMapping.clear(); 00176 nodesForLine.clear(); 00177 markedForDeleting.clear(); 00178 dontIgnoreUnchangedLines.clear(); 00179 } 00180 00181 KateCodeFoldingTree::~KateCodeFoldingTree() 00182 { 00183 } 00184 00185 bool KateCodeFoldingTree::isTopLevel(unsigned int line) 00186 { 00187 if (m_root.noChildren()) 00188 return true; // no childs 00189 00190 // look if a given lines belongs to a sub node 00191 for ( uint i=0; i < m_root.childCount(); ++i ) 00192 { 00193 KateCodeFoldingNode *node = m_root.child(i); 00194 00195 if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel)) 00196 return false; // the line is within the range of a subnode -> return toplevel=false 00197 } 00198 00199 return true; // the root node is the only node containing the given line, return toplevel=true 00200 } 00201 00202 void KateCodeFoldingTree::getLineInfo(KateLineInfo *info, unsigned int line) 00203 { 00204 // Initialze the returned structure, this will also be returned if the root node has no child nodes 00205 // or the line is not within a childnode's range. 00206 info->topLevel = true; 00207 info->startsVisibleBlock = false; 00208 info->startsInVisibleBlock = false; 00209 info->endsBlock = false; 00210 info->invalidBlockEnd = false; 00211 00212 if (m_root.noChildren()) 00213 return; 00214 00215 //let's look for some information 00216 for ( uint i=0; i < m_root.childCount(); ++i ) 00217 { 00218 KateCodeFoldingNode *node = m_root.child(i); 00219 00220 if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel)) // we found a node, which contains the given line -> do a complete lookup 00221 { 00222 info->topLevel = false; //we are definitly not toplevel 00223 findAllNodesOpenedOrClosedAt(line); //lookup all nodes, which start or and at the given line 00224 00225 for ( KateCodeFoldingNode *node = nodesForLine.first(); node; node = nodesForLine.next() ) 00226 { 00227 uint startLine = getStartLine(node); 00228 00229 // type<0 means, that a region has been closed, but not opened 00230 // eg. parantheses missmatch 00231 if (node->type < 0) 00232 info->invalidBlockEnd=true; 00233 else 00234 { 00235 if (startLine != line) // does the region we look at not start at the given line 00236 info->endsBlock = true; // than it has to be an ending 00237 else 00238 { 00239 // The line starts a new region, now determine, if it's a visible or a hidden region 00240 if (node->visible) 00241 info->startsVisibleBlock=true; 00242 else 00243 info->startsInVisibleBlock=true; 00244 } 00245 } 00246 } 00247 00248 return; 00249 } 00250 } 00251 00252 return; 00253 } 00254 00255 00256 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLine(unsigned int line) 00257 { 00258 if (m_root.noChildren()) // does we have child list + nodes ? 00259 return &m_root; 00260 00261 // lets look, if given line is within a subnode range, and then return the deepest one. 00262 for ( uint i=0; i < m_root.childCount(); ++i ) 00263 { 00264 KateCodeFoldingNode *node = m_root.child(i); 00265 00266 if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel)) 00267 { 00268 // a region surounds the line, look in the next deeper hierarchy step 00269 return findNodeForLineDescending(node,line,0); 00270 } 00271 } 00272 00273 return &m_root; 00274 } 00275 00276 00277 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLineDescending ( KateCodeFoldingNode *node, 00278 unsigned int line, unsigned int offset, bool oneStepOnly ) 00279 { 00280 if (node->noChildren()) 00281 return node; 00282 00283 // calculate the offset, between a subnodes real start line and its relative start 00284 offset += node->startLineRel; 00285 00286 for ( uint i=0; i < node->childCount(); ++i ) 00287 { 00288 KateCodeFoldingNode *subNode = node->child(i); 00289 00290 if ((subNode->startLineRel+offset<=line) && (line<=subNode->endLineRel+subNode->startLineRel+offset)) //warning fix me for invalid ends 00291 { 00292 // a subnode contains the line. 00293 // if oneStepOnly is true, we don't want to search for the deepest node, just return the found one 00294 00295 if (oneStepOnly) 00296 return subNode; 00297 else 00298 return findNodeForLineDescending (subNode,line,offset); // look into the next deeper hierarchy step 00299 } 00300 } 00301 00302 return node; // the current node has no sub nodes, or the line couldn'te be found within a subregion 00303 } 00304 00305 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForPosition(unsigned int line, unsigned int column) 00306 { 00307 KateCodeFoldingNode *node=findNodeForLine(line); 00308 00309 if (node==&m_root) return &m_root; 00310 00311 kdDebug(13000)<<"initial cmpPos"<<endl; 00312 00313 KateCodeFoldingNode *tmp; 00314 int leq=node->cmpPos(this, line,column); 00315 while (true) { 00316 switch (leq) { 00317 case 0: { 00318 if (node->noChildren()) 00319 return node; 00320 else 00321 { 00322 tmp=node; 00323 for ( uint i=0; i < node->childCount(); ++i ) 00324 { 00325 KateCodeFoldingNode *subNode = node->child(i); 00326 kdDebug(13000)<<"cmdPos(case0):calling"<<endl; 00327 leq=subNode->cmpPos(this, line,column); 00328 kdDebug(13000)<<"cmdPos(case0):returned"<<endl; 00329 if (leq==0) { 00330 tmp=subNode; 00331 break; 00332 } else if (leq==-1) break; 00333 } 00334 if (tmp!=node) node=tmp; else return node; 00335 } 00336 break; 00337 } 00338 //this could be optimized a littlebit 00339 case -1: 00340 case 1: { 00341 if (!(node->parentNode)) return &m_root; 00342 kdDebug(13000)<<"current node type"<<node->type<<endl; 00343 node=node->parentNode; 00344 kdDebug(13000)<<"cmdPos(case-1/1):calling:"<<node<<endl; 00345 leq=node->cmpPos(this, line,column); 00346 kdDebug(13000)<<"cmdPos(case-1/1):returned"<<endl; 00347 break; 00348 } 00349 } 00350 00351 } 00352 Q_ASSERT(false); 00353 return &m_root; 00354 } 00355 00356 void KateCodeFoldingTree::debugDump() 00357 { 00358 //dump all nodes for debugging 00359 kdDebug(13000)<<"The parsed region/block tree for code folding"<<endl; 00360 dumpNode(&m_root, ""); 00361 } 00362 00363 void KateCodeFoldingTree::dumpNode(KateCodeFoldingNode *node, const TQString &prefix) 00364 { 00365 //output node properties 00366 kdDebug(13000)<<prefix<<TQString(TQString("Type: %1, startLineValid %2, startLineRel %3, endLineValid %4, endLineRel %5, visible %6"). 00367 arg(node->type).arg(node->startLineValid).arg(node->startLineRel).arg(node->endLineValid). 00368 arg(node->endLineRel).arg(node->visible))<<endl; 00369 00370 //output child node properties recursive 00371 if (node->noChildren()) 00372 return; 00373 00374 TQString newprefix(prefix + " "); 00375 for ( uint i=0; i < node->childCount(); ++i ) 00376 dumpNode (node->child(i),newprefix); 00377 } 00378 00379 /* 00380 That's one of the most important functions ;) 00381 */ 00382 void KateCodeFoldingTree::updateLine(unsigned int line, 00383 TQMemArray<uint> *regionChanges, bool *updated,bool changed,bool colsChanged) 00384 { 00385 if ( (!changed) || colsChanged) 00386 { 00387 if (dontIgnoreUnchangedLines.isEmpty()) 00388 return; 00389 00390 if (dontIgnoreUnchangedLines[line]) 00391 dontIgnoreUnchangedLines.remove(line); 00392 else 00393 return; 00394 } 00395 00396 something_changed = false; 00397 00398 findAndMarkAllNodesforRemovalOpenedOrClosedAt(line); 00399 00400 if (regionChanges->isEmpty()) 00401 { 00402 // KateCodeFoldingNode *node=findNodeForLine(line); 00403 // if (node->type!=0) 00404 // if (getStartLine(node)+node->endLineRel==line) removeEnding(node,line); 00405 } 00406 else 00407 { 00408 for (unsigned int i=0;i<regionChanges->size() / 4;i++) 00409 { 00410 signed char tmp=(*regionChanges)[regionChanges->size()-2-i*2]; 00411 uint tmppos=(*regionChanges)[regionChanges->size()-1-i*2]; 00412 (*regionChanges)[regionChanges->size()-2-i*2]=(*regionChanges)[i*2]; 00413 (*regionChanges)[regionChanges->size()-1-i*2]=(*regionChanges)[i*2+1]; 00414 (*regionChanges)[i*2]=tmp; 00415 (*regionChanges)[i*2+1]=tmppos; 00416 } 00417 00418 00419 signed char data= (*regionChanges)[regionChanges->size()-2]; 00420 uint charPos=(*regionChanges)[regionChanges->size()-1]; 00421 regionChanges->resize (regionChanges->size()-2); 00422 00423 int insertPos=-1; 00424 KateCodeFoldingNode *node = findNodeForLine(line); 00425 00426 if (data<0) 00427 { 00428 // if (insertPos==-1) 00429 { 00430 unsigned int tmpLine=line-getStartLine(node); 00431 00432 for ( uint i=0; i < node->childCount(); ++i ) 00433 { 00434 if (node->child(i)->startLineRel >= tmpLine) 00435 { 00436 insertPos=i; 00437 break; 00438 } 00439 } 00440 } 00441 } 00442 else 00443 { 00444 for (; (node->parentNode) && (getStartLine(node->parentNode)==line) && (node->parentNode->type!=0); node=node->parentNode); 00445 00446 if ((getStartLine(node)==line) && (node->type!=0)) 00447 { 00448 insertPos=node->parentNode->findChild(node); 00449 node = node->parentNode; 00450 } 00451 else 00452 { 00453 for ( uint i=0; i < node->childCount(); ++i ) 00454 { 00455 if (getStartLine(node->child(i))>=line) 00456 { 00457 insertPos=i; 00458 break; 00459 } 00460 } 00461 } 00462 } 00463 00464 do 00465 { 00466 if (data<0) 00467 { 00468 if (correctEndings(data,node,line,charPos,insertPos)) 00469 { 00470 insertPos=node->parentNode->findChild(node)+1; 00471 node=node->parentNode; 00472 } 00473 else 00474 { 00475 if (insertPos!=-1) insertPos++; 00476 } 00477 } 00478 else 00479 { 00480 int startLine=getStartLine(node); 00481 if ((insertPos==-1) || (insertPos>=(int)node->childCount())) 00482 { 00483 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine); 00484 something_changed = true; 00485 node->appendChild(newNode); 00486 addOpening(newNode, data, regionChanges, line,charPos); 00487 insertPos = node->findChild(newNode)+1; 00488 } 00489 else 00490 { 00491 if (node->child(insertPos)->startLineRel == line-startLine) 00492 { 00493 addOpening(node->child(insertPos), data, regionChanges, line,charPos); 00494 insertPos++; 00495 } 00496 else 00497 { 00498 // kdDebug(13000)<<"ADDING NODE "<<endl; 00499 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine); 00500 something_changed = true; 00501 node->insertChild(insertPos, newNode); 00502 addOpening(newNode, data, regionChanges, line,charPos); 00503 insertPos++; 00504 } 00505 } 00506 } 00507 00508 if (regionChanges->isEmpty()) 00509 data = 0; 00510 else 00511 { 00512 data = (*regionChanges)[regionChanges->size()-2]; 00513 charPos=(*regionChanges)[regionChanges->size()-1]; 00514 regionChanges->resize (regionChanges->size()-2); 00515 } 00516 } while (data!=0); 00517 } 00518 00519 cleanupUnneededNodes(line); 00520 // if (something_changed) emit regionBeginEndAddedRemoved(line); 00521 (*updated) = something_changed; 00522 } 00523 00524 00525 bool KateCodeFoldingTree::removeOpening(KateCodeFoldingNode *node,unsigned int line) 00526 { 00527 signed char type; 00528 if ((type=node->type) == 0) 00529 { 00530 dontDeleteOpening(node); 00531 dontDeleteEnding(node); 00532 return false; 00533 } 00534 00535 if (!node->visible) 00536 { 00537 toggleRegionVisibility(getStartLine(node)); 00538 } 00539 00540 KateCodeFoldingNode *parent = node->parentNode; 00541 int mypos = parent->findChild(node); 00542 00543 if (mypos > -1) 00544 { 00545 //move childnodes() up 00546 for(; node->childCount()>0 ;) 00547 { 00548 KateCodeFoldingNode *tmp; 00549 parent->insertChild(mypos, tmp=node->takeChild(0)); 00550 tmp->parentNode = parent; 00551 tmp->startLineRel += node->startLineRel; 00552 mypos++; 00553 } 00554 00555 // remove the node 00556 //mypos = parent->findChild(node); 00557 bool endLineValid = node->endLineValid; 00558 int endLineRel = node->endLineRel; 00559 uint endCol=node->endCol; 00560 00561 // removes + deletes 00562 KateCodeFoldingNode *child = parent->takeChild(mypos); 00563 markedForDeleting.removeRef(child); 00564 delete child; 00565 00566 if ((type>0) && (endLineValid)) 00567 correctEndings(-type, parent, line+endLineRel/*+1*/,endCol, mypos); // why the hell did I add a +1 here ? 00568 } 00569 00570 return true; 00571 } 00572 00573 bool KateCodeFoldingTree::removeEnding(KateCodeFoldingNode *node,unsigned int /* line */) 00574 { 00575 KateCodeFoldingNode *parent = node->parentNode; 00576 00577 if (!parent) 00578 return false; 00579 00580 if (node->type == 0) 00581 return false; 00582 00583 if (node->type < 0) 00584 { 00585 // removes + deletes 00586 int i = parent->findChild (node); 00587 if (i >= 0) 00588 { 00589 KateCodeFoldingNode *child = parent->takeChild(i); 00590 markedForDeleting.removeRef(child); 00591 delete child; 00592 } 00593 00594 return true; 00595 } 00596 00597 int mypos = parent->findChild(node); 00598 int count = parent->childCount(); 00599 00600 for (int i=mypos+1; i<count; i++) 00601 { 00602 if (parent->child(i)->type == -node->type) 00603 { 00604 node->endLineValid = true; 00605 node->endLineRel = parent->child(i)->startLineRel - node->startLineRel; 00606 00607 KateCodeFoldingNode *child = parent->takeChild(i); 00608 markedForDeleting.removeRef(child); 00609 delete child; 00610 00611 count = i-mypos-1; 00612 if (count > 0) 00613 { 00614 for (int i=0; i<count; i++) 00615 { 00616 KateCodeFoldingNode *tmp = parent->takeChild(mypos+1); 00617 tmp->startLineRel -= node->startLineRel; 00618 tmp->parentNode = node; //should help 16.04.2002 00619 node->appendChild(tmp); 00620 } 00621 } 00622 return false; 00623 } 00624 } 00625 00626 if ( (parent->type == node->type) || /*temporary fix */ (!parent->parentNode)) 00627 { 00628 for (int i=mypos+1; i<(int)parent->childCount(); i++) 00629 { 00630 KateCodeFoldingNode *tmp = parent->takeChild(mypos+1); 00631 tmp->startLineRel -= node->startLineRel; 00632 tmp->parentNode = node; // SHOULD HELP 16.04.2002 00633 node->appendChild(tmp); 00634 } 00635 00636 // this should fix the bug of wrongly closed nodes 00637 if (!parent->parentNode) 00638 node->endLineValid=false; 00639 else 00640 node->endLineValid = parent->endLineValid; 00641 00642 node->endLineRel = parent->endLineRel-node->startLineRel; 00643 00644 if (node->endLineValid) 00645 return removeEnding(parent, getStartLine(parent)+parent->endLineRel); 00646 00647 return false; 00648 } 00649 00650 node->endLineValid = false; 00651 node->endLineRel = parent->endLineRel - node->startLineRel; 00652 00653 return false; 00654 } 00655 00656 00657 bool KateCodeFoldingTree::correctEndings(signed char data, KateCodeFoldingNode *node,unsigned int line,unsigned int endCol,int insertPos) 00658 { 00659 // if (node->type==0) {kdError()<<"correct Ending should never be called with the root node"<<endl; return true;} 00660 uint startLine = getStartLine(node); 00661 if (data != -node->type) 00662 { 00663 #if JW_DEBUG 00664 kdDebug(13000)<<"data!=-node->type (correctEndings)"<<endl; 00665 #endif 00666 //invalid close -> add to unopend list 00667 dontDeleteEnding(node); 00668 if (data == node->type) { 00669 node->endCol=endCol; 00670 return false; 00671 } 00672 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine); 00673 something_changed = true; 00674 newNode->startLineValid = false; 00675 newNode->endLineValid = true; 00676 newNode->endLineRel = 0; 00677 newNode->endCol=endCol; 00678 00679 if ((insertPos==-1) || (insertPos==(int)node->childCount())) 00680 node->appendChild(newNode); 00681 else 00682 node->insertChild(insertPos,newNode); 00683 00684 // find correct position 00685 return false; 00686 } 00687 else 00688 { 00689 something_changed = true; 00690 dontDeleteEnding(node); 00691 00692 // valid closing region 00693 if (!node->endLineValid) 00694 { 00695 node->endLineValid = true; 00696 node->endLineRel = line - startLine; 00697 node->endCol=endCol; 00698 //moving 00699 00700 moveSubNodesUp(node); 00701 } 00702 else 00703 { 00704 #if JW_DEBUG 00705 kdDebug(13000)<<"Closing a node which had already a valid end"<<endl; 00706 #endif 00707 // block has already an ending 00708 if (startLine+node->endLineRel == line) 00709 { 00710 node->endCol=endCol; 00711 // we won, just skip 00712 #if JW_DEBUG 00713 kdDebug(13000)<< "We won, just skipping (correctEndings)"<<endl; 00714 #endif 00715 } 00716 else 00717 { 00718 int bakEndLine = node->endLineRel+startLine; 00719 uint bakEndCol = node->endCol; 00720 node->endLineRel = line-startLine; 00721 node->endCol=endCol; 00722 00723 #if JW_DEBUG 00724 kdDebug(13000)<< "reclosed node had childnodes()"<<endl; 00725 kdDebug(13000)<<"It could be, that childnodes() need to be moved up"<<endl; 00726 #endif 00727 moveSubNodesUp(node); 00728 00729 if (node->parentNode) 00730 { 00731 correctEndings(data,node->parentNode,bakEndLine, bakEndCol,node->parentNode->findChild(node)+1); // ???? 00732 } 00733 else 00734 { 00735 //add to unopened list (bakEndLine) 00736 } 00737 } 00738 } 00739 } 00740 return true; 00741 } 00742 00743 void KateCodeFoldingTree::moveSubNodesUp(KateCodeFoldingNode *node) 00744 { 00745 int mypos = node->parentNode->findChild(node); 00746 int removepos=-1; 00747 int count = node->childCount(); 00748 for (int i=0; i<count; i++) 00749 if (node->child(i)->startLineRel >= node->endLineRel) 00750 { 00751 removepos=i; 00752 break; 00753 } 00754 #if JW_DEBUG 00755 kdDebug(13000)<<TQString("remove pos: %1").arg(removepos)<<endl; 00756 #endif 00757 if (removepos>-1) 00758 { 00759 #if JW_DEBUG 00760 kdDebug(13000)<<"Children need to be moved"<<endl; 00761 #endif 00762 KateCodeFoldingNode *moveNode; 00763 if (mypos == (int)node->parentNode->childCount()-1) 00764 { 00765 while (removepos<(int)node->childCount()) 00766 { 00767 node->parentNode->appendChild(moveNode=node->takeChild(removepos)); 00768 moveNode->parentNode = node->parentNode; 00769 moveNode->startLineRel += node->startLineRel; 00770 } 00771 } 00772 else 00773 { 00774 int insertPos=mypos; 00775 while (removepos < (int)node->childCount()) 00776 { 00777 insertPos++; 00778 node->parentNode->insertChild(insertPos, moveNode=node->takeChild(removepos)); 00779 moveNode->parentNode = node->parentNode; // That should solve a crash 00780 moveNode->startLineRel += node->startLineRel; 00781 } 00782 } 00783 } 00784 00785 } 00786 00787 00788 00789 void KateCodeFoldingTree::addOpening(KateCodeFoldingNode *node,signed char nType, TQMemArray<uint>* list,unsigned int line,unsigned int charPos) 00790 { 00791 uint startLine = getStartLine(node); 00792 if ((startLine==line) && (node->type!=0)) 00793 { 00794 #if JW_DEBUG 00795 kdDebug(13000)<<"startLine equals line"<<endl; 00796 #endif 00797 if (nType == node->type) 00798 { 00799 #if JW_DEBUG 00800 kdDebug(13000)<<"Node exists"<<endl; 00801 #endif 00802 node->deleteOpening = false; 00803 node->startCol=charPos; 00804 KateCodeFoldingNode *parent = node->parentNode; 00805 00806 if (!node->endLineValid) 00807 { 00808 int current = parent->findChild(node); 00809 int count = parent->childCount()-(current+1); 00810 node->endLineRel = parent->endLineRel - node->startLineRel; 00811 00812 // EXPERIMENTAL TEST BEGIN 00813 // move this afte the test for unopened, but closed regions within the parent node, or if there are no siblings, bubble up 00814 if (parent) 00815 if (parent->type == node->type) 00816 { 00817 if (parent->endLineValid) 00818 { 00819 removeEnding(parent, line); 00820 node->endLineValid = true; 00821 } 00822 } 00823 00824 // EXPERIMENTAL TEST BEGIN 00825 00826 if (current != (int)parent->childCount()-1) 00827 { 00828 //search for an unopened but closed region, even if the parent is of the same type 00829 #ifdef __GNUC__ 00830 #warning "FIXME: why does this seem to work?" 00831 #endif 00832 // if (node->type != parent->type) 00833 { 00834 for (int i=current+1; i<(int)parent->childCount(); i++) 00835 { 00836 if (parent->child(i)->type == -node->type) 00837 { 00838 count = (i-current-1); 00839 node->endLineValid = true; 00840 node->endLineRel = getStartLine(parent->child(i))-line; 00841 node->endCol = parent->child(i)->endCol; 00842 KateCodeFoldingNode *child = parent->takeChild(i); 00843 markedForDeleting.removeRef( child ); 00844 delete child; 00845 break; 00846 } 00847 } 00848 } 00849 // else 00850 // { 00851 // parent->endLineValid = false; 00852 // parent->endLineRel = 20000; 00853 // } 00854 00855 if (count>0) 00856 { 00857 for (int i=0;i<count;i++) 00858 { 00859 KateCodeFoldingNode *tmp; 00860 node->appendChild(tmp=parent->takeChild(current+1)); 00861 tmp->startLineRel -= node->startLineRel; 00862 tmp->parentNode = node; 00863 } 00864 } 00865 } 00866 00867 } 00868 00869 addOpening_further_iterations(node, nType, list, line, 0, startLine,node->startCol); 00870 00871 } //else ohoh, much work to do same line, but other region type 00872 } 00873 else 00874 { // create a new region 00875 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,nType,line-startLine); 00876 something_changed = true; 00877 00878 int insert_position=-1; 00879 for (int i=0; i<(int)node->childCount(); i++) 00880 { 00881 if (startLine+node->child(i)->startLineRel > line) 00882 { 00883 insert_position=i; 00884 break; 00885 } 00886 } 00887 00888 int current; 00889 if (insert_position==-1) 00890 { 00891 node->appendChild(newNode); 00892 current = node->childCount()-1; 00893 } 00894 else 00895 { 00896 node->insertChild(insert_position, newNode); 00897 current = insert_position; 00898 } 00899 00900 // if (node->type==newNode->type) 00901 // { 00902 // newNode->endLineValid=true; 00903 // node->endLineValid=false; 00904 // newNode->endLineRel=node->endLineRel-newNode->startLineRel; 00905 // node->endLineRel=20000; //FIXME 00906 00907 int count = node->childCount() - (current+1); 00908 newNode->endLineRel -= newNode->startLineRel; 00909 if (current != (int)node->childCount()-1) 00910 { 00911 if (node->type != newNode->type) 00912 { 00913 for (int i=current+1; i<(int)node->childCount(); i++) 00914 { 00915 if (node->child(i)->type == -newNode->type) 00916 { 00917 count = node->childCount() - i - 1; 00918 newNode->endLineValid = true; 00919 newNode->endLineRel = line - getStartLine(node->child(i)); 00920 KateCodeFoldingNode *child = node->takeChild(i); 00921 markedForDeleting.removeRef( child ); 00922 delete child; 00923 break; 00924 } 00925 } 00926 } 00927 else 00928 { 00929 node->endLineValid = false; 00930 node->endLineRel = 10000; 00931 } 00932 if (count > 0) 00933 { 00934 for (int i=0;i<count;i++) 00935 { 00936 KateCodeFoldingNode *tmp; 00937 newNode->appendChild(tmp=node->takeChild(current+1)); 00938 tmp->parentNode=newNode; 00939 } 00940 } 00941 // } 00942 } 00943 00944 addOpening(newNode, nType, list, line,charPos); 00945 00946 addOpening_further_iterations(node, node->type, list, line, current, startLine,node->startCol); 00947 } 00948 } 00949 00950 00951 void KateCodeFoldingTree::addOpening_further_iterations(KateCodeFoldingNode *node,signed char /* nType */, TQMemArray<uint>* 00952 list,unsigned int line,int current, unsigned int startLine,unsigned int charPos) 00953 { 00954 while (!(list->isEmpty())) 00955 { 00956 if (list->isEmpty()) 00957 return; 00958 else 00959 { 00960 signed char data = (*list)[list->size()-2]; 00961 uint charPos=(*list)[list->size()-1]; 00962 list->resize (list->size()-2); 00963 00964 if (data<0) 00965 { 00966 #if JW_DEBUG 00967 kdDebug(13000)<<"An ending was found"<<endl; 00968 #endif 00969 00970 if (correctEndings(data,node,line,charPos,-1)) 00971 return; // -1 ? 00972 00973 #if 0 00974 if(data == -nType) 00975 { 00976 if (node->endLineValid) 00977 { 00978 if (node->endLineRel+startLine==line) // We've won again 00979 { 00980 //handle next node; 00981 } 00982 else 00983 { // much moving 00984 node->endLineRel=line-startLine; 00985 node->endLineValid=true; 00986 } 00987 return; // next higher level should do the rest 00988 } 00989 else 00990 { 00991 node->endLineRel=line-startLine; 00992 node->endLineValid=true; 00993 //much moving 00994 } 00995 } //else add to unopened list 00996 #endif 00997 } 00998 else 00999 { 01000 bool needNew = true; 01001 if (current < (int)node->childCount()) 01002 { 01003 if (getStartLine(node->child(current)) == line) 01004 needNew=false; 01005 } 01006 if (needNew) 01007 { 01008 something_changed = true; 01009 KateCodeFoldingNode *newNode = new KateCodeFoldingNode(node, data, line-startLine); 01010 node->insertChild(current, newNode); //find the correct position later 01011 } 01012 01013 addOpening(node->child(current), data, list, line,charPos); 01014 current++; 01015 //lookup node or create subnode 01016 } 01017 } 01018 } // end while 01019 } 01020 01021 unsigned int KateCodeFoldingTree::getStartLine(KateCodeFoldingNode *node) 01022 { 01023 unsigned int lineStart=0; 01024 for (KateCodeFoldingNode *iter=node; iter->type != 0; iter=iter->parentNode) 01025 lineStart += iter->startLineRel; 01026 01027 return lineStart; 01028 } 01029 01030 01031 void KateCodeFoldingTree::lineHasBeenRemoved(unsigned int line) 01032 { 01033 lineMapping.clear(); 01034 dontIgnoreUnchangedLines.insert(line, &trueVal); 01035 dontIgnoreUnchangedLines.insert(line-1, &trueVal); 01036 dontIgnoreUnchangedLines.insert(line+1, &trueVal); 01037 hiddenLinesCountCacheValid = false; 01038 #if JW_DEBUG 01039 kdDebug(13000)<<TQString("KateCodeFoldingTree::lineHasBeenRemoved: %1").arg(line)<<endl; 01040 #endif 01041 01042 //line ++; 01043 findAndMarkAllNodesforRemovalOpenedOrClosedAt(line); //It's an ugly solution 01044 cleanupUnneededNodes(line); //It's an ugly solution 01045 01046 KateCodeFoldingNode *node = findNodeForLine(line); 01047 //????? if (node->endLineValid) 01048 { 01049 int startLine = getStartLine(node); 01050 if (startLine == (int)line) 01051 node->startLineRel--; 01052 else 01053 { 01054 if (node->endLineRel == 0) 01055 node->endLineValid = false; 01056 node->endLineRel--; 01057 } 01058 01059 int count = node->childCount(); 01060 for (int i=0; i<count; i++) 01061 { 01062 if (node->child(i)->startLineRel+startLine >= line) 01063 node->child(i)->startLineRel--; 01064 } 01065 } 01066 01067 if (node->parentNode) 01068 decrementBy1(node->parentNode, node); 01069 01070 for (TQValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it) 01071 { 01072 if ((*it).start > line) 01073 (*it).start--; 01074 else if ((*it).start+(*it).length > line) 01075 (*it).length--; 01076 } 01077 } 01078 01079 01080 void KateCodeFoldingTree::decrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after) 01081 { 01082 if (node->endLineRel == 0) 01083 node->endLineValid = false; 01084 node->endLineRel--; 01085 01086 for (uint i=node->findChild(after)+1; i < node->childCount(); ++i) 01087 node->child(i)->startLineRel--; 01088 01089 if (node->parentNode) 01090 decrementBy1(node->parentNode,node); 01091 } 01092 01093 01094 void KateCodeFoldingTree::lineHasBeenInserted(unsigned int line) 01095 { 01096 lineMapping.clear(); 01097 dontIgnoreUnchangedLines.insert(line, &trueVal); 01098 dontIgnoreUnchangedLines.insert(line-1, &trueVal); 01099 dontIgnoreUnchangedLines.insert(line+1, &trueVal); 01100 hiddenLinesCountCacheValid = false; 01101 //return; 01102 #if JW_DEBUG 01103 kdDebug(13000)<<TQString("KateCodeFoldingTree::lineHasBeenInserted: %1").arg(line)<<endl; 01104 #endif 01105 01106 // findAndMarkAllNodesforRemovalOpenedOrClosedAt(line); 01107 // cleanupUnneededNodes(line); 01108 01109 KateCodeFoldingNode *node = findNodeForLine(line); 01110 // ???????? if (node->endLineValid) 01111 { 01112 int startLine=getStartLine(node); 01113 if (node->type < 0) 01114 node->startLineRel++; 01115 else 01116 node->endLineRel++; 01117 01118 for (uint i=0; i < node->childCount(); ++i) 01119 { 01120 KateCodeFoldingNode *iter = node->child(i); 01121 01122 if (iter->startLineRel+startLine >= line) 01123 iter->startLineRel++; 01124 } 01125 } 01126 01127 if (node->parentNode) 01128 incrementBy1(node->parentNode, node); 01129 01130 for (TQValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it) 01131 { 01132 if ((*it).start > line) 01133 (*it).start++; 01134 else if ((*it).start+(*it).length > line) 01135 (*it).length++; 01136 } 01137 } 01138 01139 void KateCodeFoldingTree::incrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after) 01140 { 01141 node->endLineRel++; 01142 01143 for (uint i=node->findChild(after)+1; i < node->childCount(); ++i) 01144 node->child(i)->startLineRel++; 01145 01146 if (node->parentNode) 01147 incrementBy1(node->parentNode,node); 01148 } 01149 01150 01151 void KateCodeFoldingTree::findAndMarkAllNodesforRemovalOpenedOrClosedAt(unsigned int line) 01152 { 01153 #ifdef __GNUC__ 01154 #warning "FIXME: make this multiple region changes per line save"; 01155 #endif 01156 // return; 01157 markedForDeleting.clear(); 01158 KateCodeFoldingNode *node = findNodeForLine(line); 01159 if (node->type == 0) 01160 return; 01161 01162 addNodeToRemoveList(node, line); 01163 01164 while (((node->parentNode) && (node->parentNode->type!=0)) && (getStartLine(node->parentNode)==line)) 01165 { 01166 node = node->parentNode; 01167 addNodeToRemoveList(node, line); 01168 } 01169 #if JW_DEBUG 01170 kdDebug(13000)<<" added line to markedForDeleting list"<<endl; 01171 #endif 01172 } 01173 01174 01175 void KateCodeFoldingTree::addNodeToRemoveList(KateCodeFoldingNode *node,unsigned int line) 01176 { 01177 bool add=false; 01178 #ifdef __GNUC__ 01179 #warning "FIXME: make this multiple region changes per line save"; 01180 #endif 01181 unsigned int startLine=getStartLine(node); 01182 if ((startLine==line) && (node->startLineValid)) 01183 { 01184 add=true; 01185 node->deleteOpening = true; 01186 } 01187 if ((startLine+node->endLineRel==line) || ((node->endLineValid==false) && (node->deleteOpening))) 01188 { 01189 int myPos=node->parentNode->findChild(node); // this has to be implemented nicely 01190 if ((int)node->parentNode->childCount()>myPos+1) 01191 addNodeToRemoveList(node->parentNode->child(myPos+1),line); 01192 add=true; 01193 node->deleteEnding = true; 01194 } 01195 01196 if(add) 01197 markedForDeleting.append(node); 01198 01199 } 01200 01201 01202 void KateCodeFoldingTree::findAllNodesOpenedOrClosedAt(unsigned int line) 01203 { 01204 nodesForLine.clear(); 01205 KateCodeFoldingNode *node = findNodeForLine(line); 01206 if (node->type == 0) 01207 return; 01208 01209 unsigned int startLine = getStartLine(node); 01210 if (startLine == line) 01211 nodesForLine.append(node); 01212 else if ((startLine+node->endLineRel == line)) 01213 nodesForLine.append(node); 01214 01215 while (node->parentNode) 01216 { 01217 addNodeToFoundList(node->parentNode, line, node->parentNode->findChild(node)); 01218 node = node->parentNode; 01219 } 01220 #if JW_DEBUG 01221 kdDebug(13000)<<" added line to nodesForLine list"<<endl; 01222 #endif 01223 } 01224 01225 01226 void KateCodeFoldingTree::addNodeToFoundList(KateCodeFoldingNode *node,unsigned int line,int childpos) 01227 { 01228 unsigned int startLine = getStartLine(node); 01229 01230 if ((startLine==line) && (node->type!=0)) 01231 nodesForLine.append(node); 01232 else if ((startLine+node->endLineRel==line) && (node->type!=0)) 01233 nodesForLine.append(node); 01234 01235 for (int i=childpos+1; i<(int)node->childCount(); i++) 01236 { 01237 KateCodeFoldingNode *child = node->child(i); 01238 01239 if (startLine+child->startLineRel == line) 01240 { 01241 nodesForLine.append(child); 01242 addNodeToFoundList(child, line, 0); 01243 } 01244 else 01245 break; 01246 } 01247 } 01248 01249 01250 void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line) 01251 { 01252 #if JW_DEBUG 01253 kdDebug(13000)<<"void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line)"<<endl; 01254 #endif 01255 01256 // return; 01257 if (markedForDeleting.isEmpty()) 01258 return; 01259 01260 for (int i=0; i<(int)markedForDeleting.count(); i++) 01261 { 01262 KateCodeFoldingNode *node = markedForDeleting.at(i); 01263 if (node->deleteOpening) 01264 kdDebug(13000)<<"DELETE OPENING SET"<<endl; 01265 if (node->deleteEnding) 01266 kdDebug(13000)<<"DELETE ENDING SET"<<endl; 01267 01268 if ((node->deleteOpening) && (node->deleteEnding)) 01269 { 01270 #if JW_DEBUG 01271 kdDebug(13000)<<"Deleting complete node"<<endl; 01272 #endif 01273 if (node->endLineValid) // just delete it, it has been opened and closed on this line 01274 { 01275 int f = node->parentNode->findChild (node); 01276 01277 if (f >= 0) 01278 delete node->parentNode->takeChild(f); 01279 } 01280 else 01281 { 01282 removeOpening(node, line); 01283 // the node has subnodes which need to be moved up and this one has to be deleted 01284 } 01285 something_changed = true; 01286 } 01287 else 01288 { 01289 if ((node->deleteOpening) && (node->startLineValid)) 01290 { 01291 #if JW_DEBUG 01292 kdDebug(13000)<<"calling removeOpening"<<endl; 01293 #endif 01294 removeOpening(node, line); 01295 something_changed = true; 01296 } 01297 else 01298 { 01299 dontDeleteOpening(node); 01300 01301 if ((node->deleteEnding) && (node->endLineValid)) 01302 { 01303 dontDeleteEnding(node); 01304 removeEnding(node, line); 01305 something_changed = true; 01306 } 01307 else 01308 dontDeleteEnding(node); 01309 } 01310 } 01311 } 01312 } 01313 01314 void KateCodeFoldingTree::dontDeleteEnding(KateCodeFoldingNode* node) 01315 { 01316 node->deleteEnding = false; 01317 } 01318 01319 01320 void KateCodeFoldingTree::dontDeleteOpening(KateCodeFoldingNode* node) 01321 { 01322 node->deleteOpening = false; 01323 } 01324 01325 01326 void KateCodeFoldingTree::toggleRegionVisibility(unsigned int line) 01327 { 01328 // hl whole file 01329 m_buffer->line (m_buffer->count()-1); 01330 01331 lineMapping.clear(); 01332 hiddenLinesCountCacheValid = false; 01333 kdDebug(13000)<<TQString(TQString("KateCodeFoldingTree::toggleRegionVisibility() %1").arg(line))<<endl; 01334 01335 findAllNodesOpenedOrClosedAt(line); 01336 for (int i=0; i<(int)nodesForLine.count(); i++) 01337 { 01338 KateCodeFoldingNode *node=nodesForLine.at(i); 01339 if ( (!node->startLineValid) || (getStartLine(node) != line) ) 01340 { 01341 nodesForLine.remove(i); 01342 i--; 01343 } 01344 } 01345 01346 if (nodesForLine.isEmpty()) 01347 return; 01348 01349 nodesForLine.at(0)->visible = !nodesForLine.at(0)->visible; 01350 01351 if (!nodesForLine.at(0)->visible) 01352 addHiddenLineBlock(nodesForLine.at(0),line); 01353 else 01354 { 01355 for (TQValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end();++it) 01356 if ((*it).start == line+1) 01357 { 01358 hiddenLines.remove(it); 01359 break; 01360 } 01361 01362 updateHiddenSubNodes(nodesForLine.at(0)); 01363 } 01364 01365 emit regionVisibilityChangedAt(line); 01366 } 01367 01368 void KateCodeFoldingTree::updateHiddenSubNodes(KateCodeFoldingNode *node) 01369 { 01370 for (uint i=0; i < node->childCount(); ++i) 01371 { 01372 KateCodeFoldingNode *iter = node->child(i); 01373 01374 if (!iter->visible) 01375 addHiddenLineBlock(iter, getStartLine(iter)); 01376 else 01377 updateHiddenSubNodes(iter); 01378 } 01379 } 01380 01381 void KateCodeFoldingTree::addHiddenLineBlock(KateCodeFoldingNode *node,unsigned int line) 01382 { 01383 KateHiddenLineBlock data; 01384 data.start = line+1; 01385 data.length = node->endLineRel-(existsOpeningAtLineAfter(line+node->endLineRel,node)?1:0); // without -1; 01386 bool inserted = false; 01387 01388 for (TQValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it) 01389 { 01390 if (((*it).start>=data.start) && ((*it).start<=data.start+data.length-1)) // another hidden block starting at the within this block already exits -> adapt new block 01391 { 01392 // the existing block can't have lines behind the new one, because a newly hidden 01393 // block has to encapsulate already hidden ones 01394 it=hiddenLines.remove(it); 01395 --it; 01396 } 01397 else 01398 { 01399 if ((*it).start > line) 01400 { 01401 hiddenLines.insert(it, data); 01402 inserted = true; 01403 01404 break; 01405 } 01406 } 01407 } 01408 01409 if (!inserted) 01410 hiddenLines.append(data); 01411 } 01412 01413 bool KateCodeFoldingTree::existsOpeningAtLineAfter(unsigned int line, KateCodeFoldingNode *node) 01414 { 01415 for(KateCodeFoldingNode *tmp = node->parentNode; tmp; tmp=tmp->parentNode) 01416 { 01417 KateCodeFoldingNode *tmp2; 01418 unsigned int startLine=getStartLine(tmp); 01419 01420 if ((tmp2 = tmp->child(tmp->findChild(node) + 1)) 01421 && ((tmp2->startLineRel + startLine) == line)) 01422 return true; 01423 01424 if ((startLine + tmp->endLineRel) > line) 01425 return false; 01426 } 01427 01428 return false; 01429 } 01430 01431 01432 // 01433 // get the real line number for a virtual line 01434 // 01435 unsigned int KateCodeFoldingTree::getRealLine(unsigned int virtualLine) 01436 { 01437 // he, if nothing is hidden, why look at it ;) 01438 if (hiddenLines.isEmpty()) 01439 return virtualLine; 01440 01441 // kdDebug(13000)<<TQString("VirtualLine %1").arg(virtualLine)<<endl; 01442 01443 unsigned int *real=lineMapping[virtualLine]; 01444 if (real) 01445 return (*real); 01446 01447 unsigned int tmp = virtualLine; 01448 for (TQValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.begin();it!=hiddenLines.end();++it) 01449 { 01450 if ((*it).start<=virtualLine) 01451 virtualLine += (*it).length; 01452 else 01453 break; 01454 } 01455 01456 // kdDebug(13000)<<TQString("Real Line %1").arg(virtualLine)<<endl; 01457 01458 lineMapping.insert(tmp, new unsigned int(virtualLine)); 01459 return virtualLine; 01460 } 01461 01462 // 01463 // get the virtual line number for a real line 01464 // 01465 unsigned int KateCodeFoldingTree::getVirtualLine(unsigned int realLine) 01466 { 01467 // he, if nothing is hidden, why look at it ;) 01468 if (hiddenLines.isEmpty()) 01469 return realLine; 01470 01471 // kdDebug(13000)<<TQString("RealLine--> %1").arg(realLine)<<endl; 01472 01473 for (TQValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.fromLast(); it!=hiddenLines.end(); --it) 01474 { 01475 if ((*it).start <= realLine) 01476 realLine -= (*it).length; 01477 // else 01478 // break; 01479 } 01480 01481 // kdDebug(13000)<<TQString("-->virtual Line %1").arg(realLine)<<endl; 01482 01483 return realLine; 01484 } 01485 01486 // 01487 // get the number of hidden lines 01488 // 01489 unsigned int KateCodeFoldingTree::getHiddenLinesCount(unsigned int doclen) 01490 { 01491 // he, if nothing is hidden, why look at it ;) 01492 if (hiddenLines.isEmpty()) 01493 return 0; 01494 01495 if (hiddenLinesCountCacheValid) 01496 return hiddenLinesCountCache; 01497 01498 hiddenLinesCountCacheValid = true; 01499 hiddenLinesCountCache = 0; 01500 01501 for (TQValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it) 01502 { 01503 if ((*it).start+(*it).length<=doclen) 01504 hiddenLinesCountCache += (*it).length; 01505 else 01506 { 01507 hiddenLinesCountCache += ((*it).length- ((*it).length + (*it).start - doclen)); 01508 break; 01509 } 01510 } 01511 01512 return hiddenLinesCountCache; 01513 } 01514 01515 void KateCodeFoldingTree::collapseToplevelNodes() 01516 { 01517 // hl whole file 01518 m_buffer->line (m_buffer->count()-1); 01519 01520 if (m_root.noChildren ()) 01521 return; 01522 01523 for ( uint i=0; i < m_root.childCount(); ++i ) 01524 { 01525 KateCodeFoldingNode *node = m_root.child(i); 01526 01527 if (node->visible && node->startLineValid && node->endLineValid) 01528 { 01529 node->visible=false; 01530 lineMapping.clear(); 01531 hiddenLinesCountCacheValid = false; 01532 addHiddenLineBlock(node,node->startLineRel); 01533 emit regionVisibilityChangedAt(node->startLineRel); 01534 } 01535 } 01536 } 01537 01538 void KateCodeFoldingTree::expandToplevelNodes(int numLines) 01539 { 01540 // hl whole file 01541 m_buffer->line (m_buffer->count()-1); 01542 01543 KateLineInfo line; 01544 for (int i = 0; i < numLines; i++) { 01545 getLineInfo(&line, i); 01546 01547 if (line.startsInVisibleBlock) 01548 toggleRegionVisibility(i); 01549 } 01550 } 01551 01552 int KateCodeFoldingTree::collapseOne(int realLine) 01553 { 01554 // hl whole file 01555 m_buffer->line (m_buffer->count()-1); 01556 01557 KateLineInfo line; 01558 int unrelatedBlocks = 0; 01559 for (int i = realLine; i >= 0; i--) { 01560 getLineInfo(&line, i); 01561 01562 if (line.topLevel && !line.endsBlock) 01563 // optimisation 01564 break; 01565 01566 if (line.endsBlock && ( line.invalidBlockEnd ) && (i != realLine)) { 01567 unrelatedBlocks++; 01568 } 01569 01570 if (line.startsVisibleBlock) { 01571 unrelatedBlocks--; 01572 if (unrelatedBlocks == -1) { 01573 toggleRegionVisibility(i); 01574 return i; 01575 } 01576 } 01577 } 01578 return -1; 01579 } 01580 01581 void KateCodeFoldingTree::expandOne(int realLine, int numLines) 01582 { 01583 // hl whole file 01584 m_buffer->line (m_buffer->count()-1); 01585 01586 KateLineInfo line; 01587 int blockTrack = 0; 01588 for (int i = realLine; i >= 0; i--) { 01589 getLineInfo(&line, i); 01590 01591 if (line.topLevel) 01592 // done 01593 break; 01594 01595 if (line.startsInVisibleBlock && i != realLine) { 01596 if (blockTrack == 0) 01597 toggleRegionVisibility(i); 01598 01599 blockTrack--; 01600 } 01601 01602 if (line.endsBlock) 01603 blockTrack++; 01604 01605 if (blockTrack < 0) 01606 // too shallow 01607 break; 01608 } 01609 01610 blockTrack = 0; 01611 for (int i = realLine; i < numLines; i++) { 01612 getLineInfo(&line, i); 01613 01614 if (line.topLevel) 01615 // done 01616 break; 01617 01618 if (line.startsInVisibleBlock) { 01619 if (blockTrack == 0) 01620 toggleRegionVisibility(i); 01621 01622 blockTrack++; 01623 } 01624 01625 if (line.endsBlock) 01626 blockTrack--; 01627 01628 if (blockTrack < 0) 01629 // too shallow 01630 break; 01631 } 01632 } 01633 01634 void KateCodeFoldingTree::ensureVisible( uint line ) 01635 { 01636 // first have a look, if the line is really hidden 01637 bool found=false; 01638 for (TQValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.begin();it!=hiddenLines.end();++it) 01639 { 01640 if ( ((*it).start<=line) && ((*it).start+(*it).length>line) ) 01641 { 01642 found=true; 01643 break; 01644 } 01645 } 01646 01647 01648 if (!found) return; 01649 01650 kdDebug(13000)<<"line "<<line<<" is really hidden ->show block"<<endl; 01651 01652 // it looks like we really have to ensure visibility 01653 KateCodeFoldingNode *n = findNodeForLine( line ); 01654 do { 01655 if ( ! n->visible ) 01656 toggleRegionVisibility( getStartLine( n ) ); 01657 n = n->parentNode; 01658 } while( n ); 01659 01660 } 01661 01662 // kate: space-indent on; indent-width 2; replace-tabs on;