# kate Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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;

This file is part of the documentation for kate Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:36:30 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003