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