summaryrefslogtreecommitdiffstats
path: root/src/gui/util/qcompleter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/util/qcompleter.cpp')
-rw-r--r--src/gui/util/qcompleter.cpp1833
1 files changed, 0 insertions, 1833 deletions
diff --git a/src/gui/util/qcompleter.cpp b/src/gui/util/qcompleter.cpp
deleted file mode 100644
index 0cb3bbdf8c..0000000000
--- a/src/gui/util/qcompleter.cpp
+++ /dev/null
@@ -1,1833 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \class QCompleter
- \brief The QCompleter class provides completions based on an item model.
- \since 4.2
-
- You can use QCompleter to provide auto completions in any Qt
- widget, such as QLineEdit and QComboBox.
- When the user starts typing a word, QCompleter suggests possible ways of
- completing the word, based on a word list. The word list is
- provided as a QAbstractItemModel. (For simple applications, where
- the word list is static, you can pass a QStringList to
- QCompleter's constructor.)
-
- \tableofcontents
-
- \section1 Basic Usage
-
- A QCompleter is used typically with a QLineEdit or QComboBox.
- For example, here's how to provide auto completions from a simple
- word list in a QLineEdit:
-
- \snippet doc/src/snippets/code/src_gui_util_qcompleter.cpp 0
-
- A QFileSystemModel can be used to provide auto completion of file names.
- For example:
-
- \snippet doc/src/snippets/code/src_gui_util_qcompleter.cpp 1
-
- To set the model on which QCompleter should operate, call
- setModel(). By default, QCompleter will attempt to match the \l
- {completionPrefix}{completion prefix} (i.e., the word that the
- user has started typing) against the Qt::EditRole data stored in
- column 0 in the model case sensitively. This can be changed
- using setCompletionRole(), setCompletionColumn(), and
- setCaseSensitivity().
-
- If the model is sorted on the column and role that are used for completion,
- you can call setModelSorting() with either
- 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.
-
- The model can be a \l{QAbstractListModel}{list model},
- a \l{QAbstractTableModel}{table model}, or a
- \l{QAbstractItemModel}{tree model}. Completion on tree models
- is slightly more involved and is covered in the \l{Handling
- Tree Models} section below.
-
- The completionMode() determines the mode used to provide completions to
- the user.
-
- \section1 Iterating Through Completions
-
- To retrieve a single candidate string, call setCompletionPrefix()
- with the text that needs to be completed and call
- currentCompletion(). You can iterate through the list of
- completions as below:
-
- \snippet doc/src/snippets/code/src_gui_util_qcompleter.cpp 2
-
- completionCount() returns the total number of completions for the
- current prefix. completionCount() should be avoided when possible,
- since it requires a scan of the entire model.
-
- \section1 The Completion Model
-
- completionModel() return a list model that contains all possible
- completions for the current completion prefix, in the order in which
- they appear in the model. This model can be used to display the current
- completions in a custom view. Calling setCompletionPrefix() automatically
- refreshes the completion model.
-
- \section1 Handling Tree Models
-
- QCompleter can look for completions in tree models, assuming
- that any item (or sub-item or sub-sub-item) can be unambiguously
- represented as a string by specifying the path to the item. The
- completion is then performed one level at a time.
-
- Let's take the example of a user typing in a file system path.
- The model is a (hierarchical) QFileSystemModel. The completion
- occurs for every element in the path. For example, if the current
- text is \c C:\Wind, QCompleter might suggest \c Windows to
- complete the current path element. Similarly, if the current text
- is \c C:\Windows\Sy, QCompleter might suggest \c System.
-
- For this kind of completion to work, QCompleter needs to be able to
- split the path into a list of strings that are matched at each level.
- For \c C:\Windows\Sy, it needs to be split as "C:", "Windows" and "Sy".
- The default implementation of splitPath(), splits the completionPrefix
- using QDir::separator() if the model is a QFileSystemModel.
-
- To provide completions, QCompleter needs to know the path from an index.
- This is provided by pathFromIndex(). The default implementation of
- pathFromIndex(), returns the data for the \l{Qt::EditRole}{edit role}
- for list models and the absolute file path if the mode is a QFileSystemModel.
-
- \sa QAbstractItemModel, QLineEdit, QComboBox, {Completer Example}
-*/
-
-#include "qcompleter_p.h"
-
-#ifndef QT_NO_COMPLETER
-
-#include "QtGui/qscrollbar.h"
-#include "QtGui/qstringlistmodel.h"
-#include "QtGui/qdirmodel.h"
-#include "QtGui/qfilesystemmodel.h"
-#include "QtGui/qheaderview.h"
-#include "QtGui/qlistview.h"
-#include "QtGui/qapplication.h"
-#include "QtGui/qevent.h"
-#include "QtGui/qheaderview.h"
-#include "QtGui/qdesktopwidget.h"
-#include "QtGui/qlineedit.h"
-
-QT_BEGIN_NAMESPACE
-
-QCompletionModel::QCompletionModel(QCompleterPrivate *c, QObject *parent)
- : QAbstractProxyModel(*new QCompletionModelPrivate, parent),
- c(c), showAll(false)
-{
- createEngine();
-}
-
-int QCompletionModel::columnCount(const QModelIndex &) const
-{
- Q_D(const QCompletionModel);
- return d->model->columnCount();
-}
-
-void QCompletionModel::setSourceModel(QAbstractItemModel *source)
-{
- bool hadModel = (sourceModel() != 0);
-
- if (hadModel)
- QObject::disconnect(sourceModel(), 0, this, 0);
-
- QAbstractProxyModel::setSourceModel(source);
-
- if (source) {
- // TODO: Optimize updates in the source model
- connect(source, SIGNAL(modelReset()), this, SLOT(invalidate()));
- connect(source, SIGNAL(destroyed()), this, SLOT(modelDestroyed()));
- connect(source, SIGNAL(layoutChanged()), this, SLOT(invalidate()));
- connect(source, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted()));
- connect(source, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(invalidate()));
- connect(source, SIGNAL(columnsInserted(QModelIndex,int,int)), this, SLOT(invalidate()));
- connect(source, SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(invalidate()));
- connect(source, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(invalidate()));
- }
-
- invalidate();
-}
-
-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 (sortedEngine)
- engine.reset(new QSortedModelEngine(c));
- else
- engine.reset(new QUnsortedModelEngine(c));
-}
-
-QModelIndex QCompletionModel::mapToSource(const QModelIndex& index) const
-{
- Q_D(const QCompletionModel);
- if (!index.isValid())
- return engine->curParent;
-
- int row;
- QModelIndex parent = engine->curParent;
- if (!showAll) {
- if (!engine->matchCount())
- return QModelIndex();
- Q_ASSERT(index.row() < engine->matchCount());
- QIndexMapper& rootIndices = engine->historyMatch.indices;
- if (index.row() < rootIndices.count()) {
- row = rootIndices[index.row()];
- parent = QModelIndex();
- } else {
- row = engine->curMatch.indices[index.row() - rootIndices.count()];
- }
- } else {
- row = index.row();
- }
-
- return d->model->index(row, index.column(), parent);
-}
-
-QModelIndex QCompletionModel::mapFromSource(const QModelIndex& idx) const
-{
- if (!idx.isValid())
- return QModelIndex();
-
- int row = -1;
- if (!showAll) {
- if (!engine->matchCount())
- return QModelIndex();
-
- QIndexMapper& rootIndices = engine->historyMatch.indices;
- if (idx.parent().isValid()) {
- if (idx.parent() != engine->curParent)
- return QModelIndex();
- } else {
- row = rootIndices.indexOf(idx.row());
- if (row == -1 && engine->curParent.isValid())
- return QModelIndex(); // source parent and our parent don't match
- }
-
- if (row == -1) {
- QIndexMapper& indices = engine->curMatch.indices;
- engine->filterOnDemand(idx.row() - indices.last());
- row = indices.indexOf(idx.row()) + rootIndices.count();
- }
-
- if (row == -1)
- return QModelIndex();
- } else {
- if (idx.parent() != engine->curParent)
- return QModelIndex();
- row = idx.row();
- }
-
- return createIndex(row, idx.column());
-}
-
-bool QCompletionModel::setCurrentRow(int row)
-{
- if (row < 0 || !engine->matchCount())
- return false;
-
- if (row >= engine->matchCount())
- engine->filterOnDemand(row + 1 - engine->matchCount());
-
- if (row >= engine->matchCount()) // invalid row
- return false;
-
- engine->curRow = row;
- return true;
-}
-
-QModelIndex QCompletionModel::currentIndex(bool sourceIndex) const
-{
- if (!engine->matchCount())
- return QModelIndex();
-
- int row = engine->curRow;
- if (showAll)
- row = engine->curMatch.indices[engine->curRow];
-
- QModelIndex idx = createIndex(row, c->column);
- if (!sourceIndex)
- return idx;
- return mapToSource(idx);
-}
-
-QModelIndex QCompletionModel::index(int row, int column, const QModelIndex& parent) const
-{
- Q_D(const QCompletionModel);
- if (row < 0 || column < 0 || column >= columnCount(parent) || parent.isValid())
- return QModelIndex();
-
- if (!showAll) {
- if (!engine->matchCount())
- return QModelIndex();
- if (row >= engine->historyMatch.indices.count()) {
- int want = row + 1 - engine->matchCount();
- if (want > 0)
- engine->filterOnDemand(want);
- if (row >= engine->matchCount())
- return QModelIndex();
- }
- } else {
- if (row >= d->model->rowCount(engine->curParent))
- return QModelIndex();
- }
-
- return createIndex(row, column);
-}
-
-int QCompletionModel::completionCount() const
-{
- if (!engine->matchCount())
- return 0;
-
- engine->filterOnDemand(INT_MAX);
- return engine->matchCount();
-}
-
-int QCompletionModel::rowCount(const QModelIndex &parent) const
-{
- Q_D(const QCompletionModel);
- if (parent.isValid())
- return 0;
-
- if (showAll) {
- // Show all items below current parent, even if we have no valid matches
- if (engine->curParts.count() != 1 && !engine->matchCount()
- && !engine->curParent.isValid())
- return 0;
- return d->model->rowCount(engine->curParent);
- }
-
- return completionCount();
-}
-
-void QCompletionModel::setFiltered(bool filtered)
-{
- if (showAll == !filtered)
- return;
- showAll = !filtered;
- resetModel();
-}
-
-bool QCompletionModel::hasChildren(const QModelIndex &parent) const
-{
- Q_D(const QCompletionModel);
- if (parent.isValid())
- return false;
-
- if (showAll)
- return d->model->hasChildren(mapToSource(parent));
-
- if (!engine->matchCount())
- return false;
-
- return true;
-}
-
-QVariant QCompletionModel::data(const QModelIndex& index, int role) const
-{
- Q_D(const QCompletionModel);
- return d->model->data(mapToSource(index), role);
-}
-
-void QCompletionModel::modelDestroyed()
-{
- QAbstractProxyModel::setSourceModel(0); // switch to static empty model
- invalidate();
-}
-
-void QCompletionModel::rowsInserted()
-{
- invalidate();
- emit rowsAdded();
-}
-
-void QCompletionModel::invalidate()
-{
- engine->cache.clear();
- filter(engine->curParts);
-}
-
-void QCompletionModel::filter(const QStringList& parts)
-{
- Q_D(QCompletionModel);
- engine->filter(parts);
- resetModel();
-
- if (d->model->canFetchMore(engine->curParent))
- d->model->fetchMore(engine->curParent);
-}
-
-void QCompletionModel::resetModel()
-{
- if (rowCount() == 0) {
- reset();
- return;
- }
-
- emit layoutAboutToBeChanged();
- QModelIndexList piList = persistentIndexList();
- QModelIndexList empty;
- for (int i = 0; i < piList.size(); i++)
- empty.append(QModelIndex());
- changePersistentIndexList(piList, empty);
- emit layoutChanged();
-}
-
-//////////////////////////////////////////////////////////////////////////////
-void QCompletionEngine::filter(const QStringList& parts)
-{
- const QAbstractItemModel *model = c->proxy->sourceModel();
- curParts = parts;
- if (curParts.isEmpty())
- curParts.append(QString());
-
- curRow = -1;
- curParent = QModelIndex();
- curMatch = QMatchData();
- historyMatch = filterHistory();
-
- if (!model)
- return;
-
- QModelIndex parent;
- for (int i = 0; i < curParts.count() - 1; i++) {
- QString part = curParts[i];
- int emi = filter(part, parent, -1).exactMatchIndex;
- if (emi == -1)
- return;
- parent = model->index(emi, c->column, parent);
- }
-
- // Note that we set the curParent to a valid parent, even if we have no matches
- // When filtering is disabled, we show all the items under this parent
- curParent = parent;
- if (curParts.last().isEmpty())
- curMatch = QMatchData(QIndexMapper(0, model->rowCount(curParent) - 1), -1, false);
- else
- curMatch = filter(curParts.last(), curParent, 1); // build at least one
- curRow = curMatch.isValid() ? 0 : -1;
-}
-
-QMatchData QCompletionEngine::filterHistory()
-{
- QAbstractItemModel *source = c->proxy->sourceModel();
- if (curParts.count() <= 1 || c->proxy->showAll || !source)
- return QMatchData();
- bool isDirModel = false;
- bool isFsModel = false;
-#ifndef QT_NO_DIRMODEL
- isDirModel = (qobject_cast<QDirModel *>(source) != 0);
-#endif
-#ifndef QT_NO_FILESYSTEMMODEL
- isFsModel = (qobject_cast<QFileSystemModel *>(source) != 0);
-#endif
- QVector<int> v;
- QIndexMapper im(v);
- QMatchData m(im, -1, true);
-
- for (int i = 0; i < source->rowCount(); i++) {
- QString str = source->index(i, c->column).data().toString();
- if (str.startsWith(c->prefix, c->cs)
-#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN)
- && ((!isFsModel && !isDirModel) || QDir::toNativeSeparators(str) != QDir::separator())
-#endif
- )
- m.indices.append(i);
- }
- return m;
-}
-
-// Returns a match hint from the cache by chopping the search string
-bool QCompletionEngine::matchHint(QString part, const QModelIndex& parent, QMatchData *hint)
-{
- if (c->cs == Qt::CaseInsensitive)
- part = part.toLower();
-
- const CacheItem& map = cache[parent];
-
- QString key = part;
- while (!key.isEmpty()) {
- key.chop(1);
- if (map.contains(key)) {
- *hint = map[key];
- return true;
- }
- }
-
- return false;
-}
-
-bool QCompletionEngine::lookupCache(QString part, const QModelIndex& parent, QMatchData *m)
-{
- if (c->cs == Qt::CaseInsensitive)
- part = part.toLower();
- const CacheItem& map = cache[parent];
- if (!map.contains(part))
- return false;
- *m = map[part];
- return true;
-}
-
-// 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)
-{
- QMatchData old = cache[parent].take(part);
- cost = cost + m.indices.cost() - old.indices.cost();
- if (cost * sizeof(int) > 1024 * 1024) {
- QMap<QModelIndex, CacheItem>::iterator it1 = cache.begin();
- while (it1 != cache.end()) {
- CacheItem& ci = it1.value();
- int sz = ci.count()/2;
- QMap<QString, QMatchData>::iterator it2 = ci.begin();
- int i = 0;
- while (it2 != ci.end() && i < sz) {
- cost -= it2.value().indices.cost();
- it2 = ci.erase(it2);
- i++;
- }
- if (ci.count() == 0) {
- it1 = cache.erase(it1);
- } else {
- ++it1;
- }
- }
- }
-
- if (c->cs == Qt::CaseInsensitive)
- part = part.toLower();
- cache[parent][part] = m;
-}
-
-///////////////////////////////////////////////////////////////////////////////////
-QIndexMapper QSortedModelEngine::indexHint(QString part, const QModelIndex& parent, Qt::SortOrder order)
-{
- const QAbstractItemModel *model = c->proxy->sourceModel();
-
- if (c->cs == Qt::CaseInsensitive)
- part = part.toLower();
-
- const CacheItem& map = cache[parent];
-
- // Try to find a lower and upper bound for the search from previous results
- int to = model->rowCount(parent) - 1;
- int from = 0;
- const CacheItem::const_iterator it = map.lowerBound(part);
-
- // look backward for first valid hint
- for(CacheItem::const_iterator it1 = it; it1-- != map.constBegin();) {
- const QMatchData& value = it1.value();
- if (value.isValid()) {
- if (order == Qt::AscendingOrder) {
- from = value.indices.last() + 1;
- } else {
- to = value.indices.first() - 1;
- }
- break;
- }
- }
-
- // look forward for first valid hint
- for(CacheItem::const_iterator it2 = it; it2 != map.constEnd(); ++it2) {
- const QMatchData& value = it2.value();
- if (value.isValid() && !it2.key().startsWith(part)) {
- if (order == Qt::AscendingOrder) {
- to = value.indices.first() - 1;
- } else {
- from = value.indices.first() + 1;
- }
- break;
- }
- }
-
- return QIndexMapper(from, to);
-}
-
-Qt::SortOrder QSortedModelEngine::sortOrder(const QModelIndex &parent) const
-{
- const QAbstractItemModel *model = c->proxy->sourceModel();
-
- int rowCount = model->rowCount(parent);
- if (rowCount < 2)
- return Qt::AscendingOrder;
- QString first = model->data(model->index(0, c->column, parent), c->role).toString();
- QString last = model->data(model->index(rowCount - 1, c->column, parent), c->role).toString();
- return QString::compare(first, last, c->cs) <= 0 ? Qt::AscendingOrder : Qt::DescendingOrder;
-}
-
-QMatchData QSortedModelEngine::filter(const QString& part, const QModelIndex& parent, int)
-{
- const QAbstractItemModel *model = c->proxy->sourceModel();
-
- QMatchData hint;
- if (lookupCache(part, parent, &hint))
- return hint;
-
- QIndexMapper indices;
- Qt::SortOrder order = sortOrder(parent);
-
- if (matchHint(part, parent, &hint)) {
- if (!hint.isValid())
- return QMatchData();
- indices = hint.indices;
- } else {
- indices = indexHint(part, parent, order);
- }
-
- // binary search the model within 'indices' for 'part' under 'parent'
- int high = indices.to() + 1;
- int low = indices.from() - 1;
- int probe;
- QModelIndex probeIndex;
- QString probeData;
-
- while (high - low > 1)
- {
- probe = (high + low) / 2;
- probeIndex = model->index(probe, c->column, parent);
- probeData = model->data(probeIndex, c->role).toString();
- const int cmp = QString::compare(probeData, part, c->cs);
- if ((order == Qt::AscendingOrder && cmp >= 0)
- || (order == Qt::DescendingOrder && cmp < 0)) {
- high = probe;
- } else {
- low = probe;
- }
- }
-
- if ((order == Qt::AscendingOrder && low == indices.to())
- || (order == Qt::DescendingOrder && high == indices.from())) { // not found
- saveInCache(part, parent, QMatchData());
- return QMatchData();
- }
-
- probeIndex = model->index(order == Qt::AscendingOrder ? low+1 : high-1, c->column, parent);
- probeData = model->data(probeIndex, c->role).toString();
- if (!probeData.startsWith(part, c->cs)) {
- saveInCache(part, parent, QMatchData());
- return QMatchData();
- }
-
- const bool exactMatch = QString::compare(probeData, part, c->cs) == 0;
- int emi = exactMatch ? (order == Qt::AscendingOrder ? low+1 : high-1) : -1;
-
- int from = 0;
- int to = 0;
- if (order == Qt::AscendingOrder) {
- from = low + 1;
- high = indices.to() + 1;
- low = from;
- } else {
- to = high - 1;
- low = indices.from() - 1;
- high = to;
- }
-
- while (high - low > 1)
- {
- probe = (high + low) / 2;
- probeIndex = model->index(probe, c->column, parent);
- probeData = model->data(probeIndex, c->role).toString();
- const bool startsWith = probeData.startsWith(part, c->cs);
- if ((order == Qt::AscendingOrder && startsWith)
- || (order == Qt::DescendingOrder && !startsWith)) {
- low = probe;
- } else {
- high = probe;
- }
- }
-
- QMatchData m(order == Qt::AscendingOrder ? QIndexMapper(from, high - 1) : QIndexMapper(low+1, to), emi, false);
- saveInCache(part, parent, m);
- return m;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-int QUnsortedModelEngine::buildIndices(const QString& str, const QModelIndex& parent, int n,
- const QIndexMapper& indices, QMatchData* m)
-{
- Q_ASSERT(m->partial);
- Q_ASSERT(n != -1 || m->exactMatchIndex == -1);
- const QAbstractItemModel *model = c->proxy->sourceModel();
- int i, count = 0;
-
- 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))
- continue;
- m->indices.append(indices[i]);
- ++count;
- if (m->exactMatchIndex == -1 && QString::compare(data, str, c->cs) == 0) {
- m->exactMatchIndex = indices[i];
- if (n == -1)
- return indices[i];
- }
- }
- return indices[i-1];
-}
-
-void QUnsortedModelEngine::filterOnDemand(int n)
-{
- Q_ASSERT(matchCount());
- if (!curMatch.partial)
- return;
- Q_ASSERT(n >= -1);
- const QAbstractItemModel *model = c->proxy->sourceModel();
- int lastRow = model->rowCount(curParent) - 1;
- QIndexMapper im(curMatch.indices.last() + 1, lastRow);
- int lastIndex = buildIndices(curParts.last(), curParent, n, im, &curMatch);
- curMatch.partial = (lastRow != lastIndex);
- saveInCache(curParts.last(), curParent, curMatch);
-}
-
-QMatchData QUnsortedModelEngine::filter(const QString& part, const QModelIndex& parent, int n)
-{
- QMatchData hint;
-
- QVector<int> v;
- QIndexMapper im(v);
- QMatchData m(im, -1, true);
-
- const QAbstractItemModel *model = c->proxy->sourceModel();
- bool foundInCache = lookupCache(part, parent, &m);
-
- if (!foundInCache) {
- if (matchHint(part, parent, &hint) && !hint.isValid())
- return QMatchData();
- }
-
- if (!foundInCache && !hint.isValid()) {
- const int lastRow = model->rowCount(parent) - 1;
- QIndexMapper all(0, lastRow);
- int lastIndex = buildIndices(part, parent, n, all, &m);
- m.partial = (lastIndex != lastRow);
- } else {
- if (!foundInCache) { // build from hint as much as we can
- buildIndices(part, parent, INT_MAX, hint.indices, &m);
- m.partial = hint.partial;
- }
- if (m.partial && ((n == -1 && m.exactMatchIndex == -1) || (m.indices.count() < n))) {
- // need more and have more
- const int lastRow = model->rowCount(parent) - 1;
- QIndexMapper rest(hint.indices.last() + 1, lastRow);
- int want = n == -1 ? -1 : n - m.indices.count();
- int lastIndex = buildIndices(part, parent, want, rest, &m);
- m.partial = (lastRow != lastIndex);
- }
- }
-
- saveInCache(part, parent, m);
- return m;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-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)
-{
-}
-
-void QCompleterPrivate::init(QAbstractItemModel *m)
-{
- Q_Q(QCompleter);
- proxy = new QCompletionModel(this, q);
- QObject::connect(proxy, SIGNAL(rowsAdded()), q, SLOT(_q_autoResizePopup()));
- q->setModel(m);
-#ifdef QT_NO_LISTVIEW
- q->setCompletionMode(QCompleter::InlineCompletion);
-#else
- q->setCompletionMode(QCompleter::PopupCompletion);
-#endif // QT_NO_LISTVIEW
-}
-
-void QCompleterPrivate::setCurrentIndex(QModelIndex index, bool select)
-{
- Q_Q(QCompleter);
- if (!q->popup())
- return;
- if (!select) {
- popup->selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
- } else {
- if (!index.isValid())
- popup->selectionModel()->clear();
- else
- popup->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select
- | QItemSelectionModel::Rows);
- }
- index = popup->selectionModel()->currentIndex();
- if (!index.isValid())
- popup->scrollToTop();
- else
- popup->scrollTo(index, QAbstractItemView::PositionAtTop);
-}
-
-void QCompleterPrivate::_q_completionSelected(const QItemSelection& selection)
-{
- QModelIndex index;
- if (!selection.indexes().isEmpty())
- index = selection.indexes().first();
-
- _q_complete(index, true);
-}
-
-void QCompleterPrivate::_q_complete(QModelIndex index, bool highlighted)
-{
- Q_Q(QCompleter);
- QString completion;
-
- if (!index.isValid() || (!proxy->showAll && (index.row() >= proxy->engine->matchCount()))) {
- completion = prefix;
- } else {
- if (!(index.flags() & Qt::ItemIsEnabled))
- return;
- QModelIndex si = proxy->mapToSource(index);
- si = si.sibling(si.row(), column); // for clicked()
- completion = q->pathFromIndex(si);
-#ifndef QT_NO_DIRMODEL
- // add a trailing separator in inline
- if (mode == QCompleter::InlineCompletion) {
- if (qobject_cast<QDirModel *>(proxy->sourceModel()) && QFileInfo(completion).isDir())
- completion += QDir::separator();
- }
-#endif
-#ifndef QT_NO_FILESYSTEMMODEL
- // add a trailing separator in inline
- if (mode == QCompleter::InlineCompletion) {
- if (qobject_cast<QFileSystemModel *>(proxy->sourceModel()) && QFileInfo(completion).isDir())
- completion += QDir::separator();
- }
-#endif
- }
-
- if (highlighted) {
- emit q->highlighted(index);
- emit q->highlighted(completion);
- } else {
- emit q->activated(index);
- emit q->activated(completion);
- }
-}
-
-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 rh, w;
- int h = (popup->sizeHintForRow(0) * qMin(maxVisibleItems, 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 = rect.width();
- pos = widget->mapToGlobal(dir == Qt::RightToLeft ? rect.bottomRight() : rect.bottomLeft());
- } else {
- rh = widget->height();
- pos = widget->mapToGlobal(QPoint(0, widget->height() - 2));
- w = widget->width();
- }
-
- if (w > screen.width())
- w = screen.width();
- if ((pos.x() + w) > (screen.x() + screen.width()))
- pos.setX(screen.x() + screen.width() - w);
- if (pos.x() < screen.x())
- pos.setX(screen.x());
-
- int top = pos.y() - rh - screen.top() + 2;
- int bottom = screen.bottom() - pos.y();
- h = qMax(h, popup->minimumHeight());
- if (h > bottom) {
- h = qMin(qMax(top, bottom), h);
-
- if (top > bottom)
- pos.setY(pos.y() - h - rh + 2);
- }
-
- popup->setGeometry(pos.x(), pos.y(), w, h);
-
- if (!popup->isVisible())
- popup->show();
-}
-
-void QCompleterPrivate::_q_fileSystemModelDirectoryLoaded(const QString &path)
-{
- Q_Q(QCompleter);
- // Slot called when QFileSystemModel has finished loading.
- // If we hide the popup because there was no match because the model was not loaded yet,
- // we re-start the completion when we get the results
- if (hiddenBecauseNoMatch
- && prefix.startsWith(path) && prefix != (path + QLatin1Char('/'))
- && widget) {
- q->complete();
- }
-}
-
-/*!
- 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 QFileSystemModel, 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)) {
-#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
- setCaseSensitivity(Qt::CaseInsensitive);
-#else
- setCaseSensitivity(Qt::CaseSensitive);
-#endif
- }
-#endif // QT_NO_DIRMODEL
-#ifndef QT_NO_FILESYSTEMMODEL
- QFileSystemModel *fsModel = qobject_cast<QFileSystemModel *>(model);
- if (fsModel) {
-#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
- setCaseSensitivity(Qt::CaseInsensitive);
-#else
- setCaseSensitivity(Qt::CaseSensitive);
-#endif
- setCompletionRole(QFileSystemModel::FileNameRole);
- connect(fsModel, SIGNAL(directoryLoaded(QString)), this, SLOT(_q_fileSystemModelDirectoryLoaded(QString)));
- }
-#endif // QT_NO_FILESYSTEMMODEL
-}
-
-/*!
- 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 indicated as current.
-
- \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);
-#if defined(Q_OS_MAC) && !defined(QT_MAC_USE_COCOA)
- popup->show();
-#else
- popup->hide();
-#endif
-
- Qt::FocusPolicy origPolicy = Qt::NoFocus;
- if (d->widget)
- origPolicy = d->widget->focusPolicy();
- popup->setParent(0, Qt::Popup);
- popup->setFocusPolicy(Qt::NoFocus);
- if (d->widget)
- d->widget->setFocusPolicy(origPolicy);
-
- popup->setFocusProxy(d->widget);
- popup->installEventFilter(this);
- popup->setItemDelegate(new QCompleterItemDelegate(popup));
-#ifndef QT_NO_LISTVIEW
- if (QListView *listView = qobject_cast<QListView *>(popup)) {
- listView->setModelColumn(d->column);
- }
-#endif
-
- QObject::connect(popup, SIGNAL(clicked(QModelIndex)),
- this, SLOT(_q_complete(QModelIndex)));
- QObject::connect(this, SIGNAL(activated(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) {
- d->hiddenBecauseNoMatch = false;
- 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, d->column);
- 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, d->column);
- 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();
- if (e->isAccepted())
- return true;
- }
-
- // default implementation for keys not handled by the widget when popup is open
- switch (key) {
-#ifdef QT_KEYPAD_NAVIGATION
- case Qt::Key_Select:
- if (!QApplication::keypadNavigationEnabled())
- break;
-#endif
- case Qt::Key_Return:
- case Qt::Key_Enter:
- case Qt::Key_Tab:
- 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;
- }
- }
- }
-#endif
- if (!d->popup->underMouse()) {
- d->popup->hide();
- return true;
- }
- }
- return false;
-
- case QEvent::InputMethod:
- case QEvent::ShortcutOverride:
- QApplication::sendEvent(d->widget, e);
- break;
-
- default:
- return false;
- }
- return false;
-}
-
-/*!
- For QCompleter::PopupCompletion and QCompletion::UnfilteredPopupCompletion
- modes, calling this function displays the popup displaying the current
- completions. By default, if \a rect is not specified, the popup is displayed
- on the bottom of the widget(). If \a rect is specified the popup is
- displayed on the left edge of the rectangle.
-
- For QCompleter::InlineCompletion mode, the highlighted() signal is fired
- with the current completion.
-*/
-void QCompleter::complete(const QRect& rect)
-{
- Q_D(QCompleter);
- QModelIndex idx = d->proxy->currentIndex(false);
- d->hiddenBecauseNoMatch = false;
- if (d->mode == QCompleter::InlineCompletion) {
- if (idx.isValid())
- d->_q_complete(idx, true);
- return;
- }
-
- Q_ASSERT(d->widget != 0);
- if ((d->mode == QCompleter::PopupCompletion && !idx.isValid())
- || (d->mode == QCompleter::UnfilteredPopupCompletion && d->proxy->rowCount() == 0)) {
- if (d->popup)
- d->popup->hide(); // no suggestion, hide
- d->hiddenBecauseNoMatch = true;
- return;
- }
-
- popup();
- if (d->mode == QCompleter::UnfilteredPopupCompletion)
- d->setCurrentIndex(idx, false);
-
- d->showPopup(rect);
- d->popupRect = rect;
-}
-
-/*!
- Sets the current row to the \a row specified. Returns true if successful;
- otherwise returns false.
-
- This function may be used along with currentCompletion() to iterate
- through all the possible completions.
-
- \sa currentCompletion(), completionCount()
-*/
-bool QCompleter::setCurrentRow(int row)
-{
- Q_D(QCompleter);
- return d->proxy->setCurrentRow(row);
-}
-
-/*!
- Returns the current row.
-
- \sa setCurrentRow()
-*/
-int QCompleter::currentRow() const
-{
- Q_D(const QCompleter);
- return d->proxy->currentRow();
-}
-
-/*!
- Returns the number of completions for the current prefix. For an unsorted
- model with a large number of items this can be expensive. Use setCurrentRow()
- and currentCompletion() to iterate through all the completions.
-*/
-int QCompleter::completionCount() const
-{
- Q_D(const QCompleter);
- return d->proxy->completionCount();
-}
-
-/*!
- \enum QCompleter::ModelSorting
-
- This enum specifies how the items in the model are sorted.
-
- \value UnsortedModel The model is unsorted.
- \value CaseSensitivelySortedModel The model is sorted case sensitively.
- \value CaseInsensitivelySortedModel The model is sorted case insensitively.
-
- \sa setModelSorting()
-*/
-
-/*!
- \property QCompleter::modelSorting
- \brief the way the model is sorted
-
- By default, no assumptions are made about the order of the items
- in the model that provides the completions.
-
- If the model's data for the completionColumn() and completionRole() is sorted in
- ascending order, you can set this property to \l CaseSensitivelySortedModel
- or \l CaseInsensitivelySortedModel. On large models, this can lead to
- significant performance improvements because the completer object can
- then use a binary search algorithm instead of linear search algorithm.
-
- The sort order (i.e ascending or descending order) of the model is determined
- dynamically by inspecting the contents of the model.
-
- \bold{Note:} The performance improvements described above cannot take place
- when the completer's \l caseSensitivity is different to the case sensitivity
- used by the model's when sorting.
-
- \sa setCaseSensitivity(), QCompleter::ModelSorting
-*/
-void QCompleter::setModelSorting(QCompleter::ModelSorting sorting)
-{
- Q_D(QCompleter);
- if (d->sorting == sorting)
- return;
- d->sorting = sorting;
- d->proxy->createEngine();
- d->proxy->invalidate();
-}
-
-QCompleter::ModelSorting QCompleter::modelSorting() const
-{
- Q_D(const QCompleter);
- return d->sorting;
-}
-
-/*!
- \property QCompleter::completionColumn
- \brief the column in the model in which completions are searched for.
-
- If the popup() is a QListView, it is automatically setup to display
- this column.
-
- By default, the match column is 0.
-
- \sa completionRole, caseSensitivity
-*/
-void QCompleter::setCompletionColumn(int column)
-{
- Q_D(QCompleter);
- if (d->column == column)
- return;
-#ifndef QT_NO_LISTVIEW
- if (QListView *listView = qobject_cast<QListView *>(d->popup))
- listView->setModelColumn(column);
-#endif
- d->column = column;
- d->proxy->invalidate();
-}
-
-int QCompleter::completionColumn() const
-{
- Q_D(const QCompleter);
- return d->column;
-}
-
-/*!
- \property QCompleter::completionRole
- \brief the item role to be used to query the contents of items for matching.
-
- The default role is Qt::EditRole.
-
- \sa completionColumn, caseSensitivity
-*/
-void QCompleter::setCompletionRole(int role)
-{
- Q_D(QCompleter);
- if (d->role == role)
- return;
- d->role = role;
- d->proxy->invalidate();
-}
-
-int QCompleter::completionRole() const
-{
- Q_D(const QCompleter);
- return d->role;
-}
-
-/*!
- \property QCompleter::wrapAround
- \brief the completions wrap around when navigating through items
- \since 4.3
-
- The default is true.
-*/
-void QCompleter::setWrapAround(bool wrap)
-{
- Q_D(QCompleter);
- if (d->wrap == wrap)
- return;
- d->wrap = wrap;
-}
-
-bool QCompleter::wrapAround() const
-{
- Q_D(const QCompleter);
- return d->wrap;
-}
-
-/*!
- \property QCompleter::maxVisibleItems
- \brief the maximum allowed size on screen of the completer, measured in items
- \since 4.6
-
- By default, this property has a value of 7.
-*/
-int QCompleter::maxVisibleItems() const
-{
- Q_D(const QCompleter);
- return d->maxVisibleItems;
-}
-
-void QCompleter::setMaxVisibleItems(int maxItems)
-{
- Q_D(QCompleter);
- if (maxItems < 0) {
- qWarning("QCompleter::setMaxVisibleItems: "
- "Invalid max visible items (%d) must be >= 0", maxItems);
- return;
- }
- d->maxVisibleItems = maxItems;
-}
-
-/*!
- \property QCompleter::caseSensitivity
- \brief the case sensitivity of the matching
-
- The default is Qt::CaseSensitive.
-
- \sa completionColumn, completionRole, modelSorting
-*/
-void QCompleter::setCaseSensitivity(Qt::CaseSensitivity cs)
-{
- Q_D(QCompleter);
- if (d->cs == cs)
- return;
- d->cs = cs;
- d->proxy->createEngine();
- d->proxy->invalidate();
-}
-
-Qt::CaseSensitivity QCompleter::caseSensitivity() const
-{
- Q_D(const QCompleter);
- return d->cs;
-}
-
-/*!
- \property QCompleter::completionPrefix
- \brief the completion prefix used to provide completions.
-
- The completionModel() is updated to reflect the list of possible
- matches for \a prefix.
-*/
-void QCompleter::setCompletionPrefix(const QString &prefix)
-{
- Q_D(QCompleter);
- d->prefix = prefix;
- d->proxy->filter(splitPath(prefix));
-}
-
-QString QCompleter::completionPrefix() const
-{
- Q_D(const QCompleter);
- return d->prefix;
-}
-
-/*!
- Returns the model index of the current completion in the completionModel().
-
- \sa setCurrentRow(), currentCompletion(), model()
-*/
-QModelIndex QCompleter::currentIndex() const
-{
- Q_D(const QCompleter);
- return d->proxy->currentIndex(false);
-}
-
-/*!
- Returns the current completion string. This includes the \l completionPrefix.
- When used alongside setCurrentRow(), it can be used to iterate through
- all the matches.
-
- \sa setCurrentRow(), currentIndex()
-*/
-QString QCompleter::currentCompletion() const
-{
- Q_D(const QCompleter);
- return pathFromIndex(d->proxy->currentIndex(true));
-}
-
-/*!
- Returns the completion model. The completion model is a read-only list model
- that contains all the possible matches for the current completion prefix.
- The completion model is auto-updated to reflect the current completions.
-
- \note The return value of this function is defined to be an QAbstractItemModel
- purely for generality. This actual kind of model returned is an instance of an
- QAbstractProxyModel subclass.
-
- \sa completionPrefix, model()
-*/
-QAbstractItemModel *QCompleter::completionModel() const
-{
- Q_D(const QCompleter);
- return d->proxy;
-}
-
-/*!
- Returns the path for the given \a index. The completer object uses this to
- obtain the completion text from the underlying model.
-
- The default implementation returns the \l{Qt::EditRole}{edit role} of the
- item for list models. It returns the absolute file path if the model is a
- QFileSystemModel.
-
- \sa splitPath()
-*/
-
-QString QCompleter::pathFromIndex(const QModelIndex& index) const
-{
- Q_D(const QCompleter);
- if (!index.isValid())
- return QString();
-
- QAbstractItemModel *sourceModel = d->proxy->sourceModel();
- if (!sourceModel)
- return QString();
- bool isDirModel = false;
- bool isFsModel = false;
-#ifndef QT_NO_DIRMODEL
- isDirModel = qobject_cast<QDirModel *>(d->proxy->sourceModel()) != 0;
-#endif
-#ifndef QT_NO_FILESYSTEMMODEL
- isFsModel = qobject_cast<QFileSystemModel *>(d->proxy->sourceModel()) != 0;
-#endif
- if (!isDirModel && !isFsModel)
- return sourceModel->data(index, d->role).toString();
-
- QModelIndex idx = index;
- QStringList list;
- do {
- QString t;
- if (isDirModel)
- t = sourceModel->data(idx, Qt::EditRole).toString();
-#ifndef QT_NO_FILESYSTEMMODEL
- else
- t = sourceModel->data(idx, QFileSystemModel::FileNameRole).toString();
-#endif
- list.prepend(t);
- QModelIndex parent = idx.parent();
- idx = parent.sibling(parent.row(), index.column());
- } while (idx.isValid());
-
-#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN)
- if (list.count() == 1) // only the separator or some other text
- return list[0];
- list[0].clear() ; // the join below will provide the separator
-#endif
-
- return list.join(QDir::separator());
-}
-
-/*!
- Splits the given \a path into strings that are used to match at each level
- in the model().
-
- The default implementation of splitPath() splits a file system path based on
- QDir::separator() when the sourceModel() is a QFileSystemModel.
-
- When used with list models, the first item in the returned list is used for
- matching.
-
- \sa pathFromIndex(), {Handling Tree Models}
-*/
-QStringList QCompleter::splitPath(const QString& path) const
-{
- bool isDirModel = false;
- bool isFsModel = false;
-#ifndef QT_NO_DIRMODEL
- Q_D(const QCompleter);
- isDirModel = qobject_cast<QDirModel *>(d->proxy->sourceModel()) != 0;
-#endif
-#ifndef QT_NO_FILESYSTEMMODEL
-#ifdef QT_NO_DIRMODEL
- Q_D(const QCompleter);
-#endif
- isFsModel = qobject_cast<QFileSystemModel *>(d->proxy->sourceModel()) != 0;
-#endif
-
- if ((!isDirModel && !isFsModel) || path.isEmpty())
- return QStringList(completionPrefix());
-
- QString pathCopy = QDir::toNativeSeparators(path);
- QString sep = QDir::separator();
-#if defined(Q_OS_SYMBIAN)
- if (pathCopy == QLatin1String("\\"))
- return QStringList(pathCopy);
-#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
- if (pathCopy == QLatin1String("\\") || pathCopy == QLatin1String("\\\\"))
- return QStringList(pathCopy);
- QString doubleSlash(QLatin1String("\\\\"));
- if (pathCopy.startsWith(doubleSlash))
- pathCopy = pathCopy.mid(2);
- else
- doubleSlash.clear();
-#endif
-
- QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']'));
- QStringList parts = pathCopy.split(re);
-
-#if defined(Q_OS_SYMBIAN)
- // Do nothing
-#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
- if (!doubleSlash.isEmpty())
- parts[0].prepend(doubleSlash);
-#else
- if (pathCopy[0] == sep[0]) // readd the "/" at the beginning as the split removed it
- parts[0] = QDir::fromNativeSeparators(QString(sep[0]));
-#endif
-
- return parts;
-}
-
-/*!
- \fn void QCompleter::activated(const QModelIndex& index)
-
- This signal is sent when an item in the popup() is activated by the user.
- (by clicking or pressing return). The item's \a index in the completionModel()
- is given.
-
-*/
-
-/*!
- \fn void QCompleter::activated(const QString &text)
-
- This signal is sent when an item in the popup() is activated by the user (by
- clicking or pressing return). The item's \a text is given.
-
-*/
-
-/*!
- \fn void QCompleter::highlighted(const QModelIndex& index)
-
- This signal is sent when an item in the popup() is highlighted by
- the user. It is also sent if complete() is called with the completionMode()
- set to QCompleter::InlineCompletion. The item's \a index in the completionModel()
- is given.
-*/
-
-/*!
- \fn void QCompleter::highlighted(const QString &text)
-
- This signal is sent when an item in the popup() is highlighted by
- the user. It is also sent if complete() is called with the completionMode()
- set to QCompleter::InlineCompletion. The item's \a text is given.
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qcompleter.cpp"
-
-#endif // QT_NO_COMPLETER