• Skip to content
  • Skip to link menu
KDE 4.2 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 0
00029 
00030 bool KateCodeFoldingTree::trueVal = true;
00031 
00032 KateCodeFoldingNode::KateCodeFoldingNode() :
00033     parentNode(0),
00034     startLineRel(0),
00035     endLineRel(0),
00036     startCol(0),
00037     endCol(0),
00038     startLineValid(false),
00039     endLineValid(false),
00040     type(0),
00041     visible(true),
00042     deleteOpening(false),
00043     deleteEnding(false)
00044 {
00045 }//the endline fields should be initialised to not valid
00046 
00047 KateCodeFoldingNode::KateCodeFoldingNode(KateCodeFoldingNode *par, signed char typ, unsigned int sLRel):
00048     parentNode(par),
00049     startLineRel(sLRel),
00050     endLineRel(10000),
00051     startCol(0),
00052     endCol(0),
00053     startLineValid(true),
00054     endLineValid(false),
00055     type(typ),
00056     visible(true),
00057     deleteOpening(false),
00058     deleteEnding(false)
00059 {
00060 }//the endline fields should be initialised to not valid
00061 
00062 KateCodeFoldingNode::~KateCodeFoldingNode()
00063 {
00064   // delete all child nodes
00065   clearChildren ();
00066 }
00067 
00068 bool KateCodeFoldingNode::getBegin(KateCodeFoldingTree *tree, KTextEditor::Cursor* begin) {
00069   if (!startLineValid) return false;
00070   unsigned int line=startLineRel;
00071   for (KateCodeFoldingNode *n=parentNode;n;n=n->parentNode)
00072     line+=n->startLineRel;
00073 
00074   tree->m_buffer->codeFoldingColumnUpdate(line);
00075   begin->setLine(line);
00076   begin->setColumn(startCol);
00077 
00078   return true;
00079 }
00080 
00081 bool KateCodeFoldingNode::getEnd(KateCodeFoldingTree *tree, KTextEditor::Cursor *end) {
00082   if (!endLineValid) return false;
00083   unsigned int line=startLineRel+endLineRel;
00084   for (KateCodeFoldingNode *n=parentNode;n;n=n->parentNode)
00085     line+=n->startLineRel;
00086 
00087   tree->m_buffer->codeFoldingColumnUpdate(line);
00088   end->setLine(line);
00089   end->setColumn(endCol);
00090 
00091   return true;
00092 }
00093 
00094 int KateCodeFoldingNode::cmpPos(KateCodeFoldingTree *tree, uint line,uint col) {
00095     KTextEditor::Cursor cur(line,col);
00096     KTextEditor::Cursor start,end;
00097     kDebug(13000)<<"KateCodeFoldingNode::cmpPos (1)";
00098     bool startValid=getBegin(tree, &start);
00099     kDebug(13000)<<"KateCodeFoldingNode::cmpPos (2)";
00100     bool endValid=getEnd(tree, &end);
00101     kDebug(13000)<<"KateCodeFoldingNode::cmpPos (3)";
00102     if ((!endValid) && startValid) {
00103       return ((start>cur)?-1:0);
00104     }
00105     if ((!startValid) && endValid) {
00106       return ((cur>end)?1:0);
00107     }
00108     //here both have to be valid, both invalid must not happen
00109     Q_ASSERT(startValid && endValid);
00110     return  ( (cur<start)?(-1):( (cur>end) ? 1:0));
00111 }
00112 
00113 void KateCodeFoldingNode::insertChild (uint index, KateCodeFoldingNode *node)
00114 {
00115   uint s = m_children.size ();
00116 
00117   if (index > s)
00118     return;
00119 
00120   m_children.resize (++s);
00121 
00122   for (uint i=s-1; i > index; --i)
00123     m_children[i] = m_children[i-1];
00124 
00125   m_children[index] = node;
00126 }
00127 
00128 KateCodeFoldingNode *KateCodeFoldingNode::takeChild (uint index)
00129 {
00130   uint s = m_children.size ();
00131 
00132   if (index >= s)
00133     return 0;
00134 
00135   KateCodeFoldingNode *n = m_children[index];
00136 
00137   for (uint i=index; (i+1) < s; ++i)
00138     m_children[i] = m_children[i+1];
00139 
00140   m_children.resize (s-1);
00141 
00142   return n;
00143 }
00144 
00145 void KateCodeFoldingNode::clearChildren ()
00146 {
00147   for (int i=0; i < m_children.size(); ++i)
00148     delete m_children[i];
00149 
00150   m_children.resize (0);
00151 }
00152 
00153 KateCodeFoldingTree::KateCodeFoldingTree(KateBuffer *buffer): QObject(buffer), m_buffer (buffer)
00154 {
00155   clear();
00156 }
00157 
00158 void KateCodeFoldingTree::fixRoot(int endLRel)
00159 {
00160   m_root.endLineRel = endLRel;
00161 }
00162 
00163 void KateCodeFoldingTree::clear()
00164 {
00165   m_root.clearChildren();
00166 
00167   // initialize the root "special" node
00168   m_root.startLineValid=true;
00169   m_root.endLineValid=true; // temporary, should be false;
00170   m_root.endLineRel=1;      // temporary;
00171 
00172   hiddenLinesCountCacheValid=false;
00173   hiddenLines.clear();
00174   lineMapping.clear();
00175   nodesForLine.clear();
00176   markedForDeleting.clear();
00177   dontIgnoreUnchangedLines.clear();
00178 }
00179 
00180 KateCodeFoldingTree::~KateCodeFoldingTree()
00181 {
00182 }
00183 
00184 bool KateCodeFoldingTree::isTopLevel(unsigned int line)
00185 {
00186   if (m_root.noChildren())
00187     return true; // no children
00188 
00189   // look if a given lines belongs to a sub node
00190   for ( int i=0; i < m_root.childCount(); ++i )
00191   {
00192     KateCodeFoldingNode *node = m_root.child(i);
00193 
00194     if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
00195       return false;  // the line is within the range of a subnode -> return toplevel=false
00196   }
00197 
00198   return true;  // the root node is the only node containing the given line, return toplevel=true
00199 }
00200 
00201 void KateCodeFoldingTree::getLineInfo(KateLineInfo *info, unsigned int line)
00202 {
00203   // Initialze the returned structure, this will also be returned if the root node has no child nodes
00204   // or the line is not within a childnode's range.
00205   info->topLevel = true;
00206   info->startsVisibleBlock = false;
00207   info->startsInVisibleBlock = false;
00208   info->endsBlock = false;
00209   info->invalidBlockEnd = false;
00210   info->depth=0;
00211   if (m_root.noChildren())
00212     return;
00213 
00214   //let's look for some information
00215   for ( int i=0; i < m_root.childCount(); ++i )
00216   {
00217     KateCodeFoldingNode *node = m_root.child(i);
00218 
00219     if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel)) // we found a node, which contains the given line -> do a complete lookup
00220     {
00221       info->topLevel = false; //we are definitly not toplevel
00222       findAllNodesOpenedOrClosedAt(line); //lookup all nodes, which start or and at the given line
00223 
00224       foreach (KateCodeFoldingNode* node, nodesForLine)
00225       {
00226         uint startLine = getStartLine(node);
00227 
00228         // type<0 means, that a region has been closed, but not opened
00229         // eg. parantheses missmatch
00230         if (node->type < 0)
00231           info->invalidBlockEnd=true;
00232         else
00233         {
00234           if (startLine != line)  // does the region we look at not start at the given line
00235             info->endsBlock = true; // than it has to be an ending
00236           else
00237           {
00238             // The line starts a new region, now determine, if it's a visible or a hidden region
00239             if (node->visible)
00240               info->startsVisibleBlock=true;
00241             else
00242               info->startsInVisibleBlock=true;
00243           }
00244         }
00245       }
00246       KateCodeFoldingNode *node = findNodeForLine(line);
00247       int depth=0;
00248       while (node)
00249       {
00250         node = node->getParentNode();
00251         depth++;
00252       }
00253       if (depth>0) depth--;
00254       info->depth=depth;
00255       return;
00256     }
00257   }
00258 
00259   return;
00260 }
00261 
00262 
00263 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLine(unsigned int line)
00264 {
00265   if (m_root.noChildren()) // do we have child list + nodes ?
00266     return &m_root;
00267 
00268   // lets look, if given line is within a subnode range, and then return the deepest one.
00269   for ( int i=0; i < m_root.childCount(); ++i )
00270   {
00271     KateCodeFoldingNode *node = m_root.child(i);
00272 
00273     if (node->startLineValid && (node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
00274     {
00275       // a region surounds the line, look in the next deeper hierarchy step
00276       return findNodeForLineDescending(node,line,0);
00277     }
00278   }
00279 
00280   return &m_root;
00281 }
00282 
00283 
00284 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLineDescending ( KateCodeFoldingNode *node,
00285     unsigned int line, unsigned int offset, bool oneStepOnly )
00286 {
00287   if (node->noChildren())
00288     return node;
00289 
00290   // calculate the offset, between a subnodes real start line and its relative start
00291   offset += node->startLineRel;
00292 
00293   for ( int i=0; i < node->childCount(); ++i )
00294   {
00295     KateCodeFoldingNode *subNode = node->child(i);
00296 
00297     if ((subNode->startLineRel+offset<=line) && (line<=subNode->endLineRel+subNode->startLineRel+offset)) //warning fix me for invalid ends
00298     {
00299       // a subnode contains the line.
00300       // if oneStepOnly is true, we don't want to search for the deepest node, just return the found one
00301 
00302       if (oneStepOnly)
00303         return subNode;
00304       else
00305         return findNodeForLineDescending (subNode,line,offset); // look into the next deeper hierarchy step
00306     }
00307   }
00308 
00309   return node; // the current node has no sub nodes, or the line couldn'te be found within a subregion
00310 }
00311 
00312 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForPosition(unsigned int line, unsigned int column)
00313 {
00314   KateCodeFoldingNode *node=findNodeForLine(line);
00315 
00316   if (node==&m_root) return &m_root;
00317 
00318   kDebug(13000)<<"initial cmpPos";
00319 
00320   KateCodeFoldingNode *tmp;
00321   int leq=node->cmpPos(this, line,column);
00322   while (true) {
00323     switch (leq) {
00324       case 0: {
00325                 if (node->noChildren())
00326                   return node;
00327                 else
00328                 {
00329                   tmp=node;
00330                   for ( int i=0; i < node->childCount(); ++i )
00331                   {
00332                     KateCodeFoldingNode *subNode = node->child(i);
00333                     kDebug(13000)<<"cmdPos(case0):calling";
00334                     leq=subNode->cmpPos(this, line,column);
00335                     kDebug(13000)<<"cmdPos(case0):returned";
00336                     if (leq==0) {
00337                         tmp=subNode;
00338                         break;
00339                     } else if (leq==-1) break;
00340                   }
00341                   if (tmp!=node) node=tmp; else return node;
00342                 }
00343                 break;
00344               }
00345       //this could be optimized a littlebit
00346       case -1:
00347       case 1:  {
00348                   if (!(node->parentNode)) return &m_root;
00349                   kDebug(13000)<<"current node type"<<node->type;
00350                   node=node->parentNode;
00351                   kDebug(13000)<<"cmdPos(case-1/1):calling:"<<node;
00352                   leq=node->cmpPos(this, line,column);
00353                   kDebug(13000)<<"cmdPos(case-1/1):returned";
00354                   break;
00355                 }
00356     }
00357 
00358   }
00359   Q_ASSERT(false);
00360   return &m_root;
00361 }
00362 
00363 void KateCodeFoldingTree::debugDump()
00364 {
00365   //dump all nodes for debugging
00366   kDebug(13000)<<"The parsed region/block tree for code folding";
00367   dumpNode(&m_root, "");
00368 }
00369 
00370 void KateCodeFoldingTree::dumpNode(KateCodeFoldingNode *node, const QString &prefix)
00371 {
00372   //output node properties
00373   kDebug(13000)<<prefix<<QString("Type: %1, startLineValid %2, startLineRel %3, endLineValid %4, endLineRel %5, visible %6").
00374       arg(node->type).arg(node->startLineValid).arg(node->startLineRel).arg(node->endLineValid).
00375       arg(node->endLineRel).arg(node->visible)<<endl;
00376 
00377   //output child node properties recursive
00378   if (node->noChildren())
00379     return;
00380 
00381   QString newprefix(prefix + "   ");
00382   for ( int i=0; i < node->childCount(); ++i )
00383     dumpNode (node->child(i),newprefix);
00384 }
00385 
00386 /*
00387  That's one of the most important functions ;)
00388 */
00389 void KateCodeFoldingTree::updateLine(unsigned int line,
00390   QVector<int> *regionChanges, bool *updated,bool changed,bool colsChanged)
00391 {
00392   if ( (!changed) || colsChanged)
00393   {
00394     if (dontIgnoreUnchangedLines.isEmpty())
00395       return;
00396 
00397     if (dontIgnoreUnchangedLines.contains(line))
00398       dontIgnoreUnchangedLines.remove(line);
00399     else
00400       return;
00401   }
00402 
00403   something_changed = false;
00404 
00405   findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
00406 
00407   if (regionChanges->isEmpty())
00408   {
00409     //  KateCodeFoldingNode *node=findNodeForLine(line);
00410     //  if (node->type!=0)
00411     //  if (getStartLine(node)+node->endLineRel==line) removeEnding(node,line);
00412   }
00413   else
00414   {
00415     for (int i=0;i<regionChanges->size() / 4;i++)
00416     {
00417         signed char tmp=(*regionChanges)[regionChanges->size()-2-i*2];
00418         uint tmppos=(*regionChanges)[regionChanges->size()-1-i*2];
00419         (*regionChanges)[regionChanges->size()-2-i*2]=(*regionChanges)[i*2];
00420         (*regionChanges)[regionChanges->size()-1-i*2]=(*regionChanges)[i*2+1];
00421         (*regionChanges)[i*2]=tmp;
00422         (*regionChanges)[i*2+1]=tmppos;
00423     }
00424 
00425 
00426     signed char data= (*regionChanges)[regionChanges->size()-2];
00427     uint charPos=(*regionChanges)[regionChanges->size()-1];
00428     regionChanges->resize (regionChanges->size()-2);
00429 
00430     int insertPos=-1;
00431     KateCodeFoldingNode *node = findNodeForLine(line);
00432 
00433     if (data<0)
00434     {
00435       //  if (insertPos==-1)
00436       {
00437         unsigned int tmpLine=line-getStartLine(node);
00438 
00439         for ( int i=0; i < node->childCount(); ++i )
00440         {
00441           if (node->child(i)->startLineRel >= tmpLine)
00442           {
00443             insertPos=i;
00444             break;
00445           }
00446         }
00447       }
00448     }
00449     else
00450     {
00451       for (; (node->parentNode) && (getStartLine(node->parentNode)==line) &&
00452               (node->parentNode->type!=0); node=node->parentNode) {
00453           ;
00454       }
00455 
00456       if ((getStartLine(node)==line) && (node->type!=0))
00457       {
00458         insertPos=node->parentNode->findChild(node);
00459         node = node->parentNode;
00460       }
00461       else
00462       {
00463         for ( int i=0; i < node->childCount(); ++i )
00464         {
00465           if (getStartLine(node->child(i))>=line)
00466           {
00467             insertPos=i;
00468             break;
00469           }
00470         }
00471       }
00472     }
00473 
00474     do
00475     {
00476       if (data<0)
00477       {
00478         if (correctEndings(data,node,line,charPos,insertPos))
00479         {
00480           insertPos=node->parentNode->findChild(node)+1;
00481           node=node->parentNode;
00482         }
00483         else
00484         {
00485           if (insertPos!=-1) insertPos++;
00486         }
00487       }
00488       else
00489       {
00490         int startLine=getStartLine(node);
00491         if ((insertPos==-1) || (insertPos>=(int)node->childCount()))
00492         {
00493           KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
00494           something_changed = true;
00495           node->appendChild(newNode);
00496           addOpening(newNode, data, regionChanges, line,charPos);
00497           insertPos = node->findChild(newNode)+1;
00498         }
00499         else
00500         {
00501           if (node->child(insertPos)->startLineRel == line-startLine)
00502           {
00503             addOpening(node->child(insertPos), data, regionChanges, line,charPos);
00504             insertPos++;
00505           }
00506           else
00507           {
00508 //              kDebug(13000)<<"ADDING NODE ";
00509             KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
00510             something_changed = true;
00511             node->insertChild(insertPos, newNode);
00512             addOpening(newNode, data, regionChanges, line,charPos);
00513             insertPos++;
00514           }
00515         }
00516       }
00517 
00518       if (regionChanges->isEmpty())
00519         data = 0;
00520       else
00521       {
00522         data = (*regionChanges)[regionChanges->size()-2];
00523         charPos=(*regionChanges)[regionChanges->size()-1];
00524         regionChanges->resize (regionChanges->size()-2);
00525       }
00526     } while (data!=0);
00527   }
00528 
00529   cleanupUnneededNodes(line);
00530 //  if (something_changed) emit regionBeginEndAddedRemoved(line);
00531   (*updated) = something_changed;
00532 }
00533 
00534 
00535 bool KateCodeFoldingTree::removeOpening(KateCodeFoldingNode *node,unsigned int line)
00536 {
00537   signed char type;
00538   if ((type=node->type) == 0)
00539   {
00540     dontDeleteOpening(node);
00541     dontDeleteEnding(node);
00542     return false;
00543   }
00544 
00545   if (!node->visible)
00546   {
00547   toggleRegionVisibility(getStartLine(node));
00548   }
00549 
00550   KateCodeFoldingNode *parent = node->parentNode;
00551   int mypos = parent->findChild(node);
00552 
00553   if (mypos > -1)
00554   {
00555   //move childnodes() up
00556   for(; node->childCount()>0 ;)
00557   {
00558     KateCodeFoldingNode *tmp;
00559     parent->insertChild(mypos, tmp=node->takeChild(0));
00560     tmp->parentNode = parent;
00561     tmp->startLineRel += node->startLineRel;
00562     mypos++;
00563   }
00564 
00565   // remove the node
00566   //mypos = parent->findChild(node);
00567   bool endLineValid = node->endLineValid;
00568   int endLineRel = node->endLineRel;
00569   uint endCol=node->endCol;
00570 
00571   // removes + deletes
00572   KateCodeFoldingNode *child = parent->takeChild(mypos);
00573   markedForDeleting.removeAll(child);
00574   delete child;
00575 
00576   if ((type>0) && (endLineValid))
00577     correctEndings(-type, parent, line+endLineRel/*+1*/,endCol, mypos); // why the hell did I add a +1 here ?
00578   }
00579 
00580   return true;
00581 }
00582 
00583 bool KateCodeFoldingTree::removeEnding(KateCodeFoldingNode *node,unsigned int /* line */)
00584 {
00585   KateCodeFoldingNode *parent = node->parentNode;
00586 
00587   if (!parent)
00588     return false;
00589 
00590   if (node->type == 0)
00591     return false;
00592 
00593   if (node->type < 0)
00594   {
00595     // removes + deletes
00596     int i = parent->findChild (node);
00597     if (i >= 0)
00598     {
00599       KateCodeFoldingNode *child = parent->takeChild(i);
00600       markedForDeleting.removeAll(child);
00601       delete child;
00602     }
00603 
00604     return true;
00605   }
00606 
00607   int mypos = parent->findChild(node);
00608   int count = parent->childCount();
00609 
00610   for (int i=mypos+1; i<count; i++)
00611   {
00612     if (parent->child(i)->type == -node->type)
00613     {
00614       node->endLineValid = true;
00615       node->endLineRel = parent->child(i)->startLineRel - node->startLineRel;
00616 
00617       KateCodeFoldingNode *child = parent->takeChild(i);
00618       markedForDeleting.removeAll(child);
00619       delete child;
00620 
00621       count = i-mypos-1;
00622       if (count > 0)
00623       {
00624         for (int i=0; i<count; i++)
00625         {
00626           KateCodeFoldingNode *tmp = parent->takeChild(mypos+1);
00627           tmp->startLineRel -= node->startLineRel;
00628           tmp->parentNode = node; //should help 16.04.2002
00629           node->appendChild(tmp);
00630         }
00631       }
00632       return false;
00633     }
00634   }
00635 
00636   if ( (parent->type == node->type) || /*temporary fix */ (!parent->parentNode))
00637   {
00638     for (int i=mypos+1; i<(int)parent->childCount(); i++)
00639     {
00640       KateCodeFoldingNode *tmp = parent->takeChild(mypos+1);
00641       tmp->startLineRel -= node->startLineRel;
00642       tmp->parentNode = node; // SHOULD HELP 16.04.2002
00643       node->appendChild(tmp);
00644     }
00645 
00646     // this should fix the bug of wrongly closed nodes
00647     if (!parent->parentNode)
00648       node->endLineValid=false;
00649     else
00650       node->endLineValid = parent->endLineValid;
00651 
00652     node->endLineRel = parent->endLineRel-node->startLineRel;
00653 
00654     if (node->endLineValid)
00655       return removeEnding(parent, getStartLine(parent)+parent->endLineRel);
00656 
00657     return false;
00658   }
00659 
00660   node->endLineValid = false;
00661   node->endLineRel = parent->endLineRel - node->startLineRel;
00662 
00663   return false;
00664 }
00665 
00666 
00667 bool KateCodeFoldingTree::correctEndings(signed char data, KateCodeFoldingNode *node,unsigned int line,unsigned int endCol,int insertPos)
00668 {
00669 //  if (node->type==0) {kError()<<"correct Ending should never be called with the root node"<<endl; return true;}
00670   uint startLine = getStartLine(node);
00671   if (data != -node->type)
00672   {
00673 #if JW_DEBUG
00674     kDebug(13000)<<"data!=-node->type (correctEndings)";
00675 #endif
00676     //invalid close -> add to unopend list
00677     dontDeleteEnding(node);
00678     if (data == node->type) {
00679       node->endCol=endCol;
00680       return false;
00681     }
00682     KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
00683     something_changed = true;
00684     newNode->startLineValid = false;
00685     newNode->endLineValid = true;
00686     newNode->endLineRel = 0;
00687     newNode->endCol=endCol;
00688 
00689     if ((insertPos==-1) || (insertPos==(int)node->childCount()))
00690       node->appendChild(newNode);
00691     else
00692       node->insertChild(insertPos,newNode);
00693 
00694       // find correct position
00695     return false;
00696   }
00697   else
00698   {
00699     something_changed = true;
00700     dontDeleteEnding(node);
00701 
00702     // valid closing region
00703     if (!node->endLineValid)
00704     {
00705       node->endLineValid = true;
00706       node->endLineRel = line - startLine;
00707       node->endCol=endCol;
00708       //moving
00709 
00710       moveSubNodesUp(node);
00711     }
00712     else
00713     {
00714 #if JW_DEBUG
00715       kDebug(13000)<<"Closing a node which had already a valid end";
00716 #endif
00717       // block has already an ending
00718       if (startLine+node->endLineRel == line)
00719       {
00720          node->endCol=endCol;
00721          // we won, just skip
00722 #if JW_DEBUG
00723         kDebug(13000)<< "We won, just skipping (correctEndings)";
00724 #endif
00725       }
00726       else
00727       {
00728         int bakEndLine = node->endLineRel+startLine;
00729         uint bakEndCol = node->endCol;
00730         node->endLineRel = line-startLine;
00731         node->endCol=endCol;
00732 
00733 #if JW_DEBUG
00734         kDebug(13000)<< "reclosed node had childnodes()";
00735         kDebug(13000)<<"It could be, that childnodes() need to be moved up";
00736 #endif
00737   moveSubNodesUp(node);
00738 
00739         if (node->parentNode)
00740         {
00741           correctEndings(data,node->parentNode,bakEndLine, bakEndCol,node->parentNode->findChild(node)+1); // ????
00742         }
00743         else
00744         {
00745           //add to unopened list (bakEndLine)
00746         }
00747       }
00748       }
00749     }
00750     return true;
00751 }
00752 
00753 void KateCodeFoldingTree::moveSubNodesUp(KateCodeFoldingNode *node)
00754 {
00755         int mypos = node->parentNode->findChild(node);
00756         int removepos=-1;
00757         int count = node->childCount();
00758         for (int i=0; i<count; i++)
00759           if (node->child(i)->startLineRel >= node->endLineRel)
00760           {
00761             removepos=i;
00762             break;
00763           }
00764 #if JW_DEBUG
00765         kDebug(13000)<<QString("remove pos: %1").arg(removepos);
00766 #endif
00767         if (removepos>-1)
00768         {
00769 #if JW_DEBUG
00770           kDebug(13000)<<"Children need to be moved";
00771 #endif
00772           KateCodeFoldingNode *moveNode;
00773           if (mypos == (int)node->parentNode->childCount()-1)
00774           {
00775             while (removepos<(int)node->childCount())
00776             {
00777               node->parentNode->appendChild(moveNode=node->takeChild(removepos));
00778               moveNode->parentNode = node->parentNode;
00779               moveNode->startLineRel += node->startLineRel;
00780             }
00781           }
00782           else
00783           {
00784             int insertPos=mypos;
00785             while (removepos < (int)node->childCount())
00786             {
00787               insertPos++;
00788               node->parentNode->insertChild(insertPos, moveNode=node->takeChild(removepos));
00789               moveNode->parentNode = node->parentNode; // That should solve a crash
00790               moveNode->startLineRel += node->startLineRel;
00791             }
00792           }
00793         }
00794 
00795 }
00796 
00797 
00798 
00799 void KateCodeFoldingTree::addOpening(KateCodeFoldingNode *node,signed char nType, QVector<int>* list,unsigned int line,unsigned int charPos)
00800 {
00801   uint startLine = getStartLine(node);
00802   if ((startLine==line) && (node->type!=0))
00803   {
00804 #if JW_DEBUG
00805     kDebug(13000)<<"startLine equals line";
00806 #endif
00807     if (nType == node->type)
00808     {
00809 #if JW_DEBUG
00810       kDebug(13000)<<"Node exists";
00811 #endif
00812       node->deleteOpening = false;
00813       node->startCol=charPos;
00814       KateCodeFoldingNode *parent = node->parentNode;
00815 
00816       if (!node->endLineValid)
00817       {
00818         int current = parent->findChild(node);
00819         int count = parent->childCount()-(current+1);
00820         node->endLineRel = parent->endLineRel - node->startLineRel;
00821 
00822 // EXPERIMENTAL TEST BEGIN
00823 // move this afte the test for unopened, but closed regions within the parent node, or if there are no siblings, bubble up
00824         if (parent->type == node->type)
00825         {
00826           if (parent->endLineValid)
00827           {
00828             removeEnding(parent, line);
00829             node->endLineValid = true;
00830           }
00831         }
00832 
00833 // EXPERIMENTAL TEST BEGIN
00834 
00835         if (current != (int)parent->childCount()-1)
00836         {
00837         //search for an unopened but closed region, even if the parent is of the same type
00838 #ifdef __GNUC__
00839 #warning  "FIXME:  why does this seem to work?"
00840 #endif
00841 //          if (node->type != parent->type)
00842           {
00843             for (int i=current+1; i<(int)parent->childCount(); i++)
00844             {
00845               if (parent->child(i)->type == -node->type)
00846               {
00847                 count = (i-current-1);
00848                 node->endLineValid = true;
00849                 node->endLineRel = getStartLine(parent->child(i))-line;
00850                 node->endCol = parent->child(i)->endCol;
00851                 KateCodeFoldingNode *child = parent->takeChild(i);
00852                 markedForDeleting.removeAll( child );
00853                 delete child;
00854                 break;
00855               }
00856             }
00857           }
00858 //          else
00859 //          {
00860 //            parent->endLineValid = false;
00861 //            parent->endLineRel = 20000;
00862 //          }
00863 
00864           if (count>0)
00865           {
00866             for (int i=0;i<count;i++)
00867             {
00868               KateCodeFoldingNode *tmp;
00869               node->appendChild(tmp=parent->takeChild(current+1));
00870               tmp->startLineRel -= node->startLineRel;
00871               tmp->parentNode = node;
00872             }
00873           }
00874         }
00875 
00876       }
00877 
00878       addOpening_further_iterations(node, nType, list, line, 0, startLine,node->startCol);
00879 
00880     } //else ohoh, much work to do same line, but other region type
00881   }
00882   else
00883   { // create a new region
00884     KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,nType,line-startLine);
00885     something_changed = true;
00886 
00887     int insert_position=-1;
00888     for (int i=0; i<(int)node->childCount(); i++)
00889     {
00890       if (startLine+node->child(i)->startLineRel > line)
00891       {
00892          insert_position=i;
00893          break;
00894       }
00895     }
00896 
00897     int current;
00898     if (insert_position==-1)
00899     {
00900       node->appendChild(newNode);
00901       current = node->childCount()-1;
00902     }
00903     else
00904     {
00905       node->insertChild(insert_position, newNode);
00906       current = insert_position;
00907     }
00908 
00909 //    if (node->type==newNode->type)
00910 //    {
00911 //      newNode->endLineValid=true;
00912 //      node->endLineValid=false;
00913 //      newNode->endLineRel=node->endLineRel-newNode->startLineRel;
00914 //      node->endLineRel=20000; //FIXME
00915 
00916       int count = node->childCount() - (current+1);
00917       newNode->endLineRel -= newNode->startLineRel;
00918       if (current != (int)node->childCount()-1)
00919       {
00920         if (node->type != newNode->type)
00921         {
00922           for (int i=current+1; i<(int)node->childCount(); i++)
00923           {
00924             if (node->child(i)->type == -newNode->type)
00925             {
00926               count = node->childCount() - i - 1;
00927               newNode->endLineValid = true;
00928               newNode->endLineRel = line - getStartLine(node->child(i));
00929               KateCodeFoldingNode *child = node->takeChild(i);
00930               markedForDeleting.removeAll( child );
00931               delete child;
00932               break;
00933             }
00934           }
00935         }
00936         else
00937         {
00938           node->endLineValid = false;
00939           node->endLineRel = 10000;
00940         }
00941         if (count > 0)
00942         {
00943           for (int i=0;i<count;i++)
00944           {
00945             KateCodeFoldingNode *tmp;
00946             newNode->appendChild(tmp=node->takeChild(current+1));
00947             tmp->parentNode=newNode;
00948           }
00949         }
00950 //      }
00951     }
00952 
00953     addOpening(newNode, nType, list, line,charPos);
00954 
00955     addOpening_further_iterations(node, node->type, list, line, current, startLine,node->startCol);
00956   }
00957 }
00958 
00959 
00960 void KateCodeFoldingTree::addOpening_further_iterations(KateCodeFoldingNode *node,signed char /* nType */, QVector<int>*
00961     list,unsigned int line,int current, unsigned int startLine,unsigned int charPos)
00962 {
00963   while (!(list->isEmpty()))
00964   {
00965     if (list->isEmpty())
00966       return;
00967     else
00968     {
00969          signed char data = (*list)[list->size()-2];
00970          uint charPos=(*list)[list->size()-1];
00971        list->resize (list->size()-2);
00972 
00973       if (data<0)
00974       {
00975 #if JW_DEBUG
00976         kDebug(13000)<<"An ending was found";
00977 #endif
00978 
00979         if (correctEndings(data,node,line,charPos,-1))
00980           return; // -1 ?
00981 
00982 #if 0
00983         if(data == -nType)
00984         {
00985           if (node->endLineValid)
00986           {
00987             if (node->endLineRel+startLine==line) // We've won again
00988             {
00989               //handle next node;
00990             }
00991             else
00992             { // much moving
00993               node->endLineRel=line-startLine;
00994               node->endLineValid=true;
00995             }
00996             return;  // next higher level should do the rest
00997           }
00998           else
00999           {
01000             node->endLineRel=line-startLine;
01001             node->endLineValid=true;
01002             //much moving
01003           }
01004         } //else add to unopened list
01005 #endif
01006       }
01007       else
01008       {
01009         bool needNew = true;
01010         if (current < (int)node->childCount())
01011         {
01012           if (getStartLine(node->child(current)) == line)
01013             needNew=false;
01014         }
01015         if (needNew)
01016         {
01017           something_changed = true;
01018           KateCodeFoldingNode *newNode = new KateCodeFoldingNode(node, data, line-startLine);
01019           node->insertChild(current, newNode);  //find the correct position later
01020         }
01021 
01022                addOpening(node->child(current), data, list, line,charPos);
01023         current++;
01024         //lookup node or create subnode
01025       }
01026     }
01027   } // end while
01028 }
01029 
01030 unsigned int KateCodeFoldingTree::getStartLine(KateCodeFoldingNode *node)
01031 {
01032   unsigned int lineStart=0;
01033   for (KateCodeFoldingNode *iter=node; iter->type != 0; iter=iter->parentNode)
01034     lineStart += iter->startLineRel;
01035 
01036   return lineStart;
01037 }
01038 
01039 
01040 void KateCodeFoldingTree::lineHasBeenRemoved(unsigned int line)
01041 {
01042   lineMapping.clear();
01043   dontIgnoreUnchangedLines.insert(line);
01044   dontIgnoreUnchangedLines.insert(line-1);
01045   dontIgnoreUnchangedLines.insert(line+1);
01046   hiddenLinesCountCacheValid = false;
01047 #if JW_DEBUG
01048   kDebug(13000)<<QString("KateCodeFoldingTree::lineHasBeenRemoved: %1").arg(line);
01049 #endif
01050 
01051 //line ++;
01052   findAndMarkAllNodesforRemovalOpenedOrClosedAt(line); //It's an ugly solution
01053   cleanupUnneededNodes(line);  //It's an ugly solution
01054 
01055   KateCodeFoldingNode *node = findNodeForLine(line);
01056 //?????  if (node->endLineValid)
01057   {
01058     int startLine = getStartLine(node);
01059     if (startLine == (int)line)
01060       node->startLineRel--;
01061     else
01062     {
01063       if (node->endLineRel == 0)
01064         node->endLineValid = false;
01065       node->endLineRel--;
01066     }
01067 
01068     int count = node->childCount();
01069     for (int i=0; i<count; i++)
01070     {
01071       if (node->child(i)->startLineRel+startLine >= line)
01072         node->child(i)->startLineRel--;
01073     }
01074   }
01075 
01076   if (node->parentNode)
01077     decrementBy1(node->