kate Library API Documentation

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., 59 Temple Place - Suite 330, 00016 Boston, MA 02111-1307, 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 <qstring.h> 00027 00028 #define JW_DEBUG 0 00029 00030 bool KateCodeFoldingTree::trueVal = true; 00031 00032 KateCodeFoldingNode::KateCodeFoldingNode() : 00033 parentNode(0), 00034 startLineRel(0), 00035 endLineRel(0), 00036 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): QObject(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 QString &prefix) 00364 { 00365 //output node properties 00366 kdDebug(13000)<<prefix<<QString("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 QString 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 QMemArray<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 delete parent->takeChild(mypos); 00563 00564 if ((type>0) && (endLineValid)) 00565 correctEndings(-type, parent, line+endLineRel/*+1*/,endCol, mypos); // why the hell did I add a +1 here ? 00566 } 00567 00568 return true; 00569 } 00570 00571 bool KateCodeFoldingTree::removeEnding(KateCodeFoldingNode *node,unsigned int /* line */) 00572 { 00573 KateCodeFoldingNode *parent = node->parentNode; 00574 00575 if (!parent) 00576 return false; 00577 00578 if (node->type == 0) 00579 return false; 00580 00581 if (node->type < 0) 00582 { 00583 // removes + deletes 00584 int i = parent->findChild (node); 00585 if (i >= 0) 00586 delete parent->takeChild (i); 00587 00588 return true; 00589 } 00590 00591 int mypos = parent->findChild(node); 00592 int count = parent->childCount(); 00593 00594 for (int i=mypos+1; i<count; i++) 00595 { 00596 if (parent->child(i)->type == -node->type) 00597 { 00598 node->endLineValid = true; 00599 node->endLineRel = parent->child(i)->startLineRel - node->startLineRel; 00600 00601 delete parent->takeChild(i); 00602 00603 count = i-mypos-1; 00604 if (count > 0) 00605 { 00606 for (int i=0; i<count; i++) 00607 { 00608 KateCodeFoldingNode *tmp = parent->takeChild(mypos+1); 00609 tmp->startLineRel -= node->startLineRel; 00610 tmp->parentNode = node; //should help 16.04.2002 00611 node->appendChild(tmp); 00612 } 00613 } 00614 return false; 00615 } 00616 } 00617 00618 if ( (parent->type == node->type) || /*temporary fix */ (!parent->parentNode)) 00619 { 00620 for (int i=mypos+1; i<(int)parent->childCount(); i++) 00621 { 00622 KateCodeFoldingNode *tmp = parent->takeChild(mypos+1); 00623 tmp->startLineRel -= node->startLineRel; 00624 tmp->parentNode = node; // SHOULD HELP 16.04.2002 00625 node->appendChild(tmp); 00626 } 00627 00628 // this should fix the bug of wrongly closed nodes 00629 if (!parent->parentNode) 00630 node->endLineValid=false; 00631 else 00632 node->endLineValid = parent->endLineValid; 00633 00634 node->endLineRel = parent->endLineRel-node->startLineRel; 00635 00636 if (node->endLineValid) 00637 return removeEnding(parent, getStartLine(parent)+parent->endLineRel); 00638 00639 return false; 00640 } 00641 00642 node->endLineValid = false; 00643 node->endLineRel = parent->endLineRel - node->startLineRel; 00644 00645 return false; 00646 } 00647 00648 00649 bool KateCodeFoldingTree::correctEndings(signed char data, KateCodeFoldingNode *node,unsigned int line,unsigned int endCol,int insertPos) 00650 { 00651 // if (node->type==0) {kdError()<<"correct Ending should never be called with the root node"<<endl; return true;} 00652 uint startLine = getStartLine(node); 00653 if (data != -node->type) 00654 { 00655 #if JW_DEBUG 00656 kdDebug(13000)<<"data!=-node->type (correctEndings)"<<endl; 00657 #endif 00658 //invalid close -> add to unopend list 00659 dontDeleteEnding(node); 00660 if (data == node->type) { 00661 node->endCol=endCol; 00662 return false; 00663 } 00664 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine); 00665 something_changed = true; 00666 newNode->startLineValid = false; 00667 newNode->endLineValid = true; 00668 newNode->endLineRel = 0; 00669 newNode->endCol=endCol; 00670 00671 if ((insertPos==-1) || (insertPos==(int)node->childCount())) 00672 node->appendChild(newNode); 00673 else 00674 node->insertChild(insertPos,newNode); 00675 00676 // find correct position 00677 return false; 00678 } 00679 else 00680 { 00681 something_changed = true; 00682 dontDeleteEnding(node); 00683 00684 // valid closing region 00685 if (!node->endLineValid) 00686 { 00687 node->endLineValid = true; 00688 node->endLineRel = line - startLine; 00689 node->endCol=endCol; 00690 //moving 00691 00692 moveSubNodesUp(node); 00693 } 00694 else 00695 { 00696 #if JW_DEBUG 00697 kdDebug(13000)<<"Closing a node which had already a valid end"<<endl; 00698 #endif 00699 // block has already an ending 00700 if (startLine+node->endLineRel == line) 00701 { 00702 node->endCol=endCol; 00703 // we won, just skip 00704 #if JW_DEBUG 00705 kdDebug(13000)<< "We won, just skipping (correctEndings)"<<endl; 00706 #endif 00707 } 00708 else 00709 { 00710 int bakEndLine = node->endLineRel+startLine; 00711 uint bakEndCol = node->endCol; 00712 node->endLineRel = line-startLine; 00713 node->endCol=endCol; 00714 00715 #if JW_DEBUG 00716 kdDebug(13000)<< "reclosed node had childnodes()"<<endl; 00717 kdDebug(13000)<<"It could be, that childnodes() need to be moved up"<<endl; 00718 #endif 00719 moveSubNodesUp(node); 00720 00721 if (node->parentNode) 00722 { 00723 correctEndings(data,node->parentNode,bakEndLine, bakEndCol,node->parentNode->findChild(node)+1); // ???? 00724 } 00725 else 00726 { 00727 //add to unopened list (bakEndLine) 00728 } 00729 } 00730 } 00731 } 00732 return true; 00733 } 00734 00735 void KateCodeFoldingTree::moveSubNodesUp(KateCodeFoldingNode *node) 00736 { 00737 int mypos = node->parentNode->findChild(node); 00738 int removepos=-1; 00739 int count = node->childCount(); 00740 for (int i=0; i<count; i++) 00741 if (node->child(i)->startLineRel >= node->endLineRel) 00742 { 00743 removepos=i; 00744 break; 00745 } 00746 #if JW_DEBUG 00747 kdDebug(13000)<<QString("remove pos: %1").arg(removepos)<<endl; 00748 #endif 00749 if (removepos>-1) 00750 { 00751 #if JW_DEBUG 00752 kdDebug(13000)<<"Children need to be moved"<<endl; 00753 #endif 00754 KateCodeFoldingNode *moveNode; 00755 if (mypos == (int)node->parentNode->childCount()-1) 00756 { 00757 while (removepos<(int)node->childCount()) 00758 { 00759 node->parentNode->appendChild(moveNode=node->takeChild(removepos)); 00760 moveNode->parentNode = node->parentNode; 00761 moveNode->startLineRel += node->startLineRel; 00762 } 00763 } 00764 else 00765 { 00766 int insertPos=mypos; 00767 while (removepos < (int)node->childCount()) 00768 { 00769 insertPos++; 00770 node->parentNode->insertChild(insertPos, moveNode=node->takeChild(removepos)); 00771 moveNode->parentNode = node->parentNode; // That should solve a crash 00772 moveNode->startLineRel += node->startLineRel; 00773 } 00774 } 00775 } 00776 00777 } 00778 00779 00780 00781 void KateCodeFoldingTree::addOpening(KateCodeFoldingNode *node,signed char nType, QMemArray<uint>* list,unsigned int line,unsigned int charPos) 00782 { 00783 uint startLine = getStartLine(node); 00784 if ((startLine==line) && (node->type!=0)) 00785 { 00786 #if JW_DEBUG 00787 kdDebug(13000)<<"startLine equals line"<<endl; 00788 #endif 00789 if (nType == node->type) 00790 { 00791 #if JW_DEBUG 00792 kdDebug(13000)<<"Node exists"<<endl; 00793 #endif 00794 node->deleteOpening = false; 00795 node->startCol=charPos; 00796 KateCodeFoldingNode *parent = node->parentNode; 00797 00798 if (!node->endLineValid) 00799 { 00800 int current = parent->findChild(node); 00801 int count = parent->childCount()-(current+1); 00802 node->endLineRel = parent->endLineRel - node->startLineRel; 00803 00804 // EXPERIMENTAL TEST BEGIN 00805 // move this afte the test for unopened, but closed regions within the parent node, or if there are no siblings, bubble up 00806 if (parent) 00807 if (parent->type == node->type) 00808 { 00809 if (parent->endLineValid) 00810 { 00811 removeEnding(parent, line); 00812 node->endLineValid = true; 00813 } 00814 } 00815 00816 // EXPERIMENTAL TEST BEGIN 00817 00818 if (current != (int)parent->childCount()-1) 00819 { 00820 //search for an unopened but closed region, even if the parent is of the same type 00821 #ifdef __GNUC__ 00822 #warning "FIXME: why does this seem to work?" 00823 #endif 00824 // if (node->type != parent->type) 00825 { 00826 for (int i=current+1; i<(int)parent->childCount(); i++) 00827 { 00828 if (parent->child(i)->type == -node->type) 00829 { 00830 count = (i-current-1); 00831 node->endLineValid = true; 00832 node->endLineRel = getStartLine(parent->child(i))-line; 00833 node->endCol = parent->child(i)->endCol; 00834 delete parent->takeChild(i); 00835 break; 00836 } 00837 } 00838 } 00839 // else 00840 // { 00841 // parent->endLineValid = false; 00842 // parent->endLineRel = 20000; 00843 // } 00844 00845 if (count>0) 00846 { 00847 for (int i=0;i<count;i++) 00848 { 00849 KateCodeFoldingNode *tmp; 00850 node->appendChild(tmp=parent->takeChild(current+1)); 00851 tmp->startLineRel -= node->startLineRel; 00852 tmp->parentNode = node; 00853 } 00854 } 00855 } 00856 00857 } 00858 00859 addOpening_further_iterations(node, nType, list, line, 0, startLine,node->startCol); 00860 00861 } //else ohoh, much work to do same line, but other region type 00862 } 00863 else 00864 { // create a new region 00865 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,nType,line-startLine); 00866 something_changed = true; 00867 00868 int insert_position=-1; 00869 for (int i=0; i<(int)node->childCount(); i++) 00870 { 00871 if (startLine+node->child(i)->startLineRel > line) 00872 { 00873 insert_position=i; 00874 break; 00875 } 00876 } 00877 00878 int current; 00879 if (insert_position==-1) 00880 { 00881 node->appendChild(newNode); 00882 current = node->childCount()-1; 00883 } 00884 else 00885 { 00886 node->insertChild(insert_position, newNode); 00887 current = insert_position; 00888 } 00889 00890 // if (node->type==newNode->type) 00891 // { 00892 // newNode->endLineValid=true; 00893 // node->endLineValid=false; 00894 // newNode->endLineRel=node->endLineRel-newNode->startLineRel; 00895 // node->endLineRel=20000; //FIXME 00896 00897 int count = node->childCount() - (current+1); 00898 newNode->endLineRel -= newNode->startLineRel; 00899 if (current != (int)node->childCount()-1) 00900 { 00901 if (node->type != newNode->type) 00902 { 00903 for (int i=current+1; i<(int)node->childCount(); i++) 00904 { 00905 if (node->child(i)->type == -newNode->type) 00906 { 00907 count = node->childCount() - i - 1; 00908 newNode->endLineValid = true; 00909 newNode->endLineRel = line - getStartLine(node->child(i)); 00910 delete node->takeChild(i); 00911 break; 00912 } 00913 } 00914 } 00915 else 00916 { 00917 node->endLineValid = false; 00918 node->endLineRel = 10000; 00919 } 00920 if (count > 0) 00921 { 00922 for (int i=0;i<count;i++) 00923 { 00924 KateCodeFoldingNode *tmp; 00925 newNode->appendChild(tmp=node->takeChild(current+1)); 00926 tmp->parentNode=newNode; 00927 } 00928 } 00929 // } 00930 } 00931 00932 addOpening(newNode, nType, list, line,charPos); 00933 00934 addOpening_further_iterations(node, node->type, list, line, current, startLine,node->startCol); 00935 } 00936 } 00937 00938 00939 void KateCodeFoldingTree::addOpening_further_iterations(KateCodeFoldingNode *node,signed char /* nType */, QMemArray<uint>* 00940 list,unsigned int line,int current, unsigned int startLine,unsigned int charPos) 00941 { 00942 while (!(list->isEmpty())) 00943 { 00944 if (list->isEmpty()) 00945 return; 00946 else 00947 { 00948 signed char data = (*list)[list->size()-2]; 00949 uint charPos=(*list)[list->size()-1]; 00950 list->resize (list->size()-2); 00951 00952 if (data<0) 00953 { 00954 #if JW_DEBUG 00955 kdDebug(13000)<<"An ending was found"<<endl; 00956 #endif 00957 00958 if (correctEndings(data,node,line,charPos,-1)) 00959 return; // -1 ? 00960 00961 #if 0 00962 if(data == -nType) 00963 { 00964 if (node->endLineValid) 00965 { 00966 if (node->endLineRel+startLine==line) // We've won again 00967 { 00968 //handle next node; 00969 } 00970 else 00971 { // much moving 00972 node->endLineRel=line-startLine; 00973 node->endLineValid=true; 00974 } 00975 return; // next higher level should do the rest 00976 } 00977 else 00978 { 00979 node->endLineRel=line-startLine; 00980 node->endLineValid=true; 00981 //much moving 00982 } 00983 } //else add to unopened list 00984 #endif 00985 } 00986 else 00987 { 00988 bool needNew = true; 00989 if (current < (int)node->childCount()) 00990 { 00991 if (getStartLine(node->child(current)) == line) 00992 needNew=false; 00993 } 00994 if (needNew) 00995 { 00996 something_changed = true; 00997 KateCodeFoldingNode *newNode = new KateCodeFoldingNode(node, data, line-startLine); 00998 node->insertChild(current, newNode); //find the correct position later 00999 } 01000 01001 addOpening(node->child(current), data, list, line,charPos); 01002 current++; 01003 //lookup node or create subnode 01004 } 01005 } 01006 } // end while 01007 } 01008 01009 unsigned int KateCodeFoldingTree::getStartLine(KateCodeFoldingNode *node) 01010 { 01011 unsigned int lineStart=0; 01012 for (KateCodeFoldingNode *iter=node; iter->type != 0; iter=iter->parentNode) 01013 lineStart += iter->startLineRel; 01014 01015 return lineStart; 01016 } 01017 01018 01019 void KateCodeFoldingTree::lineHasBeenRemoved(unsigned int line) 01020 { 01021 lineMapping.clear(); 01022 dontIgnoreUnchangedLines.insert(line, &trueVal); 01023 dontIgnoreUnchangedLines.insert(line-1, &trueVal); 01024 dontIgnoreUnchangedLines.insert(line+1, &trueVal); 01025 hiddenLinesCountCacheValid = false; 01026 #if JW_DEBUG 01027 kdDebug(13000)<<QString("KateCodeFoldingTree::lineHasBeenRemoved: %1").arg(line)<<endl; 01028 #endif 01029 01030 //line ++; 01031 findAndMarkAllNodesforRemovalOpenedOrClosedAt(line); //It's an ugly solution 01032 cleanupUnneededNodes(line); //It's an ugly solution 01033 01034 KateCodeFoldingNode *node = findNodeForLine(line); 01035 //????? if (node->endLineValid) 01036 { 01037 int startLine = getStartLine(node); 01038 if (startLine == (int)line) 01039 node->startLineRel--; 01040 else 01041 { 01042 if (node->endLineRel == 0) 01043 node->endLineValid = false; 01044 node->endLineRel--; 01045 } 01046 01047 int count = node->childCount(); 01048 for (int i=0; i<count; i++) 01049 { 01050 if (node->child(i)->startLineRel+startLine >= line) 01051 node->child(i)->startLineRel--; 01052 } 01053 } 01054 01055 if (node->parentNode) 01056 decrementBy1(node->parentNode, node); 01057 01058 for (QValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it) 01059 { 01060 if ((*it).start > line) 01061 (*it).start--; 01062 else if ((*it).start+(*it).length > line) 01063 (*it).length--; 01064 } 01065 } 01066 01067 01068 void KateCodeFoldingTree::decrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after) 01069 { 01070 if (node->endLineRel == 0) 01071 node->endLineValid = false; 01072 node->endLineRel--; 01073 01074 for (uint i=node->findChild(after)+1; i < node->childCount(); ++i) 01075 node->child(i)->startLineRel--; 01076 01077 if (node->parentNode) 01078 decrementBy1(node->parentNode,node); 01079 } 01080 01081 01082 void KateCodeFoldingTree::lineHasBeenInserted(unsigned int line) 01083 { 01084 lineMapping.clear(); 01085 dontIgnoreUnchangedLines.insert(line, &trueVal); 01086 dontIgnoreUnchangedLines.insert(line-1, &trueVal); 01087 dontIgnoreUnchangedLines.insert(line+1, &trueVal); 01088 hiddenLinesCountCacheValid = false; 01089 //return; 01090 #if JW_DEBUG 01091 kdDebug(13000)<<QString("KateCodeFoldingTree::lineHasBeenInserted: %1").arg(line)<<endl; 01092 #endif 01093 01094 // findAndMarkAllNodesforRemovalOpenedOrClosedAt(line); 01095 // cleanupUnneededNodes(line); 01096 01097 KateCodeFoldingNode *node = findNodeForLine(line); 01098 // ???????? if (node->endLineValid) 01099 { 01100 int startLine=getStartLine(node); 01101 if (node->type < 0) 01102 node->startLineRel++; 01103 else 01104 node->endLineRel++; 01105 01106 for (uint i=0; i < node->childCount(); ++i) 01107 { 01108 KateCodeFoldingNode *iter = node->child(i); 01109 01110 if (iter->startLineRel+startLine >= line) 01111 iter->startLineRel++; 01112 } 01113 } 01114 01115 if (node->parentNode) 01116 incrementBy1(node->parentNode, node); 01117 01118 for (QValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it) 01119 { 01120 if ((*it).start > line) 01121 (*it).start++; 01122 else if ((*it).start+(*it).length > line) 01123 (*it).length++; 01124 } 01125 } 01126 01127 void KateCodeFoldingTree::incrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after) 01128 { 01129 node->endLineRel++; 01130 01131 for (uint i=node->findChild(after)+1; i < node->childCount(); ++i) 01132 node->child(i)->startLineRel++; 01133 01134 if (node->parentNode) 01135 incrementBy1(node->parentNode,node); 01136 } 01137 01138 01139 void KateCodeFoldingTree::findAndMarkAllNodesforRemovalOpenedOrClosedAt(unsigned int line) 01140 { 01141 #ifdef __GNUC__ 01142 #warning "FIXME: make this multiple region changes per line save"; 01143 #endif 01144 // return; 01145 markedForDeleting.clear(); 01146 KateCodeFoldingNode *node = findNodeForLine(line); 01147 if (node->type == 0) 01148 return; 01149 01150 addNodeToRemoveList(node, line); 01151 01152 while (((node->parentNode) && (node->parentNode->type!=0)) && (getStartLine(node->parentNode)==line)) 01153 { 01154 node = node->parentNode; 01155 addNodeToRemoveList(node, line); 01156 } 01157 #if JW_DEBUG 01158 kdDebug(13000)<<" added line to markedForDeleting list"<<endl; 01159 #endif 01160 } 01161 01162 01163 void KateCodeFoldingTree::addNodeToRemoveList(KateCodeFoldingNode *node,unsigned int line) 01164 { 01165 bool add=false; 01166 #ifdef __GNUC__ 01167 #warning "FIXME: make this multiple region changes per line save"; 01168 #endif 01169 unsigned int startLine=getStartLine(node); 01170 if ((startLine==line) && (node->startLineValid)) 01171 { 01172 add=true; 01173 node->deleteOpening = true; 01174 } 01175 if ((startLine+node->endLineRel==line) || ((node->endLineValid==false) && (node->deleteOpening))) 01176 { 01177 int myPos=node->parentNode->findChild(node); // this has to be implemented nicely 01178 if ((int)node->parentNode->childCount()>myPos+1) 01179 addNodeToRemoveList(node->parentNode->child(myPos+1),line); 01180 add=true; 01181 node->deleteEnding = true; 01182 } 01183 01184 if(add) 01185 markedForDeleting.append(node); 01186 01187 } 01188 01189 01190 void KateCodeFoldingTree::findAllNodesOpenedOrClosedAt(unsigned int line) 01191 { 01192 nodesForLine.clear(); 01193 KateCodeFoldingNode *node = findNodeForLine(line); 01194 if (node->type == 0) 01195 return; 01196 01197 unsigned int startLine = getStartLine(node); 01198 if (startLine == line) 01199 nodesForLine.append(node); 01200 else if ((startLine+node->endLineRel == line)) 01201 nodesForLine.append(node); 01202 01203 while (node->parentNode) 01204 { 01205 addNodeToFoundList(node->parentNode, line, node->parentNode->findChild(node)); 01206 node = node->parentNode; 01207 } 01208 #if JW_DEBUG 01209 kdDebug(13000)<<" added line to nodesForLine list"<<endl; 01210 #endif 01211 } 01212 01213 01214 void KateCodeFoldingTree::addNodeToFoundList(KateCodeFoldingNode *node,unsigned int line,int childpos) 01215 { 01216 unsigned int startLine = getStartLine(node); 01217 01218 if ((startLine==line) && (node->type!=0)) 01219 nodesForLine.append(node); 01220 else if ((startLine+node->endLineRel==line) && (node->type!=0)) 01221 nodesForLine.append(node); 01222 01223 for (int i=childpos+1; i<(int)node->childCount(); i++) 01224 { 01225 KateCodeFoldingNode *child = node->child(i); 01226 01227 if (startLine+child->startLineRel == line) 01228 { 01229 nodesForLine.append(child); 01230 addNodeToFoundList(child, line, 0); 01231 } 01232 else 01233 break; 01234 } 01235 } 01236 01237 01238 void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line) 01239 { 01240 #if JW_DEBUG 01241 kdDebug(13000)<<"void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line)"<<endl; 01242 #endif 01243 01244 // return; 01245 if (markedForDeleting.isEmpty()) 01246 return; 01247 01248 for (int i=0; i<(int)markedForDeleting.count(); i++) 01249 { 01250 KateCodeFoldingNode *node = markedForDeleting.at(i); 01251 if (node->deleteOpening) 01252 kdDebug(13000)<<"DELETE OPENING SET"<<endl; 01253 if (node->deleteEnding) 01254 kdDebug(13000)<<"DELETE ENDING SET"<<endl; 01255 01256 if ((node->deleteOpening) && (node->deleteEnding)) 01257 { 01258 #if JW_DEBUG 01259 kdDebug(13000)<<"Deleting complete node"<<endl; 01260 #endif 01261 if (node->endLineValid) // just delete it, it has been opened and closed on this line 01262 { 01263 int f = node->parentNode->findChild (node); 01264 01265 if (f >= 0) 01266 delete node->parentNode->takeChild(f); 01267 } 01268 else 01269 { 01270 removeOpening(node, line); 01271 // the node has subnodes which need to be moved up and this one has to be deleted 01272 } 01273 something_changed = true; 01274 } 01275 else 01276 { 01277 if ((node->deleteOpening) && (node->startLineValid)) 01278 { 01279 #if JW_DEBUG 01280 kdDebug(13000)<<"calling removeOpening"<<endl; 01281 #endif 01282 removeOpening(node, line); 01283 something_changed = true; 01284 } 01285 else 01286 { 01287 dontDeleteOpening(node); 01288 01289 if ((node->deleteEnding) && (node->endLineValid)) 01290 { 01291 dontDeleteEnding(node); 01292 removeEnding(node, line); 01293 something_changed = true; 01294 } 01295 else 01296 dontDeleteEnding(node); 01297 } 01298 } 01299 } 01300 } 01301 01302 void KateCodeFoldingTree::dontDeleteEnding(KateCodeFoldingNode* node) 01303 { 01304 node->deleteEnding = false; 01305 } 01306 01307 01308 void KateCodeFoldingTree::dontDeleteOpening(KateCodeFoldingNode* node) 01309 { 01310 node->deleteOpening = false; 01311 } 01312 01313 01314 void KateCodeFoldingTree::toggleRegionVisibility(unsigned int line) 01315 { 01316 // hl whole file 01317 m_buffer->line (m_buffer->count()-1); 01318 01319 lineMapping.clear(); 01320 hiddenLinesCountCacheValid = false; 01321 kdDebug(13000)<<QString("KateCodeFoldingTree::toggleRegionVisibility() %1").arg(line)<<endl; 01322 01323 findAllNodesOpenedOrClosedAt(line); 01324 for (int i=0; i<(int)nodesForLine.count(); i++) 01325 { 01326 KateCodeFoldingNode *node=nodesForLine.at(i); 01327 if ( (!node->startLineValid) || (getStartLine(node) != line) ) 01328 { 01329 nodesForLine.remove(i); 01330 i--; 01331 } 01332 } 01333 01334 if (nodesForLine.isEmpty()) 01335 return; 01336 01337 nodesForLine.at(0)->visible = !nodesForLine.at(0)->visible; 01338 01339 if (!nodesForLine.at(0)->visible) 01340 addHiddenLineBlock(nodesForLine.at(0),line); 01341 else 01342 { 01343 for (QValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end();++it) 01344 if ((*it).start == line+1) 01345 { 01346 hiddenLines.remove(it); 01347 break; 01348 } 01349 01350 updateHiddenSubNodes(nodesForLine.at(0)); 01351 } 01352 01353 emit regionVisibilityChangedAt(line); 01354 } 01355 01356 void KateCodeFoldingTree::updateHiddenSubNodes(KateCodeFoldingNode *node) 01357 { 01358 for (uint i=0; i < node->childCount(); ++i) 01359 { 01360 KateCodeFoldingNode *iter = node->child(i); 01361 01362 if (!iter->visible) 01363 addHiddenLineBlock(iter, getStartLine(iter)); 01364 else 01365 updateHiddenSubNodes(iter); 01366 } 01367 } 01368 01369 void KateCodeFoldingTree::addHiddenLineBlock(KateCodeFoldingNode *node,unsigned int line) 01370 { 01371 KateHiddenLineBlock data; 01372 data.start = line+1; 01373 data.length = node->endLineRel-(existsOpeningAtLineAfter(line+node->endLineRel,node)?1:0); // without -1; 01374 bool inserted = false; 01375 01376 for (QValueList<KateHiddenLineBlock>::Iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it) 01377 { 01378 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 01379 { 01380 // the existing block can't have lines behind the new one, because a newly hidden 01381 // block has to encapsulate already hidden ones 01382 it=hiddenLines.remove(it); 01383 --it; 01384 } 01385 else 01386 { 01387 if ((*it).start > line) 01388 { 01389 hiddenLines.insert(it, data); 01390 inserted = true; 01391 01392 break; 01393 } 01394 } 01395 } 01396 01397 if (!inserted) 01398 hiddenLines.append(data); 01399 } 01400 01401 bool KateCodeFoldingTree::existsOpeningAtLineAfter(unsigned int line, KateCodeFoldingNode *node) 01402 { 01403 for(KateCodeFoldingNode *tmp = node->parentNode; tmp; tmp=tmp->parentNode) 01404 { 01405 KateCodeFoldingNode *tmp2; 01406 unsigned int startLine=getStartLine(tmp); 01407 01408 if ((tmp2 = tmp->child(tmp->findChild(node) + 1)) 01409 && ((tmp2->startLineRel + startLine) == line)) 01410 return true; 01411 01412 if ((startLine + tmp->endLineRel) > line) 01413 return false; 01414 } 01415 01416 return false; 01417 } 01418 01419 01420 // 01421 // get the real line number for a virtual line 01422 // 01423 unsigned int KateCodeFoldingTree::getRealLine(unsigned int virtualLine) 01424 { 01425 // he, if nothing is hidden, why look at it ;) 01426 if (hiddenLines.isEmpty()) 01427 return virtualLine; 01428 01429 // kdDebug(13000)<<QString("VirtualLine %1").arg(virtualLine)<<endl; 01430 01431 unsigned int *real=lineMapping[virtualLine]; 01432 if (real) 01433 return (*real); 01434 01435 unsigned int tmp = virtualLine; 01436 for (QValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.begin();it!=hiddenLines.end();++it) 01437 { 01438 if ((*it).start<=virtualLine) 01439 virtualLine += (*it).length; 01440 else 01441 break; 01442 } 01443 01444 // kdDebug(13000)<<QString("Real Line %1").arg(virtualLine)<<endl; 01445 01446 lineMapping.insert(tmp, new unsigned int(virtualLine)); 01447 return virtualLine; 01448 } 01449 01450 // 01451 // get the virtual line number for a real line 01452 // 01453 unsigned int KateCodeFoldingTree::getVirtualLine(unsigned int realLine) 01454 { 01455 // he, if nothing is hidden, why look at it ;) 01456 if (hiddenLines.isEmpty()) 01457 return realLine; 01458 01459 // kdDebug(13000)<<QString("RealLine--> %1").arg(realLine)<<endl; 01460 01461 for (QValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.fromLast(); it!=hiddenLines.end(); --it) 01462 { 01463 if ((*it).start <= realLine) 01464 realLine -= (*it).length; 01465 // else 01466 // break; 01467 } 01468 01469 // kdDebug(13000)<<QString("-->virtual Line %1").arg(realLine)<<endl; 01470 01471 return realLine; 01472 } 01473 01474 // 01475 // get the number of hidden lines 01476 // 01477 unsigned int KateCodeFoldingTree::getHiddenLinesCount(unsigned int doclen) 01478 { 01479 // he, if nothing is hidden, why look at it ;) 01480 if (hiddenLines.isEmpty()) 01481 return 0; 01482 01483 if (hiddenLinesCountCacheValid) 01484 return hiddenLinesCountCache; 01485 01486 hiddenLinesCountCacheValid = true; 01487 hiddenLinesCountCache = 0; 01488 01489 for (QValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it) 01490 { 01491 if ((*it).start+(*it).length<=doclen) 01492 hiddenLinesCountCache += (*it).length; 01493 else 01494 { 01495 hiddenLinesCountCache += ((*it).length- ((*it).length + (*it).start - doclen)); 01496 break; 01497 } 01498 } 01499 01500 return hiddenLinesCountCache; 01501 } 01502 01503 void KateCodeFoldingTree::collapseToplevelNodes() 01504 { 01505 // hl whole file 01506 m_buffer->line (m_buffer->count()-1); 01507 01508 if (m_root.noChildren ()) 01509 return; 01510 01511 for ( uint i=0; i < m_root.childCount(); ++i ) 01512 { 01513 KateCodeFoldingNode *node = m_root.child(i); 01514 01515 if (node->visible && node->startLineValid && node->endLineValid) 01516 { 01517 node->visible=false; 01518 lineMapping.clear(); 01519 hiddenLinesCountCacheValid = false; 01520 addHiddenLineBlock(node,node->startLineRel); 01521 emit regionVisibilityChangedAt(node->startLineRel); 01522 } 01523 } 01524 } 01525 01526 void KateCodeFoldingTree::expandToplevelNodes(int numLines) 01527 { 01528 // hl whole file 01529 m_buffer->line (m_buffer->count()-1); 01530 01531 KateLineInfo line; 01532 for (int i = 0; i < numLines; i++) { 01533 getLineInfo(&line, i); 01534 01535 if (line.startsInVisibleBlock) 01536 toggleRegionVisibility(i); 01537 } 01538 } 01539 01540 int KateCodeFoldingTree::collapseOne(int realLine) 01541 { 01542 // hl whole file 01543 m_buffer->line (m_buffer->count()-1); 01544 01545 KateLineInfo line; 01546 int unrelatedBlocks = 0; 01547 for (int i = realLine; i >= 0; i--) { 01548 getLineInfo(&line, i); 01549 01550 if (line.topLevel && !line.endsBlock) 01551 // optimisation 01552 break; 01553 01554 if (line.endsBlock && ( line.invalidBlockEnd ) && (i != realLine)) { 01555 unrelatedBlocks++; 01556 } 01557 01558 if (line.startsVisibleBlock) { 01559 unrelatedBlocks--; 01560 if (unrelatedBlocks == -1) { 01561 toggleRegionVisibility(i); 01562 return i; 01563 } 01564 } 01565 } 01566 return -1; 01567 } 01568 01569 void KateCodeFoldingTree::expandOne(int realLine, int numLines) 01570 { 01571 // hl whole file 01572 m_buffer->line (m_buffer->count()-1); 01573 01574 KateLineInfo line; 01575 int blockTrack = 0; 01576 for (int i = realLine; i >= 0; i--) { 01577 getLineInfo(&line, i); 01578 01579 if (line.topLevel) 01580 // done 01581 break; 01582 01583 if (line.startsInVisibleBlock && i != realLine) { 01584 if (blockTrack == 0) 01585 toggleRegionVisibility(i); 01586 01587 blockTrack--; 01588 } 01589 01590 if (line.endsBlock) 01591 blockTrack++; 01592 01593 if (blockTrack < 0) 01594 // too shallow 01595 break; 01596 } 01597 01598 blockTrack = 0; 01599 for (int i = realLine; i < numLines; i++) { 01600 getLineInfo(&line, i); 01601 01602 if (line.topLevel) 01603 // done 01604 break; 01605 01606 if (line.startsInVisibleBlock) { 01607 if (blockTrack == 0) 01608 toggleRegionVisibility(i); 01609 01610 blockTrack++; 01611 } 01612 01613 if (line.endsBlock) 01614 blockTrack--; 01615 01616 if (blockTrack < 0) 01617 // too shallow 01618 break; 01619 } 01620 } 01621 01622 void KateCodeFoldingTree::ensureVisible( uint line ) 01623 { 01624 // first have a look, if the line is really hidden 01625 bool found=false; 01626 for (QValueList<KateHiddenLineBlock>::ConstIterator it=hiddenLines.begin();it!=hiddenLines.end();++it) 01627 { 01628 if ( ((*it).start<=line) && ((*it).start+(*it).length>line) ) 01629 { 01630 found=true; 01631 break; 01632 } 01633 } 01634 01635 01636 if (!found) return; 01637 01638 kdDebug(13000)<<"line "<<line<<" is really hidden ->show block"<<endl; 01639 01640 // it looks like we really have to ensure visibility 01641 KateCodeFoldingNode *n = findNodeForLine( line ); 01642 do { 01643 if ( ! n->visible ) 01644 toggleRegionVisibility( getStartLine( n ) ); 01645 n = n->parentNode; 01646 } while( n ); 01647 01648 } 01649 01650 // kate: space-indent on; indent-width 2; replace-tabs on;
KDE Logo
This file is part of the documentation for kate Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 23:39:57 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003