• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Kate

katecodefoldinghelpers.cpp

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

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal