kate Library API Documentation

docwordcompletion.cpp

00001 /* 00002 This library is free software; you can redistribute it and/or 00003 modify it under the terms of the GNU Library General Public 00004 License version 2 as published by the Free Software Foundation. 00005 00006 This library is distributed in the hope that it will be useful, 00007 but WITHOUT ANY WARRANTY; without even the implied warranty of 00008 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00009 Library General Public License for more details. 00010 00011 You should have received a copy of the GNU Library General Public License 00012 along with this library; see the file COPYING.LIB. If not, write to 00013 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00014 Boston, MA 02111-1307, USA. 00015 00016 --- 00017 file: docwordcompletion.cpp 00018 00019 KTextEditor plugin to autocompletion with document words. 00020 Copyright Anders Lund <anders.lund@lund.tdcadsl.dk>, 2003 00021 00022 The following completion methods are supported: 00023 * Completion with bigger matching words in 00024 either direction (backward/forward). 00025 * NOT YET Pop up a list of all bigger matching words in document 00026 00027 */ 00028 //BEGIN includes 00029 #include "docwordcompletion.h" 00030 00031 #include <ktexteditor/document.h> 00032 #include <ktexteditor/viewcursorinterface.h> 00033 #include <ktexteditor/editinterface.h> 00034 #include <ktexteditor/variableinterface.h> 00035 00036 #include <kapplication.h> 00037 #include <kconfig.h> 00038 #include <kdialog.h> 00039 #include <kgenericfactory.h> 00040 #include <klocale.h> 00041 #include <kaction.h> 00042 #include <knotifyclient.h> 00043 #include <kparts/part.h> 00044 #include <kiconloader.h> 00045 00046 #include <qregexp.h> 00047 #include <qstring.h> 00048 #include <qdict.h> 00049 #include <qspinbox.h> 00050 #include <qlabel.h> 00051 #include <qlayout.h> 00052 #include <qhbox.h> 00053 #include <qwhatsthis.h> 00054 #include <qcheckbox.h> 00055 00056 // #include <kdebug.h> 00057 //END 00058 00059 //BEGIN DocWordCompletionPlugin 00060 K_EXPORT_COMPONENT_FACTORY( ktexteditor_docwordcompletion, KGenericFactory<DocWordCompletionPlugin>( "ktexteditor_docwordcompletion" ) ) 00061 DocWordCompletionPlugin::DocWordCompletionPlugin( QObject *parent, 00062 const char* name, 00063 const QStringList& /*args*/ ) 00064 : KTextEditor::Plugin ( (KTextEditor::Document*) parent, name ) 00065 { 00066 readConfig(); 00067 } 00068 00069 void DocWordCompletionPlugin::readConfig() 00070 { 00071 KConfig *config = kapp->config(); 00072 config->setGroup( "DocWordCompletion Plugin" ); 00073 m_treshold = config->readNumEntry( "treshold", 3 ); 00074 m_autopopup = config->readBoolEntry( "autopopup", true ); 00075 } 00076 00077 void DocWordCompletionPlugin::writeConfig() 00078 { 00079 KConfig *config = kapp->config(); 00080 config->setGroup("DocWordCompletion Plugin"); 00081 config->writeEntry("autopopup", m_autopopup ); 00082 config->writeEntry("treshold", m_treshold ); 00083 } 00084 00085 void DocWordCompletionPlugin::addView(KTextEditor::View *view) 00086 { 00087 DocWordCompletionPluginView *nview = new DocWordCompletionPluginView (m_treshold, m_autopopup, view, "Document word completion"); 00088 m_views.append (nview); 00089 } 00090 00091 void DocWordCompletionPlugin::removeView(KTextEditor::View *view) 00092 { 00093 for (uint z=0; z < m_views.count(); z++) 00094 if (m_views.at(z)->parentClient() == view) 00095 { 00096 DocWordCompletionPluginView *nview = m_views.at(z); 00097 m_views.remove (nview); 00098 delete nview; 00099 } 00100 } 00101 00102 KTextEditor::ConfigPage* DocWordCompletionPlugin::configPage( uint, QWidget *parent, const char *name ) 00103 { 00104 return new DocWordCompletionConfigPage( this, parent, name ); 00105 } 00106 00107 QString DocWordCompletionPlugin::configPageName( uint ) const 00108 { 00109 return i18n("Word Completion Plugin"); 00110 } 00111 00112 QString DocWordCompletionPlugin::configPageFullName( uint ) const 00113 { 00114 return i18n("Configure the Word Completion Plugin"); 00115 } 00116 00117 // FIXME provide sucn a icon 00118 QPixmap DocWordCompletionPlugin::configPagePixmap( uint, int size ) const 00119 { 00120 return UserIcon( "kte_wordcompletion", size ); 00121 } 00122 //END 00123 00124 //BEGIN DocWordCompletionPluginView 00125 struct DocWordCompletionPluginViewPrivate 00126 { 00127 uint line, col; // start position of last match (where to search from) 00128 uint cline, ccol; // cursor position 00129 uint lilen; // length of last insertion 00130 QString last; // last word we were trying to match 00131 QString lastIns; // latest applied completion 00132 QRegExp re; // hrm 00133 KToggleAction *autopopup; // for accessing state 00134 uint treshold; // the required length of a word before popping up the completion list automatically 00135 }; 00136 00137 DocWordCompletionPluginView::DocWordCompletionPluginView( uint treshold, bool autopopup, KTextEditor::View *view, const char *name ) 00138 : QObject( view, name ), 00139 KXMLGUIClient( view ), 00140 m_view( view ), 00141 d( new DocWordCompletionPluginViewPrivate ) 00142 { 00143 d->treshold = treshold; 00144 view->insertChildClient( this ); 00145 setInstance( KGenericFactory<DocWordCompletionPlugin>::instance() ); 00146 00147 (void) new KAction( i18n("Reuse Word Behind"), CTRL+Key_H, this, 00148 SLOT(completeBackwards()), actionCollection(), "doccomplete_bw" ); 00149 (void) new KAction( i18n("Reuse Word Ahead"), CTRL+Key_J, this, 00150 SLOT(completeForwards()), actionCollection(), "doccomplete_fw" ); 00151 (void) new KAction( i18n("Pop Up Completion List"), CTRL+Key_Y, this, 00152 SLOT(popupCompletionList()), actionCollection(), "doccomplete_pu" ); 00153 d->autopopup = new KToggleAction( i18n("Automatic Completion Popup"), 0, this, 00154 SLOT(toggleAutoPopup()), actionCollection(), "enable_autopopup" ); 00155 00156 d->autopopup->setChecked( autopopup ); 00157 toggleAutoPopup(); 00158 00159 setXMLFile("docwordcompletionui.rc"); 00160 00161 KTextEditor::VariableInterface *vi = KTextEditor::variableInterface( view->document() ); 00162 if ( vi ) 00163 { 00164 QString e = vi->variable("wordcompletion-autopopup"); 00165 if ( ! e.isEmpty() ) 00166 d->autopopup->setEnabled( e == "true" ); 00167 00168 connect( view->document(), SIGNAL(variableChanged(const QString &, const QString &)), 00169 this, SLOT(slotVariableChanged(const QString &, const QString &)) ); 00170 } 00171 } 00172 00173 void DocWordCompletionPluginView::settreshold( uint t ) 00174 { 00175 d->treshold = t; 00176 } 00177 00178 void DocWordCompletionPluginView::completeBackwards() 00179 { 00180 complete( false ); 00181 } 00182 00183 void DocWordCompletionPluginView::completeForwards() 00184 { 00185 complete(); 00186 } 00187 00188 // Pop up the editors completion list if applicable 00189 void DocWordCompletionPluginView::popupCompletionList( QString w ) 00190 { 00191 if ( w.isEmpty() ) 00192 w = word(); 00193 if ( w.isEmpty() ) 00194 return; 00195 00196 KTextEditor::CodeCompletionInterface *cci = codeCompletionInterface( m_view ); 00197 cci->showCompletionBox( allMatches( w ), w.length() ); 00198 } 00199 00200 void DocWordCompletionPluginView::toggleAutoPopup() 00201 { 00202 if ( d->autopopup->isChecked() ) 00203 connect( m_view->document(), SIGNAL(textChanged()), this, SLOT(autoPopupCompletionList()) ); 00204 else 00205 disconnect( m_view->document(), SIGNAL(textChanged()), this, SLOT(autoPopupCompletionList()) ); 00206 } 00207 00208 // for autopopup FIXME - don't pop up if reuse word is inserting 00209 void DocWordCompletionPluginView::autoPopupCompletionList() 00210 { 00211 QString w = word(); 00212 if ( w.length() == d->treshold ) 00213 { 00214 popupCompletionList( w ); 00215 } 00216 } 00217 00218 // Do one completion, searching in the desired direction, 00219 // if possible 00220 void DocWordCompletionPluginView::complete( bool fw ) 00221 { 00222 // setup 00223 KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() ); 00224 // find the word we are typing 00225 uint cline, ccol; 00226 viewCursorInterface( m_view )->cursorPosition( &cline, &ccol ); 00227 QString wrd = word(); 00228 if ( wrd.isEmpty() ) return; 00229 00230 /* IF the current line is equal to the previous line 00231 AND the position - the length of the last inserted string 00232 is equal to the old position 00233 AND the lastinsertedlength last characters of the word is 00234 equal to the last inserted string 00235 */ 00236 if ( cline == d-> cline && 00237 ccol - d->lilen == d->ccol && 00238 wrd.endsWith( d->lastIns ) ) 00239 { 00240 // this is a repeted activation 00241 ccol = d->ccol; 00242 wrd = d->last; 00243 } 00244 else 00245 { 00246 d->cline = cline; 00247 d->ccol = ccol; 00248 d->last = wrd; 00249 d->lastIns = QString::null; 00250 d->line = d->cline; 00251 d->col = d->ccol - wrd.length(); 00252 d->lilen = 0; 00253 } 00254 00255 d->re.setPattern( "\\b" + wrd + "(\\w+)" ); 00256 int inc = fw ? 1 : -1; 00257 int pos ( 0 ); 00258 QString ln = ei->textLine( d->line ); 00259 00260 if ( ! fw ) 00261 ln = ln.mid( 0, d->col ); 00262 00263 while ( true ) 00264 { 00265 pos = fw ? 00266 d->re.search( ln, d->col ) : 00267 d->re.searchRev( ln, d->col ); 00268 00269 if ( pos > -1 ) // we matched a word 00270 { 00271 QString m = d->re.cap( 1 ); 00272 if ( m != d->lastIns ) 00273 { 00274 // we got good a match! replace text and return. 00275 if ( d->lilen ) 00276 ei->removeText( d->cline, d->ccol, d->cline, d->ccol + d->lilen ); 00277 ei->insertText( d->cline, d->ccol, m ); 00278 00279 d->lastIns = m; 00280 d->lilen = m.length(); 00281 d->col = pos; // for next try 00282 00283 if ( fw ) 00284 d->col += m.length(); 00285 00286 return; 00287 } 00288 00289 // equal to last one, continue 00290 else 00291 { 00292 d->col = pos; // for next try 00293 if ( fw ) 00294 d->col += m.length(); 00295 else // FIXME figure out if all of that is really nessecary 00296 { 00297 if ( pos == 0 ) 00298 { 00299 if ( d->line > 0 ) 00300 { 00301 d->line += inc; 00302 ln = ei->textLine( d->line ); 00303 d->col = ln.length(); 00304 } 00305 else 00306 { 00307 KNotifyClient::beep(); 00308 return; 00309 } 00310 } 00311 else 00312 d->col--; 00313 } 00314 } 00315 } 00316 00317 else // no match 00318 { 00319 if ( ! fw && d->line == 0) 00320 { 00321 KNotifyClient::beep(); 00322 return; 00323 } 00324 else if ( fw && d->line >= ei->numLines() ) 00325 { 00326 KNotifyClient::beep(); 00327 return; 00328 } 00329 00330 d->line += inc; 00331 if ( fw ) 00332 d->col++; 00333 00334 ln = ei->textLine( d->line ); 00335 d->col = fw ? 0 : ln.length(); 00336 } 00337 } // while true 00338 } 00339 00340 // Return the string to complete (the letters behind the cursor) 00341 QString DocWordCompletionPluginView::word() 00342 { 00343 uint cline, ccol; 00344 viewCursorInterface( m_view )->cursorPositionReal( &cline, &ccol ); 00345 if ( ! ccol ) return QString::null; // no word 00346 KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() ); 00347 d->re.setPattern( "\\b(\\w+)$" ); 00348 if ( d->re.searchRev( 00349 ei->text( cline, 0, cline, ccol ) 00350 ) < 0 ) 00351 return QString::null; // no word 00352 return d->re.cap( 1 ); 00353 } 00354 00355 // Scan throught the entire document for possible completions, 00356 // ignoring any dublets 00357 QValueList<KTextEditor::CompletionEntry> DocWordCompletionPluginView::allMatches( const QString &word ) 00358 { 00359 QValueList<KTextEditor::CompletionEntry> l; 00360 uint i( 0 ); 00361 int pos( 0 ); 00362 d->re.setPattern( "\\b("+word+"\\w+)" ); 00363 QString s, m; 00364 KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() ); 00365 QDict<int> seen; // maybe slow with > 17 matches 00366 int sawit(1); // to ref for the dict 00367 00368 while( i < ei->numLines() ) 00369 { 00370 s = ei->textLine( i ); 00371 pos = 0; 00372 while ( pos >= 0 ) 00373 { 00374 pos = d->re.search( s, pos ); 00375 if ( pos >= 0 ) 00376 { 00377 m = d->re.cap( 1 ); 00378 if ( ! seen[ m ] ) { 00379 seen.insert( m, &sawit ); 00380 KTextEditor::CompletionEntry e; 00381 e.text = m; 00382 l.append( e ); 00383 } 00384 pos += d->re.matchedLength(); 00385 } 00386 } 00387 i++; 00388 } 00389 return l; 00390 } 00391 00392 void DocWordCompletionPluginView::slotVariableChanged( const QString &var, const QString &val ) 00393 { 00394 if ( var == "wordcompletion-autopopup" ) 00395 d->autopopup->setEnabled( val == "true" ); 00396 else if ( var == "wordcompletion-treshold" ) 00397 d->treshold = val.toInt(); 00398 } 00399 //END 00400 00401 //BEGIN DocWordCompletionConfigPage 00402 DocWordCompletionConfigPage::DocWordCompletionConfigPage( DocWordCompletionPlugin *completion, QWidget *parent, const char *name ) 00403 : KTextEditor::ConfigPage( parent, name ) 00404 , m_completion( completion ) 00405 { 00406 QVBoxLayout *lo = new QVBoxLayout( this ); 00407 lo->setSpacing( KDialog::spacingHint() ); 00408 00409 cbAutoPopup = new QCheckBox( i18n("Automatically show completion list"), this ); 00410 lo->addWidget( cbAutoPopup ); 00411 00412 QHBox *hb = new QHBox( this ); 00413 hb->setSpacing( KDialog::spacingHint() ); 00414 lo->addWidget( hb ); 00415 new QLabel( i18n("when the word is"), hb ); 00416 sbAutoPopup = new QSpinBox( 1, 30, 1, hb ); 00417 new QLabel( i18n("characters long."), hb ); 00418 00419 QWhatsThis::add( cbAutoPopup, i18n( 00420 "Enable the automatic completion list popup as default. The popup can " 00421 "be disabled on a view basis from the 'Tools' menu.") ); 00422 QWhatsThis::add( sbAutoPopup, i18n( 00423 "Define the length a word should have before the completion list " 00424 "is displayed.") ); 00425 00426 cbAutoPopup->setChecked( m_completion->autoPopupEnabled() ); 00427 sbAutoPopup->setValue( m_completion->treshold() ); 00428 00429 lo->addStretch(); 00430 } 00431 00432 void DocWordCompletionConfigPage::apply() 00433 { 00434 m_completion->setAutoPopupEnabled( cbAutoPopup->isChecked() ); 00435 m_completion->setTreshold( sbAutoPopup->value() ); 00436 m_completion->writeConfig(); 00437 } 00438 00439 void DocWordCompletionConfigPage::reset() 00440 { 00441 cbAutoPopup->setChecked( m_completion->autoPopupEnabled() ); 00442 sbAutoPopup->setValue( m_completion->treshold() ); 00443 } 00444 00445 void DocWordCompletionConfigPage::defaults() 00446 { 00447 cbAutoPopup->setChecked( true ); 00448 sbAutoPopup->setValue( 3 ); 00449 } 00450 00451 //END DocWordCompletionConfigPage 00452 00453 #include "docwordcompletion.moc"
KDE Logo
This file is part of the documentation for kate Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:35:04 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003