00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
00057
00058
00059
00060 K_EXPORT_COMPONENT_FACTORY( ktexteditor_docwordcompletion,
KGenericFactory<DocWordCompletionPlugin>(
"ktexteditor_docwordcompletion" ) )
00061 DocWordCompletionPlugin::DocWordCompletionPlugin(
QObject *parent,
00062 const
char* name,
00063 const
QStringList& )
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
00118
QPixmap DocWordCompletionPlugin::configPagePixmap( uint,
int size )
const
00119
{
00120
return UserIcon(
"kte_wordcompletion", size );
00121 }
00122
00123
00124
00125
struct DocWordCompletionPluginViewPrivate
00126 {
00127 uint line, col;
00128 uint cline, ccol;
00129 uint lilen;
00130
QString last;
00131
QString lastIns;
00132
QRegExp re;
00133
KToggleAction *autopopup;
00134 uint treshold;
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
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
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
00228
00229
void DocWordCompletionPluginView::complete(
bool fw )
00230 {
00231
00232 KTextEditor::EditInterface *ei = KTextEditor::editInterface( m_view->document() );
00233
00234 uint cline, ccol;
00235 viewCursorInterface( m_view )->cursorPositionReal( &cline, &ccol );
00236
QString wrd = word();
00237
if ( wrd.isEmpty() )
return;
00238
00239
00240
00241
00242
00243
00244
00245
if ( cline == d-> cline &&
00246 ccol - d->lilen == d->ccol &&
00247 wrd.endsWith( d->lastIns ) )
00248 {
00249
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 )
00279 {
00280
QString m = d->re.cap( 1 );
00281
if ( m != d->lastIns )
00282 {
00283
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;
00291
00292
if ( fw )
00293 d->col += m.length();
00294
00295
return;
00296 }
00297
00298
00299
else
00300 {
00301 d->col = pos;
00302
if ( fw )
00303 d->col += m.length();
00304
else
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
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 }
00347 }
00348
00349
00350
QString DocWordCompletionPluginView::word()
00351 {
00352 uint cline, ccol;
00353 viewCursorInterface( m_view )->cursorPositionReal( &cline, &ccol );
00354
if ( ! ccol )
return QString::null;
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;
00361
return d->re.cap( 1 );
00362 }
00363
00364
00365
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;
00375
int sawit(1);
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
00409
00410
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
00472
00473
#include "docwordcompletion.moc"