00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "katecompletionwidget.h"
00020
00021 #include <QtGui/QBoxLayout>
00022 #include <QtGui/QApplication>
00023 #include <QtGui/QDesktopWidget>
00024 #include <QtGui/QHeaderView>
00025 #include <QtCore/QTimer>
00026 #include <QtGui/QLabel>
00027 #include <QtGui/QToolButton>
00028 #include <QtGui/QSizeGrip>
00029 #include <QtGui/QPushButton>
00030 #include <QtGui/QAbstractScrollArea>
00031 #include <QtGui/QScrollBar>
00032
00033 #include <kicon.h>
00034 #include <kdialog.h>
00035
00036 #include <ktexteditor/cursorfeedback.h>
00037
00038 #include "kateview.h"
00039 #include "katesmartmanager.h"
00040 #include "katerenderer.h"
00041 #include "kateconfig.h"
00042 #include "katedocument.h"
00043 #include "katesmartrange.h"
00044 #include "kateedit.h"
00045
00046 #include "katecompletionmodel.h"
00047 #include "katecompletiontree.h"
00048 #include "katecompletionconfig.h"
00049 #include "kateargumenthinttree.h"
00050 #include "kateargumenthintmodel.h"
00051
00052
00053
00054 KateCompletionWidget::KateCompletionWidget(KateView* parent)
00055 : QFrame(parent, Qt::ToolTip)
00056 , m_presentationModel(new KateCompletionModel(this))
00057 , m_completionRange(0L)
00058 , m_entryList(new KateCompletionTree(this))
00059 , m_argumentHintModel(new KateArgumentHintModel(this))
00060 , m_argumentHintTree(new KateArgumentHintTree(this))
00061 , m_automaticInvocationDelay(300)
00062 , m_filterInstalled(false)
00063 , m_configWidget(new KateCompletionConfig(m_presentationModel, view()))
00064 , m_inCompletionList(false)
00065 , m_isSuspended(false)
00066 , m_dontShowArgumentHints(false)
00067 , m_needShow(false)
00068 , m_expandedAddedHeightBase(0)
00069 , m_expandingAddedHeight(0)
00070 {
00071
00072 setFrameStyle( QFrame::Box | QFrame::Plain );
00073 setLineWidth( 1 );
00074
00075
00076 m_entryList->setModel(m_presentationModel);
00077 m_entryList->setColumnWidth(0, 0);
00078 m_entryList->setColumnWidth(1, 0);
00079 m_entryList->setColumnWidth(2, 0);
00080
00081 m_argumentHintTree->setParent(0, Qt::ToolTip);
00082 m_argumentHintTree->setModel(m_argumentHintModel);
00083
00084 connect(m_entryList->verticalScrollBar(), SIGNAL(valueChanged(int)), m_presentationModel, SLOT(placeExpandingWidgets()));
00085 connect(m_argumentHintTree->verticalScrollBar(), SIGNAL(valueChanged(int)), m_argumentHintModel, SLOT(placeExpandingWidgets()));
00086 connect(view(), SIGNAL(focusOut(KTextEditor::View*)), this, SLOT(viewFocusOut()));
00087
00088 m_automaticInvocationTimer = new QTimer(this);
00089 m_automaticInvocationTimer->setSingleShot(true);
00090 connect(m_automaticInvocationTimer, SIGNAL(timeout()), this, SLOT(automaticInvocation()));
00091
00092 QVBoxLayout* vl = new QVBoxLayout(this);
00093 vl->addWidget(m_entryList);
00094 vl->setMargin(0);
00095
00096
00097 connect(m_presentationModel, SIGNAL(modelReset()), this, SLOT(modelReset()), Qt::QueuedConnection);
00098 connect(m_presentationModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)), SLOT(rowsInserted(const QModelIndex&, int, int)));
00099 connect(m_argumentHintModel, SIGNAL(contentStateChanged(bool)), this, SLOT(argumentHintsChanged(bool)));
00100
00101 connect(view(), SIGNAL(cursorPositionChanged(KTextEditor::View*, const KTextEditor::Cursor&)), SLOT(cursorPositionChanged()));
00102 connect(view()->doc()->history(), SIGNAL(editDone(KateEditInfo*)), SLOT(editDone(KateEditInfo*)), Qt::QueuedConnection);
00103 connect(view(), SIGNAL(verticalScrollPositionChanged (KTextEditor::View*, const KTextEditor::Cursor&)), this, SLOT(updatePositionSlot()));
00104
00105
00106
00107
00108 setFocusPolicy(Qt::ClickFocus);
00109 m_argumentHintTree->setFocusPolicy(Qt::ClickFocus);
00110
00111 foreach (QWidget* childWidget, findChildren<QWidget*>())
00112 childWidget->setFocusPolicy(Qt::NoFocus);
00113 }
00114
00115 KateCompletionWidget::~KateCompletionWidget() {
00116 }
00117
00118 void KateCompletionWidget::viewFocusOut() {
00119 abortCompletion();
00120 }
00121
00122 void KateCompletionWidget::modelContentChanged() {
00123 int realItemCount = 0;
00124 foreach (KTextEditor::CodeCompletionModel* model, m_presentationModel->completionModels())
00125 realItemCount += model->rowCount();
00126 if( !m_isSuspended && (!isVisible() || m_needShow) && realItemCount != 0 ) {
00127 m_needShow = false;
00128 updateAndShow();
00129 }
00130
00131 if(m_presentationModel->rowCount(QModelIndex()) == 0 && m_argumentHintModel->rowCount(QModelIndex()) == 0) {
00132 kDebug( 13035 ) << "hiding because no content";
00133 hide();
00134 return;
00135 }
00136
00137
00138 m_entryList->setCurrentIndex(model()->index(0,0));
00139 if(!model()->indexIsItem(m_entryList->currentIndex())) {
00140 QModelIndex firstIndex = model()->index(0,0, m_entryList->currentIndex());
00141 m_entryList->setCurrentIndex(firstIndex);
00142
00143 }
00144 }
00145
00146 KateArgumentHintTree* KateCompletionWidget::argumentHintTree() const {
00147 return m_argumentHintTree;
00148 }
00149
00150 KateArgumentHintModel* KateCompletionWidget::argumentHintModel() const {
00151 return m_argumentHintModel;
00152 }
00153
00154 const KateCompletionModel* KateCompletionWidget::model() const {
00155 return m_presentationModel;
00156 }
00157
00158 KateCompletionModel* KateCompletionWidget::model() {
00159 return m_presentationModel;
00160 }
00161
00162 void KateCompletionWidget::rowsInserted(const QModelIndex& parent, int rowFrom, int rowEnd)
00163 {
00164 if (!parent.isValid())
00165 for (int i = rowFrom; i <= rowEnd; ++i)
00166 m_entryList->expand(m_presentationModel->index(i, 0, parent));
00167 }
00168
00169 KateView * KateCompletionWidget::view( ) const
00170 {
00171 return static_cast<KateView*>(const_cast<QObject*>(parent()));
00172 }
00173
00174 void KateCompletionWidget::argumentHintsChanged(bool hasContent)
00175 {
00176 m_dontShowArgumentHints = !hasContent;
00177
00178 if( m_dontShowArgumentHints )
00179 m_argumentHintTree->hide();
00180 else
00181 updateArgumentHintGeometry();
00182 }
00183
00184 void KateCompletionWidget::startCompletion( const KTextEditor::Range & word, KTextEditor::CodeCompletionModel * model, KTextEditor::CodeCompletionModel::InvocationType invocationType)
00185 {
00186 m_isSuspended = false;
00187 m_inCompletionList = true;
00188 m_needShow = true;
00189
00190 disconnect(this->model(), SIGNAL(contentGeometryChanged()), this, SLOT(modelContentChanged()));
00191
00192 m_dontShowArgumentHints = true;
00193
00194 if (!word.isValid()) {
00195 kWarning(13035) << "Invalid range given to start code completion!";
00196 return;
00197 }
00198
00199 kDebug(13035) << word << " " << model;
00200
00201 if (!m_filterInstalled) {
00202 if (!QApplication::activeWindow()) {
00203 kWarning(13035) << "No active window to install event filter on!!";
00204 return;
00205 }
00206
00207 QApplication::activeWindow()->installEventFilter(this);
00208 m_filterInstalled = true;
00209 }
00210
00211 if (isCompletionActive())
00212 abortCompletion();
00213
00214 m_completionRange = view()->doc()->smartManager()->newSmartRange(word);
00215 m_completionRange->setInsertBehavior(KTextEditor::SmartRange::ExpandRight | KTextEditor::SmartRange::ExpandLeft);
00216 if(!m_completionRange->isValid()) {
00217 kWarning(13035) << "Could not construct valid smart-range from" << word << "instead got" << *m_completionRange;
00218 abortCompletion();
00219 return;
00220 }
00221
00222 connect(m_completionRange->smartStart().notifier(), SIGNAL(characterDeleted(KTextEditor::SmartCursor*, bool)), SLOT(startCharacterDeleted(KTextEditor::SmartCursor*, bool)));
00223
00224 cursorPositionChanged();
00225
00226 if (model)
00227 model->completionInvoked(view(), word, invocationType);
00228 else
00229 foreach (KTextEditor::CodeCompletionModel* model, m_sourceModels)
00230 model->completionInvoked(view(), word, invocationType);
00231
00232 kDebug( 13035 ) << "msdofjdsoifdsflkdsjf";
00233 if (model)
00234 m_presentationModel->setCompletionModel(model);
00235 else
00236 m_presentationModel->setCompletionModels(m_sourceModels);
00237
00238 if (!m_presentationModel->completionModels().isEmpty()) {
00239 m_presentationModel->setCurrentCompletion(view()->doc()->text(KTextEditor::Range(m_completionRange->start(), view()->cursorPosition())));
00240 }
00241
00242 connect(this->model(), SIGNAL(contentGeometryChanged()), this, SLOT(modelContentChanged()));
00243
00244 modelContentChanged();
00245 }
00246
00247 void KateCompletionWidget::updateAndShow()
00248 {
00249 setUpdatesEnabled(false);
00250
00251 updatePosition(true);
00252
00253 if (!m_presentationModel->completionModels().isEmpty()) {
00254 show();
00255 m_entryList->resizeColumns(false, true);
00256
00257 m_argumentHintModel->buildRows();
00258 if( m_argumentHintModel->rowCount(QModelIndex()) != 0 )
00259 argumentHintsChanged(true);
00260 }
00261
00262 setUpdatesEnabled(true);
00263 }
00264
00265 void KateCompletionWidget::updatePositionSlot()
00266 {
00267 updatePosition();
00268 }
00269
00270 void KateCompletionWidget::updatePosition(bool force)
00271 {
00272 if (!force && !isCompletionActive())
00273 return;
00274
00275 QPoint cursorPosition = view()->cursorToCoordinate(m_completionRange->start());
00276 if (cursorPosition == QPoint(-1,-1))
00277
00278 return abortCompletion();
00279
00280 QPoint p = view()->mapToGlobal( cursorPosition );
00281 int x = p.x() - m_entryList->columnViewportPosition(m_presentationModel->translateColumn(KTextEditor::CodeCompletionModel::Name)) - 2;
00282 int y = p.y();
00283
00284
00285
00286
00287 y += view()->renderer()->config()->fontMetrics().height();
00288
00289 if (x + width() > QApplication::desktop()->screenGeometry(view()).right())
00290 x = QApplication::desktop()->screenGeometry(view()).right() - width();
00291
00292 if( x < QApplication::desktop()->screenGeometry(view()).left() )
00293 x = QApplication::desktop()->screenGeometry(view()).left();
00294
00295 move( QPoint(x,y) );
00296
00297 updateHeight();
00298
00299 updateArgumentHintGeometry();
00300 }
00301
00302 void KateCompletionWidget::updateArgumentHintGeometry()
00303 {
00304 if( !m_dontShowArgumentHints ) {
00305
00306 QRect geom = m_argumentHintTree->geometry();
00307 geom.moveTo(pos());
00308 geom.setWidth(width());
00309 geom.moveBottom(pos().y() - view()->renderer()->config()->fontMetrics().height()*2);
00310 m_argumentHintTree->updateGeometry(geom);
00311 }
00312 }
00313
00314 void KateCompletionWidget::updateHeight()
00315 {
00316 QRect geom = geometry();
00317
00318 int baseHeight = geom.height() - m_expandingAddedHeight;
00319
00320 if( m_expandedAddedHeightBase != baseHeight && m_expandedAddedHeightBase - baseHeight > -2 && m_expandedAddedHeightBase - baseHeight < 2 )
00321 {
00322
00323
00324
00325 baseHeight = m_expandedAddedHeightBase;
00326 }
00327
00328 if( baseHeight < 300 ) {
00329 baseHeight = 300;
00330 m_expandingAddedHeight = 0;
00331
00332 }
00333
00334 int newExpandingAddedHeight = 0;
00335
00336
00337
00338 newExpandingAddedHeight = model()->expandingWidgetsHeight();
00339
00340
00341
00342 int screenBottom = QApplication::desktop()->screenGeometry(view()).bottom();
00343
00344 int bottomPosition = baseHeight + newExpandingAddedHeight + geometry().top();
00345
00346
00347
00348
00349
00350 if( bottomPosition > screenBottom-50 ) {
00351 newExpandingAddedHeight -= bottomPosition - (screenBottom-50);
00352
00353 }
00354
00355 int finalHeight = baseHeight+newExpandingAddedHeight;
00356
00357 if( finalHeight < 50 ) {
00358 return;
00359 }
00360
00361 m_expandingAddedHeight = baseHeight;
00362 m_expandedAddedHeightBase = geometry().height();
00363
00364 geom.setHeight(finalHeight);
00365
00366 setGeometry(geom);
00367 }
00368
00369
00370 void KateCompletionWidget::cursorPositionChanged( )
00371 {
00372 if (!isCompletionActive()) {
00373
00374 return;
00375 }
00376
00377 KTextEditor::Cursor cursor = view()->cursorPosition();
00378
00379 if (m_completionRange->start() > cursor || m_completionRange->end() < cursor)
00380 return abortCompletion();
00381
00382 QString currentCompletion = view()->doc()->text(KTextEditor::Range(m_completionRange->start(), view()->cursorPosition()));
00383
00384
00385 static QRegExp allowedText("^(\\w*)");
00386 if (!allowedText.exactMatch(currentCompletion))
00387 return abortCompletion();
00388
00389 m_presentationModel->setCurrentCompletion(currentCompletion);
00390 }
00391
00392 bool KateCompletionWidget::isCompletionActive( ) const
00393 {
00394 return m_completionRange && isVisible();
00395 }
00396
00397 void KateCompletionWidget::abortCompletion( )
00398 {
00399 kDebug(13035) ;
00400
00401 m_isSuspended = false;
00402
00403 bool wasActive = isCompletionActive();
00404
00405 clear();
00406
00407 if(isVisible())
00408 hide();
00409
00410 delete m_completionRange;
00411 m_completionRange = 0L;
00412
00413 if (wasActive)
00414 view()->sendCompletionAborted();
00415 }
00416
00417 void KateCompletionWidget::clear() {
00418 m_presentationModel->clearCompletionModels();
00419 m_argumentHintTree->clearCompletion();
00420 m_argumentHintModel->clear();
00421 }
00422
00423 void KateCompletionWidget::execute(bool shift)
00424 {
00425 kDebug(13035) ;
00426
00427 if (!isCompletionActive())
00428 return;
00429
00430 if( shift ) {
00431 QModelIndex index = selectedIndex();
00432
00433 if( index.isValid() )
00434 index.data(KTextEditor::CodeCompletionModel::AccessibilityAccept);
00435
00436 return;
00437 }
00438
00439 QModelIndex toExecute = m_entryList->selectionModel()->currentIndex();
00440
00441 if (!toExecute.isValid())
00442 return abortCompletion();
00443
00444 toExecute = m_presentationModel->mapToSource(toExecute);
00445
00446 if (!toExecute.isValid()) {
00447 kWarning() << k_funcinfo << "Could not map index" << m_entryList->selectionModel()->currentIndex() << "to source index.";
00448 return abortCompletion();
00449 }
00450
00451 KTextEditor::Cursor start = m_completionRange->start();
00452
00453
00454 view()->doc()->editStart(true, Kate::CodeCompletionEdit);
00455
00456 KTextEditor::CodeCompletionModel* model = static_cast<KTextEditor::CodeCompletionModel*>(const_cast<QAbstractItemModel*>(toExecute.model()));
00457 Q_ASSERT(model);
00458
00459 KTextEditor::CodeCompletionModel2* model2 = dynamic_cast<KTextEditor::CodeCompletionModel2*>(model);
00460
00461 if(model2)
00462 model2->executeCompletionItem2(view()->document(), *m_completionRange, toExecute);
00463 else if(toExecute.parent().isValid())
00464
00465 view()->document()->replaceText(*m_completionRange, model->data(toExecute.sibling(toExecute.row(), KTextEditor::CodeCompletionModel::Name)).toString());
00466 else
00467 model->executeCompletionItem(view()->document(), *m_completionRange, toExecute.row());
00468
00469 view()->doc()->editEnd();
00470
00471 hide();
00472
00473 view()->sendCompletionExecuted(start, model, toExecute);
00474 }
00475
00476 void KateCompletionWidget::resizeEvent( QResizeEvent * event )
00477 {
00478 QWidget::resizeEvent(event);
00479
00480 m_entryList->resizeColumns(true);
00481 }
00482
00483 void KateCompletionWidget::showEvent ( QShowEvent * event )
00484 {
00485 m_isSuspended = false;
00486
00487 QWidget::showEvent(event);
00488
00489 if( !m_dontShowArgumentHints && m_argumentHintModel->rowCount(QModelIndex()) != 0 )
00490 m_argumentHintTree->show();
00491 }
00492
00493 void KateCompletionWidget::hideEvent( QHideEvent * event )
00494 {
00495 QWidget::hideEvent(event);
00496 m_argumentHintTree->hide();
00497
00498 if (isCompletionActive())
00499 abortCompletion();
00500 }
00501
00502 KateSmartRange * KateCompletionWidget::completionRange( ) const
00503 {
00504 return m_completionRange;
00505 }
00506
00507 void KateCompletionWidget::modelReset( )
00508 {
00509 m_argumentHintTree->expandAll();
00510 m_entryList->expandAll();
00511 }
00512
00513 KateCompletionTree* KateCompletionWidget::treeView() const {
00514 return m_entryList;
00515 }
00516
00517 QModelIndex KateCompletionWidget::selectedIndex() const {
00518 if( m_inCompletionList )
00519 return m_entryList->currentIndex();
00520 else
00521 return m_argumentHintTree->currentIndex();
00522 }
00523
00524 bool KateCompletionWidget::cursorLeft( bool shift ) {
00525 if( shift ) {
00526 QModelIndex index = selectedIndex();
00527
00528 if( index.isValid() )
00529 index.data(KTextEditor::CodeCompletionModel::AccessibilityPrevious);
00530
00531 return true;
00532 }
00533
00534 if (canCollapseCurrentItem() ) {
00535 setCurrentItemExpanded(false);
00536 return true;
00537 }
00538 return false;
00539 }
00540
00541 bool KateCompletionWidget::cursorRight( bool shift ) {
00542 if( shift ) {
00543 QModelIndex index = selectedIndex();
00544
00545 if( index.isValid() )
00546 index.data(KTextEditor::CodeCompletionModel::AccessibilityNext);
00547
00548 return true;
00549 }
00550
00551 if ( canExpandCurrentItem() ) {
00552 setCurrentItemExpanded(true);
00553 return true;
00554 }
00555 return false;
00556 }
00557
00558 bool KateCompletionWidget::canExpandCurrentItem() const {
00559 if( m_inCompletionList ) {
00560 if( !m_entryList->currentIndex().isValid() ) return false;
00561 return model()->isExpandable( m_entryList->currentIndex() ) && !model()->isExpanded( m_entryList->currentIndex() );
00562 } else {
00563 if( !m_argumentHintTree->currentIndex().isValid() ) return false;
00564 return argumentHintModel()->isExpandable( m_argumentHintTree->currentIndex() ) && !argumentHintModel()->isExpanded( m_argumentHintTree->currentIndex() );
00565 }
00566 }
00567
00568 bool KateCompletionWidget::canCollapseCurrentItem() const {
00569 if( m_inCompletionList ) {
00570 if( !m_entryList->currentIndex().isValid() ) return false;
00571 return model()->isExpandable( m_entryList->currentIndex() ) && model()->isExpanded( m_entryList->currentIndex() );
00572 }else{
00573 if( !m_argumentHintTree->currentIndex().isValid() ) return false;
00574 return m_argumentHintModel->isExpandable( m_argumentHintTree->currentIndex() ) && m_argumentHintModel->isExpanded( m_argumentHintTree->currentIndex() );
00575 }
00576 }
00577
00578 void KateCompletionWidget::setCurrentItemExpanded( bool expanded ) {
00579 if( m_inCompletionList ) {
00580 if( !m_entryList->currentIndex().isValid() ) return;
00581 model()->setExpanded(m_entryList->currentIndex(), expanded);
00582 updateHeight();
00583 }else{
00584 if( !m_argumentHintTree->currentIndex().isValid() ) return;
00585 m_argumentHintModel->setExpanded(m_argumentHintTree->currentIndex(), expanded);
00586 }
00587 }
00588
00589 void KateCompletionWidget::startCharacterDeleted( KTextEditor::SmartCursor*, bool deletedBefore )
00590 {
00591 if (deletedBefore)
00592
00593 QTimer::singleShot(0, this, SLOT(abortCompletion()));
00594 }
00595
00596 bool KateCompletionWidget::eventFilter( QObject * watched, QEvent * event )
00597 {
00598 bool ret = QFrame::eventFilter(watched, event);
00599
00600 if (watched != this)
00601 if (event->type() == QEvent::Move)
00602 updatePosition();
00603
00604 return ret;
00605 }
00606
00607 void KateCompletionWidget::cursorDown( bool shift )
00608 {
00609 if( shift ) {
00610 QModelIndex index = selectedIndex();
00611 if( dynamic_cast<const ExpandingWidgetModel*>(index.model()) ) {
00612 const ExpandingWidgetModel* model = static_cast<const ExpandingWidgetModel*>(index.model());
00613 if( model->isExpanded(index) ) {
00614 QWidget* widget = model->expandingWidget(index);
00615 QAbstractScrollArea* area = qobject_cast<QAbstractScrollArea*>(widget);
00616 if( area && area->verticalScrollBar() )
00617 area->verticalScrollBar()->setSliderPosition( area->verticalScrollBar()->sliderPosition() + area->verticalScrollBar()->singleStep() );
00618 }
00619 }
00620 return;
00621 }
00622
00623 if( m_inCompletionList )
00624 m_entryList->nextCompletion();
00625 else {
00626 if( !m_argumentHintTree->nextCompletion() )
00627 switchList();
00628 }
00629 }
00630
00631 void KateCompletionWidget::cursorUp( bool shift )
00632 {
00633 if( shift ) {
00634 QModelIndex index = selectedIndex();
00635 if( dynamic_cast<const ExpandingWidgetModel*>(index.model()) ) {
00636 const ExpandingWidgetModel* model = static_cast<const ExpandingWidgetModel*>(index.model());
00637 if( model->isExpanded(index) ) {
00638 QWidget* widget = model->expandingWidget(index);
00639 QAbstractScrollArea* area = qobject_cast<QAbstractScrollArea*>(widget);
00640 if( area && area->verticalScrollBar() )
00641 area->verticalScrollBar()->setSliderPosition( area->verticalScrollBar()->sliderPosition() - area->verticalScrollBar()->singleStep() );
00642 }
00643 }
00644 return;
00645 }
00646
00647 if( m_inCompletionList ) {
00648 if( !m_entryList->previousCompletion() )
00649 switchList();
00650 }else{
00651 m_argumentHintTree->previousCompletion();
00652 }
00653 }
00654
00655 void KateCompletionWidget::pageDown( )
00656 {
00657 if( m_inCompletionList )
00658 m_entryList->pageDown();
00659 else {
00660 if( !m_argumentHintTree->pageDown() )
00661 switchList();
00662 }
00663 }
00664
00665 void KateCompletionWidget::pageUp( )
00666 {
00667 if( m_inCompletionList ) {
00668 if( !m_entryList->pageUp() )
00669 switchList();
00670 }else{
00671 m_argumentHintTree->pageUp();
00672 }
00673 }
00674
00675 void KateCompletionWidget::top( )
00676 {
00677 if( m_inCompletionList )
00678 m_entryList->top();
00679 else
00680 m_argumentHintTree->top();
00681 }
00682
00683 void KateCompletionWidget::bottom( )
00684 {
00685 if( m_inCompletionList )
00686 m_entryList->bottom();
00687 else
00688 m_argumentHintTree->bottom();
00689 }
00690
00691 void KateCompletionWidget::switchList() {
00692 if( m_inCompletionList ) {
00693 m_entryList->setCurrentIndex(QModelIndex());
00694 if( m_argumentHintModel->rowCount(QModelIndex()) != 0 )
00695 m_argumentHintTree->setCurrentIndex(m_argumentHintModel->index(m_argumentHintModel->rowCount(QModelIndex())-1, 0));
00696 } else {
00697 m_argumentHintTree->setCurrentIndex(QModelIndex());
00698 if( m_presentationModel->rowCount(QModelIndex()) != 0 )
00699 m_entryList->setCurrentIndex(m_presentationModel->index(0, 0));
00700 }
00701 m_inCompletionList = !m_inCompletionList;
00702 }
00703
00704 void KateCompletionWidget::showConfig( )
00705 {
00706 abortCompletion();
00707
00708 m_configWidget->exec();
00709 }
00710
00711 void KateCompletionWidget::registerCompletionModel(KTextEditor::CodeCompletionModel* model)
00712 {
00713 m_sourceModels.append(model);
00714
00715 if (isCompletionActive()) {
00716 m_presentationModel->addCompletionModel(model);
00717 }
00718 }
00719
00720 void KateCompletionWidget::unregisterCompletionModel(KTextEditor::CodeCompletionModel* model)
00721 {
00722 m_sourceModels.removeAll(model);
00723 }
00724
00725 int KateCompletionWidget::automaticInvocationDelay() const {
00726 return m_automaticInvocationDelay;
00727 }
00728
00729 void KateCompletionWidget::setAutomaticInvocationDelay(int delay) {
00730 m_automaticInvocationDelay = delay;
00731 }
00732
00733
00734 void KateCompletionWidget::editDone(KateEditInfo * edit)
00735 {
00736 if (!view()->config()->automaticCompletionInvocation()
00737 || (edit->editSource() != Kate::UserInputEdit)
00738 || edit->isRemoval()
00739 || isCompletionActive()
00740 || edit->newText().isEmpty() )
00741 {
00742 m_automaticInvocationTimer->stop();
00743 return;
00744 }
00745
00746 m_automaticInvocationLine = edit->newText().last();
00747
00748 if (m_automaticInvocationLine.isEmpty()) {
00749 m_automaticInvocationTimer->stop();
00750 return;
00751 }
00752
00753 m_automaticInvocationTimer->start(m_automaticInvocationDelay);
00754 }
00755
00756 void KateCompletionWidget::automaticInvocation()
00757 {
00758 if(m_automaticInvocationLine.isEmpty())
00759 return;
00760
00761 QString lastLine = m_automaticInvocationLine;
00762 QChar lastChar = lastLine.at(lastLine.count() - 1);
00763
00764 if (lastChar.isLetter() || lastChar.isNumber() || lastChar == '.' || lastChar == '_' || lastChar == '>') {
00765
00766 KTextEditor::Range range = determineRange();
00767 if (range.isValid())
00768 startCompletion(range, 0, KTextEditor::CodeCompletionModel::AutomaticInvocation);
00769 else
00770 kWarning(13035) << "Completion range was invalid even though it was expected to be valid.";
00771 }
00772 }
00773
00774 void KateCompletionWidget::userInvokedCompletion()
00775 {
00776 startCompletion(determineRange(), 0, KTextEditor::CodeCompletionModel::UserInvocation);
00777 }
00778
00779 KTextEditor::Range KateCompletionWidget::determineRange() const
00780 {
00781 KTextEditor::Cursor end = view()->cursorPosition();
00782
00783
00784
00785 Q_ASSERT(end.isValid());
00786
00787 QString text = view()->document()->line(end.line());
00788
00789 static QRegExp findWordStart( "\\b([_\\w]+)$" );
00790 static QRegExp findWordEnd( "^([_\\w]*)\\b" );
00791
00792 KTextEditor::Cursor start = end;
00793
00794 if (findWordStart.lastIndexIn(text.left(end.column())) >= 0)
00795 start.setColumn(findWordStart.pos(1));
00796
00797 if (findWordEnd.indexIn(text.mid(end.column())) >= 0)
00798 end.setColumn(end.column() + findWordEnd.cap(1).length());
00799
00800 return KTextEditor::Range(start, end);
00801 }
00802
00803 #include "katecompletionwidget.moc"
00804
00805