• Skip to content
  • Skip to link menu
KDE 4.1 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->parentNode, node);
01078 
01079   for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it != hiddenLines.end(); ++it)
01080   {
01081     if ((*it).start > line)
01082       (*it).start--;
01083     else if ((*it).start+(*it).length > line)
01084       (*it).length--;
01085   }
01086 }
01087 
01088 
01089 void KateCodeFoldingTree::decrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after)
01090 {
01091   if (node->endLineRel == 0)
01092     node->endLineValid = false;
01093   node->endLineRel--;
01094 
01095   for (int i=node->findChild(after)+1; i < node->childCount(); ++i)
01096     node->child(i)->startLineRel--;
01097 
01098   if (node->parentNode)
01099     decrementBy1(node->parentNode,node);
01100 }
01101 
01102 
01103 void KateCodeFoldingTree::lineHasBeenInserted(unsigned int line)
01104 {
01105   lineMapping.clear();
01106   dontIgnoreUnchangedLines.insert(line);
01107   dontIgnoreUnchangedLines.insert(line-1l);
01108   dontIgnoreUnchangedLines.insert(line+1);
01109   hiddenLinesCountCacheValid = false;
01110 //return;
01111 #if JW_DEBUG
01112   kDebug(13000)<<QString("KateCodeFoldingTree::lineHasBeenInserted: %1").arg(line);
01113 #endif
01114 
01115 //  findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
01116 //  cleanupUnneededNodes(line);
01117 
01118   KateCodeFoldingNode *node = findNodeForLine(line);
01119 // ????????  if (node->endLineValid)
01120   {
01121     int startLine=getStartLine(node);
01122     if (node->type < 0)
01123       node->startLineRel++;
01124     else
01125       node->endLineRel++;
01126 
01127     for (int i=0; i < node->childCount(); ++i)
01128     {
01129       KateCodeFoldingNode *iter = node->child(i);
01130 
01131       if (iter->startLineRel+startLine >= line)
01132         iter->startLineRel++;
01133     }
01134   }
01135 
01136   if (node->parentNode)
01137     incrementBy1(node->parentNode, node);
01138 
01139   for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
01140   {
01141     if ((*it).start > line)
01142       (*it).start++;
01143     else if ((*it).start+(*it).length > line)
01144       (*it).length++;
01145   }
01146 }
01147 
01148 void KateCodeFoldingTree::incrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after)
01149 {
01150   node->endLineRel++;
01151 
01152   for (int i=node->findChild(after)+1; i < node->childCount(); ++i)
01153     node->child(i)->startLineRel++;
01154 
01155   if (node->parentNode)
01156     incrementBy1(node->parentNode,node);
01157 }
01158 
01159 
01160 void KateCodeFoldingTree::findAndMarkAllNodesforRemovalOpenedOrClosedAt(unsigned int line)
01161 {
01162 #ifdef __GNUC__
01163 #warning "FIXME:  make this multiple region changes per line save";
01164 #endif
01165 //  return;
01166   markedForDeleting.clear();
01167   KateCodeFoldingNode *node = findNodeForLine(line);
01168   if (node->type == 0)
01169     return;
01170 
01171   addNodeToRemoveList(node, line);
01172 
01173   while (((node->parentNode) && (node->parentNode->type!=0)) && (getStartLine(node->parentNode)==line))
01174   {
01175     node = node->parentNode;
01176     addNodeToRemoveList(node, line);
01177   }
01178 #if JW_DEBUG
01179   kDebug(13000)<<" added line to markedForDeleting list";
01180 #endif
01181 }
01182 
01183 
01184 void KateCodeFoldingTree::addNodeToRemoveList(KateCodeFoldingNode *node,unsigned int line)
01185 {
01186   bool add=false;
01187 #ifdef __GNUC__
01188 #warning "FIXME:  make this multiple region changes per line save";
01189 #endif
01190   unsigned int startLine=getStartLine(node);
01191   if ((startLine==line) && (node->startLineValid))
01192   {
01193     add=true;
01194     node->deleteOpening = true;
01195   }
01196   if ((startLine+node->endLineRel==line) || ((node->endLineValid==false) && (node->deleteOpening)))
01197   {
01198     int myPos=node->parentNode->findChild(node); // this has to be implemented nicely
01199     if ((int)node->parentNode->childCount()>myPos+1)
01200      addNodeToRemoveList(node->parentNode->child(myPos+1),line);
01201     add=true;
01202     node->deleteEnding = true;
01203   }
01204 
01205   if(add)
01206   markedForDeleting.append(node);
01207 
01208 }
01209 
01210 
01211 void KateCodeFoldingTree::findAllNodesOpenedOrClosedAt(unsigned int line)
01212 {
01213   nodesForLine.clear();
01214   KateCodeFoldingNode *node = findNodeForLine(line);
01215   if (node->type == 0)
01216     return;
01217 
01218   unsigned int startLine = getStartLine(node);
01219   if (startLine == line)
01220     nodesForLine.append(node);
01221   else if ((startLine+node->endLineRel == line))
01222     nodesForLine.append(node);
01223 
01224   while (node->parentNode)
01225   {
01226     addNodeToFoundList(node->parentNode, line, node->parentNode->findChild(node));
01227     node = node->parentNode;
01228   }
01229 #if JW_DEBUG
01230   kDebug(13000)<<" added line to nodesForLine list";
01231 #endif
01232 }
01233 
01234 
01235 void KateCodeFoldingTree::addNodeToFoundList(KateCodeFoldingNode *node,unsigned int line,int childpos)
01236 {
01237   unsigned int startLine = getStartLine(node);
01238 
01239   if ((startLine==line) && (node->type!=0))
01240     nodesForLine.append(node);
01241   else if ((startLine+node->endLineRel==line) && (node->type!=0))
01242     nodesForLine.append(node);
01243 
01244   for (int i=childpos+1; i<(int)node->childCount(); i++)
01245   {
01246     KateCodeFoldingNode *child = node->child(i);
01247 
01248     if (startLine+child->startLineRel == line)
01249     {
01250       nodesForLine.append(child);
01251       addNodeToFoundList(child, line, 0);
01252     }
01253     else
01254       break;
01255   }
01256 }
01257 
01258 
01259 void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line)
01260 {
01261 #if JW_DEBUG
01262   kDebug(13000)<<"void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line)";
01263 #endif
01264 
01265 //  return;
01266   if (markedForDeleting.isEmpty())
01267     return;
01268 
01269   for (int i=0; i<(int)markedForDeleting.count(); i++)
01270   {
01271     KateCodeFoldingNode *node = markedForDeleting.at(i);
01272     if (node->deleteOpening)
01273       kDebug(13000)<<"DELETE OPENING SET";
01274     if (node->deleteEnding)
01275       kDebug(13000)<<"DELETE ENDING SET";
01276 
01277     if ((node->deleteOpening) && (node->deleteEnding))
01278     {
01279 #if JW_DEBUG
01280       kDebug(13000)<<"Deleting complete node";
01281 #endif
01282       if (node->endLineValid)    // just delete it, it has been opened and closed on this line
01283       {
01284         int f = node->parentNode->findChild (node);
01285 
01286         if (f >= 0)
01287           delete node->parentNode->takeChild(f);
01288       }
01289       else
01290       {
01291         removeOpening(node, line);
01292         // the node has subnodes which need to be moved up and this one has to be deleted
01293       }
01294       something_changed = true;
01295     }
01296     else
01297     {
01298       if ((node->deleteOpening) && (node->startLineValid))
01299       {
01300 #if JW_DEBUG
01301         kDebug(13000)<<"calling removeOpening";
01302 #endif
01303         removeOpening(node, line);
01304         something_changed = true;
01305       }
01306       else
01307       {
01308         dontDeleteOpening(node);
01309 
01310         if ((node->deleteEnding) && (node->endLineValid))
01311         {
01312           dontDeleteEnding(node);
01313           removeEnding(node, line);
01314           something_changed = true;
01315         }
01316         else
01317           dontDeleteEnding(node);
01318       }
01319     }
01320   }
01321 }
01322 
01323 void KateCodeFoldingTree::dontDeleteEnding(KateCodeFoldingNode* node)
01324 {
01325   node->deleteEnding = false;
01326 }
01327 
01328 
01329 void KateCodeFoldingTree::dontDeleteOpening(KateCodeFoldingNode* node)
01330 {
01331   node->deleteOpening = false;
01332 }
01333 
01334 
01335 void KateCodeFoldingTree::toggleRegionVisibility(unsigned int line)
01336 {
01337   // hl whole file
01338   m_buffer->line (m_buffer->count()-1);
01339 
01340   lineMapping.clear();
01341   hiddenLinesCountCacheValid = false;
01342   kDebug(13000)<<QString("KateCodeFoldingTree::toggleRegionVisibility() %1").arg(line);
01343 
01344   findAllNodesOpenedOrClosedAt(line);
01345   for (int i=0; i<(int)nodesForLine.count(); i++)
01346   {
01347     KateCodeFoldingNode *node=nodesForLine.at(i);
01348     if ( (!node->startLineValid) || (getStartLine(node) != line) )
01349     {
01350       nodesForLine.removeAt(i);
01351       if (!node->startLineValid) addNodeToRemoveList(node, line);
01352       i--;
01353     }
01354   }
01355 
01356   if (nodesForLine.isEmpty())
01357     return;
01358 
01359   nodesForLine.at(0)->visible = !nodesForLine.at(0)->visible;
01360 
01361   if (!nodesForLine.at(0)->visible)
01362     addHiddenLineBlock(nodesForLine.at(0),line);
01363   else
01364   {
01365     for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it!=hiddenLines.end();++it)
01366       if ((*it).start == line+1)
01367       {
01368         hiddenLines.erase(it);
01369         break;
01370       }
01371 
01372     updateHiddenSubNodes(nodesForLine.at(0));
01373   }
01374 
01375   emit regionVisibilityChangedAt(line);
01376 }
01377 
01378 void KateCodeFoldingTree::updateHiddenSubNodes(KateCodeFoldingNode *node)
01379 {
01380   for (int i=0; i < node->childCount(); ++i)
01381   {
01382     KateCodeFoldingNode *iter = node->child(i);
01383 
01384     if (!iter->visible)
01385       addHiddenLineBlock(iter, getStartLine(iter));
01386     else
01387       updateHiddenSubNodes(iter);
01388   }
01389 }
01390 
01391 void KateCodeFoldingTree::addHiddenLineBlock(KateCodeFoldingNode *node,unsigned int line)
01392 {
01393   KateHiddenLineBlock data;
01394   data.start = line+1;
01395   data.length = node->endLineRel-(existsOpeningAtLineAfter(line+node->endLineRel,node)?1:0); // without -1;
01396   bool inserted = false;
01397 
01398   for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
01399   {
01400     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
01401     {
01402       // the existing block can't have lines behind the new one, because a newly hidden
01403       //  block has to encapsulate already hidden ones
01404       it=hiddenLines.erase(it);
01405       --it;
01406     }
01407     else
01408     {
01409       if ((*it).start > line)
01410       {
01411         hiddenLines.insert(it, data);
01412         inserted = true;
01413 
01414         break;
01415       }
01416     }
01417   }
01418 
01419   if (!inserted)
01420     hiddenLines.append(data);
01421 }
01422 
01423 bool KateCodeFoldingTree::existsOpeningAtLineAfter(unsigned int line, KateCodeFoldingNode *node)
01424 {
01425   for(KateCodeFoldingNode *tmp = node->parentNode; tmp; tmp=tmp->parentNode)
01426   {
01427     KateCodeFoldingNode *tmp2;
01428     unsigned int startLine=getStartLine(tmp);
01429 
01430     if ( (tmp->findChild(node)+1) >= tmp->childCount()) return false;
01431     if ((tmp2 = tmp->child(tmp->findChild(node) + 1))
01432          && ((tmp2->startLineRel + startLine) == line))
01433       return true;
01434 
01435     if ((startLine + tmp->endLineRel) > line)
01436       return false;
01437   }
01438 
01439   return false;
01440 }
01441 
01442 
01443 //
01444 // get the real line number for a virtual line
01445 //
01446 unsigned int KateCodeFoldingTree::getRealLine(unsigned int virtualLine)
01447 {
01448   // he, if nothing is hidden, why look at it ;)
01449   if (hiddenLines.isEmpty())
01450     return virtualLine;
01451 
01452   // kDebug(13000)<<QString("VirtualLine %1").arg(virtualLine);
01453 
01454   if (lineMapping.contains(virtualLine))
01455     return lineMapping[virtualLine];
01456 
01457   unsigned int tmp = virtualLine;
01458   for (QList<KateHiddenLineBlock>::const_iterator it=hiddenLines.begin();it!=hiddenLines.end();++it)
01459   {
01460     if ((*it).start<=virtualLine)
01461       virtualLine += (*it).length;
01462     else
01463       break;
01464   }
01465 
01466   // kDebug(13000)<<QString("Real Line %1").arg(virtualLine);
01467 
01468   lineMapping.insert(tmp, virtualLine);
01469   return virtualLine;
01470 }
01471 
01472 //
01473 // get the virtual line number for a real line
01474 //
01475 unsigned int KateCodeFoldingTree::getVirtualLine(unsigned int realLine)
01476 {
01477   // he, if nothing is hidden, why look at it ;)
01478   if (hiddenLines.isEmpty())
01479     return realLine;
01480 
01481   // kDebug(13000)<<QString("RealLine--> %1").arg(realLine);
01482 
01483   for (int i = hiddenLines.size()-1; i >= 0; --i)
01484   {
01485     if (hiddenLines[i].start <= realLine)
01486       realLine -= hiddenLines[i].length;
01487     // else
01488       // break;
01489   }
01490 
01491   // kDebug(13000)<<QString("-->virtual Line %1").arg(realLine);
01492 
01493   return realLine;
01494 }
01495 
01496 //
01497 // get the number of hidden lines
01498 //
01499 unsigned int KateCodeFoldingTree::getHiddenLinesCount(unsigned int doclen)
01500 {
01501   // he, if nothing is hidden, why look at it ;)
01502   if (hiddenLines.isEmpty())
01503     return 0;
01504 
01505   if (hiddenLinesCountCacheValid)
01506     return hiddenLinesCountCache;
01507 
01508   hiddenLinesCountCacheValid = true;
01509   hiddenLinesCountCache = 0;
01510 
01511   for (QList<KateHiddenLineBlock>::const_iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
01512   {
01513     if ((*it).start+(*it).length<=doclen)
01514       hiddenLinesCountCache += (*it).length;
01515     else
01516     {
01517       hiddenLinesCountCache += ((*it).length- ((*it).length + (*it).start - doclen));
01518       break;
01519     }
01520   }
01521 
01522   return hiddenLinesCountCache;
01523 }
01524 
01525 void KateCodeFoldingTree::collapseToplevelNodes()
01526 {
01527   // hl whole file
01528   m_buffer->line (m_buffer->count()-1);
01529 
01530   if (m_root.noChildren ())
01531     return;
01532 
01533   for ( int i=0; i < m_root.childCount(); ++i )
01534   {
01535     KateCodeFoldingNode *node = m_root.child(i);
01536 
01537     if (node->visible && node->startLineValid && node->endLineValid)
01538     {
01539         node->visible=false;
01540         lineMapping.clear();
01541         hiddenLinesCountCacheValid = false;
01542         addHiddenLineBlock(node,node->startLineRel);
01543         emit regionVisibilityChangedAt(node->startLineRel);
01544     }
01545   }
01546 }
01547 
01548 void KateCodeFoldingTree::expandToplevelNodes(int numLines)
01549 {
01550   // hl whole file
01551   m_buffer->line (m_buffer->count()-1);
01552 
01553   KateLineInfo line;
01554   for (int i = 0; i < numLines; i++) {
01555     getLineInfo(&line, i);
01556 
01557     if (line.startsInVisibleBlock)
01558       toggleRegionVisibility(i);
01559   }
01560 }
01561 
01562 int KateCodeFoldingTree::collapseOne(int realLine)
01563 {
01564   // hl whole file
01565   m_buffer->line (m_buffer->count()-1);
01566 
01567   KateLineInfo line;
01568   int unrelatedBlocks = 0;
01569   for (int i = realLine; i >= 0; i--) {
01570     getLineInfo(&line, i);
01571 
01572     if (line.topLevel && !line.endsBlock)
01573       // optimization
01574       break;
01575 
01576     if (line.endsBlock  && ( line.invalidBlockEnd ) && (i != realLine)) {
01577       unrelatedBlocks++;
01578     }
01579 
01580     if (line.startsVisibleBlock) {
01581       unrelatedBlocks--;
01582       if (unrelatedBlocks == -1) {
01583         toggleRegionVisibility(i);
01584         return i;
01585       }
01586     }
01587   }
01588   return -1;
01589 }
01590 
01591 void KateCodeFoldingTree::expandOne(int realLine, int numLines)
01592 {
01593   // hl whole file
01594   m_buffer->line (m_buffer->count()-1);
01595 
01596   KateLineInfo line;
01597   int blockTrack = 0;
01598   for (int i = realLine; i >= 0; i--) {
01599     getLineInfo(&line, i);
01600 
01601     if (line.topLevel)
01602       // done
01603       break;
01604 
01605     if (line.startsInVisibleBlock && i != realLine) {
01606       if (blockTrack == 0)
01607         toggleRegionVisibility(i);
01608 
01609       blockTrack--;
01610     }
01611 
01612     if (line.endsBlock)
01613       blockTrack++;
01614 
01615     if (blockTrack < 0)
01616       // too shallow
01617       break;
01618   }
01619 
01620   blockTrack = 0;
01621   for (int i = realLine; i < numLines; i++) {
01622     getLineInfo(&line, i);
01623 
01624     if (line.topLevel)
01625       // done
01626       break;
01627 
01628     if (line.startsInVisibleBlock) {
01629       if (blockTrack == 0)
01630         toggleRegionVisibility(i);
01631 
01632       blockTrack++;
01633     }
01634 
01635     if (line.endsBlock)
01636       blockTrack--;
01637 
01638     if (blockTrack < 0)
01639       // too shallow
01640       break;
01641   }
01642 }
01643 
01644 void KateCodeFoldingTree::ensureVisible( uint line )
01645 {
01646   // first have a look, if the line is really hidden
01647   bool found=false;
01648   for (QList<KateHiddenLineBlock>::const_iterator it=hiddenLines.begin();it!=hiddenLines.end();++it)
01649   {
01650     if ( ((*it).start<=line)  && ((*it).start+(*it).length>line) )
01651     {
01652       found=true;
01653       break;
01654     }
01655   }
01656 
01657 
01658   if (!found) return;
01659 
01660   kDebug(13000)<<"line "<<line<<" is really hidden ->show block";
01661 
01662   // it looks like we really have to ensure visibility
01663   KateCodeFoldingNode *n = findNodeForLine( line );
01664   do {
01665     if ( ! n->visible )
01666       toggleRegionVisibility( getStartLine( n ) );
01667     n = n->parentNode;
01668   } while( n );
01669 
01670 }
01671 
01672 // kate: space-indent on; indent-width 2; replace-tabs on;

Kate

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

kdelibs

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