00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "katetemplatehandler.h"
00019 #include "katetemplatehandler.moc"
00020 #include "katedocument.h"
00021 #include "katesupercursor.h"
00022 #include "katearbitraryhighlight.h"
00023 #include "kateview.h"
00024 #include <qregexp.h>
00025 #include <kdebug.h>
00026 #include <qvaluelist.h>
00027
00028 KateTemplateHandler::KateTemplateHandler(
00029 KateDocument *doc,
00030 uint line, uint column,
00031 const QString &templateString,
00032 const QMap<QString, QString> &initialValues )
00033 : QObject( doc )
00034 , KateKeyInterceptorFunctor()
00035 , m_doc( doc )
00036 , m_currentTabStop( -1 )
00037 , m_currentRange( 0 )
00038 , m_initOk( false )
00039 , m_recursion( false )
00040 {
00041 connect( m_doc, SIGNAL( destroyed() ), this, SLOT( slotDocumentDestroyed() ) );
00042 m_ranges = new KateSuperRangeList( false, this );
00043
00044 if ( !m_doc->setTabInterceptor( this ) )
00045 {
00046 deleteLater();
00047 return ;
00048 }
00049
00050 KateArbitraryHighlight *kah = doc->arbitraryHL();
00051
00052
00053
00054
00055
00056 QValueList<KateTemplateHandlerPlaceHolderInfo> buildList;
00057 QRegExp rx( "([$%])\\{([^}\\s]+)\\}" );
00058 rx.setMinimal( true );
00059 int pos = 0;
00060 int opos = 0;
00061 QString insertString = templateString;
00062
00063 while ( pos >= 0 )
00064 {
00065 pos = rx.search( insertString, pos );
00066
00067 if ( pos > -1 )
00068 {
00069 if ( ( pos - opos ) > 0 )
00070 {
00071 if ( insertString[ pos - 1 ] == '\\' )
00072 {
00073 insertString.remove( pos - 1, 1 );
00074 opos = pos;
00075 continue;
00076 }
00077 }
00078
00079 QString placeholder = rx.cap( 2 );
00080 QString value = initialValues[ placeholder ];
00081
00082
00083 if ( rx.cap( 1 ) != "%" || placeholder == value )
00084 buildList.append( KateTemplateHandlerPlaceHolderInfo( pos, value.length(), placeholder ) );
00085
00086 insertString.replace( pos, rx.matchedLength(), value );
00087 pos += value.length();
00088 opos = pos;
00089 }
00090 }
00091
00092 doc->editStart();
00093
00094 if ( !doc->insertText( line, column, insertString ) )
00095 {
00096 deleteLater();
00097 doc->editEnd();
00098 return ;
00099 }
00100
00101 if ( buildList.isEmpty() )
00102 {
00103 m_initOk = true;
00104 deleteLater();
00105 doc->editEnd();
00106 return ;
00107 }
00108
00109 doc->undoSafePoint();
00110 doc->editEnd();
00111 generateRangeTable( line, column, insertString, buildList );
00112 kah->addHighlightToDocument( m_ranges );
00113
00114 for ( KateSuperRangeList::const_iterator it = m_ranges->begin();it != m_ranges->end();++it )
00115 {
00116 m_doc->tagLines( ( *it ) ->start().line(), ( *it ) ->end().line() );
00117 }
00118
00119
00120
00121
00122
00123 connect( doc, SIGNAL( textInserted( int, int ) ), this, SLOT( slotTextInserted( int, int ) ) );
00124 connect( doc, SIGNAL( aboutToRemoveText( const KateTextRange& ) ), this, SLOT( slotAboutToRemoveText( const KateTextRange& ) ) );
00125 connect( doc, SIGNAL( textRemoved() ), this, SLOT( slotTextRemoved() ) );
00126
00127 ( *this ) ( Qt::Key_Tab );
00128 }
00129
00130 KateTemplateHandler::~KateTemplateHandler()
00131 {
00132 m_ranges->setAutoManage( true );
00133
00134 if ( m_doc )
00135 {
00136 m_doc->removeTabInterceptor( this );
00137
00138 for ( KateSuperRangeList::const_iterator it = m_ranges->begin();it != m_ranges->end();++it )
00139 {
00140 m_doc->tagLines( ( *it ) ->start().line(), ( *it ) ->end().line() );
00141 }
00142 }
00143
00144 m_ranges->clear();
00145 }
00146
00147 void KateTemplateHandler::slotDocumentDestroyed() {m_doc = 0;}
00148
00149 void KateTemplateHandler::generateRangeTable( uint insertLine, uint insertCol, const QString& insertString, const QValueList<KateTemplateHandlerPlaceHolderInfo> &buildList )
00150 {
00151 uint line = insertLine;
00152 uint col = insertCol;
00153 uint colInText = 0;
00154
00155 for ( QValueList<KateTemplateHandlerPlaceHolderInfo>::const_iterator it = buildList.begin();it != buildList.end();++it )
00156 {
00157 KateTemplatePlaceHolder *ph = m_dict[ ( *it ).placeholder ];
00158
00159 if ( !ph )
00160 {
00161 ph = new KateTemplatePlaceHolder;
00162 ph->isInitialValue = true;
00163 ph->isCursor = ( ( *it ).placeholder == "cursor" );
00164 m_dict.insert( ( *it ).placeholder, ph );
00165
00166 if ( !ph->isCursor ) m_tabOrder.append( ph );
00167
00168 ph->ranges.setAutoManage( false );
00169 }
00170
00171
00172 while ( colInText < ( *it ).begin )
00173 {
00174 ++col;
00175
00176 if ( insertString.at( colInText ) == '\n' )
00177 {
00178 col = 0;
00179 line++;
00180 }
00181
00182 ++colInText;
00183 }
00184
00185 KateArbitraryHighlightRange *hlr = new KateArbitraryHighlightRange( m_doc, KateTextCursor( line, col ),
00186 KateTextCursor( line, ( *it ).len + col ) );
00187 colInText += ( *it ).len;
00188 col += ( *it ).len;
00189 hlr->allowZeroLength();
00190 hlr->setUnderline( true );
00191 hlr->setOverline( true );
00192
00193 ph->ranges.append( hlr );
00194 m_ranges->append( hlr );
00195 }
00196
00197 KateTemplatePlaceHolder *cursor = m_dict[ "cursor" ];
00198
00199 if ( cursor ) m_tabOrder.append( cursor );
00200 }
00201
00202 void KateTemplateHandler::slotTextInserted( int line, int col )
00203 {
00204 #ifdef __GNUC__
00205 #warning FIXME undo/redo detection
00206 #endif
00207
00208 if ( m_recursion ) return ;
00209
00210
00211 KateTextCursor cur( line, col );
00212
00213 if ( ( !m_currentRange ) ||
00214 ( ( !m_currentRange->includes( cur ) ) && ( ! ( ( m_currentRange->start() == m_currentRange->end() ) && m_currentRange->end() == cur ) )
00215 ) ) locateRange( cur );
00216
00217 if ( !m_currentRange ) return ;
00218
00219 KateTemplatePlaceHolder *ph = m_tabOrder.at( m_currentTabStop );
00220
00221 QString sourceText = m_doc->text ( m_currentRange->start().line(), m_currentRange->start().col(),
00222 m_currentRange->end().line(), m_currentRange->end().col(), false );
00223
00224 ph->isInitialValue = false;
00225 bool undoDontMerge = m_doc->m_undoDontMerge;
00226 Q_ASSERT( m_doc->editSessionNumber == 0 );
00227 m_recursion = true;
00228
00229 m_doc->editStart( );
00230
00231 for ( KateSuperRangeList::const_iterator it = ph->ranges.begin();it != ph->ranges.end();++it )
00232 {
00233 if ( ( *it ) == m_currentRange ) continue;
00234
00235 KateTextCursor start = ( *it ) ->start();
00236 KateTextCursor end = ( *it ) ->end();
00237 m_doc->removeText( start.line(), start.col(), end.line(), end.col(), false );
00238 m_doc->insertText( start.line(), start.col(), sourceText );
00239 }
00240
00241 m_doc->m_undoDontMerge = false;
00242 m_doc->m_undoComplexMerge = true;
00243 m_doc->undoSafePoint();
00244 m_doc->editEnd();
00245 m_doc->m_undoDontMerge = undoDontMerge;
00246 m_recursion = false;
00247
00248 if ( ph->isCursor ) deleteLater();
00249 }
00250
00251 void KateTemplateHandler::locateRange( const KateTextCursor& cursor )
00252 {
00253
00254
00255
00256
00257
00258 for ( uint i = 0;i < m_tabOrder.count();i++ )
00259 {
00260 KateTemplatePlaceHolder *ph = m_tabOrder.at( i );
00261
00262 for ( KateSuperRangeList::const_iterator it = ph->ranges.begin();it != ph->ranges.end();++it )
00263 {
00264 if ( ( *it ) ->includes( cursor ) )
00265 {
00266 m_currentTabStop = i;
00267 m_currentRange = ( *it );
00268
00269 return ;
00270 }
00271 }
00272
00273 }
00274
00275 m_currentRange = 0;
00276
00277
00278
00279
00280 deleteLater();
00281 }
00282
00283
00284 bool KateTemplateHandler::operator() ( KKey key )
00285 {
00286 if ( key==Qt::Key_Tab )
00287 {
00288 m_currentTabStop++;
00289
00290 if ( m_currentTabStop >= ( int ) m_tabOrder.count() )
00291 m_currentTabStop = 0;
00292 }
00293 else
00294 {
00295 m_currentTabStop--;
00296
00297 if ( m_currentTabStop < 0 ) m_currentTabStop = m_tabOrder.count() - 1;
00298 }
00299
00300 m_currentRange = m_tabOrder.at( m_currentTabStop ) ->ranges.at( 0 );
00301
00302 if ( m_tabOrder.at( m_currentTabStop ) ->isInitialValue )
00303 {
00304 m_doc->activeView()->setSelection( m_currentRange->start(), m_currentRange->end() );
00305 }
00306 else m_doc->activeView()->setSelection( m_currentRange->end(), m_currentRange->end() );
00307
00308 m_doc->activeView() ->setCursorPositionReal( m_currentRange->end().line(), m_currentRange->end().col() );
00309 m_doc->activeView() ->tagLine( m_currentRange->end() );
00310
00311 return true;
00312 }
00313
00314 void KateTemplateHandler::slotAboutToRemoveText( const KateTextRange &range )
00315 {
00316 if ( m_recursion ) return ;
00317
00318 if ( m_currentRange && ( !m_currentRange->includes( range.start() ) ) ) locateRange( range.start() );
00319
00320 if ( m_currentRange != 0 )
00321 {
00322 if ( m_currentRange->end() <= range.end() ) return ;
00323 }
00324
00325 if ( m_doc )
00326 {
00327 disconnect( m_doc, SIGNAL( textInserted( int, int ) ), this, SLOT( slotTextInserted( int, int ) ) );
00328 disconnect( m_doc, SIGNAL( aboutToRemoveText( const KateTextRange& ) ), this, SLOT( slotAboutToRemoveText( const KateTextRange& ) ) );
00329 disconnect( m_doc, SIGNAL( textRemoved() ), this, SLOT( slotTextRemoved() ) );
00330 }
00331
00332 deleteLater();
00333 }
00334
00335 void KateTemplateHandler::slotTextRemoved()
00336 {
00337 if ( m_recursion ) return ;
00338 if ( !m_currentRange ) return ;
00339
00340 slotTextInserted( m_currentRange->start().line(), m_currentRange->start().col() );
00341 }
00342