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

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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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