📄 qcompleter.cpp
字号:
void QCompleterPrivate::_q_autoResizePopup(){ if (!popup || !popup->isVisible()) return; showPopup(popupRect);}void QCompleterPrivate::showPopup(const QRect& rect){ const QRect screen = QApplication::desktop()->availableGeometry(widget); Qt::LayoutDirection dir = widget->layoutDirection(); QPoint pos; int rw, rh, w; int h = (popup->sizeHintForRow(0) * qMin(7, popup->model()->rowCount()) + 3) + 3; QScrollBar *hsb = popup->horizontalScrollBar(); if (hsb && hsb->isVisible()) h += popup->horizontalScrollBar()->sizeHint().height(); if (rect.isValid()) { rh = rect.height(); w = rw = rect.width(); pos = widget->mapToGlobal(dir == Qt::RightToLeft ? rect.bottomRight() : rect.bottomLeft()); } else { rh = widget->height(); rw = widget->width(); pos = widget->mapToGlobal(QPoint(0, widget->height() - 2)); w = widget->width(); } if ((pos.x() + rw) > (screen.x() + screen.width())) pos.setX(screen.x() + screen.width() - w); if (pos.x() < screen.x()) pos.setX(screen.x()); if (((pos.y() + rh) > (screen.y() + screen.height())) && ((pos.y() - h - rh) >= 0)) pos.setY(pos.y() - qMax(h, popup->minimumHeight()) - rh + 2); popup->setGeometry(pos.x(), pos.y(), w, h); if (!popup->isVisible()) popup->show();}/*! Constructs a completer object with the given \a parent.*/QCompleter::QCompleter(QObject *parent): QObject(*new QCompleterPrivate(), parent){ Q_D(QCompleter); d->init();}/*! Constructs a completer object with the given \a parent that provides completions from the specified \a model.*/QCompleter::QCompleter(QAbstractItemModel *model, QObject *parent) : QObject(*new QCompleterPrivate(), parent){ Q_D(QCompleter); d->init(model);}#ifndef QT_NO_STRINGLISTMODEL/*! Constructs a QCompleter object with the given \a parent that uses the specified \a list as a source of possible completions.*/QCompleter::QCompleter(const QStringList& list, QObject *parent): QObject(*new QCompleterPrivate(), parent){ Q_D(QCompleter); d->init(new QStringListModel(list, this));}#endif // QT_NO_STRINGLISTMODEL/*! Destroys the completer object.*/QCompleter::~QCompleter(){}/*! Sets the widget for which completion are provided for to \a widget. This function is automatically called when a QCompleter is set on a QLineEdit using QLineEdit::setCompleter() or on a QComboBox using QComboBox::setCompleter(). The widget needs to be set explicitly when providing completions for custom widgets. \sa widget(), setModel(), setPopup() */void QCompleter::setWidget(QWidget *widget){ Q_D(QCompleter); if (d->widget) d->widget->removeEventFilter(this); d->widget = widget; if (d->widget) d->widget->installEventFilter(this); if (d->popup) { d->popup->hide(); d->popup->setFocusProxy(d->widget); }}/*! Returns the widget for which the completer object is providing completions. \sa setWidget() */QWidget *QCompleter::widget() const{ Q_D(const QCompleter); return d->widget;}/*! Sets the model which provides completions to \a model. The \a model can be list model or a tree model. If a model has been already previously set and it has the QCompleter as its parent, it is deleted. For convenience, if \a model is a QDirModel, QCompleter switches its caseSensitivity to Qt::CaseInsensitive on Windows and Qt::CaseSensitive on other platforms. \sa completionModel(), modelSorting, {Handling Tree Models}*/void QCompleter::setModel(QAbstractItemModel *model){ Q_D(QCompleter); QAbstractItemModel *oldModel = d->proxy->sourceModel(); d->proxy->setSourceModel(model); if (d->popup) setPopup(d->popup); // set the model and make new connections if (oldModel && oldModel->QObject::parent() == this) delete oldModel;#ifndef QT_NO_DIRMODEL if (qobject_cast<QDirModel *>(model)) {#ifdef Q_OS_WIN setCaseSensitivity(Qt::CaseInsensitive);#else setCaseSensitivity(Qt::CaseSensitive);#endif }#endif // QT_NO_DIRMODEL}/*! Returns the model that provides completion strings. \sa completionModel()*/QAbstractItemModel *QCompleter::model() const{ Q_D(const QCompleter); return d->proxy->sourceModel();}/*! \enum QCompleter::CompletionMode This enum specifies how completions are provided to the user. \value PopupCompletion Current completions are displayed in a popup window. \value InlineCompletion Completions appear inline (as selected text). \value UnfilteredPopupCompletion All possible completions are displayed in a popup window with the most likely suggestion selected. \sa setCompletionMode()*//*! \property QCompleter::completionMode \brief how the completions are provided to the user The default value is QCompleter::PopupCompletion.*/void QCompleter::setCompletionMode(QCompleter::CompletionMode mode){ Q_D(QCompleter); d->mode = mode; d->proxy->setFiltered(mode != QCompleter::UnfilteredPopupCompletion); if (mode == QCompleter::InlineCompletion) { if (d->widget) d->widget->removeEventFilter(this); if (d->popup) { d->popup->deleteLater(); d->popup = 0; } } else { if (d->widget) d->widget->installEventFilter(this); }}QCompleter::CompletionMode QCompleter::completionMode() const{ Q_D(const QCompleter); return d->mode;}/*! Sets the popup used to display completions to \a popup. QCompleter takes ownership of the view. A QListView is automatically created when the completionMode() is set to QCompleter::PopupCompletion or QCompleter::UnfilteredPopupCompletion. The default popup displays the completionColumn(). Ensure that this function is called before the view settings are modified. This is required since view's properties may require that a model has been set on the view (for example, hiding columns in the view requires a model to be set on the view). \sa popup()*/void QCompleter::setPopup(QAbstractItemView *popup){ Q_D(QCompleter); Q_ASSERT(popup != 0); if (d->popup) { QObject::disconnect(d->popup->selectionModel(), 0, this, 0); QObject::disconnect(d->popup, 0, this, 0); } if (d->popup != popup) delete d->popup; if (popup->model() != d->proxy) popup->setModel(d->proxy); popup->hide(); popup->setParent(0, Qt::Popup); popup->setFocusPolicy(Qt::NoFocus); popup->setFocusProxy(d->widget); popup->installEventFilter(this); popup->setItemDelegate(new QCompleterItemDelegate(popup)); QObject::connect(popup, SIGNAL(clicked(QModelIndex)), this, SLOT(_q_complete(QModelIndex))); QObject::connect(popup, SIGNAL(clicked(QModelIndex)), popup, SLOT(hide())); QObject::connect(popup->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(_q_completionSelected(QItemSelection))); d->popup = popup;}/*! Returns the popup used to display completions. \sa setPopup()*/QAbstractItemView *QCompleter::popup() const{ Q_D(const QCompleter);#ifndef QT_NO_LISTVIEW if (!d->popup && completionMode() != QCompleter::InlineCompletion) { QListView *listView = new QListView; listView->setEditTriggers(QAbstractItemView::NoEditTriggers); listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); listView->setSelectionBehavior(QAbstractItemView::SelectRows); listView->setSelectionMode(QAbstractItemView::SingleSelection); listView->setModelColumn(d->column); QCompleter *that = const_cast<QCompleter*>(this); that->setPopup(listView); }#endif // QT_NO_LISTVIEW return d->popup;}/*! \reimp*/bool QCompleter::event(QEvent *ev){ return QObject::event(ev);}/*! \reimp*/bool QCompleter::eventFilter(QObject *o, QEvent *e){ Q_D(QCompleter); if (d->eatFocusOut && o == d->widget && e->type() == QEvent::FocusOut) { if (d->popup && d->popup->isVisible()) return true; } if (o != d->popup) return QObject::eventFilter(o, e); switch (e->type()) { case QEvent::KeyPress: { QKeyEvent *ke = static_cast<QKeyEvent *>(e); QModelIndex curIndex = d->popup->currentIndex(); QModelIndexList selList = d->popup->selectionModel()->selectedIndexes(); const int key = ke->key(); // In UnFilteredPopup mode, select the current item if ((key == Qt::Key_Up || key == Qt::Key_Down) && selList.isEmpty() && curIndex.isValid() && d->mode == QCompleter::UnfilteredPopupCompletion) { d->setCurrentIndex(curIndex); return true; } // Handle popup navigation keys. These are hardcoded because up/down might make the // widget do something else (lineedit cursor moves to home/end on mac, for instance) switch (key) { case Qt::Key_End: case Qt::Key_Home: if (ke->modifiers() & Qt::ControlModifier) return false; break; case Qt::Key_Up: if (!curIndex.isValid()) { int rowCount = d->proxy->rowCount(); QModelIndex lastIndex = d->proxy->index(rowCount - 1, 0); d->setCurrentIndex(lastIndex); return true; } else if (curIndex.row() == 0) { if (d->wrap) d->setCurrentIndex(QModelIndex()); return true; } return false; case Qt::Key_Down: if (!curIndex.isValid()) { QModelIndex firstIndex = d->proxy->index(0, 0); d->setCurrentIndex(firstIndex); return true; } else if (curIndex.row() == d->proxy->rowCount() - 1) { if (d->wrap) d->setCurrentIndex(QModelIndex()); return true; } return false; case Qt::Key_PageUp: case Qt::Key_PageDown: return false; } // Send the event to the widget. If the widget accepted the event, do nothing // If the widget did not accept the event, provide a default implementation d->eatFocusOut = false; (static_cast<QObject *>(d->widget))->event(ke); d->eatFocusOut = true; if (!d->widget || e->isAccepted() || !d->popup->isVisible()) { // widget lost focus, hide the popup if (d->widget && (!d->widget->hasFocus()#ifdef QT_KEYPAD_NAVIGATION || (QApplication::keypadNavigationEnabled() && !d->widget->hasEditFocus())#endif )) d->popup->hide(); return true; } // default implementation for keys not handled by the widget when popup is open switch (key) { case Qt::Key_Return: case Qt::Key_Enter: case Qt::Key_Tab:#ifdef QT_KEYPAD_NAVIGATION case Qt::Key_Select: if (!QApplication::keypadNavigationEnabled()) break;#endif d->popup->hide(); if (curIndex.isValid()) d->_q_complete(curIndex); break; case Qt::Key_F4: if (ke->modifiers() & Qt::AltModifier) d->popup->hide(); break; case Qt::Key_Backtab: case Qt::Key_Escape: d->popup->hide(); break; default: break; } return true; }#ifdef QT_KEYPAD_NAVIGATION case QEvent::KeyRelease: { QKeyEvent *ke = static_cast<QKeyEvent *>(e); if (QApplication::keypadNavigationEnabled() && ke->key() == Qt::Key_Back) { // Send the event to the 'widget'. This is what we did for KeyPress, so we need // to do the same for KeyRelease, in case the widget's KeyPress event set // up something (such as a timer) that is relying on also receiving the // key release. I see this as a bug in Qt, and should really set it up for all // the affected keys. However, it is difficult to tell how this will affect // existing code, and I can't test for every combination! d->eatFocusOut = false; static_cast<QObject *>(d->widget)->event(ke); d->eatFocusOut = true; } break; }#endif case QEvent::MouseButtonPress: {#ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled()) { // if we've clicked in the widget (or its descendant), let it handle the click QWidget *source = qobject_cast<QWidget *>(o); if (source) { QPoint pos = source->mapToGlobal((static_cast<QMouseEvent *>(e))->pos()); QWidget *target = QApplication::widgetAt(pos); if (target && (d->widget->isAncestorOf(target) || target == d->widget)) { d->eatFocusOut = false; static_cast<QObject *>(target)->event(e); d->eatFocusOut = true; return true; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -