• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

katetemplatehandler.cpp

Go to the documentation of this file.
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 
00019 #include "katetemplatehandler.h"
00020 #include "katetemplatehandler.moc"
00021 #include "katedocument.h"
00022 #include "katesmartcursor.h"
00023 #include "kateview.h"
00024 #include "kateconfig.h"
00025 #include "katerenderer.h"
00026 
00027 #include <ktexteditor/cursor.h>
00028 #include <ktexteditor/smartcursor.h>
00029 #include <ktexteditor/smartrange.h>
00030 #include <ktexteditor/range.h>
00031 #include <ktexteditor/attribute.h>
00032 
00033 #include <QtCore/QRegExp>
00034 #include <kdebug.h>
00035 
00036 KateTemplateHandler::KateTemplateHandler(
00037   KateDocument *doc,
00038   const KTextEditor::Cursor& position,
00039   const QString &templateString,
00040   const QMap<QString, QString> &initialValues )
00041     : QObject( doc )
00042     , KateKeyInterceptorFunctor()
00043     , m_doc( doc )
00044     , m_currentTabStop( -1 )
00045     , m_currentRange( 0 )
00046     , m_initOk( false )
00047     , m_recursion( false )
00048     , m_templateRange(0)
00049 {
00050   connect( m_doc, SIGNAL( destroyed() ), this, SLOT( slotDocumentDestroyed() ) );
00051 
00052   if ( !m_doc->setTabInterceptor( this ) )
00053   {
00054     deleteLater();
00055     return ;
00056   }
00057 
00058   /*KateArbitraryHighlight *kah = doc->arbitraryHL();
00059   KateArbitraryHighlightRange *hlr=new KateArbitraryHighlightRange(doc,KTextEditor::Cursor(line,column),
00060    KTextEditor::Cursor(line,column+3));
00061   hlr->setUnderline(true);
00062   hlr->setOverline(true);
00063   l->append(hlr);*/
00064   QList<KateTemplateHandlerPlaceHolderInfo> buildList;
00065   QRegExp rx( "([$%])\\{([^}\\s]+)\\}" );
00066   rx.setMinimal( true );
00067   int pos = 0;
00068   int opos = 0;
00069   QString insertString = templateString;
00070 
00071   while ( pos >= 0 )
00072   {
00073     pos = rx.indexIn( insertString, pos );
00074 
00075     if ( pos > -1 )
00076     {
00077       if ( ( pos - opos ) > 0 )
00078       {
00079         if ( insertString[ pos - 1 ] == '\\' )
00080         {
00081           insertString.remove( pos - 1, 1 );
00082           opos = pos;
00083           continue;
00084         }
00085       }
00086 
00087       QString placeholder = rx.cap( 2 );
00088       QString value = initialValues[ placeholder ];
00089 
00090       // don't add %{MACRO} to the tab navigation, unless there was not value
00091       if ( rx.cap( 1 ) != "%" || placeholder == value )
00092         buildList.append( KateTemplateHandlerPlaceHolderInfo( pos, value.length(), placeholder ) );
00093 
00094       insertString.replace( pos, rx.matchedLength(), value );
00095       pos += value.length();
00096       opos = pos;
00097     }
00098   }
00099 
00100   doc->editStart();
00101 
00102   if ( !doc->insertText( position, insertString ) )
00103   {
00104     deleteLater();
00105     doc->editEnd();
00106     return ;
00107   }
00108 
00109   if ( buildList.isEmpty() )
00110   {
00111     m_initOk = true;
00112     deleteLater();
00113     doc->editEnd();
00114     return ;
00115   }
00116 
00117   doc->undoSafePoint();
00118   doc->editEnd();
00119   generateRangeTable( position, insertString, buildList );
00120   //kah->addHighlightToDocument( m_ranges );
00121 
00122     //m_ranges->tagAll();
00123 
00124   /* connect(doc,SIGNAL(charactersInteractivelyInserted(int ,int ,const QString&)),this,
00125    SLOT(slotCharactersInteractivlyInserted(int,int,const QString&)));
00126    connect(doc,SIGNAL(charactersSemiInteractivelyInserted(const KTextEditor::Cursor& ,const QString&)),this,
00127    SLOT(slotCharactersInteractivlyInserted(const KTextEditor::Cursor&,const QString&)));*/
00128   connect( doc, SIGNAL( textInserted(KTextEditor::Document*, const KTextEditor::Range& ) ), this, SLOT( slotTextInserted(KTextEditor::Document*, const KTextEditor::Range& ) ) );
00129   connect( doc, SIGNAL( aboutToRemoveText( const KTextEditor::Range& ) ), this, SLOT( slotAboutToRemoveText( const KTextEditor::Range& ) ) );
00130   connect( doc, SIGNAL( textRemoved() ), this, SLOT( slotTextRemoved() ) );
00131 
00132   ( *this ) ( Qt::Key_Tab );
00133 }
00134 
00135 KateTemplateHandler::~KateTemplateHandler()
00136 {
00137   if ( m_doc )
00138   {
00139     m_doc->removeTabInterceptor( this );
00140   }
00141   delete m_templateRange;
00142 #ifdef __GNUC__
00143   #warning delete placeholder infos here
00144 #endif
00145 }
00146 
00147 void KateTemplateHandler::slotRangeDeleted(KTextEditor::SmartRange* range) {
00148   if (range==m_templateRange) m_templateRange=0;
00149 }
00150 
00151 void KateTemplateHandler::slotDocumentDestroyed() {m_doc = 0;}
00152 
00153 void KateTemplateHandler::generateRangeTable( const KTextEditor::Cursor& insertPosition, const QString& insertString, const QList<KateTemplateHandlerPlaceHolderInfo> &buildList )
00154 {
00155 
00156   KateRendererConfig *config=m_doc->activeKateView()->renderer()->config();
00157   kDebug(13020)<<config->templateEditablePlaceholderColor()<<config->templateBackgroundColor()<<config->templateFocusedEditablePlaceholderColor()<<config->templateNotEditablePlaceholderColor();
00158   //editable/master placeholder
00159 /*  KTextEditor::Attribute::Ptr attributeEditableElement(new KTextEditor::Attribute());
00160   attributeEditableElement->setBackground(QBrush(config->templateEditablePlaceholderColor(),Qt::Dense4Pattern));
00161   KTextEditor::Attribute::Ptr attributeEditableElementFocus(new KTextEditor::Attribute());
00162   attributeEditableElementFocus->setBackground(QBrush(config->templateFocusedEditablePlaceholderColor(),Qt::Dense4Pattern));
00163   attributeEditableElement->setDynamicAttribute(KTextEditor::Attribute::ActivateCaretIn,attributeEditableElementFocus);
00164   //not editable/slave placeholder
00165   KTextEditor::Attribute::Ptr attributeNotEditableElement(new KTextEditor::Attribute());
00166   attributeNotEditableElement->setBackground(QBrush(config->templateNotEditablePlaceholderColor(),Qt::Dense4Pattern));
00167   //template background
00168   KTextEditor::Attribute::Ptr attributeTemplateBackground(new KTextEditor::Attribute());
00169   attributeTemplateBackground->setBackground(QBrush(config->templateBackgroundColor(),Qt::Dense7Pattern));*/
00170   QColor color;
00171   color=config->templateEditablePlaceholderColor();
00172   color.setAlpha(0x88);
00173   KTextEditor::Attribute::Ptr attributeEditableElement(new KTextEditor::Attribute());
00174   attributeEditableElement->setBackground(QBrush(color));
00175   KTextEditor::Attribute::Ptr attributeEditableElementFocus(new KTextEditor::Attribute());
00176   color=config->templateFocusedEditablePlaceholderColor();
00177   color.setAlpha(0x88);
00178   attributeEditableElementFocus->setBackground(QBrush(color));
00179   attributeEditableElement->setDynamicAttribute(KTextEditor::Attribute::ActivateCaretIn,attributeEditableElementFocus);
00180   //not editable/slave placeholder
00181   KTextEditor::Attribute::Ptr attributeNotEditableElement(new KTextEditor::Attribute());
00182   color=config->templateNotEditablePlaceholderColor();
00183   color.setAlpha(0x88);
00184   attributeNotEditableElement->setBackground(QBrush(color));
00185   //template background
00186   KTextEditor::Attribute::Ptr attributeTemplateBackground(new KTextEditor::Attribute());
00187   color=config->templateBackgroundColor();
00188   color.setAlpha(0x88);
00189   attributeTemplateBackground->setBackground(QBrush(color));
00190 
00191 //  m_doc->insertText(insertPosition,insertString);
00192   KTextEditor::SmartCursor *endC= m_doc->newSmartCursor(insertPosition);
00193   endC->advance(insertString.length());
00194   m_templateRange=m_doc->newSmartRange(KTextEditor::Range(insertPosition,*endC));
00195   connect(m_templateRange->primaryNotifier(),SIGNAL(rangeDeleted(KTextEditor::SmartRange*)),this,SLOT(slotRangeDeleted(KTextEditor::SmartRange*)));
00196   kDebug(13020)<<insertPosition.line()<<"/"<<insertPosition.column()<<"--"<<endC->line()<<"/"<<endC->column()<<"++++"<<m_templateRange;
00197   delete endC;
00198   m_templateRange->setAttribute(attributeTemplateBackground);
00199 
00200   uint line = insertPosition.line();
00201   uint col = insertPosition.column();
00202   uint colInText = 0;
00203 
00204   foreach (const KateTemplateHandlerPlaceHolderInfo& info, buildList)
00205   {
00206     bool firstOccurrence=false;
00207     KateTemplatePlaceHolder *ph = m_dict[ info.placeholder ];
00208 
00209     if ( !ph )
00210     {
00211       firstOccurrence=true;
00212       ph = new KateTemplatePlaceHolder(( info.placeholder == "cursor" ),true,false);
00213 
00214       m_dict.insert( info.placeholder, ph );
00215 
00216       if ( !ph->isCursor ) m_tabOrder.append( ph );
00217     }
00218 
00219     // FIXME handle space/tab replacement correctly make it use of the indenter
00220     while ( colInText < info.begin )
00221     {
00222       ++col;
00223 
00224       if ( insertString.at( colInText ) == '\n' )
00225       {
00226         col = 0;
00227         line++;
00228       }
00229 
00230       ++colInText;
00231     }
00232 
00233     KTextEditor::SmartCursor *tmpC=m_doc->newSmartCursor(KTextEditor::Cursor(line,col));;
00234     tmpC->advance(info.len);
00235     KTextEditor::SmartRange *hlr=m_doc->newSmartRange(KTextEditor::Range(KTextEditor::Cursor(line,col),*tmpC),m_templateRange,KTextEditor::SmartRange::ExpandRight);
00236     hlr->setAttribute(firstOccurrence?attributeEditableElement:attributeNotEditableElement);
00237     hlr->setParentRange(m_templateRange);
00238     delete tmpC;
00239     ph->ranges.append(hlr);
00240 
00241     colInText += info.len;
00242     col += info.len;
00243       //hlr->allowZeroLength();
00244     //hlr->setBehavior(KateSmartRange::ExpandRight);
00245   }
00246 
00247   KateTemplatePlaceHolder *cursor = m_dict[ "cursor" ];
00248 
00249   if ( cursor ) m_tabOrder.append( cursor );
00250   m_doc->addHighlightToDocument(m_templateRange,true);
00251 }
00252 
00253 void KateTemplateHandler::slotTextInserted(KTextEditor::Document*, const KTextEditor::Range& range)
00254 {
00255   if (m_doc->isEditRunning() && (!m_doc->isWithUndo())) return;
00256 
00257 #ifdef __GNUC__
00258 #warning FIXME undo/redo detection
00259 #endif
00260   kDebug(13020)<<"KateTemplateHandler::slotTextInserted *****";
00261   if ( m_recursion ) return ;
00262   kDebug(13020)<<"KateTemplateHandler::slotTextInserted: no recurssion";
00263   //if (m_editSessionNumber!=0) return; // assume that this is due an udno/redo operation right now
00264   KTextEditor::Cursor cur=range.start();
00265   KTextEditor::Cursor curE=range.end();
00266 
00267   kDebug(13020)<<cur.line()<<"/"<<cur.column()<<"---"<<m_currentRange->start().line()<<"/"<<m_currentRange->start().column()<<"+++"<<m_currentRange->end().line()<<"/"<<m_currentRange->end().column();
00268 
00269   kDebug(13020)<<m_doc->text(range);
00270 
00271   if ( ( !m_currentRange ) ||
00272        ( ( !m_currentRange->contains( cur ) ) && ( ! ( ( m_currentRange->start() == m_currentRange->end() ) && ( (m_currentRange->end() == cur) || 
00273 (m_currentRange->start()==curE) ) ) )
00274        ) ) locateRange( cur,curE );
00275 
00276   if ( !m_currentRange ) return ;
00277 
00278 
00279   bool expandedLeft=false;
00280 
00281   if (m_currentRange->start()==curE) {
00282     expandedLeft=true;
00283     m_currentRange->setRange(KTextEditor::Range(cur,m_currentRange->end()));
00284   }
00285 
00286   kDebug(13020)<<"KateTemplateHandler::slotTextInserted: m_currentRange is not null";
00287 
00288   KateTemplatePlaceHolder *ph = m_tabOrder.at( m_currentTabStop );
00289 
00290   m_recursion = true;
00291   m_doc->editStart( /*false*/ );
00292 
00293   QString sourceText = m_doc->text ( *m_currentRange );
00294   kDebug(13020)<<"KateTemplateHandler::slotTextInserted:"<<ph->isReplacableSpace<<"--->"<<sourceText<<"<---";
00295   if ( (sourceText.length()==0) || (ph->isReplacableSpace && (sourceText==" ")) ) {
00296     ph->isReplacableSpace = true;
00297     sourceText=QString(" ");
00298     KTextEditor::Cursor start = m_currentRange->start();
00299     m_doc->insertText( m_currentRange->start(), sourceText );
00300     m_currentRange->setRange(KTextEditor::Range(start,m_currentRange->end()));
00301     m_doc->activeView()->setSelection( *m_currentRange );
00302     kDebug()<<"inserted a replaceable space:"<<m_currentRange->start().line()<<"/"<<m_currentRange->start().column()<<"+++"<<m_currentRange->end().line()<<"/"<<m_currentRange->end().column();
00303   }
00304   else {
00305    if (ph->isReplacableSpace && sourceText.startsWith(' ')) {
00306     m_doc->removeText( KTextEditor::Range(m_currentRange->start(),1));
00307     sourceText=sourceText.right(sourceText.length()-1);
00308    } else if (ph->isReplacableSpace && expandedLeft) {
00309     m_doc->removeText( KTextEditor::Range(KTextEditor::Cursor(m_currentRange->end().line(),m_currentRange->end().column()-1),1) );
00310     sourceText=sourceText.left(sourceText.length()-1);
00311    }
00312    ph->isReplacableSpace = false;
00313   }
00314   ph->isInitialValue = false;
00315 
00316   bool undoDontMerge = m_doc->undoDontMerge();
00317   //Q_ASSERT( !m_doc->isEditRunning() );
00318 
00319 
00320     foreach ( KTextEditor::SmartRange* range, ph->ranges )
00321   {
00322     if ( range == m_currentRange ) continue;
00323     kDebug(13020)<<"KateTemplateHandler::slotTextInserted: updating a range:"<<range->start().line()<<"/"<<range->start().column()<<"+++"<<range->end().line()<<"/"<<range->end().column();
00324     KTextEditor::Cursor start = range->start();
00325     KTextEditor::Cursor end = range->end();
00326     //m_doc->removeText( start.line(), start.column(), end.line(), end.column(), false );
00327     //m_doc->insertText( start.line(), start.column(), sourceText );
00328     m_doc->removeText( *range, false );
00329     kDebug(13020)<<"KateTemplateHandler::slotTextInserted: updating a range(2):"<<range->start().line()<<"/"<<range->start().column()<<"+++"<<range->end().line()<<"/"<<range->end().column();
00330     m_doc->insertText( start, sourceText );
00331     range->setRange(KTextEditor::Range(start,range->end()));
00332     kDebug(13020)<<"KateTemplateHandler::slotTextInserted: updating a range(3):"<<range->start().line()<<"/"<<range->start().column()<<"+++"<<range->end().line()<<"/"<<range->end().column();
00333   }
00334 
00335   m_doc->setUndoDontMerge(false);
00336   m_doc->setUndoDontMergeComplex(true);
00337   m_doc->undoSafePoint();
00338   m_doc->editEnd();
00339   m_doc->setUndoDontMerge(undoDontMerge);
00340   m_recursion = false;
00341 
00342   if ( ph->isCursor ) deleteLater();
00343 }
00344 
00345 void KateTemplateHandler::locateRange( const KTextEditor::Cursor& cursor, const KTextEditor::Cursor& cursor2 )
00346 {
00347   /* if (m_currentRange) {
00348     m_doc->tagLines(m_currentRange->start().line(),m_currentRange->end().line());
00349 
00350    }*/
00351 
00352   for ( int i = 0;i < m_tabOrder.count();i++ )
00353   {
00354     KateTemplatePlaceHolder *ph = m_tabOrder.at( i );
00355 
00356     foreach ( KTextEditor::SmartRange* range, ph->ranges)
00357     {
00358     kDebug(13020)<<"KateTemplateHandler::locateRange:"<<"CURSOR:"<<cursor.line()<<"|"<<cursor.column()<<" RANGE:"<<range->start().line()<<"/"<<range->start().column()<<"+++"<<range->end().line()<<"/"<<range->end().column();
00359       if ( range->contains( cursor ) )
00360       {
00361         m_currentTabStop = i;
00362         m_currentRange = range;
00363         //m_doc->tagLines(m_currentRange->start().line(),m_currentRange->end().line());
00364         return ;
00365       }
00366     }
00367 
00368   }
00369 
00370   for ( int i = 0;i < m_tabOrder.count();i++ )
00371   {
00372     KateTemplatePlaceHolder *ph = m_tabOrder.at( i );
00373 
00374     foreach ( KTextEditor::SmartRange* range, ph->ranges)
00375     {
00376     kDebug(13020)<<"KateTemplateHandler::locateRange:"<<"CURSOR:"<<cursor.line()<<"|"<<cursor.column()<<" RANGE:"<<range->start().line()<<"/"<<range->start().column()<<"+++"<<range->end().line()<<"/"<<range->end().column();
00377       if ( range->contains( cursor2 ) )
00378       {
00379         m_currentTabStop = i;
00380         m_currentRange = range;
00381         //m_doc->tagLines(m_currentRange->start().line(),m_currentRange->end().line());
00382         return ;
00383       }
00384     }
00385 
00386   }
00387 
00388   m_currentRange = 0;
00389   /*while (m_ranges->count()>0)
00390    delete (m_ranges->take(0));
00391   disconnect(m_ranges,0,0,0);
00392   delete m_ranges;*/
00393   KateTemplatePlaceHolder *cur = m_dict[ "cursor" ];
00394   if (cur) {
00395     if (cur->isInitialValue) { //this check should never be important
00396       m_doc->removeText(*(cur->ranges[0]));
00397     }
00398   }
00399   deleteLater();
00400 }
00401 
00402 
00403 bool KateTemplateHandler::operator() ( int key )
00404 {
00405   if ( key==Qt::Key_Tab )
00406   {
00407     m_currentTabStop++;
00408 
00409     if ( m_currentTabStop >= ( int ) m_tabOrder.count() )
00410       m_currentTabStop = 0;
00411   }
00412   else
00413   {
00414     m_currentTabStop--;
00415 
00416     if ( m_currentTabStop < 0 ) m_currentTabStop = m_tabOrder.count() - 1;
00417   }
00418 
00419   m_currentRange = m_tabOrder.at( m_currentTabStop )->ranges[0];
00420 
00421   KateTemplatePlaceHolder *ph=m_tabOrder.at( m_currentTabStop );
00422   if (  ph->isInitialValue || ph->isReplacableSpace)
00423   {
00424     m_doc->activeView()->setSelection( *m_currentRange );
00425   }
00426   else m_doc->activeView()->setSelection( KTextEditor::Range(m_currentRange->end(), m_currentRange->end()) );
00427 
00428   KTextEditor::Cursor curpos=m_currentRange->end();
00429 
00430   m_doc->activeView()->setCursorPosition( curpos );
00431   m_doc->activeKateView()->tagLine( m_currentRange->end() );
00432   return true;
00433 }
00434 
00435 void KateTemplateHandler::slotAboutToRemoveText( const KTextEditor::Range& range )
00436 {
00437   if ( m_recursion ) return ;
00438 
00439 kDebug(13020)<<"KateTemplateHandler::slotAboutToRemoveText (remove):"<<range.start().line()<<"/"<<range.start().column()<<"+++"<<range.end().line()<<"/"<<range.end().column();
00440 
00441   if (range.start()==range.end()) return;
00442 
00443   if (m_currentRange) {
00444     KTextEditor::Cursor cur=range.start();
00445     kDebug(13020)<<cur.line()<<"/"<<cur.column()<<"---"<<m_currentRange->start().line()<<"/"<<m_currentRange->start().column()<<"+++"<<m_currentRange->end().line()<<"/"<<m_currentRange->end().column();
00446   }
00447   if ( m_currentRange && ( !m_currentRange->contains( range.start() ) ) ) {
00448     kDebug(13020)<<"KateTemplateHandler::slotAboutToRemoveText: about to locate range";
00449     locateRange( range.start(), KTextEditor::Cursor(-1,-1) );
00450   }
00451 
00452   if ( m_currentRange != 0 )
00453   {
00454     if ( range.end() <= m_currentRange->end() ) return ;
00455   }
00456 
00457   kDebug(13020)<<"KateTemplateHandler::slotAboutToRemoveText: disconnect & leave";
00458   if ( m_doc )
00459   {
00460     disconnect( m_doc, SIGNAL( textInserted(KTextEditor::Document*, const KTextEditor::Range& ) ), this, SLOT( slotTextInserted(KTextEditor::Document*, const KTextEditor::Range& ) ) );
00461     disconnect( m_doc, SIGNAL( aboutToRemoveText( const KTextEditor::Range& ) ), this, SLOT( slotAboutToRemoveText( const KTextEditor::Range& ) ) );
00462     disconnect( m_doc, SIGNAL( textRemoved() ), this, SLOT( slotTextRemoved() ) );
00463   }
00464 
00465   deleteLater();
00466 }
00467 
00468 void KateTemplateHandler::slotTextRemoved()
00469 {
00470   if ( m_recursion ) return ;
00471   if ( !m_currentRange ) return ;
00472 
00473   slotTextInserted( m_doc,*m_currentRange);
00474 }
00475 

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal