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