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

Kate

katecodefolding.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 "katecodefolding.h"
00020 #include "katecodefolding.moc"
00021 
00022 #include "katebuffer.h"
00023 #include "katecursor.h"
00024 #include <kdebug.h>
00025 
00026 #include <QtCore/QString>
00027 
00028 /*#define JW_DEBUG 1*/
00029 #undef JW_DEBUG
00030 
00031 bool KateCodeFoldingTree::trueVal = true;
00032 
00033 KateCodeFoldingNode::KateCodeFoldingNode() :
00034     parentNode(0),
00035     startLineRel(0),
00036     endLineRel(0),
00037     startCol(0),
00038     endCol(0),
00039     startLineValid(false),
00040     endLineValid(false),
00041     type(0),
00042     visible(true),
00043     deleteOpening(false),
00044     deleteEnding(false)
00045 {
00046 }//the endline fields should be initialised to not valid
00047 
00048 KateCodeFoldingNode::KateCodeFoldingNode(KateCodeFoldingNode *par, signed char typ, unsigned int sLRel):
00049     parentNode(par),
00050     startLineRel(sLRel),
00051     endLineRel(10000),
00052     startCol(0),
00053     endCol(0),
00054     startLineValid(true),
00055     endLineValid(false),
00056     type(typ),
00057     visible(true),
00058     deleteOpening(false),
00059     deleteEnding(false)
00060 {
00061 }//the endline fields should be initialised to not valid
00062 
00063 KateCodeFoldingNode::~KateCodeFoldingNode()
00064 {
00065   // delete all child nodes
00066   clearChildren ();
00067 }
00068 
00069 bool KateCodeFoldingNode::getBegin(KateCodeFoldingTree *tree, KTextEditor::Cursor* begin) {
00070   if (!startLineValid) return false;
00071   unsigned int line=startLineRel;
00072   for (KateCodeFoldingNode *n=parentNode;n;n=n->parentNode)
00073     line+=n->startLineRel;
00074 
00075   tree->m_buffer->codeFoldingColumnUpdate(line);
00076   begin->setLine(line);
00077   begin->setColumn(startCol);
00078 
00079   return true;
00080 }
00081 
00082 bool KateCodeFoldingNode::getEnd(KateCodeFoldingTree *tree, KTextEditor::Cursor *end) {
00083   if (!endLineValid) return false;
00084   unsigned int line=startLineRel+endLineRel;
00085   for (KateCodeFoldingNode *n=parentNode;n;n=n->parentNode)
00086     line+=n->startLineRel;
00087 
00088   tree->m_buffer->codeFoldingColumnUpdate(line);
00089   end->setLine(line);
00090   end->setColumn(endCol);
00091 
00092   return true;
00093 }
00094 
00095 int KateCodeFoldingNode::cmpPos(KateCodeFoldingTree *tree, uint line,uint col) {
00096     KTextEditor::Cursor cur(line,col);
00097     KTextEditor::Cursor start,end;
00098     kDebug(13000)<<"KateCodeFoldingNode::cmpPos (1)";
00099     bool startValid=getBegin(tree, &start);
00100     kDebug(13000)<<"KateCodeFoldingNode::cmpPos (2)";
00101     bool endValid=getEnd(tree, &end);
00102     kDebug(13000)<<"KateCodeFoldingNode::cmpPos (3)";
00103     if ((!endValid) && startValid) {
00104       return ((start>cur)?-1:0);
00105     }
00106     if ((!startValid) && endValid) {
00107       return ((cur>end)?1:0);
00108     }
00109     //here both have to be valid, both invalid must not happen
00110     Q_ASSERT(startValid && endValid);
00111     return  ( (cur<start)?(-1):( (cur>end) ? 1:0));
00112 }
00113 
00114 void KateCodeFoldingNode::insertChild (uint index, KateCodeFoldingNode *node)
00115 {
00116   uint s = m_children.size ();
00117 
00118   if (index > s)
00119     return;
00120 
00121   m_children.resize (++s);
00122 
00123   for (uint i=s-1; i > index; --i)
00124     m_children[i] = m_children[i-1];
00125 
00126   m_children[index] = node;
00127 }
00128 
00129 KateCodeFoldingNode *KateCodeFoldingNode::takeChild (uint index)
00130 {
00131   uint s = m_children.size ();
00132 
00133   if (index >= s)
00134     return 0;
00135 
00136   KateCodeFoldingNode *n = m_children[index];
00137 
00138   for (uint i=index; (i+1) < s; ++i)
00139     m_children[i] = m_children[i+1];
00140 
00141   m_children.resize (s-1);
00142 
00143   return n;
00144 }
00145 
00146 void KateCodeFoldingNode::clearChildren ()
00147 {
00148   for (int i=0; i < m_children.size(); ++i)
00149     delete m_children[i];
00150 
00151   m_children.resize (0);
00152 }
00153 
00154 KateCodeFoldingTree::KateCodeFoldingTree(KateBuffer *buffer): QObject(buffer), m_buffer (buffer),m_clearCache(false)
00155 {
00156   clear();
00157 }
00158 
00159 void KateCodeFoldingTree::fixRoot(int endLRel)
00160 {
00161   m_root.endLineRel = endLRel;
00162 }
00163 
00164 void KateCodeFoldingTree::clear()
00165 {
00166   m_root.clearChildren();
00167 
00168   // initialize the root "special" node
00169   m_root.startLineValid=true;
00170   m_root.endLineValid=true; // temporary, should be false;
00171   m_root.endLineRel=1;      // temporary;
00172 
00173   hiddenLinesCountCacheValid=false;
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 children
00189 
00190   // look if a given lines belongs to a sub node
00191   for ( int 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   info->depth=0;
00212   if (m_root.noChildren())
00213     return;
00214 
00215   //let's look for some information
00216   for ( int 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       foreach (KateCodeFoldingNode* node, nodesForLine)
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       KateCodeFoldingNode *node = findNodeForLine(line);
00248       int depth=0;
00249       while (node)
00250       {
00251         node = node->getParentNode();
00252         depth++;
00253       }
00254       if (depth>0) depth--;
00255       info->depth=depth;
00256       return;
00257     }
00258   }
00259 
00260   return;
00261 }
00262 
00263 
00264 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLine(unsigned int line)
00265 {
00266   if (m_root.noChildren()) // do we have child list + nodes ?
00267     return &m_root;
00268 
00269   // lets look, if given line is within a subnode range, and then return the deepest one.
00270   for ( int i=0; i < m_root.childCount(); ++i )
00271   {
00272     KateCodeFoldingNode *node = m_root.child(i);
00273 
00274     if (node->startLineValid && (node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
00275     {
00276       // a region surounds the line, look in the next deeper hierarchy step
00277       return findNodeForLineDescending(node,line,0);
00278     }
00279   }
00280 
00281   return &m_root;
00282 }
00283 
00284 
00285 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLineDescending ( KateCodeFoldingNode *node,
00286     unsigned int line, unsigned int offset, bool oneStepOnly )
00287 {
00288   if (node->noChildren())
00289     return node;
00290 
00291   // calculate the offset, between a subnodes real start line and its relative start
00292   offset += node->startLineRel;
00293 
00294   for ( int i=0; i < node->childCount(); ++i )
00295   {
00296     KateCodeFoldingNode *subNode = node->child(i);
00297 
00298     if ((subNode->startLineRel+offset<=line) && (line<=subNode->endLineRel+subNode->startLineRel+offset)) //warning fix me for invalid ends
00299     {
00300       // a subnode contains the line.
00301       // if oneStepOnly is true, we don't want to search for the deepest node, just return the found one
00302 
00303       if (oneStepOnly)
00304         return subNode;
00305       else
00306         return findNodeForLineDescending (subNode,line,offset); // look into the next deeper hierarchy step
00307     }
00308   }
00309 
00310   return node; // the current node has no sub nodes, or the line couldn'te be found within a subregion
00311 }
00312 
00313 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForPosition(unsigned int line, unsigned int column)
00314 {
00315   KateCodeFoldingNode *node=findNodeForLine(line);
00316 
00317   if (node==&m_root) return &m_root;
00318 
00319   kDebug(13000)<<"initial cmpPos";
00320 
00321   KateCodeFoldingNode *tmp;
00322   int leq=node->cmpPos(this, line,column);
00323   while (true) {
00324     switch (leq) {
00325       case 0: {
00326                 if (node->noChildren())
00327                   return node;
00328                 else
00329                 {
00330                   tmp=node;
00331                   for ( int i=0; i < node->childCount(); ++i )
00332                   {
00333                     KateCodeFoldingNode *subNode = node->child(i);
00334                     kDebug(13000)<<"cmdPos(case0):calling";
00335                     leq=subNode->cmpPos(this, line,column);
00336                     kDebug(13000)<<"cmdPos(case0):returned";
00337                     if (leq==0) {
00338                         tmp=subNode;
00339                         break;
00340                     } else if (leq==-1) break;
00341                   }
00342                   if (tmp!=node) node=tmp; else return node;
00343                 }
00344                 break;
00345               }
00346       //this could be optimized a littlebit
00347       case -1:
00348       case 1:  {
00349                   if (!(node->parentNode)) return &m_root;
00350                   kDebug(13000)<<"current node type"<<node->type;
00351                   node=node->parentNode;
00352                   kDebug(13000)<<"cmdPos(case-1/1):calling:"<<node;
00353                   leq=node->cmpPos(this, line,column);
00354                   kDebug(13000)<<"cmdPos(case-1/1):returned";
00355                   break;
00356                 }
00357     }
00358 
00359   }
00360   Q_ASSERT(false);
00361   return &m_root;
00362 }
00363 
00364 void KateCodeFoldingTree::debugDump()
00365 {
00366   //dump all nodes for debugging
00367   kDebug(13000)<<"The parsed region/block tree for code folding";
00368   dumpNode(&m_root, "");
00369 }
00370 
00371 void KateCodeFoldingTree::dumpNode(KateCodeFoldingNode *node, const QString &prefix)
00372 {
00373   //output node properties
00374   kDebug(13000)<<node<<prefix<<QString("Type: %1, startLineValid %2, startLineRel %3, endLineValid %4, endLineRel %5, visible %6").
00375       arg(node->type).arg(node->startLineValid).arg(node->startLineRel).arg(node->endLineValid).
00376       arg(node->endLineRel).arg(node->visible)<<"Parent:"<<node->parentNode<<endl;
00377 
00378   //output child node properties recursive
00379   if (node->noChildren())
00380     return;
00381 
00382   QString newprefix(prefix + "   ");
00383   for ( int i=0; i < node->childCount(); ++i )
00384     dumpNode (node->child(i),newprefix);
00385 }
00386 
00387 /*
00388  That's one of the most important functions ;)
00389 */
00390 void KateCodeFoldingTree::updateLine(unsigned int line,
00391   QVector<int> *regionChanges, bool *updated,bool changed,bool colsChanged)
00392 {
00393   if ( (!changed) || colsChanged)
00394   {
00395     if (dontIgnoreUnchangedLines.isEmpty())
00396       return;
00397 
00398     if (dontIgnoreUnchangedLines.contains(line))
00399       dontIgnoreUnchangedLines.remove(line);
00400     else
00401       return;
00402   }
00403 
00404   something_changed = false;
00405 
00406   findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
00407 
00408   if (regionChanges->isEmpty())
00409   {
00410     //  KateCodeFoldingNode *node=findNodeForLine(line);
00411     //  if (node->type!=0)
00412     //  if (getStartLine(node)+node->endLineRel==line) removeEnding(node,line);
00413   }
00414   else
00415   {
00416     for (int i=0;i<regionChanges->size() / 4;i++)
00417     {
00418         signed char tmp=(*regionChanges)[regionChanges->size()-2-i*2];
00419         uint tmppos=(*regionChanges)[regionChanges->size()-1-i*2];
00420         (*regionChanges)[regionChanges->size()-2-i*2]=(*regionChanges)[i*2];
00421         (*regionChanges)[regionChanges->size()-1-i*2]=(*regionChanges)[i*2+1];
00422         (*regionChanges)[i*2]=tmp;
00423         (*regionChanges)[i*2+1]=tmppos;
00424     }
00425 
00426 
00427     signed char data= (*regionChanges)[regionChanges->size()-2];
00428     uint charPos=(*regionChanges)[regionChanges->size()-1];
00429     regionChanges->resize (regionChanges->size()-2);
00430 
00431     int insertPos=-1;
00432     KateCodeFoldingNode *node = findNodeForLine(line);
00433 
00434     if (data<0)
00435     {
00436       //  if (insertPos==-1)
00437       {
00438         unsigned int tmpLine=line-getStartLine(node);
00439 
00440         for ( int i=0; i < node->childCount(); ++i )
00441         {
00442           if (node->child(i)->startLineRel >= tmpLine)
00443           {
00444             insertPos=i;
00445             break;
00446           }
00447         }
00448       }
00449     }
00450     else
00451     {
00452       for (; (node->parentNode) && (getStartLine(node->parentNode)==line) &&
00453               (node->parentNode->type!=0); node=node->parentNode) {
00454           ;
00455       }
00456 
00457       if ((getStartLine(node)==line) && (node->type!=0))
00458       {
00459         insertPos=node->parentNode->findChild(node);
00460         node = node->parentNode;
00461       }
00462       else
00463       {
00464         for ( int i=0; i < node->childCount(); ++i )
00465         {
00466           if (getStartLine(node->child(i))>=line)
00467           {
00468             insertPos=i;
00469             break;
00470           }
00471         }
00472       }
00473     }
00474 
00475     do
00476     {
00477       if (data<0)
00478       {
00479         if (correctEndings(data,node,line,charPos,insertPos))
00480         {
00481           insertPos=node->parentNode->findChild(node)+1;
00482           node=node->parentNode;
00483         }
00484         else
00485         {
00486           if (insertPos!=-1) insertPos++;
00487         }
00488       }
00489       else
00490       {
00491         int startLine=getStartLine(node);
00492         if ((insertPos==-1) || (insertPos>=(int)node->childCount()))
00493         {
00494           KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
00495           something_changed = true;
00496           node->appendChild(newNode);
00497           addOpening(newNode, data, regionChanges, line,charPos);
00498           insertPos = node->findChild(newNode)+1;
00499         }
00500         else
00501         {
00502           if (node->child(insertPos)->startLineRel == line-startLine)
00503           {
00504             addOpening(node->child(insertPos), data, regionChanges, line,charPos);
00505             insertPos++;
00506           }
00507           else
00508           {
00509 //              kDebug(13000)<<"ADDING NODE ";
00510             KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
00511             something_changed = true;
00512             node->insertChild(insertPos, newNode);
00513             addOpening(newNode, data, regionChanges, line,charPos);
00514             insertPos++;
00515           }
00516         }
00517       }
00518 
00519       if (regionChanges->isEmpty())
00520         data = 0;
00521       else
00522       {
00523         data = (*regionChanges)[regionChanges->size()-2];
00524         charPos=(*regionChanges)[regionChanges->size()-1];
00525         regionChanges->resize (regionChanges->size()-2);
00526       }
00527     } while (data!=0);
00528   }
00529 
00530   cleanupUnneededNodes(line);
00531 //  if (something_changed) emit regionBeginEndAddedRemoved(line);
00532   (*updated) = something_changed;
00533 }
00534 
00535 
00536 bool KateCodeFoldingTree::removeOpening(KateCodeFoldingNode *node,unsigned int line)
00537 {
00538   signed char type;
00539   if ((type=node->type) == 0)
00540   {
00541     dontDeleteOpening(node);
00542     dontDeleteEnding(node);
00543     return false;
00544   }
00545 
00546   if (!node->visible)
00547   {
00548     m_clearCache=true;
00549     toggleRegionVisibility(getStartLine(node));
00550     m_clearCache=false;
00551   }
00552 
00553   KateCodeFoldingNode *parent = node->parentNode;
00554   int mypos = parent->findChild(node);
00555 
00556   if (mypos > -1)
00557   {
00558   //move childnodes() up
00559   for(; node->childCount()>0 ;)
00560   {
00561     KateCodeFoldingNode *tmp;
00562     parent->insertChild(mypos, tmp=node->takeChild(0));
00563     tmp->parentNode = parent;
00564     tmp->startLineRel += node->startLineRel;
00565     mypos++;
00566   }
00567 
00568   // remove the node
00569   //mypos = parent->findChild(node);
00570   bool endLineValid = node->endLineValid;
00571   int endLineRel = node->endLineRel;
00572   uint endCol=node->endCol;
00573 
00574   // removes + deletes
00575   KateCodeFoldingNode *child = parent->takeChild(mypos);
00576   markedForDeleting.removeAll(child);
00577 //   removeParentReferencesFromChilds(child);
00578   delete child;
00579 
00580   if ((type>0) && (endLineValid))
00581     correctEndings(-type, parent, line+endLineRel/*+1*/,endCol, mypos); // why the hell did I add a +1 here ?
00582   }
00583 
00584   return true;
00585 }
00586 
00587 bool KateCodeFoldingTree::removeEnding(KateCodeFoldingNode *node,unsigned int /* line */)
00588 {
00589   KateCodeFoldingNode *parent = node->parentNode;
00590 
00591   if (!parent)
00592     return false;
00593 
00594   if (node->type == 0)
00595     return false;
00596 
00597   if (node->type < 0)
00598   {
00599     // removes + deletes
00600     int i = parent->findChild (node);
00601     if (i >= 0)
00602     {
00603       KateCodeFoldingNode *child = parent->takeChild(i);
00604       markedForDeleting.removeAll(child);
00605 //       removeParentReferencesFromChilds(child);
00606       delete child;
00607     }
00608 
00609     return true;
00610   }
00611 
00612   int mypos = parent->findChild(node);
00613   int count = parent->childCount();
00614 
00615   for (int i=mypos+1; i<count; i++)
00616   {
00617     if (parent->child(i)->type == -node->type)
00618     {
00619       node->endLineValid = true;
00620       node->endLineRel = parent->child(i)->startLineRel - node->startLineRel;
00621 
00622       KateCodeFoldingNode *child = parent->takeChild(i);
00623       markedForDeleting.removeAll(child);
00624 //       removeParentReferencesFromChilds(child);
00625       delete child;
00626 
00627       count = i-mypos-1;
00628       if (count > 0)
00629       {
00630         for (int i=0; i<count; i++)
00631         {
00632           KateCodeFoldingNode *tmp = parent->takeChild(mypos+1);
00633           tmp->startLineRel -= node->startLineRel;
00634           tmp->parentNode = node; //should help 16.04.2002
00635           node->appendChild(tmp);
00636         }
00637       }
00638       return false;
00639     }
00640   }
00641 
00642   if ( (parent->type == node->type) || /*temporary fix */ (!parent->parentNode))
00643   {
00644     for (int i=mypos+1; i<(int)parent->childCount(); i++)
00645     {
00646       KateCodeFoldingNode *tmp = parent->takeChild(mypos+1);
00647       tmp->startLineRel -= node->startLineRel;
00648       tmp->parentNode = node; // SHOULD HELP 16.04.2002
00649       node->appendChild(tmp);
00650     }
00651 
00652     // this should fix the bug of wrongly closed nodes
00653     if (!parent->parentNode)
00654       node->endLineValid=false;
00655     else
00656       node->endLineValid = parent->endLineValid;
00657 
00658     node->endLineRel = parent->endLineRel-node->startLineRel;
00659 
00660     if (node->endLineValid)
00661       return removeEnding(parent, getStartLine(parent)+parent->endLineRel);
00662 
00663     return false;
00664   }
00665 
00666   node->endLineValid = false;
00667   node->endLineRel = parent->endLineRel - node->startLineRel;
00668 
00669   return false;
00670 }
00671 
00672 
00673 bool KateCodeFoldingTree::correctEndings(signed char data, KateCodeFoldingNode *node,unsigned int line,unsigned int endCol,int insertPos)
00674 {
00675 //  if (node->type==0) {kError()<<"correct Ending should never be called with the root node"<<endl; return true;}
00676   uint startLine = getStartLine(node);
00677   if (data != -node->type)
00678   {
00679 #ifdef JW_DEBUG
00680     kDebug(13000)<<"data!=-node->type (correctEndings)";
00681 #endif
00682     //invalid close -> add to unopend list
00683     dontDeleteEnding(node);
00684     if (data == node->type) {
00685       node->endCol=endCol;
00686       return false;
00687     }
00688     KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
00689     something_changed = true;
00690     newNode->startLineValid = false;
00691     newNode->endLineValid = true;
00692     newNode->endLineRel = 0;
00693     newNode->endCol=endCol;
00694 
00695     if ((insertPos==-1) || (insertPos==(int)node->childCount()))
00696       node->appendChild(newNode);
00697     else
00698       node->insertChild(insertPos,newNode);
00699 
00700       // find correct position
00701     return false;
00702   }
00703   else
00704   {
00705     something_changed = true;
00706     dontDeleteEnding(node);
00707 
00708     // valid closing region
00709     if (!node->endLineValid)
00710     {
00711       node->endLineValid = true;
00712       node->endLineRel = line - startLine;
00713       node->endCol=endCol;
00714       //moving
00715 
00716       moveSubNodesUp(node);
00717     }
00718     else
00719     {
00720 #ifdef JW_DEBUG
00721       kDebug(13000)<<"Closing a node which had already a valid end";
00722 #endif
00723       // block has already an ending
00724       if (startLine+node->endLineRel == line)
00725       {
00726          node->endCol=endCol;
00727          // we won, just skip
00728 #ifdef JW_DEBUG
00729         kDebug(13000)<< "We won, just skipping (correctEndings)";
00730 #endif
00731       }
00732       else
00733       {
00734         int bakEndLine = node->endLineRel+startLine;
00735         uint bakEndCol = node->endCol;
00736         node->endLineRel = line-startLine;
00737         node->endCol=endCol;
00738 
00739 #ifdef JW_DEBUG
00740         kDebug(13000)<< "reclosed node had childnodes()";
00741         kDebug(13000)<<"It could be, that childnodes() need to be moved up";
00742 #endif
00743   moveSubNodesUp(node);
00744 
00745         if (node->parentNode)
00746         {
00747           correctEndings(data,node->parentNode,bakEndLine, bakEndCol,node->parentNode->findChild(node)+1); // ????
00748         }
00749         else
00750         {
00751           //add to unopened list (bakEndLine)
00752         }
00753       }
00754       }
00755     }
00756     return true;
00757 }
00758 
00759 void KateCodeFoldingTree::moveSubNodesUp(KateCodeFoldingNode *node)
00760 {
00761         int mypos = node->parentNode->findChild(node);
00762         int removepos=-1;
00763         int count = node->childCount();
00764         for (int i=0; i<count; i++)
00765           if (node->child(i)->startLineRel >= node->endLineRel)
00766           {
00767             removepos=i;
00768             break;
00769           }
00770 #ifdef JW_DEBUG
00771         kDebug(13000)<<QString("remove pos: %1").arg(removepos);
00772 #endif
00773         if (removepos>-1)
00774         {
00775 #ifdef JW_DEBUG
00776           kDebug(13000)<<"Children need to be moved";
00777 #endif
00778           KateCodeFoldingNode *moveNode;
00779           if (mypos == (int)node->parentNode->childCount()-1)
00780           {
00781             while (removepos<(int)node->childCount())
00782             {
00783               node->parentNode->appendChild(moveNode=node->takeChild(removepos));
00784               moveNode->parentNode = node->parentNode;
00785               moveNode->startLineRel += node->startLineRel;
00786             }
00787           }
00788           else
00789           {
00790             int insertPos=mypos;
00791             while (removepos < (int)node->childCount())
00792             {
00793               insertPos++;
00794               node->parentNode->insertChild(insertPos, moveNode=node->takeChild(removepos));
00795               moveNode->parentNode = node->parentNode; // That should solve a crash
00796               moveNode->startLineRel += node->startLineRel;
00797             }
00798           }
00799         }
00800 
00801 }
00802 
00803 
00804 
00805 void KateCodeFoldingTree::addOpening(KateCodeFoldingNode *node,signed char nType, QVector<int>* list,unsigned int line,unsigned int charPos)
00806 {
00807   uint startLine = getStartLine(node);
00808   if ((startLine==line) && (node->type!=0))
00809   {
00810 #ifdef JW_DEBUG
00811     kDebug(13000)<<"startLine equals line";
00812 #endif
00813     if (nType == node->type)
00814     {
00815 #ifdef JW_DEBUG
00816       kDebug(13000)<<"Node exists";
00817 #endif
00818       node->deleteOpening = false;
00819       node->startCol=charPos;
00820       KateCodeFoldingNode *parent = node->parentNode;
00821 
00822       if (!node->endLineValid)
00823       {
00824         int current = parent->findChild(node);
00825         int count = parent->childCount()-(current+1);
00826         node->endLineRel = parent->endLineRel - node->startLineRel;
00827 
00828 // EXPERIMENTAL TEST BEGIN
00829 // move this afte the test for unopened, but closed regions within the parent node, or if there are no siblings, bubble up
00830         if (parent->type == node->type)
00831         {
00832           if (parent->endLineValid)
00833           {
00834             removeEnding(parent, line);
00835             node->endLineValid = true;
00836           }
00837         }
00838 
00839 // EXPERIMENTAL TEST BEGIN
00840 
00841         if (current != (int)parent->childCount()-1)
00842         {
00843         //search for an unopened but closed region, even if the parent is of the same type
00844 #ifdef __GNUC__
00845 #warning  "FIXME:  why does this seem to work?"
00846 #endif
00847 //          if (node->type != parent->type)
00848           {
00849             for (int i=current+1; i<(int)parent->childCount(); i++)
00850             {
00851               if (parent->child(i)->type == -node->type)
00852               {
00853                 count = (i-current-1);
00854                 node->endLineValid = true;
00855                 node->endLineRel = getStartLine(parent->child(i))-line;
00856                 node->endCol = parent->child(i)->endCol;
00857                 KateCodeFoldingNode *child = parent->takeChild(i);
00858                 markedForDeleting.removeAll( child );
00859 //                 removeParentReferencesFromChilds(child);
00860                 delete child;
00861                 break;
00862               }
00863             }
00864           }
00865 //          else
00866 //          {
00867 //            parent->endLineValid = false;
00868 //            parent->endLineRel = 20000;
00869 //          }
00870 
00871           if (count>0)
00872           {
00873             for (int i=0;i<count;i++)
00874             {
00875               KateCodeFoldingNode *tmp;
00876               node->appendChild(tmp=parent->takeChild(current+1));
00877               tmp->startLineRel -= node->startLineRel;
00878               tmp->parentNode = node;
00879             }
00880           }
00881         }
00882 
00883       }
00884 
00885       addOpening_further_iterations(node, nType, list, line, 0, startLine,node->startCol);
00886 
00887     } //else ohoh, much work to do same line, but other region type
00888   }
00889   else
00890   { // create a new region
00891     KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,nType,line-startLine);
00892     something_changed = true;
00893 
00894     int insert_position=-1;
00895     for (int i=0; i<(int)node->childCount(); i++)
00896     {
00897       if (startLine+node->child(i)->startLineRel > line)
00898       {
00899          insert_position=i;
00900          break;
00901       }
00902     }
00903 
00904     int current;
00905     if (insert_position==-1)
00906     {
00907       node->appendChild(newNode);
00908       current = node->childCount()-1;
00909     }
00910     else
00911     {
00912       node->insertChild(insert_position, newNode);
00913       current = insert_position;
00914     }
00915 
00916 //    if (node->type==newNode->type)
00917 //    {
00918 //      newNode->endLineValid=true;
00919 //      node->endLineValid=false;
00920 //      newNode->endLineRel=node->endLineRel-newNode->startLineRel;
00921 //      node->endLineRel=20000; //FIXME
00922 
00923       int count = node->childCount() - (current+1);
00924       newNode->endLineRel -= newNode->startLineRel;
00925       if (current != (int)node->childCount()-1)
00926       {
00927         if (node->type != newNode->type)
00928         {
00929           for (int i=current+1; i<(int)node->childCount(); i++)
00930           {
00931             if (node->child(i)->type == -newNode->type)
00932             {
00933               count = node->childCount() - i - 1;
00934               newNode->endLineValid = true;
00935               newNode->endLineRel = line - getStartLine(node->child(i));
00936               KateCodeFoldingNode *child = node->takeChild(i);
00937               markedForDeleting.removeAll( child );
00938 //               removeParentReferencesFromChilds(child);
00939               delete child;
00940               break;
00941             }
00942           }
00943         }
00944         else
00945         {
00946           node->endLineValid = false;
00947           node->endLineRel = 10000;
00948         }
00949         if (count > 0)
00950         {
00951           for (int i=0;i<count;i++)
00952           {
00953             KateCodeFoldingNode *tmp;
00954             newNode->appendChild(tmp=node->takeChild(current+1));
00955             tmp->parentNode=newNode;
00956           }
00957         }
00958 //      }
00959     }
00960 
00961     addOpening(newNode, nType, list, line,charPos);
00962 
00963     addOpening_further_iterations(node, node->type, list, line, current, startLine,node->startCol);
00964   }
00965 }
00966 
00967 
00968 void KateCodeFoldingTree::addOpening_further_iterations(KateCodeFoldingNode *node,signed char /* nType */, QVector<int>*
00969     list,unsigned int line,int current, unsigned int startLine,unsigned int charPos)
00970 {
00971   Q_UNUSED(charPos)
00972 
00973   while (!(list->isEmpty()))
00974   {
00975     if (list->isEmpty())
00976       return;
00977     else
00978     {
00979          signed char data = (*list)[list->size()-2];
00980          uint charPos=(*list)[list->size()-1];
00981        list->resize (list->size()-2);
00982 
00983       if (data<0)
00984       {
00985 #ifdef JW_DEBUG
00986         kDebug(13000)<<"An ending was found";
00987 #endif
00988 
00989         if (correctEndings(data,node,line,charPos,-1))
00990           return; // -1 ?
00991 
00992 #if 0
00993         if(data == -nType)
00994         {
00995           if (node->endLineValid)
00996           {
00997             if (node->endLineRel+startLine==line) // We've won again
00998             {
00999               //handle next node;
01000             }
01001             else
01002             { // much moving
01003               node->endLineRel=line-startLine;
01004               node->endLineValid=true;
01005             }
01006             return;  // next higher level should do the rest
01007           }
01008           else
01009           {
01010             node->endLineRel=line-startLine;
01011             node->endLineValid=true;
01012             //much moving
01013           }
01014         } //else add to unopened list
01015 #endif
01016       }
01017       else
01018       {
01019         bool needNew = true;
01020         if (current < (int)node->childCount())
01021         {
01022           if (getStartLine(node->child(current)) == line)
01023             needNew=false;
01024         }
01025         if (needNew)
01026         {
01027           something_changed = true;
01028           KateCodeFoldingNode *newNode = new KateCodeFoldingNode(node, data, line-startLine);
01029           node->insertChild(current, newNode);  //find the correct position later
01030         }
01031 
01032                addOpening(node->child(current), data, list, line,charPos);
01033         current++;
01034         //lookup node or create subnode
01035       }
01036     }
01037   } // end while
01038 }
01039 
01040 unsigned int KateCodeFoldingTree::getStartLine(KateCodeFoldingNode *node)
01041 {
01042   unsigned int lineStart=0;
01043   for (KateCodeFoldingNode *iter=node; iter->type != 0; iter=iter->parentNode)
01044     lineStart += iter->startLineRel;
01045 
01046   return lineStart;
01047 }
01048 
01049 
01050 void KateCodeFoldingTree::lineHasBeenRemoved(unsigned int line)
01051 {
01052   
01053   lineMapping.clear();
01054   dontIgnoreUnchangedLines.insert(line);
01055   dontIgnoreUnchangedLines.insert(line-1);
01056   dontIgnoreUnchangedLines.insert(line+1);
01057   hiddenLinesCountCacheValid = false;
01058 #ifdef JW_DEBUG
01059   kDebug(13000)<<QString("KateCodeFoldingTree::lineHasBeenRemoved: %1").arg(line);
01060   debugDump();
01061 #endif
01062 
01063 //line ++;
01064   findAndMarkAllNodesforRemovalOpenedOrClosedAt(line); //It's an ugly solution
01065   cleanupUnneededNodes(line);  //It's an ugly solution
01066 
01067   KateCodeFoldingNode *node = findNodeForLine(line);
01068 //?????  if (node->endLineValid)
01069   {
01070     int startLine = getStartLine(node);
01071     if (startLine == (int)line)
01072       node->startLineRel--;
01073     else
01074     {
01075       if (node->endLineRel == 0)
01076         node->endLineValid = false;
01077       node->endLineRel--;
01078     }
01079 
01080     int count = node->childCount();
01081     for (int i=0; i<count; i++)
01082     {
01083       if (node->child(i)->startLineRel+startLine >= line)
01084         node->child(i)->startLineRel--;
01085     }
01086   }
01087 
01088   if (node->parentNode)
01089     decrementBy1(node->parentNode, node);
01090 
01091   for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it != hiddenLines.end(); ++it)
01092   {
01093     if ((*it).start > line)
01094       (*it).start--;
01095     else if ((*it).start+(*it).length > line)
01096       (*it).length--;
01097   }
01098 }
01099 
01100 
01101 void KateCodeFoldingTree::decrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after)
01102 {
01103   if (node->endLineRel == 0)
01104     node->endLineValid = false;
01105   node->endLineRel--;
01106 
01107   for (int i=node->findChild(after)+1; i < node->childCount(); ++i)
01108     node->child(i)->startLineRel--;
01109 
01110   if (node->parentNode)
01111     decrementBy1(node->parentNode,node);
01112 }
01113 
01114 
01115 void KateCodeFoldingTree::lineHasBeenInserted(unsigned int line)
01116 {
01117   lineMapping.clear();
01118   dontIgnoreUnchangedLines.insert(line);
01119   dontIgnoreUnchangedLines.insert(line-1l);
01120   dontIgnoreUnchangedLines.insert(line+1);
01121   hiddenLinesCountCacheValid = false;
01122 //return;
01123 #ifdef JW_DEBUG
01124   kDebug(13000)<<QString("KateCodeFoldingTree::lineHasBeenInserted: %1").arg(line);
01125 #endif
01126 
01127 //  findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
01128 //  cleanupUnneededNodes(line);
01129 
01130   KateCodeFoldingNode *node = findNodeForLine(line);
01131 // ????????  if (node->endLineValid)
01132   {
01133     int startLine=getStartLine(node);
01134     if (node->type < 0)
01135       node->startLineRel++;
01136     else
01137       node->endLineRel++;
01138 
01139     for (int i=0; i < node->childCount(); ++i)
01140     {
01141       KateCodeFoldingNode *iter = node->child(i);
01142 
01143       if (iter->startLineRel+startLine >= line)
01144         iter->startLineRel++;
01145     }
01146   }
01147 
01148   if (node->parentNode)
01149     incrementBy1(node->parentNode, node);
01150 
01151   for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
01152   {
01153     if ((*it).start > line)
01154       (*it).start++;
01155     else if ((*it).start+(*it).length > line)
01156       (*it).length++;
01157   }
01158 }
01159 
01160 void KateCodeFoldingTree::incrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after)
01161 {
01162   node->endLineRel++;
01163 
01164   for (int i=node->findChild(after)+1; i < node->childCount(); ++i)
01165     node->child(i)->startLineRel++;
01166 
01167   if (node->parentNode)
01168     incrementBy1(node->parentNode,node);
01169 }
01170 
01171 
01172 void KateCodeFoldingTree::findAndMarkAllNodesforRemovalOpenedOrClosedAt(unsigned int line)
01173 {
01174 #ifdef __GNUC__
01175 #warning "FIXME:  make this multiple region changes per line save";
01176 #endif
01177 //  return;
01178   markedForDeleting.clear();
01179   KateCodeFoldingNode *node = findNodeForLine(line);
01180   if (node->type == 0)
01181     return;
01182 
01183   addNodeToRemoveList(node, line);
01184 
01185   while (((node->parentNode) && (node->parentNode->type!=0)) && (getStartLine(node->parentNode)==line))
01186   {
01187     node = node->parentNode;
01188     addNodeToRemoveList(node, line);
01189   }
01190 #ifdef JW_DEBUG
01191   kDebug(13000)<<" added line to markedForDeleting list";
01192 #endif
01193 }
01194 
01195 
01196 void KateCodeFoldingTree::addNodeToRemoveList(KateCodeFoldingNode *node,unsigned int line)
01197 {
01198   bool add=false;
01199 #ifdef __GNUC__
01200 #warning "FIXME:  make this multiple region changes per line save";
01201 #endif
01202   unsigned int startLine=getStartLine(node);
01203   if ((startLine==line) && (node->startLineValid))
01204   {
01205     add=true;
01206     node->deleteOpening = true;
01207   }
01208   if ((startLine+node->endLineRel==line) || ((node->endLineValid==false) && (node->deleteOpening)))
01209   {
01210     int myPos=node->parentNode->findChild(node); // this has to be implemented nicely
01211     if ((int)node->parentNode->childCount()>myPos+1)
01212      addNodeToRemoveList(node->parentNode->child(myPos+1),line);
01213     add=true;
01214     node->deleteEnding = true;
01215   }
01216 
01217   if(add)
01218   markedForDeleting.append(node);
01219   kDebug(13000)<<"marking for deletion:"<<node;
01220 }
01221 
01222 
01223 void KateCodeFoldingTree::findAllNodesOpenedOrClosedAt(unsigned int line)
01224 {
01225   nodesForLine.clear();
01226   KateCodeFoldingNode *node = findNodeForLine(line);
01227   if (node->type == 0)
01228     return;
01229 
01230   unsigned int startLine = getStartLine(node);
01231   if (startLine == line)
01232     nodesForLine.append(node);
01233   else if ((startLine+node->endLineRel == line))
01234     nodesForLine.append(node);
01235 
01236   while (node->parentNode)
01237   {
01238     addNodeToFoundList(node->parentNode, line, node->parentNode->findChild(node));
01239     node = node->parentNode;
01240   }
01241 /*#ifdef JW_DEBUG
01242   kDebug(13000)<<" added line to nodesForLine list";
01243 #endif*/
01244 }
01245 
01246 
01247 void KateCodeFoldingTree::addNodeToFoundList(KateCodeFoldingNode *node,unsigned int line,int childpos)
01248 {
01249   unsigned int startLine = getStartLine(node);
01250 
01251   if ((startLine==line) && (node->type!=0))
01252     nodesForLine.append(node);
01253   else if ((startLine+node->endLineRel==line) && (node->type!=0))
01254     nodesForLine.append(node);
01255 
01256   for (int i=childpos+1; i<(int)node->childCount(); i++)
01257   {
01258     KateCodeFoldingNode *child = node->child(i);
01259 
01260     if (startLine+child->startLineRel == line)
01261     {
01262       nodesForLine.append(child);
01263       addNodeToFoundList(child, line, 0);
01264     }
01265     else
01266       break;
01267   }
01268 }
01269 
01270 
01271 void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line)
01272 {
01273 #ifdef JW_DEBUG
01274   kDebug(13000)<<"void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line):"<<line;
01275 #endif
01276 
01277 //  return;
01278   if (markedForDeleting.isEmpty())
01279     return;
01280 
01281   for (int i=0; i<(int)markedForDeleting.count(); i++)
01282   {
01283     KateCodeFoldingNode *node = markedForDeleting.at(i);
01284 #ifdef JW_DEBUG
01285     kDebug(13000)<<"index:"<<i<<" node:"<<node<<endl;
01286 #endif
01287     if (node->deleteOpening)
01288       kDebug(13000)<<"DELETE OPENING SET";
01289     if (node->deleteEnding)
01290       kDebug(13000)<<"DELETE ENDING SET";
01291 
01292     if ((node->deleteOpening) && (node->deleteEnding))
01293     {
01294 #ifdef JW_DEBUG
01295       kDebug(13000)<<"Deleting complete node";
01296 #endif
01297       if (node->endLineValid)    // just delete it, it has been opened and closed on this line
01298       {
01299         int f = node->parentNode->findChild (node);
01300 
01301         if (f >= 0) {
01302          KateCodeFoldingNode *delN=node->parentNode->takeChild(f);
01303 //          removeParentReferencesFromChilds(delN);
01304          delete delN;
01305         }
01306       }
01307       else
01308       {
01309         removeOpening(node, line);
01310         // the node has subnodes which need to be moved up and this one has to be deleted
01311       }
01312       something_changed = true;
01313     }
01314     else
01315     {
01316       if ((node->deleteOpening) && (node->startLineValid))
01317       {
01318 #ifdef JW_DEBUG
01319         kDebug(13000)<<"calling removeOpening";
01320 #endif
01321         removeOpening(node, line);
01322         something_changed = true;
01323       }
01324       else
01325       {
01326         dontDeleteOpening(node);
01327 
01328         if ((node->deleteEnding) && (node->endLineValid))
01329         {
01330           dontDeleteEnding(node);
01331           removeEnding(node, line);
01332           something_changed = true;
01333         }
01334         else
01335           dontDeleteEnding(node);
01336       }
01337     }
01338   }
01339 }
01340 
01341 void KateCodeFoldingTree::dontDeleteEnding(KateCodeFoldingNode* node)
01342 {
01343   node->deleteEnding = false;
01344 }
01345 
01346 
01347 void KateCodeFoldingTree::dontDeleteOpening(KateCodeFoldingNode* node)
01348 {
01349   node->deleteOpening = false;
01350 }
01351 
01352 
01353 KateCodeFoldingNode *KateCodeFoldingTree::findNodeStartingAt(unsigned int line){
01354   findAllNodesOpenedOrClosedAt(line);
01355   for (int i=0; i<(int)nodesForLine.count(); i++)
01356   {
01357     KateCodeFoldingNode *node=nodesForLine.at(i);
01358     if ( (!node->startLineValid) || (getStartLine(node) != line) )
01359     {
01360       nodesForLine.removeAt(i);
01361       if (!node->startLineValid) addNodeToRemoveList(node, line);
01362       i--;
01363     }
01364   }
01365 
01366   if (nodesForLine.isEmpty())
01367     return 0;
01368   return nodesForLine.at(0);
01369 }
01370 
01371 
01372 void KateCodeFoldingTree::toggleRegionVisibility(unsigned int line)
01373 {
01374   // hl whole file
01375   m_buffer->ensureHighlighted (m_buffer->count()-1);
01376 
01377   lineMapping.clear();
01378   hiddenLinesCountCacheValid = false;
01379   kDebug(13000)<<QString("KateCodeFoldingTree::toggleRegionVisibility() %1").arg(line);
01380 
01381   findAllNodesOpenedOrClosedAt(line);
01382   for (int i=0; i<(int)nodesForLine.count(); i++)
01383   {
01384     KateCodeFoldingNode *node=nodesForLine.at(i);
01385     if ( (!node->startLineValid) || (getStartLine(node) != line) )
01386     {
01387       nodesForLine.removeAt(i);
01388       if (!node->startLineValid) addNodeToRemoveList(node, line);
01389       i--;
01390     }
01391   }
01392 
01393   if (nodesForLine.isEmpty())
01394     return;
01395 
01396   nodesForLine.at(0)->visible = !nodesForLine.at(0)->visible;
01397 
01398   if (!nodesForLine.at(0)->visible)
01399     addHiddenLineBlock(nodesForLine.at(0),line);
01400   else
01401   {
01402     for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it!=hiddenLines.end();++it)
01403       if ((*it).start == line+1)
01404       {
01405         hiddenLines.erase(it);
01406         break;
01407       }
01408 
01409     updateHiddenSubNodes(nodesForLine.at(0));
01410   }
01411 
01412   emit regionVisibilityChangedAt(line,m_clearCache);
01413 }
01414 
01415 void KateCodeFoldingTree::updateHiddenSubNodes(KateCodeFoldingNode *node)
01416 {
01417   for (int i=0; i < node->childCount(); ++i)
01418   {
01419     KateCodeFoldingNode *iter = node->child(i);
01420 
01421     if (!iter->visible)
01422       addHiddenLineBlock(iter, getStartLine(iter));
01423     else
01424       updateHiddenSubNodes(iter);
01425   }
01426 }
01427 
01428 void KateCodeFoldingTree::addHiddenLineBlock(KateCodeFoldingNode *node,unsigned int line)
01429 {
01430   KateHiddenLineBlock data;
01431   data.start = line+1;
01432   data.length = node->endLineRel-(existsOpeningAtLineAfter(line+node->endLineRel,node)?1:0); // without -1;
01433   bool inserted = false;
01434 
01435   for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
01436   {
01437     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
01438     {
01439       // the existing block can't have lines behind the new one, because a newly hidden
01440       //  block has to encapsulate already hidden ones
01441       it=hiddenLines.erase(it);
01442       --it;
01443     }
01444     else
01445     {
01446       if ((*it).start > line)
01447       {
01448         hiddenLines.insert(it, data);
01449         inserted = true;
01450 
01451         break;
01452       }
01453     }
01454   }
01455 
01456   if (!inserted)
01457     hiddenLines.append(data);
01458 }
01459 
01460 bool KateCodeFoldingTree::existsOpeningAtLineAfter(unsigned int line, KateCodeFoldingNode *node)
01461 {
01462   for(KateCodeFoldingNode *tmp = node->parentNode; tmp; tmp=tmp->parentNode)
01463   {
01464     KateCodeFoldingNode *tmp2;
01465     unsigned int startLine=getStartLine(tmp);
01466 
01467     if ( (tmp->findChild(node)+1) >= tmp->childCount()) return false;
01468     if ((tmp2 = tmp->child(tmp->findChild(node) + 1))
01469          && ((tmp2->startLineRel + startLine) == line))
01470       return true;
01471 
01472     if ((startLine + tmp->endLineRel) > line)
01473       return false;
01474   }
01475 
01476   return false;
01477 }
01478 
01479 
01480 //
01481 // get the real line number for a virtual line
01482 //
01483 unsigned int KateCodeFoldingTree::getRealLine(unsigned int virtualLine)
01484 {
01485   // he, if nothing is hidden, why look at it ;)
01486   if (hiddenLines.isEmpty())
01487     return virtualLine;
01488 
01489   // kDebug(13000) << "virtualLine" << virtualLine;
01490 
01491   if (lineMapping.contains(virtualLine))
01492     return lineMapping[virtualLine];
01493 
01494   unsigned int realLine = virtualLine;
01495   for (QList<KateHiddenLineBlock>::const_iterator it=hiddenLines.constBegin();it!=hiddenLines.constEnd();++it)
01496   {
01497     if ((*it).start <= realLine)
01498       realLine += (*it).length;
01499     else
01500       break;
01501   }
01502 
01503   // kDebug(13000) << "realLine" << realLine;
01504 
01505   lineMapping.insert(virtualLine, realLine);
01506   return realLine;
01507 }
01508 
01509 //
01510 // get the virtual line number for a real line
01511 //
01512 unsigned int KateCodeFoldingTree::getVirtualLine(unsigned int realLine)
01513 {
01514   // he, if nothing is hidden, why look at it ;)
01515   if (hiddenLines.isEmpty())
01516     return realLine;
01517 
01518   // kDebug(13000) << "realLine" << realLine;
01519   int virtualLine = realLine;
01520 
01521   for (int i = hiddenLines.size()-1; i >= 0; --i) {
01522     if ((int)hiddenLines[i].start <= virtualLine) {
01523         virtualLine -= hiddenLines[i].length;
01524         if (virtualLine < (int)hiddenLines[i].start)
01525             virtualLine = hiddenLines[i].start-1;
01526     }
01527     // else
01528       // break;
01529   }
01530 
01531   // kDebug(13000) << "virtualLine" << virtualLine;
01532 
01533   return virtualLine;
01534 }
01535 
01536 //
01537 // get the number of hidden lines
01538 //
01539 unsigned int KateCodeFoldingTree::getHiddenLinesCount(unsigned int doclen)
01540 {
01541   // he, if nothing is hidden, why look at it ;)
01542   if (hiddenLines.isEmpty())
01543     return 0;
01544 
01545   if (hiddenLinesCountCacheValid)
01546     return hiddenLinesCountCache;
01547 
01548   hiddenLinesCountCacheValid = true;
01549   hiddenLinesCountCache = 0;
01550 
01551   for (QList<KateHiddenLineBlock>::const_iterator it=hiddenLines.constBegin(); it!=hiddenLines.constEnd(); ++it)
01552   {
01553     if ((*it).start+(*it).length<=doclen)
01554       hiddenLinesCountCache += (*it).length;
01555     else
01556     {
01557       hiddenLinesCountCache += ((*it).length- ((*it).length + (*it).start - doclen));
01558       break;
01559     }
01560   }
01561 
01562   return hiddenLinesCountCache;
01563 }
01564 
01565 void KateCodeFoldingTree::collapseToplevelNodes()
01566 {
01567   // hl whole file
01568   m_buffer->ensureHighlighted (m_buffer->count()-1);
01569 
01570   if (m_root.noChildren ())
01571     return;
01572 
01573   for ( int i=0; i < m_root.childCount(); ++i )
01574   {
01575     KateCodeFoldingNode *node = m_root.child(i);
01576 
01577     if (node->visible && node->startLineValid && node->endLineValid)
01578     {
01579         node->visible=false;
01580         lineMapping.clear();
01581         hiddenLinesCountCacheValid = false;
01582         addHiddenLineBlock(node,node->startLineRel);
01583         emit regionVisibilityChangedAt(node->startLineRel,m_clearCache);
01584     }
01585   }
01586 }
01587 
01588 void KateCodeFoldingTree::expandToplevelNodes(int numLines)
01589 {
01590   // hl whole file
01591   m_buffer->ensureHighlighted (m_buffer->count()-1);
01592 
01593   KateLineInfo line;
01594   for (int i = 0; i < numLines; i++) {
01595     getLineInfo(&line, i);
01596 
01597     if (line.startsInVisibleBlock)
01598       toggleRegionVisibility(i);
01599   }
01600 }
01601 
01602 int KateCodeFoldingTree::collapseOne(int realLine)
01603 {
01604   // hl whole file
01605   m_buffer->ensureHighlighted (m_buffer->count()-1);
01606 
01607   KateLineInfo line;
01608   int unrelatedBlocks = 0;
01609   for (int i = realLine; i >= 0; i--) {
01610     getLineInfo(&line, i);
01611 
01612     if (line.topLevel && !line.endsBlock)
01613       // optimization
01614       break;
01615 
01616     if (line.endsBlock && !line.invalidBlockEnd && (i != realLine)) {
01617       unrelatedBlocks++;
01618     }
01619 
01620     if (line.startsVisibleBlock) {
01621       unrelatedBlocks--;
01622       if (unrelatedBlocks == -1) {
01623         toggleRegionVisibility(i);
01624         return i;
01625       }
01626     }
01627   }
01628   return -1;
01629 }
01630 
01631 void KateCodeFoldingTree::expandOne(int realLine, int numLines)
01632 {
01633   // hl whole file
01634   m_buffer->ensureHighlighted (m_buffer->count()-1);
01635 
01636   KateLineInfo line;
01637   int blockTrack = 0;
01638   for (int i = realLine; i >= 0; i--) {
01639     getLineInfo(&line, i);
01640 
01641     if (line.topLevel)
01642       // done
01643       break;
01644 
01645     if (line.startsInVisibleBlock && i != realLine) {
01646       if (blockTrack == 0)
01647         toggleRegionVisibility(i);
01648 
01649       blockTrack--;
01650     }
01651 
01652     if (line.endsBlock)
01653       blockTrack++;
01654 
01655     if (blockTrack < 0)
01656       // too shallow
01657       break;
01658   }
01659 
01660   blockTrack = 0;
01661   for (int i = realLine; i < numLines; i++) {
01662     getLineInfo(&line, i);
01663 
01664     if (line.topLevel)
01665       // done
01666       break;
01667 
01668     if (line.startsInVisibleBlock) {
01669       if (blockTrack == 0)
01670         toggleRegionVisibility(i);
01671 
01672       blockTrack++;
01673     }
01674 
01675     if (line.endsBlock)
01676       blockTrack--;
01677 
01678     if (blockTrack < 0)
01679       // too shallow
01680       break;
01681   }
01682 }
01683 
01684 void KateCodeFoldingTree::ensureVisible( uint line )
01685 {
01686   // first have a look, if the line is really hidden
01687   bool found=false;
01688   for (QList<KateHiddenLineBlock>::const_iterator it=hiddenLines.constBegin();it!=hiddenLines.constEnd();++it)
01689   {
01690     if ( ((*it).start<=line)  && ((*it).start+(*it).length>line) )
01691     {
01692       found=true;
01693       break;
01694     }
01695   }
01696 
01697 
01698   if (!found) return;
01699 
01700   kDebug(13000)<<"line "<<line<<" is really hidden ->show block";
01701 
01702   // it looks like we really have to ensure visibility
01703   KateCodeFoldingNode *n = findNodeForLine( line );
01704   do {
01705     if ( ! n->visible )
01706       toggleRegionVisibility( getStartLine( n ) );
01707     n = n->parentNode;
01708   } while( n );
01709 
01710 }
01711 
01712 // void KateCodeFoldingTree::removeParentReferencesFromChilds(KateCodeFoldingNode* node) {
01713 //   for (int i=0;i<node->childCount();i++) {
01714 //     KateCodeFoldingNode *n=node->child(i);
01715 //     kDebug(13000)<<"removing node from markedForDeleting list"<<n<<endl;
01716 //     markedForDeleting.removeAll(n);
01717 //     n->parentNode=0;
01718 //     removeParentReferencesFromChilds(n);
01719 //   }
01720 // }
01721 
01722 // 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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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