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