|
|
|
/* This file is part of the KDE libraries
|
|
|
|
Copyright (C) 2004 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 "katetemplatehandler.h"
|
|
|
|
#include "katetemplatehandler.moc"
|
|
|
|
#include "katedocument.h"
|
|
|
|
#include "katesupercursor.h"
|
|
|
|
#include "katearbitraryhighlight.h"
|
|
|
|
#include "kateview.h"
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <tqvaluelist.h>
|
|
|
|
|
|
|
|
KateTemplateHandler::KateTemplateHandler(
|
|
|
|
KateDocument *doc,
|
|
|
|
uint line, uint column,
|
|
|
|
const TQString &templateString,
|
|
|
|
const TQMap<TQString, TQString> &initialValues )
|
|
|
|
: TQObject( doc )
|
|
|
|
, KateKeyInterceptorFunctor()
|
|
|
|
, m_doc( doc )
|
|
|
|
, m_currentTabStop( -1 )
|
|
|
|
, m_currentRange( 0 )
|
|
|
|
, m_initOk( false )
|
|
|
|
, m_recursion( false )
|
|
|
|
{
|
|
|
|
connect( m_doc, TQ_SIGNAL( destroyed() ), this, TQ_SLOT( slotDocumentDestroyed() ) );
|
|
|
|
m_ranges = new KateSuperRangeList( false, this ); //false/*,this*/);
|
|
|
|
|
|
|
|
if ( !m_doc->setTabInterceptor( this ) )
|
|
|
|
{
|
|
|
|
deleteLater();
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
KateArbitraryHighlight *kah = doc->arbitraryHL();
|
|
|
|
/*KateArbitraryHighlightRange *hlr=new KateArbitraryHighlightRange(doc,KateTextCursor(line,column),
|
|
|
|
KateTextCursor(line,column+3));
|
|
|
|
hlr->setUnderline(true);
|
|
|
|
hlr->setOverline(true);
|
|
|
|
l->append(hlr);*/
|
|
|
|
TQValueList<KateTemplateHandlerPlaceHolderInfo> buildList;
|
|
|
|
TQRegExp rx( "([$%])\\{([^}\\s]+)\\}" );
|
|
|
|
rx.setMinimal( true );
|
|
|
|
int pos = 0;
|
|
|
|
int opos = 0;
|
|
|
|
TQString insertString = templateString;
|
|
|
|
|
|
|
|
while ( pos >= 0 )
|
|
|
|
{
|
|
|
|
pos = rx.search( insertString, pos );
|
|
|
|
|
|
|
|
if ( pos > -1 )
|
|
|
|
{
|
|
|
|
if ( ( pos - opos ) > 0 )
|
|
|
|
{
|
|
|
|
if ( insertString[ pos - 1 ] == '\\' )
|
|
|
|
{
|
|
|
|
insertString.remove( pos - 1, 1 );
|
|
|
|
opos = pos;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString placeholder = rx.cap( 2 );
|
|
|
|
TQString value = initialValues[ placeholder ];
|
|
|
|
|
|
|
|
// don't add %{MACRO} to the tab navigation, unless there was not value
|
|
|
|
if ( rx.cap( 1 ) != "%" || placeholder == value )
|
|
|
|
buildList.append( KateTemplateHandlerPlaceHolderInfo( pos, value.length(), placeholder ) );
|
|
|
|
|
|
|
|
insertString.replace( pos, rx.matchedLength(), value );
|
|
|
|
pos += value.length();
|
|
|
|
opos = pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
doc->editStart();
|
|
|
|
|
|
|
|
if ( !doc->insertText( line, column, insertString ) )
|
|
|
|
{
|
|
|
|
deleteLater();
|
|
|
|
doc->editEnd();
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( buildList.isEmpty() )
|
|
|
|
{
|
|
|
|
m_initOk = true;
|
|
|
|
deleteLater();
|
|
|
|
doc->editEnd();
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
doc->undoSafePoint();
|
|
|
|
doc->editEnd();
|
|
|
|
generateRangeTable( line, column, insertString, buildList );
|
|
|
|
kah->addHighlightToDocument( m_ranges );
|
|
|
|
|
|
|
|
for ( KateSuperRangeList::const_iterator it = m_ranges->begin();it != m_ranges->end();++it )
|
|
|
|
{
|
|
|
|
m_doc->tagLines( ( *it ) ->start().line(), ( *it ) ->end().line() );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* connect(doc,TQ_SIGNAL(charactersInteractivelyInserted(int ,int ,const TQString&)),this,
|
|
|
|
TQ_SLOT(slotCharactersInteractivlyInserted(int,int,const TQString&)));
|
|
|
|
connect(doc,TQ_SIGNAL(charactersSemiInteractivelyInserted(int ,int ,const TQString&)),this,
|
|
|
|
TQ_SLOT(slotCharactersInteractivlyInserted(int,int,const TQString&)));*/
|
|
|
|
connect( doc, TQ_SIGNAL( textInserted( int, int ) ), this, TQ_SLOT( slotTextInserted( int, int ) ) );
|
|
|
|
connect( doc, TQ_SIGNAL( aboutToRemoveText( const KateTextRange& ) ), this, TQ_SLOT( slotAboutToRemoveText( const KateTextRange& ) ) );
|
|
|
|
connect( doc, TQ_SIGNAL( textRemoved() ), this, TQ_SLOT( slotTextRemoved() ) );
|
|
|
|
|
|
|
|
( *this ) ( TQt::Key_Tab );
|
|
|
|
}
|
|
|
|
|
|
|
|
KateTemplateHandler::~KateTemplateHandler()
|
|
|
|
{
|
|
|
|
m_ranges->setAutoManage( true );
|
|
|
|
|
|
|
|
if ( m_doc )
|
|
|
|
{
|
|
|
|
m_doc->removeTabInterceptor( this );
|
|
|
|
|
|
|
|
for ( KateSuperRangeList::const_iterator it = m_ranges->begin();it != m_ranges->end();++it )
|
|
|
|
{
|
|
|
|
m_doc->tagLines( ( *it ) ->start().line(), ( *it ) ->end().line() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ranges->clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KateTemplateHandler::slotDocumentDestroyed() {m_doc = 0;}
|
|
|
|
|
|
|
|
void KateTemplateHandler::generateRangeTable( uint insertLine, uint insertCol, const TQString& insertString, const TQValueList<KateTemplateHandlerPlaceHolderInfo> &buildList )
|
|
|
|
{
|
|
|
|
uint line = insertLine;
|
|
|
|
uint col = insertCol;
|
|
|
|
uint colInText = 0;
|
|
|
|
|
|
|
|
for ( TQValueList<KateTemplateHandlerPlaceHolderInfo>::const_iterator it = buildList.begin();it != buildList.end();++it )
|
|
|
|
{
|
|
|
|
KateTemplatePlaceHolder *ph = m_dict[ ( *it ).placeholder ];
|
|
|
|
|
|
|
|
if ( !ph )
|
|
|
|
{
|
|
|
|
ph = new KateTemplatePlaceHolder;
|
|
|
|
ph->isInitialValue = true;
|
|
|
|
ph->isCursor = ( ( *it ).placeholder == "cursor" );
|
|
|
|
m_dict.insert( ( *it ).placeholder, ph );
|
|
|
|
|
|
|
|
if ( !ph->isCursor ) m_tabOrder.append( ph );
|
|
|
|
|
|
|
|
ph->ranges.setAutoManage( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME handle space/tab replacement correctly make it use of the indenter
|
|
|
|
while ( colInText < ( *it ).begin )
|
|
|
|
{
|
|
|
|
++col;
|
|
|
|
|
|
|
|
if ( insertString.at( colInText ) == '\n' )
|
|
|
|
{
|
|
|
|
col = 0;
|
|
|
|
line++;
|
|
|
|
}
|
|
|
|
|
|
|
|
++colInText;
|
|
|
|
}
|
|
|
|
|
|
|
|
KateArbitraryHighlightRange *hlr = new KateArbitraryHighlightRange( m_doc, KateTextCursor( line, col ),
|
|
|
|
KateTextCursor( line, ( *it ).len + col ) );
|
|
|
|
colInText += ( *it ).len;
|
|
|
|
col += ( *it ).len;
|
|
|
|
hlr->allowZeroLength();
|
|
|
|
hlr->setUnderline( true );
|
|
|
|
hlr->setOverline( true );
|
|
|
|
//hlr->setBehaviour(KateSuperRange::ExpandRight);
|
|
|
|
ph->ranges.append( hlr );
|
|
|
|
m_ranges->append( hlr );
|
|
|
|
}
|
|
|
|
|
|
|
|
KateTemplatePlaceHolder *cursor = m_dict[ "cursor" ];
|
|
|
|
|
|
|
|
if ( cursor ) m_tabOrder.append( cursor );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KateTemplateHandler::slotTextInserted( int line, int col )
|
|
|
|
{
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#warning FIXME undo/redo detection
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( m_recursion ) return ;
|
|
|
|
|
|
|
|
//if (m_editSessionNumber!=0) return; // assume that this is due an udno/redo operation right now
|
|
|
|
KateTextCursor cur( line, col );
|
|
|
|
|
|
|
|
if ( ( !m_currentRange ) ||
|
|
|
|
( ( !m_currentRange->includes( cur ) ) && ( ! ( ( m_currentRange->start() == m_currentRange->end() ) && m_currentRange->end() == cur ) )
|
|
|
|
) ) locateRange( cur );
|
|
|
|
|
|
|
|
if ( !m_currentRange ) return ;
|
|
|
|
|
|
|
|
KateTemplatePlaceHolder *ph = m_tabOrder.at( m_currentTabStop );
|
|
|
|
|
|
|
|
TQString sourceText = m_doc->text ( m_currentRange->start().line(), m_currentRange->start().col(),
|
|
|
|
m_currentRange->end().line(), m_currentRange->end().col(), false );
|
|
|
|
|
|
|
|
ph->isInitialValue = false;
|
|
|
|
bool undoDontMerge = m_doc->m_undoDontMerge;
|
|
|
|
Q_ASSERT( m_doc->editSessionNumber == 0 );
|
|
|
|
m_recursion = true;
|
|
|
|
|
|
|
|
m_doc->editStart( /*false*/ );
|
|
|
|
|
|
|
|
for ( KateSuperRangeList::const_iterator it = ph->ranges.begin();it != ph->ranges.end();++it )
|
|
|
|
{
|
|
|
|
if ( ( *it ) == m_currentRange ) continue;
|
|
|
|
|
|
|
|
KateTextCursor start = ( *it ) ->start();
|
|
|
|
KateTextCursor end = ( *it ) ->end();
|
|
|
|
m_doc->removeText( start.line(), start.col(), end.line(), end.col(), false );
|
|
|
|
m_doc->insertText( start.line(), start.col(), sourceText );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_doc->m_undoDontMerge = false;
|
|
|
|
m_doc->m_undoComplexMerge = true;
|
|
|
|
m_doc->undoSafePoint();
|
|
|
|
m_doc->editEnd();
|
|
|
|
m_doc->m_undoDontMerge = undoDontMerge;
|
|
|
|
m_recursion = false;
|
|
|
|
|
|
|
|
if ( ph->isCursor ) deleteLater();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KateTemplateHandler::locateRange( const KateTextCursor& cursor )
|
|
|
|
{
|
|
|
|
/* if (m_currentRange) {
|
|
|
|
m_doc->tagLines(m_currentRange->start().line(),m_currentRange->end().line());
|
|
|
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
for ( uint i = 0;i < m_tabOrder.count();i++ )
|
|
|
|
{
|
|
|
|
KateTemplatePlaceHolder *ph = m_tabOrder.at( i );
|
|
|
|
|
|
|
|
for ( KateSuperRangeList::const_iterator it = ph->ranges.begin();it != ph->ranges.end();++it )
|
|
|
|
{
|
|
|
|
if ( ( *it ) ->includes( cursor ) )
|
|
|
|
{
|
|
|
|
m_currentTabStop = i;
|
|
|
|
m_currentRange = ( *it );
|
|
|
|
//m_doc->tagLines(m_currentRange->start().line(),m_currentRange->end().line());
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
m_currentRange = 0;
|
|
|
|
/*while (m_ranges->count()>0)
|
|
|
|
delete (m_ranges->take(0));
|
|
|
|
disconnect(m_ranges,0,0,0);
|
|
|
|
delete m_ranges;*/
|
|
|
|
deleteLater();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KateTemplateHandler::operator() ( KKey key )
|
|
|
|
{
|
|
|
|
if ( key==TQt::Key_Tab )
|
|
|
|
{
|
|
|
|
m_currentTabStop++;
|
|
|
|
|
|
|
|
if ( m_currentTabStop >= ( int ) m_tabOrder.count() )
|
|
|
|
m_currentTabStop = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_currentTabStop--;
|
|
|
|
|
|
|
|
if ( m_currentTabStop < 0 ) m_currentTabStop = m_tabOrder.count() - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_currentRange = m_tabOrder.at( m_currentTabStop ) ->ranges.at( 0 );
|
|
|
|
|
|
|
|
if ( m_tabOrder.at( m_currentTabStop ) ->isInitialValue )
|
|
|
|
{
|
|
|
|
m_doc->activeView()->setSelection( m_currentRange->start(), m_currentRange->end() );
|
|
|
|
}
|
|
|
|
else m_doc->activeView()->setSelection( m_currentRange->end(), m_currentRange->end() );
|
|
|
|
|
|
|
|
m_doc->activeView() ->setCursorPositionReal( m_currentRange->end().line(), m_currentRange->end().col() );
|
|
|
|
m_doc->activeView() ->tagLine( m_currentRange->end() );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KateTemplateHandler::slotAboutToRemoveText( const KateTextRange &range )
|
|
|
|
{
|
|
|
|
if ( m_recursion ) return ;
|
|
|
|
|
|
|
|
if ( m_currentRange && ( !m_currentRange->includes( range.start() ) ) ) locateRange( range.start() );
|
|
|
|
|
|
|
|
if ( m_currentRange != 0 )
|
|
|
|
{
|
|
|
|
if ( m_currentRange->end() <= range.end() ) return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( m_doc )
|
|
|
|
{
|
|
|
|
disconnect( m_doc, TQ_SIGNAL( textInserted( int, int ) ), this, TQ_SLOT( slotTextInserted( int, int ) ) );
|
|
|
|
disconnect( m_doc, TQ_SIGNAL( aboutToRemoveText( const KateTextRange& ) ), this, TQ_SLOT( slotAboutToRemoveText( const KateTextRange& ) ) );
|
|
|
|
disconnect( m_doc, TQ_SIGNAL( textRemoved() ), this, TQ_SLOT( slotTextRemoved() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteLater();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KateTemplateHandler::slotTextRemoved()
|
|
|
|
{
|
|
|
|
if ( m_recursion ) return ;
|
|
|
|
if ( !m_currentRange ) return ;
|
|
|
|
|
|
|
|
slotTextInserted( m_currentRange->start().line(), m_currentRange->start().col() );
|
|
|
|
}
|
|
|
|
|