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 Above"), CTRL+Key_8, this, 00148 SLOT(completeBackwards()), actionCollection(), "doccomplete_bw" ); 00149 (void) new KAction( i18n("Reuse Word Below"), CTRL+Key_9, this, 00150 SLOT(completeForwards()), actionCollection(), "doccomplete_fw" ); 00151 (void) new KAction( i18n("Pop Up Completion List"), 0, 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 if ( ! connect( m_view->document(), SIGNAL(charactersInteractivelyInserted(int ,int ,const QString&)), 00204 this, SLOT(autoPopupCompletionList()) )) 00205 { 00206 connect( m_view->document(), SIGNAL(textChanged()), this, SLOT(autoPopupCompletionList()) ); 00207 } 00208 } else { 00209 disconnect( m_view->document(), SIGNAL(textChanged()), this, SLOT(autoPopupCompletionList()) ); 00210 disconnect( m_view->document(), SIGNAL(charactersInteractivelyInserted(int ,int ,const QString&)), 00211 this, SLOT(autoPopupCompletionList()) ); 00212 00213 } 00214 } 00215 00216 // for autopopup FIXME - don't pop up if reuse word is inserting 00217 void DocWordCompletionPluginView::autoPopupCompletionList() 00218 { 00219 if ( ! m_view->hasFocus() ) return; 00220 QString w = word(); 00221 if ( w.length() >= d->treshold ) 00222 { 00223 popupCompletionList( w ); 00224 } 00225 } 00226 00227 // Do one completion, searching in the desired direction, 00228 // if possible 00229 void DocWordCompletionPluginView::complete( bool fw ) 00230 { 00231 // setup 00232 KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() ); 00233 // find the word we are typing 00234 uint cline, ccol; 00235 viewCursorInterface( m_view )->cursorPositionReal( &cline, &ccol ); 00236 QString wrd = word(); 00237 if ( wrd.isEmpty() ) return; 00238 00239 /* IF the current line is equal to the previous line 00240 AND the position - the length of the last inserted string 00241 is equal to the old position 00242 AND the lastinsertedlength last characters of the word is 00243 equal to the last inserted string 00244 */ 00245 if ( cline == d-> cline && 00246 ccol - d->lilen == d->ccol && 00247 wrd.endsWith( d->lastIns ) ) 00248 { 00249 // this is a repeted activation 00250 ccol = d->ccol; 00251 wrd = d->last; 00252 } 00253 else 00254 { 00255 d->cline = cline; 00256 d->ccol = ccol; 00257 d->last = wrd; 00258 d->lastIns = QString::null; 00259 d->line = d->cline; 00260 d->col = d->ccol - wrd.length(); 00261 d->lilen = 0; 00262 } 00263 00264 d->re.setPattern( "\\b" + wrd + "(\\w+)" ); 00265 int inc = fw ? 1 : -1; 00266 int pos ( 0 ); 00267 QString ln = ei->textLine( d->line ); 00268 00269 if ( ! fw ) 00270 ln = ln.mid( 0, d->col ); 00271 00272 while ( true ) 00273 { 00274 pos = fw ? 00275 d->re.search( ln, d->col ) : 00276 d->re.searchRev( ln, d->col ); 00277 00278 if ( pos > -1 ) // we matched a word 00279 { 00280 QString m = d->re.cap( 1 ); 00281 if ( m != d->lastIns ) 00282 { 00283 // we got good a match! replace text and return. 00284 if ( d->lilen ) 00285 ei->removeText( d->cline, d->ccol, d->cline, d->ccol + d->lilen ); 00286 ei->insertText( d->cline, d->ccol, m ); 00287 00288 d->lastIns = m; 00289 d->lilen = m.length(); 00290 d->col = pos; // for next try 00291 00292 if ( fw ) 00293 d->col += m.length(); 00294 00295 return; 00296 } 00297 00298 // equal to last one, continue 00299 else 00300 { 00301 d->col = pos; // for next try 00302 if ( fw ) 00303 d->col += m.length(); 00304 else // FIXME figure out if all of that is really nessecary 00305 { 00306 if ( pos == 0 ) 00307 { 00308 if ( d->line > 0 ) 00309 { 00310 d->line += inc; 00311 ln = ei->textLine( d->line ); 00312 d->col = ln.length(); 00313 } 00314 else 00315 { 00316 KNotifyClient::beep(); 00317 return; 00318 } 00319 } 00320 else 00321 d->col--; 00322 } 00323 } 00324 } 00325 00326 else // no match 00327 { 00328 if ( ! fw && d->line == 0) 00329 { 00330 KNotifyClient::beep(); 00331 return; 00332 } 00333 else if ( fw && d->line >= ei->numLines() ) 00334 { 00335 KNotifyClient::beep(); 00336 return; 00337 } 00338 00339 d->line += inc; 00340 if ( fw ) 00341 d->col++; 00342 00343 ln = ei->textLine( d->line ); 00344 d->col = fw ? 0 : ln.length(); 00345 } 00346 } // while true 00347 } 00348 00349 // Return the string to complete (the letters behind the cursor) 00350 QString DocWordCompletionPluginView::word() 00351 { 00352 uint cline, ccol; 00353 viewCursorInterface( m_view )->cursorPositionReal( &cline, &ccol ); 00354 if ( ! ccol ) return QString::null; // no word 00355 KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() ); 00356 d->re.setPattern( "\\b(\\w+)$" ); 00357 if ( d->re.searchRev( 00358 ei->text( cline, 0, cline, ccol ) 00359 ) < 0 ) 00360 return QString::null; // no word 00361 return d->re.cap( 1 ); 00362 } 00363 00364 // Scan throught the entire document for possible completions, 00365 // ignoring any dublets 00366 QValueList<KTextEditor::CompletionEntry> DocWordCompletionPluginView::allMatches( const QString &word ) 00367 { 00368 QValueList<KTextEditor::CompletionEntry> l; 00369 uint i( 0 ); 00370 int pos( 0 ); 00371 d->re.setPattern( "\\b("+word+"\\w+)" ); 00372 QString s, m; 00373 KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() ); 00374 QDict<int> seen; // maybe slow with > 17 matches 00375 int sawit(1); // to ref for the dict 00376 00377 while( i < ei->numLines() ) 00378 { 00379 s = ei->textLine( i ); 00380 pos = 0; 00381 while ( pos >= 0 ) 00382 { 00383 pos = d->re.search( s, pos ); 00384 if ( pos >= 0 ) 00385 { 00386 m = d->re.cap( 1 ); 00387 if ( ! seen[ m ] ) { 00388 seen.insert( m, &sawit ); 00389 KTextEditor::CompletionEntry e; 00390 e.text = m; 00391 l.append( e ); 00392 } 00393 pos += d->re.matchedLength(); 00394 } 00395 } 00396 i++; 00397 } 00398 return l; 00399 } 00400 00401 void DocWordCompletionPluginView::slotVariableChanged( const QString &var, const QString &val ) 00402 { 00403 if ( var == "wordcompletion-autopopup" ) 00404 d->autopopup->setEnabled( val == "true" ); 00405 else if ( var == "wordcompletion-treshold" ) 00406 d->treshold = val.toInt(); 00407 } 00408 //END 00409 00410 //BEGIN DocWordCompletionConfigPage 00411 DocWordCompletionConfigPage::DocWordCompletionConfigPage( DocWordCompletionPlugin *completion, QWidget *parent, const char *name ) 00412 : KTextEditor::ConfigPage( parent, name ) 00413 , m_completion( completion ) 00414 { 00415 QVBoxLayout *lo = new QVBoxLayout( this ); 00416 lo->setSpacing( KDialog::spacingHint() ); 00417 00418 cbAutoPopup = new QCheckBox( i18n("Automatically &show completion list"), this ); 00419 lo->addWidget( cbAutoPopup ); 00420 00421 QHBox *hb = new QHBox( this ); 00422 hb->setSpacing( KDialog::spacingHint() ); 00423 lo->addWidget( hb ); 00424 QLabel *l = new QLabel( i18n( 00425 "Translators: This is the first part of two strings wich will comprise the " 00426 "sentence 'Show completions when a word is at least N characters'. The first " 00427 "part is on the right side of the N, which is represented by a spinbox " 00428 "widget, followed by the second part: 'characters long'. Characters is a " 00429 "ingeger number between and including 1 and 30. Feel free to leave the " 00430 "second part of the sentence blank if it suits your language better. ", 00431 "Show completions &when a word is at least"), hb ); 00432 sbAutoPopup = new QSpinBox( 1, 30, 1, hb ); 00433 l->setBuddy( sbAutoPopup ); 00434 lSbRight = new QLabel( i18n( 00435 "This is the second part of two strings that will comprise teh sentence " 00436 "'Show completions when a word is at least N characters'", 00437 "characters long."), hb ); 00438 00439 QWhatsThis::add( cbAutoPopup, i18n( 00440 "Enable the automatic completion list popup as default. The popup can " 00441 "be disabled on a view basis from the 'Tools' menu.") ); 00442 QWhatsThis::add( sbAutoPopup, i18n( 00443 "Define the length a word should have before the completion list " 00444 "is displayed.") ); 00445 00446 cbAutoPopup->setChecked( m_completion->autoPopupEnabled() ); 00447 sbAutoPopup->setValue( m_completion->treshold() ); 00448 00449 lo->addStretch(); 00450 } 00451 00452 void DocWordCompletionConfigPage::apply() 00453 { 00454 m_completion->setAutoPopupEnabled( cbAutoPopup->isChecked() ); 00455 m_completion->setTreshold( sbAutoPopup->value() ); 00456 m_completion->writeConfig(); 00457 } 00458 00459 void DocWordCompletionConfigPage::reset() 00460 { 00461 cbAutoPopup->setChecked( m_completion->autoPopupEnabled() ); 00462 sbAutoPopup->setValue( m_completion->treshold() ); 00463 } 00464 00465 void DocWordCompletionConfigPage::defaults() 00466 { 00467 cbAutoPopup->setChecked( true ); 00468 sbAutoPopup->setValue( 3 ); 00469 } 00470 00471 //END DocWordCompletionConfigPage 00472 00473 #include "docwordcompletion.moc"
KDE Logo
This file is part of the documentation for kate Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:46:02 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003