katetemplatehandler.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2004 Joseph Wenninger <jowenn@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 Boston, MA 02110-1301, USA. 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 ); //false/*,this*/); 00043 00044 if ( !m_doc->setTabInterceptor( this ) ) 00045 { 00046 deleteLater(); 00047 return ; 00048 } 00049 00050 KateArbitraryHighlight *kah = doc->arbitraryHL(); 00051 /*KateArbitraryHighlightRange *hlr=new KateArbitraryHighlightRange(doc,KateTextCursor(line,column), 00052 KateTextCursor(line,column+3)); 00053 hlr->setUnderline(true); 00054 hlr->setOverline(true); 00055 l->append(hlr);*/ 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 // don't add %{MACRO} to the tab navigation, unless there was not value 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 /* connect(doc,SIGNAL(charactersInteractivelyInserted(int ,int ,const QString&)),this, 00120 SLOT(slotCharactersInteractivlyInserted(int,int,const QString&))); 00121 connect(doc,SIGNAL(charactersSemiInteractivelyInserted(int ,int ,const QString&)),this, 00122 SLOT(slotCharactersInteractivlyInserted(int,int,const QString&)));*/ 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 // FIXME handle space/tab replacement correctly make it use of the indenter 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 //hlr->setBehaviour(KateSuperRange::ExpandRight); 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 //if (m_editSessionNumber!=0) return; // assume that this is due an udno/redo operation right now 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( /*false*/ ); 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 /* if (m_currentRange) { 00254 m_doc->tagLines(m_currentRange->start().line(),m_currentRange->end().line()); 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 //m_doc->tagLines(m_currentRange->start().line(),m_currentRange->end().line()); 00269 return ; 00270 } 00271 } 00272 00273 } 00274 00275 m_currentRange = 0; 00276 /*while (m_ranges->count()>0) 00277 delete (m_ranges->take(0)); 00278 disconnect(m_ranges,0,0,0); 00279 delete m_ranges;*/ 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