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