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->setSelection( m_currentRange->start(), m_currentRange->end() );
00305 }
00306
else m_doc->setSelection( m_currentRange->end(), m_currentRange->end() );
00307
00308 m_doc->activeView() ->setCursorPosition( 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