/* This file is part of the KDE libraries
Copyright ( C ) 2002 Joseph Wenninger < jowenn @ kde . org >
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Library General Public License for more details .
You should have received a copy of the GNU Library General Public License
along with this library ; see the file COPYING . LIB . If not , write to
the Free Software Foundation , Inc . , 51 Franklin Street , Fifth Floor ,
Boston , MA 02110 - 1301 , USA .
*/
# include "katecodefoldinghelpers.h"
# include "katecodefoldinghelpers.moc"
# include "katebuffer.h"
# include "katecursor.h"
# include <kdebug.h>
# include <tqstring.h>
# define JW_DEBUG 0
bool KateCodeFoldingTree : : trueVal = true ;
KateCodeFoldingNode : : KateCodeFoldingNode ( ) :
parentNode ( 0 ) ,
startLineRel ( 0 ) ,
endLineRel ( 0 ) ,
startCol ( 0 ) ,
endCol ( 0 ) ,
startLineValid ( false ) ,
endLineValid ( false ) ,
type ( 0 ) ,
visible ( true ) ,
deleteOpening ( false ) ,
deleteEnding ( false )
{
} //the endline fields should be initialised to not valid
KateCodeFoldingNode : : KateCodeFoldingNode ( KateCodeFoldingNode * par , signed char typ , unsigned int sLRel ) :
parentNode ( par ) ,
startLineRel ( sLRel ) ,
endLineRel ( 10000 ) ,
startCol ( 0 ) ,
endCol ( 0 ) ,
startLineValid ( true ) ,
endLineValid ( false ) ,
type ( typ ) ,
visible ( true ) ,
deleteOpening ( false ) ,
deleteEnding ( false )
{
} //the endline fields should be initialised to not valid
KateCodeFoldingNode : : ~ KateCodeFoldingNode ( )
{
// delete all child nodes
clearChildren ( ) ;
}
bool KateCodeFoldingNode : : getBegin ( KateCodeFoldingTree * tree , KateTextCursor * begin ) {
if ( ! startLineValid ) return false ;
unsigned int line = startLineRel ;
for ( KateCodeFoldingNode * n = parentNode ; n ; n = n - > parentNode )
line + = n - > startLineRel ;
tree - > m_buffer - > codeFoldingColumnUpdate ( line ) ;
begin - > setLine ( line ) ;
begin - > setCol ( startCol ) ;
return true ;
}
bool KateCodeFoldingNode : : getEnd ( KateCodeFoldingTree * tree , KateTextCursor * end ) {
if ( ! endLineValid ) return false ;
unsigned int line = startLineRel + endLineRel ;
for ( KateCodeFoldingNode * n = parentNode ; n ; n = n - > parentNode )
line + = n - > startLineRel ;
tree - > m_buffer - > codeFoldingColumnUpdate ( line ) ;
end - > setLine ( line ) ;
end - > setCol ( endCol ) ;
return true ;
}
int KateCodeFoldingNode : : cmpPos ( KateCodeFoldingTree * tree , uint line , uint col ) {
KateTextCursor cur ( line , col ) ;
KateTextCursor start , end ;
kdDebug ( 13000 ) < < " KateCodeFoldingNode::cmpPos (1) " < < endl ;
bool startValid = getBegin ( tree , & start ) ;
kdDebug ( 13000 ) < < " KateCodeFoldingNode::cmpPos (2) " < < endl ;
bool endValid = getEnd ( tree , & end ) ;
kdDebug ( 13000 ) < < " KateCodeFoldingNode::cmpPos (3) " < < endl ;
if ( ( ! endValid ) & & startValid ) {
return ( ( start > cur ) ? - 1 : 0 ) ;
}
if ( ( ! startValid ) & & endValid ) {
return ( ( cur > end ) ? 1 : 0 ) ;
}
//here both have to be valid, both invalid must not happen
Q_ASSERT ( startValid & & endValid ) ;
return ( ( cur < start ) ? ( - 1 ) : ( ( cur > end ) ? 1 : 0 ) ) ;
}
void KateCodeFoldingNode : : insertChild ( uint index , KateCodeFoldingNode * node )
{
uint s = m_children . size ( ) ;
if ( index > s )
return ;
m_children . resize ( + + s ) ;
for ( uint i = s - 1 ; i > index ; - - i )
m_children [ i ] = m_children [ i - 1 ] ;
m_children [ index ] = node ;
}
KateCodeFoldingNode * KateCodeFoldingNode : : takeChild ( uint index )
{
uint s = m_children . size ( ) ;
if ( index > = s )
return 0 ;
KateCodeFoldingNode * n = m_children [ index ] ;
for ( uint i = index ; ( i + 1 ) < s ; + + i )
m_children [ i ] = m_children [ i + 1 ] ;
m_children . resize ( s - 1 ) ;
return n ;
}
void KateCodeFoldingNode : : clearChildren ( )
{
for ( uint i = 0 ; i < m_children . size ( ) ; + + i )
delete m_children [ i ] ;
m_children . resize ( 0 ) ;
}
KateCodeFoldingTree : : KateCodeFoldingTree ( KateBuffer * buffer ) : TQObject ( buffer ) , m_buffer ( buffer )
{
clear ( ) ;
}
void KateCodeFoldingTree : : fixRoot ( int endLRel )
{
m_root . endLineRel = endLRel ;
}
void KateCodeFoldingTree : : clear ( )
{
m_root . clearChildren ( ) ;
// initialize the root "special" node
m_root . startLineValid = true ;
m_root . endLineValid = true ; // temporary, should be false;
m_root . endLineRel = 1 ; // temporary;
hiddenLinesCountCacheValid = false ;
lineMapping . setAutoDelete ( true ) ;
hiddenLines . clear ( ) ;
lineMapping . clear ( ) ;
nodesForLine . clear ( ) ;
markedForDeleting . clear ( ) ;
dontIgnoreUnchangedLines . clear ( ) ;
}
KateCodeFoldingTree : : ~ KateCodeFoldingTree ( )
{
}
bool KateCodeFoldingTree : : isTopLevel ( unsigned int line )
{
if ( m_root . noChildren ( ) )
return true ; // no childs
// look if a given lines belongs to a sub node
for ( uint i = 0 ; i < m_root . childCount ( ) ; + + i )
{
KateCodeFoldingNode * node = m_root . child ( i ) ;
if ( ( node - > startLineRel < = line ) & & ( line < = node - > startLineRel + node - > endLineRel ) )
return false ; // the line is within the range of a subnode -> return toplevel=false
}
return true ; // the root node is the only node containing the given line, return toplevel=true
}
void KateCodeFoldingTree : : getLineInfo ( KateLineInfo * info , unsigned int line )
{
// Initialze the returned structure, this will also be returned if the root node has no child nodes
// or the line is not within a childnode's range.
info - > topLevel = true ;
info - > startsVisibleBlock = false ;
info - > startsInVisibleBlock = false ;
info - > endsBlock = false ;
info - > invalidBlockEnd = false ;
if ( m_root . noChildren ( ) )
return ;
//let's look for some information
for ( uint i = 0 ; i < m_root . childCount ( ) ; + + i )
{
KateCodeFoldingNode * node = m_root . child ( i ) ;
if ( ( node - > startLineRel < = line ) & & ( line < = node - > startLineRel + node - > endLineRel ) ) // we found a node, which contains the given line -> do a complete lookup
{
info - > topLevel = false ; //we are definitly not toplevel
findAllNodesOpenedOrClosedAt ( line ) ; //lookup all nodes, which start or and at the given line
for ( KateCodeFoldingNode * node = nodesForLine . first ( ) ; node ; node = nodesForLine . next ( ) )
{
uint startLine = getStartLine ( node ) ;
// type<0 means, that a region has been closed, but not opened
// eg. parantheses missmatch
if ( node - > type < 0 )
info - > invalidBlockEnd = true ;
else
{
if ( startLine ! = line ) // does the region we look at not start at the given line
info - > endsBlock = true ; // than it has to be an ending
else
{
// The line starts a new region, now determine, if it's a visible or a hidden region
if ( node - > visible )
info - > startsVisibleBlock = true ;
else
info - > startsInVisibleBlock = true ;
}
}
}
return ;
}
}
return ;
}
KateCodeFoldingNode * KateCodeFoldingTree : : findNodeForLine ( unsigned int line )
{
if ( m_root . noChildren ( ) ) // does we have child list + nodes ?
return & m_root ;
// lets look, if given line is within a subnode range, and then return the deepest one.
for ( uint i = 0 ; i < m_root . childCount ( ) ; + + i )
{
KateCodeFoldingNode * node = m_root . child ( i ) ;
if ( ( node - > startLineRel < = line ) & & ( line < = node - > startLineRel + node - > endLineRel ) )
{
// a region surounds the line, look in the next deeper hierarchy step
return findNodeForLineDescending ( node , line , 0 ) ;
}
}
return & m_root ;
}
KateCodeFoldingNode * KateCodeFoldingTree : : findNodeForLineDescending ( KateCodeFoldingNode * node ,
unsigned int line , unsigned int offset , bool oneStepOnly )
{
if ( node - > noChildren ( ) )
return node ;
// calculate the offset, between a subnodes real start line and its relative start
offset + = node - > startLineRel ;
for ( uint i = 0 ; i < node - > childCount ( ) ; + + i )
{
KateCodeFoldingNode * subNode = node - > child ( i ) ;
if ( ( subNode - > startLineRel + offset < = line ) & & ( line < = subNode - > endLineRel + subNode - > startLineRel + offset ) ) //warning fix me for invalid ends
{
// a subnode contains the line.
// if oneStepOnly is true, we don't want to search for the deepest node, just return the found one
if ( oneStepOnly )
return subNode ;
else
return findNodeForLineDescending ( subNode , line , offset ) ; // look into the next deeper hierarchy step
}
}
return node ; // the current node has no sub nodes, or the line couldn'te be found within a subregion
}
KateCodeFoldingNode * KateCodeFoldingTree : : findNodeForPosition ( unsigned int line , unsigned int column )
{
KateCodeFoldingNode * node = findNodeForLine ( line ) ;
if ( node = = & m_root ) return & m_root ;
kdDebug ( 13000 ) < < " initial cmpPos " < < endl ;
KateCodeFoldingNode * tmp ;
int leq = node - > cmpPos ( this , line , column ) ;
while ( true ) {
switch ( leq ) {
case 0 : {
if ( node - > noChildren ( ) )
return node ;
else
{
tmp = node ;
for ( uint i = 0 ; i < node - > childCount ( ) ; + + i )
{
KateCodeFoldingNode * subNode = node - > child ( i ) ;
kdDebug ( 13000 ) < < " cmdPos(case0):calling " < < endl ;
leq = subNode - > cmpPos ( this , line , column ) ;
kdDebug ( 13000 ) < < " cmdPos(case0):returned " < < endl ;
if ( leq = = 0 ) {
tmp = subNode ;
break ;
} else if ( leq = = - 1 ) break ;
}
if ( tmp ! = node ) node = tmp ; else return node ;
}
break ;
}
//this could be optimized a littlebit
case - 1 :
case 1 : {
if ( ! ( node - > parentNode ) ) return & m_root ;
kdDebug ( 13000 ) < < " current node type " < < node - > type < < endl ;
node = node - > parentNode ;
kdDebug ( 13000 ) < < " cmdPos(case-1/1):calling: " < < node < < endl ;
leq = node - > cmpPos ( this , line , column ) ;
kdDebug ( 13000 ) < < " cmdPos(case-1/1):returned " < < endl ;
break ;
}
}
}
Q_ASSERT ( false ) ;
return & m_root ;
}
void KateCodeFoldingTree : : debugDump ( )
{
//dump all nodes for debugging
kdDebug ( 13000 ) < < " The parsed region/block tree for code folding " < < endl ;
dumpNode ( & m_root , " " ) ;
}
void KateCodeFoldingTree : : dumpNode ( KateCodeFoldingNode * node , const TQString & prefix )
{
//output node properties
kdDebug ( 13000 ) < < prefix < < TQString ( TQString ( " Type: %1, startLineValid %2, startLineRel %3, endLineValid %4, endLineRel %5, visible %6 " ) .
arg ( node - > type ) . arg ( node - > startLineValid ) . arg ( node - > startLineRel ) . arg ( node - > endLineValid ) .
arg ( node - > endLineRel ) . arg ( node - > visible ) ) < < endl ;
//output child node properties recursive
if ( node - > noChildren ( ) )
return ;
TQString newprefix ( prefix + " " ) ;
for ( uint i = 0 ; i < node - > childCount ( ) ; + + i )
dumpNode ( node - > child ( i ) , newprefix ) ;
}
/*
That ' s one of the most important functions ; )
*/
void KateCodeFoldingTree : : updateLine ( unsigned int line ,
TQMemArray < uint > * regionChanges , bool * updated , bool changed , bool colsChanged )
{
if ( ( ! changed ) | | colsChanged )
{
if ( dontIgnoreUnchangedLines . isEmpty ( ) )
return ;
if ( dontIgnoreUnchangedLines [ line ] )
dontIgnoreUnchangedLines . remove ( line ) ;
else
return ;
}
something_changed = false ;
findAndMarkAllNodesforRemovalOpenedOrClosedAt ( line ) ;
if ( regionChanges - > isEmpty ( ) )
{
// KateCodeFoldingNode *node=findNodeForLine(line);
// if (node->type!=0)
// if (getStartLine(node)+node->endLineRel==line) removeEnding(node,line);
}
else
{
for ( unsigned int i = 0 ; i < regionChanges - > size ( ) / 4 ; i + + )
{
signed char tmp = ( * regionChanges ) [ regionChanges - > size ( ) - 2 - i * 2 ] ;
uint tmppos = ( * regionChanges ) [ regionChanges - > size ( ) - 1 - i * 2 ] ;
( * regionChanges ) [ regionChanges - > size ( ) - 2 - i * 2 ] = ( * regionChanges ) [ i * 2 ] ;
( * regionChanges ) [ regionChanges - > size ( ) - 1 - i * 2 ] = ( * regionChanges ) [ i * 2 + 1 ] ;
( * regionChanges ) [ i * 2 ] = tmp ;
( * regionChanges ) [ i * 2 + 1 ] = tmppos ;
}
signed char data = ( * regionChanges ) [ regionChanges - > size ( ) - 2 ] ;
uint charPos = ( * regionChanges ) [ regionChanges - > size ( ) - 1 ] ;
regionChanges - > resize ( regionChanges - > size ( ) - 2 ) ;
int insertPos = - 1 ;
KateCodeFoldingNode * node = findNodeForLine ( line ) ;
if ( data < 0 )
{
// if (insertPos==-1)
{
unsigned int tmpLine = line - getStartLine ( node ) ;
for ( uint i = 0 ; i < node - > childCount ( ) ; + + i )
{
if ( node - > child ( i ) - > startLineRel > = tmpLine )
{
insertPos = i ;
break ;
}
}
}
}
else
{
for ( ; ( node - > parentNode ) & & ( getStartLine ( node - > parentNode ) = = line ) & & ( node - > parentNode - > type ! = 0 ) ; node = node - > parentNode ) ;
if ( ( getStartLine ( node ) = = line ) & & ( node - > type ! = 0 ) )
{
insertPos = node - > parentNode - > findChild ( node ) ;
node = node - > parentNode ;
}
else
{
for ( uint i = 0 ; i < node - > childCount ( ) ; + + i )
{
if ( getStartLine ( node - > child ( i ) ) > = line )
{
insertPos = i ;
break ;
}
}
}
}
do
{
if ( data < 0 )
{
if ( correctEndings ( data , node , line , charPos , insertPos ) )
{
insertPos = node - > parentNode - > findChild ( node ) + 1 ;
node = node - > parentNode ;
}
else
{
if ( insertPos ! = - 1 ) insertPos + + ;
}
}
else
{
int startLine = getStartLine ( node ) ;
if ( ( insertPos = = - 1 ) | | ( insertPos > = ( int ) node - > childCount ( ) ) )
{
KateCodeFoldingNode * newNode = new KateCodeFoldingNode ( node , data , line - startLine ) ;
something_changed = true ;
node - > appendChild ( newNode ) ;
addOpening ( newNode , data , regionChanges , line , charPos ) ;
insertPos = node - > findChild ( newNode ) + 1 ;
}
else
{
if ( node - > child ( insertPos ) - > startLineRel = = line - startLine )
{
addOpening ( node - > child ( insertPos ) , data , regionChanges , line , charPos ) ;
insertPos + + ;
}
else
{
// kdDebug(13000)<<"ADDING NODE "<<endl;
KateCodeFoldingNode * newNode = new KateCodeFoldingNode ( node , data , line - startLine ) ;
something_changed = true ;
node - > insertChild ( insertPos , newNode ) ;
addOpening ( newNode , data , regionChanges , line , charPos ) ;
insertPos + + ;
}
}
}
if ( regionChanges - > isEmpty ( ) )
data = 0 ;
else
{
data = ( * regionChanges ) [ regionChanges - > size ( ) - 2 ] ;
charPos = ( * regionChanges ) [ regionChanges - > size ( ) - 1 ] ;
regionChanges - > resize ( regionChanges - > size ( ) - 2 ) ;
}
} while ( data ! = 0 ) ;
}
cleanupUnneededNodes ( line ) ;
// if (something_changed) emit regionBeginEndAddedRemoved(line);
( * updated ) = something_changed ;
}
bool KateCodeFoldingTree : : removeOpening ( KateCodeFoldingNode * node , unsigned int line )
{
signed char type ;
if ( ( type = node - > type ) = = 0 )
{
dontDeleteOpening ( node ) ;
dontDeleteEnding ( node ) ;
return false ;
}
if ( ! node - > visible )
{
toggleRegionVisibility ( getStartLine ( node ) ) ;
}
KateCodeFoldingNode * parent = node - > parentNode ;
int mypos = parent - > findChild ( node ) ;
if ( mypos > - 1 )
{
//move childnodes() up
for ( ; node - > childCount ( ) > 0 ; )
{
KateCodeFoldingNode * tmp ;
parent - > insertChild ( mypos , tmp = node - > takeChild ( 0 ) ) ;
tmp - > parentNode = parent ;
tmp - > startLineRel + = node - > startLineRel ;
mypos + + ;
}
// remove the node
//mypos = parent->findChild(node);
bool endLineValid = node - > endLineValid ;
int endLineRel = node - > endLineRel ;
uint endCol = node - > endCol ;
// removes + deletes
KateCodeFoldingNode * child = parent - > takeChild ( mypos ) ;
markedForDeleting . removeRef ( child ) ;
delete child ;
if ( ( type > 0 ) & & ( endLineValid ) )
correctEndings ( - type , parent , line + endLineRel /*+1*/ , endCol , mypos ) ; // why the hell did I add a +1 here ?
}
return true ;
}
bool KateCodeFoldingTree : : removeEnding ( KateCodeFoldingNode * node , unsigned int /* line */ )
{
KateCodeFoldingNode * parent = node - > parentNode ;
if ( ! parent )
return false ;
if ( node - > type = = 0 )
return false ;
if ( node - > type < 0 )
{
// removes + deletes
int i = parent - > findChild ( node ) ;
if ( i > = 0 )
{
KateCodeFoldingNode * child = parent - > takeChild ( i ) ;
markedForDeleting . removeRef ( child ) ;
delete child ;
}
return true ;
}
int mypos = parent - > findChild ( node ) ;
int count = parent - > childCount ( ) ;
for ( int i = mypos + 1 ; i < count ; i + + )
{
if ( parent - > child ( i ) - > type = = - node - > type )
{
node - > endLineValid = true ;
node - > endLineRel = parent - > child ( i ) - > startLineRel - node - > startLineRel ;
KateCodeFoldingNode * child = parent - > takeChild ( i ) ;
markedForDeleting . removeRef ( child ) ;
delete child ;
count = i - mypos - 1 ;
if ( count > 0 )
{
for ( int i = 0 ; i < count ; i + + )
{
KateCodeFoldingNode * tmp = parent - > takeChild ( mypos + 1 ) ;
tmp - > startLineRel - = node - > startLineRel ;
tmp - > parentNode = node ; //should help 16.04.2002
node - > appendChild ( tmp ) ;
}
}
return false ;
}
}
if ( ( parent - > type = = node - > type ) | | /*temporary fix */ ( ! parent - > parentNode ) )
{
for ( int i = mypos + 1 ; i < ( int ) parent - > childCount ( ) ; i + + )
{
KateCodeFoldingNode * tmp = parent - > takeChild ( mypos + 1 ) ;
tmp - > startLineRel - = node - > startLineRel ;
tmp - > parentNode = node ; // SHOULD HELP 16.04.2002
node - > appendChild ( tmp ) ;
}
// this should fix the bug of wrongly closed nodes
if ( ! parent - > parentNode )
node - > endLineValid = false ;
else
node - > endLineValid = parent - > endLineValid ;
node - > endLineRel = parent - > endLineRel - node - > startLineRel ;
if ( node - > endLineValid )
return removeEnding ( parent , getStartLine ( parent ) + parent - > endLineRel ) ;
return false ;
}
node - > endLineValid = false ;
node - > endLineRel = parent - > endLineRel - node - > startLineRel ;
return false ;
}
bool KateCodeFoldingTree : : correctEndings ( signed char data , KateCodeFoldingNode * node , unsigned int line , unsigned int endCol , int insertPos )
{
// if (node->type==0) {kdError()<<"correct Ending should never be called with the root node"<<endl; return true;}
uint startLine = getStartLine ( node ) ;
if ( data ! = - node - > type )
{
# if JW_DEBUG
kdDebug ( 13000 ) < < " data!=-node->type (correctEndings) " < < endl ;
# endif
//invalid close -> add to unopend list
dontDeleteEnding ( node ) ;
if ( data = = node - > type ) {
node - > endCol = endCol ;
return false ;
}
KateCodeFoldingNode * newNode = new KateCodeFoldingNode ( node , data , line - startLine ) ;
something_changed = true ;
newNode - > startLineValid = false ;
newNode - > endLineValid = true ;
newNode - > endLineRel = 0 ;
newNode - > endCol = endCol ;
if ( ( insertPos = = - 1 ) | | ( insertPos = = ( int ) node - > childCount ( ) ) )
node - > appendChild ( newNode ) ;
else
node - > insertChild ( insertPos , newNode ) ;
// find correct position
return false ;
}
else
{
something_changed = true ;
dontDeleteEnding ( node ) ;
// valid closing region
if ( ! node - > endLineValid )
{
node - > endLineValid = true ;
node - > endLineRel = line - startLine ;
node - > endCol = endCol ;
//moving
moveSubNodesUp ( node ) ;
}
else
{
# if JW_DEBUG
kdDebug ( 13000 ) < < " Closing a node which had already a valid end " < < endl ;
# endif
// block has already an ending
if ( startLine + node - > endLineRel = = line )
{
node - > endCol = endCol ;
// we won, just skip
# if JW_DEBUG
kdDebug ( 13000 ) < < " We won, just skipping (correctEndings) " < < endl ;
# endif
}
else
{
int bakEndLine = node - > endLineRel + startLine ;
uint bakEndCol = node - > endCol ;
node - > endLineRel = line - startLine ;
node - > endCol = endCol ;
# if JW_DEBUG
kdDebug ( 13000 ) < < " reclosed node had childnodes() " < < endl ;
kdDebug ( 13000 ) < < " It could be, that childnodes() need to be moved up " < < endl ;
# endif
moveSubNodesUp ( node ) ;
if ( node - > parentNode )
{
correctEndings ( data , node - > parentNode , bakEndLine , bakEndCol , node - > parentNode - > findChild ( node ) + 1 ) ; // ????
}
else
{
//add to unopened list (bakEndLine)
}
}
}
}
return true ;
}
void KateCodeFoldingTree : : moveSubNodesUp ( KateCodeFoldingNode * node )
{
int mypos = node - > parentNode - > findChild ( node ) ;
int removepos = - 1 ;
int count = node - > childCount ( ) ;
for ( int i = 0 ; i < count ; i + + )
if ( node - > child ( i ) - > startLineRel > = node - > endLineRel )
{
removepos = i ;
break ;
}
# if JW_DEBUG
kdDebug ( 13000 ) < < TQString ( " remove pos: %1 " ) . arg ( removepos ) < < endl ;
# endif
if ( removepos > - 1 )
{
# if JW_DEBUG
kdDebug ( 13000 ) < < " Children need to be moved " < < endl ;
# endif
KateCodeFoldingNode * moveNode ;
if ( mypos = = ( int ) node - > parentNode - > childCount ( ) - 1 )
{
while ( removepos < ( int ) node - > childCount ( ) )
{
node - > parentNode - > appendChild ( moveNode = node - > takeChild ( removepos ) ) ;
moveNode - > parentNode = node - > parentNode ;
moveNode - > startLineRel + = node - > startLineRel ;
}
}
else
{
int insertPos = mypos ;
while ( removepos < ( int ) node - > childCount ( ) )
{
insertPos + + ;
node - > parentNode - > insertChild ( insertPos , moveNode = node - > takeChild ( removepos ) ) ;
moveNode - > parentNode = node - > parentNode ; // That should solve a crash
moveNode - > startLineRel + = node - > startLineRel ;
}
}
}
}
void KateCodeFoldingTree : : addOpening ( KateCodeFoldingNode * node , signed char nType , TQMemArray < uint > * list , unsigned int line , unsigned int charPos )
{
uint startLine = getStartLine ( node ) ;
if ( ( startLine = = line ) & & ( node - > type ! = 0 ) )
{
# if JW_DEBUG
kdDebug ( 13000 ) < < " startLine equals line " < < endl ;
# endif
if ( nType = = node - > type )
{
# if JW_DEBUG
kdDebug ( 13000 ) < < " Node exists " < < endl ;
# endif
node - > deleteOpening = false ;
node - > startCol = charPos ;
KateCodeFoldingNode * parent = node - > parentNode ;
if ( ! node - > endLineValid )
{
int current = parent - > findChild ( node ) ;
int count = parent - > childCount ( ) - ( current + 1 ) ;
node - > endLineRel = parent - > endLineRel - node - > startLineRel ;
// EXPERIMENTAL TEST BEGIN
// move this afte the test for unopened, but closed regions within the parent node, or if there are no siblings, bubble up
if ( parent )
if ( parent - > type = = node - > type )
{
if ( parent - > endLineValid )
{
removeEnding ( parent , line ) ;
node - > endLineValid = true ;
}
}
// EXPERIMENTAL TEST BEGIN
if ( current ! = ( int ) parent - > childCount ( ) - 1 )
{
//search for an unopened but closed region, even if the parent is of the same type
# ifdef __GNUC__
# warning "FIXME: why does this seem to work?"
# endif
// if (node->type != parent->type)
{
for ( int i = current + 1 ; i < ( int ) parent - > childCount ( ) ; i + + )
{
if ( parent - > child ( i ) - > type = = - node - > type )
{
count = ( i - current - 1 ) ;
node - > endLineValid = true ;
node - > endLineRel = getStartLine ( parent - > child ( i ) ) - line ;
node - > endCol = parent - > child ( i ) - > endCol ;
KateCodeFoldingNode * child = parent - > takeChild ( i ) ;
markedForDeleting . removeRef ( child ) ;
delete child ;
break ;
}
}
}
// else
// {
// parent->endLineValid = false;
// parent->endLineRel = 20000;
// }
if ( count > 0 )
{
for ( int i = 0 ; i < count ; i + + )
{
KateCodeFoldingNode * tmp ;
node - > appendChild ( tmp = parent - > takeChild ( current + 1 ) ) ;
tmp - > startLineRel - = node - > startLineRel ;
tmp - > parentNode = node ;
}
}
}
}
addOpening_further_iterations ( node , nType , list , line , 0 , startLine , node - > startCol ) ;
} //else ohoh, much work to do same line, but other region type
}
else
{ // create a new region
KateCodeFoldingNode * newNode = new KateCodeFoldingNode ( node , nType , line - startLine ) ;
something_changed = true ;
int insert_position = - 1 ;
for ( int i = 0 ; i < ( int ) node - > childCount ( ) ; i + + )
{
if ( startLine + node - > child ( i ) - > startLineRel > line )
{
insert_position = i ;
break ;
}
}
int current ;
if ( insert_position = = - 1 )
{
node - > appendChild ( newNode ) ;
current = node - > childCount ( ) - 1 ;
}
else
{
node - > insertChild ( insert_position , newNode ) ;
current = insert_position ;
}
// if (node->type==newNode->type)
// {
// newNode->endLineValid=true;
// node->endLineValid=false;
// newNode->endLineRel=node->endLineRel-newNode->startLineRel;
// node->endLineRel=20000; //FIXME
int count = node - > childCount ( ) - ( current + 1 ) ;
newNode - > endLineRel - = newNode - > startLineRel ;
if ( current ! = ( int ) node - > childCount ( ) - 1 )
{
if ( node - > type ! = newNode - > type )
{
for ( int i = current + 1 ; i < ( int ) node - > childCount ( ) ; i + + )
{
if ( node - > child ( i ) - > type = = - newNode - > type )
{
count = node - > childCount ( ) - i - 1 ;
newNode - > endLineValid = true ;
newNode - > endLineRel = line - getStartLine ( node - > child ( i ) ) ;
KateCodeFoldingNode * child = node - > takeChild ( i ) ;
markedForDeleting . removeRef ( child ) ;
delete child ;
break ;
}
}
}
else
{
node - > endLineValid = false ;
node - > endLineRel = 10000 ;
}
if ( count > 0 )
{
for ( int i = 0 ; i < count ; i + + )
{
KateCodeFoldingNode * tmp ;
newNode - > appendChild ( tmp = node - > takeChild ( current + 1 ) ) ;
tmp - > parentNode = newNode ;
}
}
// }
}
addOpening ( newNode , nType , list , line , charPos ) ;
addOpening_further_iterations ( node , node - > type , list , line , current , startLine , node - > startCol ) ;
}
}
void KateCodeFoldingTree : : addOpening_further_iterations ( KateCodeFoldingNode * node , signed char /* nType */ , TQMemArray < uint > *
list , unsigned int line , int current , unsigned int startLine , unsigned int charPos )
{
while ( ! ( list - > isEmpty ( ) ) )
{
if ( list - > isEmpty ( ) )
return ;
else
{
signed char data = ( * list ) [ list - > size ( ) - 2 ] ;
uint charPos = ( * list ) [ list - > size ( ) - 1 ] ;
list - > resize ( list - > size ( ) - 2 ) ;
if ( data < 0 )
{
# if JW_DEBUG
kdDebug ( 13000 ) < < " An ending was found " < < endl ;
# endif
if ( correctEndings ( data , node , line , charPos , - 1 ) )
return ; // -1 ?
#if 0
if ( data = = - nType )
{
if ( node - > endLineValid )
{
if ( node - > endLineRel + startLine = = line ) // We've won again
{
//handle next node;
}
else
{ // much moving
node - > endLineRel = line - startLine ;
node - > endLineValid = true ;
}
return ; // next higher level should do the rest
}
else
{
node - > endLineRel = line - startLine ;
node - > endLineValid = true ;
//much moving
}
} //else add to unopened list
# endif
}
else
{
bool needNew = true ;
if ( current < ( int ) node - > childCount ( ) )
{
if ( getStartLine ( node - > child ( current ) ) = = line )
needNew = false ;
}
if ( needNew )
{
something_changed = true ;
KateCodeFoldingNode * newNode = new KateCodeFoldingNode ( node , data , line - startLine ) ;
node - > insertChild ( current , newNode ) ; //find the correct position later
}
addOpening ( node - > child ( current ) , data , list , line , charPos ) ;
current + + ;
//lookup node or create subnode
}
}
} // end while
}
unsigned int KateCodeFoldingTree : : getStartLine ( KateCodeFoldingNode * node )
{
unsigned int lineStart = 0 ;
for ( KateCodeFoldingNode * iter = node ; iter - > type ! = 0 ; iter = iter - > parentNode )
lineStart + = iter - > startLineRel ;
return lineStart ;
}
void KateCodeFoldingTree : : lineHasBeenRemoved ( unsigned int line )
{
lineMapping . clear ( ) ;
dontIgnoreUnchangedLines . insert ( line , & trueVal ) ;
dontIgnoreUnchangedLines . insert ( line - 1 , & trueVal ) ;
dontIgnoreUnchangedLines . insert ( line + 1 , & trueVal ) ;
hiddenLinesCountCacheValid = false ;
# if JW_DEBUG
kdDebug ( 13000 ) < < TQString ( " KateCodeFoldingTree::lineHasBeenRemoved: %1 " ) . arg ( line ) < < endl ;
# endif
//line ++;
findAndMarkAllNodesforRemovalOpenedOrClosedAt ( line ) ; //It's an ugly solution
cleanupUnneededNodes ( line ) ; //It's an ugly solution
KateCodeFoldingNode * node = findNodeForLine ( line ) ;
//????? if (node->endLineValid)
{
int startLine = getStartLine ( node ) ;
if ( startLine = = ( int ) line )
node - > startLineRel - - ;
else
{
if ( node - > endLineRel = = 0 )
node - > endLineValid = false ;
node - > endLineRel - - ;
}
int count = node - > childCount ( ) ;
for ( int i = 0 ; i < count ; i + + )
{
if ( node - > child ( i ) - > startLineRel + startLine > = line )
node - > child ( i ) - > startLineRel - - ;
}
}
if ( node - > parentNode )
decrementBy1 ( node - > parentNode , node ) ;
for ( TQValueList < KateHiddenLineBlock > : : Iterator it = hiddenLines . begin ( ) ; it ! = hiddenLines . end ( ) ; + + it )
{
if ( ( * it ) . start > line )
( * it ) . start - - ;
else if ( ( * it ) . start + ( * it ) . length > line )
( * it ) . length - - ;
}
}
void KateCodeFoldingTree : : decrementBy1 ( KateCodeFoldingNode * node , KateCodeFoldingNode * after )
{
if ( node - > endLineRel = = 0 )
node - > endLineValid = false ;
node - > endLineRel - - ;
for ( uint i = node - > findChild ( after ) + 1 ; i < node - > childCount ( ) ; + + i )
node - > child ( i ) - > startLineRel - - ;
if ( node - > parentNode )
decrementBy1 ( node - > parentNode , node ) ;
}
void KateCodeFoldingTree : : lineHasBeenInserted ( unsigned int line )
{
lineMapping . clear ( ) ;
dontIgnoreUnchangedLines . insert ( line , & trueVal ) ;
dontIgnoreUnchangedLines . insert ( line - 1 , & trueVal ) ;
dontIgnoreUnchangedLines . insert ( line + 1 , & trueVal ) ;
hiddenLinesCountCacheValid = false ;
//return;
# if JW_DEBUG
kdDebug ( 13000 ) < < TQString ( " KateCodeFoldingTree::lineHasBeenInserted: %1 " ) . arg ( line ) < < endl ;
# endif
// findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
// cleanupUnneededNodes(line);
KateCodeFoldingNode * node = findNodeForLine ( line ) ;
// ???????? if (node->endLineValid)
{
int startLine = getStartLine ( node ) ;
if ( node - > type < 0 )
node - > startLineRel + + ;
else
node - > endLineRel + + ;
for ( uint i = 0 ; i < node - > childCount ( ) ; + + i )
{
KateCodeFoldingNode * iter = node - > child ( i ) ;
if ( iter - > startLineRel + startLine > = line )
iter - > startLineRel + + ;
}
}
if ( node - > parentNode )
incrementBy1 ( node - > parentNode , node ) ;
for ( TQValueList < KateHiddenLineBlock > : : Iterator it = hiddenLines . begin ( ) ; it ! = hiddenLines . end ( ) ; + + it )
{
if ( ( * it ) . start > line )
( * it ) . start + + ;
else if ( ( * it ) . start + ( * it ) . length > line )
( * it ) . length + + ;
}
}
void KateCodeFoldingTree : : incrementBy1 ( KateCodeFoldingNode * node , KateCodeFoldingNode * after )
{
node - > endLineRel + + ;
for ( uint i = node - > findChild ( after ) + 1 ; i < node - > childCount ( ) ; + + i )
node - > child ( i ) - > startLineRel + + ;
if ( node - > parentNode )
incrementBy1 ( node - > parentNode , node ) ;
}
void KateCodeFoldingTree : : findAndMarkAllNodesforRemovalOpenedOrClosedAt ( unsigned int line )
{
# ifdef __GNUC__
# warning "FIXME: make this multiple region changes per line save";
# endif
// return;
markedForDeleting . clear ( ) ;
KateCodeFoldingNode * node = findNodeForLine ( line ) ;
if ( node - > type = = 0 )
return ;
addNodeToRemoveList ( node , line ) ;
while ( ( ( node - > parentNode ) & & ( node - > parentNode - > type ! = 0 ) ) & & ( getStartLine ( node - > parentNode ) = = line ) )
{
node = node - > parentNode ;
addNodeToRemoveList ( node , line ) ;
}
# if JW_DEBUG
kdDebug ( 13000 ) < < " added line to markedForDeleting list " < < endl ;
# endif
}
void KateCodeFoldingTree : : addNodeToRemoveList ( KateCodeFoldingNode * node , unsigned int line )
{
bool add = false ;
# ifdef __GNUC__
# warning "FIXME: make this multiple region changes per line save";
# endif
unsigned int startLine = getStartLine ( node ) ;
if ( ( startLine = = line ) & & ( node - > startLineValid ) )
{
add = true ;
node - > deleteOpening = true ;
}
if ( ( startLine + node - > endLineRel = = line ) | | ( ( node - > endLineValid = = false ) & & ( node - > deleteOpening ) ) )
{
int myPos = node - > parentNode - > findChild ( node ) ; // this has to be implemented nicely
if ( ( int ) node - > parentNode - > childCount ( ) > myPos + 1 )
addNodeToRemoveList ( node - > parentNode - > child ( myPos + 1 ) , line ) ;
add = true ;
node - > deleteEnding = true ;
}
if ( add )
markedForDeleting . append ( node ) ;
}
void KateCodeFoldingTree : : findAllNodesOpenedOrClosedAt ( unsigned int line )
{
nodesForLine . clear ( ) ;
KateCodeFoldingNode * node = findNodeForLine ( line ) ;
if ( node - > type = = 0 )
return ;
unsigned int startLine = getStartLine ( node ) ;
if ( startLine = = line )
nodesForLine . append ( node ) ;
else if ( ( startLine + node - > endLineRel = = line ) )
nodesForLine . append ( node ) ;
while ( node - > parentNode )
{
addNodeToFoundList ( node - > parentNode , line , node - > parentNode - > findChild ( node ) ) ;
node = node - > parentNode ;
}
# if JW_DEBUG
kdDebug ( 13000 ) < < " added line to nodesForLine list " < < endl ;
# endif
}
void KateCodeFoldingTree : : addNodeToFoundList ( KateCodeFoldingNode * node , unsigned int line , int childpos )
{
unsigned int startLine = getStartLine ( node ) ;
if ( ( startLine = = line ) & & ( node - > type ! = 0 ) )
nodesForLine . append ( node ) ;
else if ( ( startLine + node - > endLineRel = = line ) & & ( node - > type ! = 0 ) )
nodesForLine . append ( node ) ;
for ( int i = childpos + 1 ; i < ( int ) node - > childCount ( ) ; i + + )
{
KateCodeFoldingNode * child = node - > child ( i ) ;
if ( startLine + child - > startLineRel = = line )
{
nodesForLine . append ( child ) ;
addNodeToFoundList ( child , line , 0 ) ;
}
else
break ;
}
}
void KateCodeFoldingTree : : cleanupUnneededNodes ( unsigned int line )
{
# if JW_DEBUG
kdDebug ( 13000 ) < < " void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line) " < < endl ;
# endif
// return;
if ( markedForDeleting . isEmpty ( ) )
return ;
for ( int i = 0 ; i < ( int ) markedForDeleting . count ( ) ; i + + )
{
KateCodeFoldingNode * node = markedForDeleting . at ( i ) ;
if ( node - > deleteOpening )
kdDebug ( 13000 ) < < " DELETE OPENING SET " < < endl ;
if ( node - > deleteEnding )
kdDebug ( 13000 ) < < " DELETE ENDING SET " < < endl ;
if ( ( node - > deleteOpening ) & & ( node - > deleteEnding ) )
{
# if JW_DEBUG
kdDebug ( 13000 ) < < " Deleting complete node " < < endl ;
# endif
if ( node - > endLineValid ) // just delete it, it has been opened and closed on this line
{
int f = node - > parentNode - > findChild ( node ) ;
if ( f > = 0 )
delete node - > parentNode - > takeChild ( f ) ;
}
else
{
removeOpening ( node , line ) ;
// the node has subnodes which need to be moved up and this one has to be deleted
}
something_changed = true ;
}
else
{
if ( ( node - > deleteOpening ) & & ( node - > startLineValid ) )
{
# if JW_DEBUG
kdDebug ( 13000 ) < < " calling removeOpening " < < endl ;
# endif
removeOpening ( node , line ) ;
something_changed = true ;
}
else
{
dontDeleteOpening ( node ) ;
if ( ( node - > deleteEnding ) & & ( node - > endLineValid ) )
{
dontDeleteEnding ( node ) ;
removeEnding ( node , line ) ;
something_changed = true ;
}
else
dontDeleteEnding ( node ) ;
}
}
}
}
void KateCodeFoldingTree : : dontDeleteEnding ( KateCodeFoldingNode * node )
{
node - > deleteEnding = false ;
}
void KateCodeFoldingTree : : dontDeleteOpening ( KateCodeFoldingNode * node )
{
node - > deleteOpening = false ;
}
void KateCodeFoldingTree : : toggleRegionVisibility ( unsigned int line )
{
// hl whole file
m_buffer - > line ( m_buffer - > count ( ) - 1 ) ;
lineMapping . clear ( ) ;
hiddenLinesCountCacheValid = false ;
kdDebug ( 13000 ) < < TQString ( TQString ( " KateCodeFoldingTree::toggleRegionVisibility() %1 " ) . arg ( line ) ) < < endl ;
findAllNodesOpenedOrClosedAt ( line ) ;
for ( int i = 0 ; i < ( int ) nodesForLine . count ( ) ; i + + )
{
KateCodeFoldingNode * node = nodesForLine . at ( i ) ;
if ( ( ! node - > startLineValid ) | | ( getStartLine ( node ) ! = line ) )
{
nodesForLine . remove ( i ) ;
i - - ;
}
}
if ( nodesForLine . isEmpty ( ) )
return ;
nodesForLine . at ( 0 ) - > visible = ! nodesForLine . at ( 0 ) - > visible ;
if ( ! nodesForLine . at ( 0 ) - > visible )
addHiddenLineBlock ( nodesForLine . at ( 0 ) , line ) ;
else
{
for ( TQValueList < KateHiddenLineBlock > : : Iterator it = hiddenLines . begin ( ) ; it ! = hiddenLines . end ( ) ; + + it )
if ( ( * it ) . start = = line + 1 )
{
hiddenLines . remove ( it ) ;
break ;
}
updateHiddenSubNodes ( nodesForLine . at ( 0 ) ) ;
}
emit regionVisibilityChangedAt ( line ) ;
}
void KateCodeFoldingTree : : updateHiddenSubNodes ( KateCodeFoldingNode * node )
{
for ( uint i = 0 ; i < node - > childCount ( ) ; + + i )
{
KateCodeFoldingNode * iter = node - > child ( i ) ;
if ( ! iter - > visible )
addHiddenLineBlock ( iter , getStartLine ( iter ) ) ;
else
updateHiddenSubNodes ( iter ) ;
}
}
void KateCodeFoldingTree : : addHiddenLineBlock ( KateCodeFoldingNode * node , unsigned int line )
{
KateHiddenLineBlock data ;
data . start = line + 1 ;
data . length = node - > endLineRel - ( existsOpeningAtLineAfter ( line + node - > endLineRel , node ) ? 1 : 0 ) ; // without -1;
bool inserted = false ;
for ( TQValueList < KateHiddenLineBlock > : : Iterator it = hiddenLines . begin ( ) ; it ! = hiddenLines . end ( ) ; + + it )
{
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
{
// the existing block can't have lines behind the new one, because a newly hidden
// block has to encapsulate already hidden ones
it = hiddenLines . remove ( it ) ;
- - it ;
}
else
{
if ( ( * it ) . start > line )
{
hiddenLines . insert ( it , data ) ;
inserted = true ;
break ;
}
}
}
if ( ! inserted )
hiddenLines . append ( data ) ;
}
bool KateCodeFoldingTree : : existsOpeningAtLineAfter ( unsigned int line , KateCodeFoldingNode * node )
{
for ( KateCodeFoldingNode * tmp = node - > parentNode ; tmp ; tmp = tmp - > parentNode )
{
KateCodeFoldingNode * tmp2 ;
unsigned int startLine = getStartLine ( tmp ) ;
if ( ( tmp2 = tmp - > child ( tmp - > findChild ( node ) + 1 ) )
& & ( ( tmp2 - > startLineRel + startLine ) = = line ) )
return true ;
if ( ( startLine + tmp - > endLineRel ) > line )
return false ;
}
return false ;
}
//
// get the real line number for a virtual line
//
unsigned int KateCodeFoldingTree : : getRealLine ( unsigned int virtualLine )
{
// he, if nothing is hidden, why look at it ;)
if ( hiddenLines . isEmpty ( ) )
return virtualLine ;
// kdDebug(13000)<<TQString("VirtualLine %1").arg(virtualLine)<<endl;
unsigned int * real = lineMapping [ virtualLine ] ;
if ( real )
return ( * real ) ;
unsigned int tmp = virtualLine ;
for ( TQValueList < KateHiddenLineBlock > : : ConstIterator it = hiddenLines . begin ( ) ; it ! = hiddenLines . end ( ) ; + + it )
{
if ( ( * it ) . start < = virtualLine )
virtualLine + = ( * it ) . length ;
else
break ;
}
// kdDebug(13000)<<TQString("Real Line %1").arg(virtualLine)<<endl;
lineMapping . insert ( tmp , new unsigned int ( virtualLine ) ) ;
return virtualLine ;
}
//
// get the virtual line number for a real line
//
unsigned int KateCodeFoldingTree : : getVirtualLine ( unsigned int realLine )
{
// he, if nothing is hidden, why look at it ;)
if ( hiddenLines . isEmpty ( ) )
return realLine ;
// kdDebug(13000)<<TQString("RealLine--> %1").arg(realLine)<<endl;
for ( TQValueList < KateHiddenLineBlock > : : ConstIterator it = hiddenLines . fromLast ( ) ; it ! = hiddenLines . end ( ) ; - - it )
{
if ( ( * it ) . start < = realLine )
realLine - = ( * it ) . length ;
// else
// break;
}
// kdDebug(13000)<<TQString("-->virtual Line %1").arg(realLine)<<endl;
return realLine ;
}
//
// get the number of hidden lines
//
unsigned int KateCodeFoldingTree : : getHiddenLinesCount ( unsigned int doclen )
{
// he, if nothing is hidden, why look at it ;)
if ( hiddenLines . isEmpty ( ) )
return 0 ;
if ( hiddenLinesCountCacheValid )
return hiddenLinesCountCache ;
hiddenLinesCountCacheValid = true ;
hiddenLinesCountCache = 0 ;
for ( TQValueList < KateHiddenLineBlock > : : ConstIterator it = hiddenLines . begin ( ) ; it ! = hiddenLines . end ( ) ; + + it )
{
if ( ( * it ) . start + ( * it ) . length < = doclen )
hiddenLinesCountCache + = ( * it ) . length ;
else
{
hiddenLinesCountCache + = ( ( * it ) . length - ( ( * it ) . length + ( * it ) . start - doclen ) ) ;
break ;
}
}
return hiddenLinesCountCache ;
}
void KateCodeFoldingTree : : collapseToplevelNodes ( )
{
// hl whole file
m_buffer - > line ( m_buffer - > count ( ) - 1 ) ;
if ( m_root . noChildren ( ) )
return ;
for ( uint i = 0 ; i < m_root . childCount ( ) ; + + i )
{
KateCodeFoldingNode * node = m_root . child ( i ) ;
if ( node - > visible & & node - > startLineValid & & node - > endLineValid )
{
node - > visible = false ;
lineMapping . clear ( ) ;
hiddenLinesCountCacheValid = false ;
addHiddenLineBlock ( node , node - > startLineRel ) ;
emit regionVisibilityChangedAt ( node - > startLineRel ) ;
}
}
}
void KateCodeFoldingTree : : expandToplevelNodes ( int numLines )
{
// hl whole file
m_buffer - > line ( m_buffer - > count ( ) - 1 ) ;
KateLineInfo line ;
for ( int i = 0 ; i < numLines ; i + + ) {
getLineInfo ( & line , i ) ;
if ( line . startsInVisibleBlock )
toggleRegionVisibility ( i ) ;
}
}
int KateCodeFoldingTree : : collapseOne ( int realLine )
{
// hl whole file
m_buffer - > line ( m_buffer - > count ( ) - 1 ) ;
KateLineInfo line ;
int unrelatedBlocks = 0 ;
for ( int i = realLine ; i > = 0 ; i - - ) {
getLineInfo ( & line , i ) ;
if ( line . topLevel & & ! line . endsBlock )
// optimisation
break ;
if ( line . endsBlock & & ( line . invalidBlockEnd ) & & ( i ! = realLine ) ) {
unrelatedBlocks + + ;
}
if ( line . startsVisibleBlock ) {
unrelatedBlocks - - ;
if ( unrelatedBlocks = = - 1 ) {
toggleRegionVisibility ( i ) ;
return i ;
}
}
}
return - 1 ;
}
void KateCodeFoldingTree : : expandOne ( int realLine , int numLines )
{
// hl whole file
m_buffer - > line ( m_buffer - > count ( ) - 1 ) ;
KateLineInfo line ;
int blockTrack = 0 ;
for ( int i = realLine ; i > = 0 ; i - - ) {
getLineInfo ( & line , i ) ;
if ( line . topLevel )
// done
break ;
if ( line . startsInVisibleBlock & & i ! = realLine ) {
if ( blockTrack = = 0 )
toggleRegionVisibility ( i ) ;
blockTrack - - ;
}
if ( line . endsBlock )
blockTrack + + ;
if ( blockTrack < 0 )
// too shallow
break ;
}
blockTrack = 0 ;
for ( int i = realLine ; i < numLines ; i + + ) {
getLineInfo ( & line , i ) ;
if ( line . topLevel )
// done
break ;
if ( line . startsInVisibleBlock ) {
if ( blockTrack = = 0 )
toggleRegionVisibility ( i ) ;
blockTrack + + ;
}
if ( line . endsBlock )
blockTrack - - ;
if ( blockTrack < 0 )
// too shallow
break ;
}
}
void KateCodeFoldingTree : : ensureVisible ( uint line )
{
// first have a look, if the line is really hidden
bool found = false ;
for ( TQValueList < KateHiddenLineBlock > : : ConstIterator it = hiddenLines . begin ( ) ; it ! = hiddenLines . end ( ) ; + + it )
{
if ( ( ( * it ) . start < = line ) & & ( ( * it ) . start + ( * it ) . length > line ) )
{
found = true ;
break ;
}
}
if ( ! found ) return ;
kdDebug ( 13000 ) < < " line " < < line < < " is really hidden ->show block " < < endl ;
// it looks like we really have to ensure visibility
KateCodeFoldingNode * n = findNodeForLine ( line ) ;
do {
if ( ! n - > visible )
toggleRegionVisibility ( getStartLine ( n ) ) ;
n = n - > parentNode ;
} while ( n ) ;
}