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.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Jul 20 14:15:48 2006 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003