QCompleter::setFilterMode() add property filterMode.
QCompleter::setFilterMode(Qt::MatchContains) will enable filtering out entries that contain typed characters in any place, instead of the default behavior when only those entries that start with typed characters are displayed. Qt::MatchEndsWith is also possible. QCompleter::setFilterMode(Qt::MatchStartsWith) will bring the default behavior back. Task-number: QTBUG-3414 Change-Id: I3845704c59eb8fc401e9a650c54a9c934ed28c2e Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
parent
ef5455429f
commit
6b95130faa
@ -82,7 +82,8 @@
|
||||
QCompleter::CaseSensitivelySortedModel or
|
||||
QCompleter::CaseInsensitivelySortedModel as the argument. On large models,
|
||||
this can lead to significant performance improvements, because QCompleter
|
||||
can then use binary search instead of linear search.
|
||||
can then use binary search instead of linear search. The binary search only
|
||||
works when the filterMode is Qt::MatchStartsWith.
|
||||
|
||||
The model can be a \l{QAbstractListModel}{list model},
|
||||
a \l{QAbstractTableModel}{table model}, or a
|
||||
@ -199,16 +200,18 @@ void QCompletionModel::setSourceModel(QAbstractItemModel *source)
|
||||
void QCompletionModel::createEngine()
|
||||
{
|
||||
bool sortedEngine = false;
|
||||
switch (c->sorting) {
|
||||
case QCompleter::UnsortedModel:
|
||||
sortedEngine = false;
|
||||
break;
|
||||
case QCompleter::CaseSensitivelySortedModel:
|
||||
sortedEngine = c->cs == Qt::CaseSensitive;
|
||||
break;
|
||||
case QCompleter::CaseInsensitivelySortedModel:
|
||||
sortedEngine = c->cs == Qt::CaseInsensitive;
|
||||
break;
|
||||
if (c->filterMode == Qt::MatchStartsWith) {
|
||||
switch (c->sorting) {
|
||||
case QCompleter::UnsortedModel:
|
||||
sortedEngine = false;
|
||||
break;
|
||||
case QCompleter::CaseSensitivelySortedModel:
|
||||
sortedEngine = c->cs == Qt::CaseSensitive;
|
||||
break;
|
||||
case QCompleter::CaseInsensitivelySortedModel:
|
||||
sortedEngine = c->cs == Qt::CaseInsensitive;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sortedEngine)
|
||||
@ -522,6 +525,8 @@ bool QCompletionEngine::lookupCache(QString part, const QModelIndex& parent, QMa
|
||||
// When the cache size exceeds 1MB, it clears out about 1/2 of the cache.
|
||||
void QCompletionEngine::saveInCache(QString part, const QModelIndex& parent, const QMatchData& m)
|
||||
{
|
||||
if (c->filterMode == Qt::MatchEndsWith)
|
||||
return;
|
||||
QMatchData old = cache[parent].take(part);
|
||||
cost = cost + m.indices.cost() - old.indices.cost();
|
||||
if (cost * sizeof(int) > 1024 * 1024) {
|
||||
@ -703,9 +708,35 @@ int QUnsortedModelEngine::buildIndices(const QString& str, const QModelIndex& pa
|
||||
|
||||
for (i = 0; i < indices.count() && count != n; ++i) {
|
||||
QModelIndex idx = model->index(indices[i], c->column, parent);
|
||||
QString data = model->data(idx, c->role).toString();
|
||||
if (!data.startsWith(str, c->cs) || !(model->flags(idx) & Qt::ItemIsSelectable))
|
||||
|
||||
if (!(model->flags(idx) & Qt::ItemIsSelectable))
|
||||
continue;
|
||||
|
||||
QString data = model->data(idx, c->role).toString();
|
||||
|
||||
switch (c->filterMode) {
|
||||
case Qt::MatchStartsWith:
|
||||
if (!data.startsWith(str, c->cs))
|
||||
continue;
|
||||
break;
|
||||
case Qt::MatchContains:
|
||||
if (!data.contains(str, c->cs))
|
||||
continue;
|
||||
break;
|
||||
case Qt::MatchEndsWith:
|
||||
if (!data.endsWith(str, c->cs))
|
||||
continue;
|
||||
break;
|
||||
case Qt::MatchExactly:
|
||||
case Qt::MatchFixedString:
|
||||
case Qt::MatchCaseSensitive:
|
||||
case Qt::MatchRegExp:
|
||||
case Qt::MatchWildcard:
|
||||
case Qt::MatchWrap:
|
||||
case Qt::MatchRecursive:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
m->indices.append(indices[i]);
|
||||
++count;
|
||||
if (m->exactMatchIndex == -1 && QString::compare(data, str, c->cs) == 0) {
|
||||
@ -773,9 +804,9 @@ QMatchData QUnsortedModelEngine::filter(const QString& part, const QModelIndex&
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
QCompleterPrivate::QCompleterPrivate()
|
||||
: widget(0), proxy(0), popup(0), cs(Qt::CaseSensitive), role(Qt::EditRole), column(0),
|
||||
maxVisibleItems(7), sorting(QCompleter::UnsortedModel), wrap(true), eatFocusOut(true),
|
||||
hiddenBecauseNoMatch(false)
|
||||
: widget(0), proxy(0), popup(0), filterMode(Qt::MatchStartsWith), cs(Qt::CaseSensitive),
|
||||
role(Qt::EditRole), column(0), maxVisibleItems(7), sorting(QCompleter::UnsortedModel),
|
||||
wrap(true), eatFocusOut(true), hiddenBecauseNoMatch(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1097,6 +1128,48 @@ QCompleter::CompletionMode QCompleter::completionMode() const
|
||||
return d->mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QCompleter::filterMode
|
||||
\brief how the filtering is performed
|
||||
\since 5.2
|
||||
|
||||
If filterMode is set to Qt::MatchStartsWith, only those entries that start
|
||||
with the typed characters will be displayed. Qt::MatchContains will display
|
||||
the entries that contain the typed characters, and Qt::MatchEndsWith the
|
||||
ones that end with the typed characters.
|
||||
|
||||
Currently, only these three modes are implemented. Setting filterMode to
|
||||
any other Qt::MatchFlag will issue a warning, and no action will be
|
||||
performed.
|
||||
|
||||
The default mode is Qt::MatchStartsWith.
|
||||
*/
|
||||
|
||||
void QCompleter::setFilterMode(Qt::MatchFlags filterMode)
|
||||
{
|
||||
Q_D(QCompleter);
|
||||
|
||||
if (d->filterMode == filterMode)
|
||||
return;
|
||||
|
||||
if (filterMode != Qt::MatchStartsWith
|
||||
&& filterMode != Qt::MatchContains
|
||||
&& filterMode != Qt::MatchEndsWith) {
|
||||
qWarning("Unhandled QCompleter::filterMode flag is used.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->filterMode = filterMode;
|
||||
d->proxy->createEngine();
|
||||
d->proxy->invalidate();
|
||||
}
|
||||
|
||||
Qt::MatchFlags QCompleter::filterMode() const
|
||||
{
|
||||
Q_D(const QCompleter);
|
||||
return d->filterMode;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the popup used to display completions to \a popup. QCompleter takes
|
||||
ownership of the view.
|
||||
|
@ -63,6 +63,7 @@ class Q_WIDGETS_EXPORT QCompleter : public QObject
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString completionPrefix READ completionPrefix WRITE setCompletionPrefix)
|
||||
Q_PROPERTY(ModelSorting modelSorting READ modelSorting WRITE setModelSorting)
|
||||
Q_PROPERTY(Qt::MatchFlags filterMode READ filterMode WRITE setFilterMode)
|
||||
Q_PROPERTY(CompletionMode completionMode READ completionMode WRITE setCompletionMode)
|
||||
Q_PROPERTY(int completionColumn READ completionColumn WRITE setCompletionColumn)
|
||||
Q_PROPERTY(int completionRole READ completionRole WRITE setCompletionRole)
|
||||
@ -99,6 +100,9 @@ public:
|
||||
void setCompletionMode(CompletionMode mode);
|
||||
CompletionMode completionMode() const;
|
||||
|
||||
void setFilterMode(Qt::MatchFlags filterMode);
|
||||
Qt::MatchFlags filterMode() const;
|
||||
|
||||
QAbstractItemView *popup() const;
|
||||
void setPopup(QAbstractItemView *popup);
|
||||
|
||||
|
@ -82,6 +82,7 @@ public:
|
||||
QCompletionModel *proxy;
|
||||
QAbstractItemView *popup;
|
||||
QCompleter::CompletionMode mode;
|
||||
Qt::MatchFlags filterMode;
|
||||
|
||||
QString prefix;
|
||||
Qt::CaseSensitivity cs;
|
||||
|
@ -1418,6 +1418,135 @@ void tst_QCompleter::task253125_lineEditCompletion()
|
||||
|
||||
QCOMPARE(edit.text(), QString("iota"));
|
||||
|
||||
edit.clear();
|
||||
completer->setCompletionMode(QCompleter::PopupCompletion);
|
||||
completer->setFilterMode(Qt::MatchContains);
|
||||
|
||||
QTest::keyClick(&edit, 't');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString("beta"));
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("beta"));
|
||||
|
||||
edit.clear();
|
||||
|
||||
QTest::keyClick(&edit, 'p');
|
||||
QTest::keyClick(&edit, 'p');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString("kappa"));
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("kappa"));
|
||||
|
||||
edit.clear();
|
||||
completer->setFilterMode(Qt::MatchStartsWith);
|
||||
|
||||
QTest::keyClick(&edit, 't');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString("theta"));
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("theta"));
|
||||
|
||||
edit.clear();
|
||||
|
||||
QTest::keyClick(&edit, 'p');
|
||||
QTest::keyClick(&edit, 'p');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString());
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("pp"));
|
||||
|
||||
edit.clear();
|
||||
|
||||
QTest::keyClick(&edit, 'u');
|
||||
QTest::keyClick(&edit, 'p');
|
||||
QTest::keyClick(&edit, 's');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString("upsilon"));
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("upsilon"));
|
||||
|
||||
edit.clear();
|
||||
completer->setFilterMode(Qt::MatchEndsWith);
|
||||
|
||||
QTest::keyClick(&edit, 'm');
|
||||
QTest::keyClick(&edit, 'm');
|
||||
QTest::keyClick(&edit, 'a');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString("gamma"));
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("gamma"));
|
||||
|
||||
edit.clear();
|
||||
|
||||
QTest::keyClick(&edit, 'g');
|
||||
QTest::keyClick(&edit, 'm');
|
||||
QTest::keyClick(&edit, 'a');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString("sigma"));
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("sigma"));
|
||||
|
||||
edit.clear();
|
||||
|
||||
QTest::keyClick(&edit, 'm');
|
||||
QTest::keyClick(&edit, 'm');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString());
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("mm"));
|
||||
|
||||
edit.clear();
|
||||
completer->setFilterMode(Qt::MatchStartsWith);
|
||||
|
||||
QTest::keyClick(&edit, 'z');
|
||||
QTest::keyClick(&edit, 'e');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString("zeta"));
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("zeta"));
|
||||
|
||||
edit.clear();
|
||||
completer->setFilterMode(Qt::MatchEndsWith);
|
||||
|
||||
QTest::keyClick(&edit, 'e');
|
||||
QTest::keyClick(&edit, 'g');
|
||||
QTest::keyClick(&edit, 'a');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString("omega"));
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("omega"));
|
||||
|
||||
edit.clear();
|
||||
completer->setFilterMode(Qt::MatchContains);
|
||||
|
||||
QTest::keyClick(&edit, 'c');
|
||||
QTest::keyClick(&edit, 'r');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString("omicron"));
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("omicron"));
|
||||
|
||||
edit.clear();
|
||||
|
||||
QTest::keyClick(&edit, 'z');
|
||||
QTest::keyClick(&edit, 'z');
|
||||
QCOMPARE(edit.completer()->currentCompletion(), QString());
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Down);
|
||||
QTest::keyClick(edit.completer()->popup(), Qt::Key_Enter);
|
||||
|
||||
QCOMPARE(edit.text(), QString("zz"));
|
||||
|
||||
delete completer;
|
||||
delete model;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user