summaryrefslogtreecommitdiffstats
path: root/kate/part/katetemplatehandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kate/part/katetemplatehandler.cpp')
-rw-r--r--kate/part/katetemplatehandler.cpp342
1 files changed, 342 insertions, 0 deletions
diff --git a/kate/part/katetemplatehandler.cpp b/kate/part/katetemplatehandler.cpp
new file mode 100644
index 000000000..3ca86ff70
--- /dev/null
+++ b/kate/part/katetemplatehandler.cpp
@@ -0,0 +1,342 @@
+/* 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 <qregexp.h>
+#include <kdebug.h>
+#include <qvaluelist.h>
+
+KateTemplateHandler::KateTemplateHandler(
+ KateDocument *doc,
+ uint line, uint column,
+ const QString &templateString,
+ const QMap<QString, QString> &initialValues )
+ : QObject( doc )
+ , KateKeyInterceptorFunctor()
+ , m_doc( doc )
+ , m_currentTabStop( -1 )
+ , m_currentRange( 0 )
+ , m_initOk( false )
+ , m_recursion( false )
+{
+ connect( m_doc, SIGNAL( destroyed() ), this, 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);*/
+ QValueList<KateTemplateHandlerPlaceHolderInfo> buildList;
+ QRegExp rx( "([$%])\\{([^}\\s]+)\\}" );
+ rx.setMinimal( true );
+ int pos = 0;
+ int opos = 0;
+ QString 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;
+ }
+ }
+
+ QString placeholder = rx.cap( 2 );
+ QString 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,SIGNAL(charactersInteractivelyInserted(int ,int ,const QString&)),this,
+ SLOT(slotCharactersInteractivlyInserted(int,int,const QString&)));
+ connect(doc,SIGNAL(charactersSemiInteractivelyInserted(int ,int ,const QString&)),this,
+ SLOT(slotCharactersInteractivlyInserted(int,int,const QString&)));*/
+ connect( doc, SIGNAL( textInserted( int, int ) ), this, SLOT( slotTextInserted( int, int ) ) );
+ connect( doc, SIGNAL( aboutToRemoveText( const KateTextRange& ) ), this, SLOT( slotAboutToRemoveText( const KateTextRange& ) ) );
+ connect( doc, SIGNAL( textRemoved() ), this, SLOT( slotTextRemoved() ) );
+
+ ( *this ) ( Qt::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 QString& insertString, const QValueList<KateTemplateHandlerPlaceHolderInfo> &buildList )
+{
+ uint line = insertLine;
+ uint col = insertCol;
+ uint colInText = 0;
+
+ for ( QValueList<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 );
+
+ QString 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==Qt::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, SIGNAL( textInserted( int, int ) ), this, SLOT( slotTextInserted( int, int ) ) );
+ disconnect( m_doc, SIGNAL( aboutToRemoveText( const KateTextRange& ) ), this, SLOT( slotAboutToRemoveText( const KateTextRange& ) ) );
+ disconnect( m_doc, SIGNAL( textRemoved() ), this, SLOT( slotTextRemoved() ) );
+ }
+
+ deleteLater();
+}
+
+void KateTemplateHandler::slotTextRemoved()
+{
+ if ( m_recursion ) return ;
+ if ( !m_currentRange ) return ;
+
+ slotTextInserted( m_currentRange->start().line(), m_currentRange->start().col() );
+}
+