1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QCOMPLETER_P_H
41 #define QCOMPLETER_P_H
42 
43 
44 //
45 //  W A R N I N G
46 //  -------------
47 //
48 // This file is not part of the Qt API.  It exists purely as an
49 // implementation detail.  This header file may change from version to
50 // version without notice, or even be removed.
51 //
52 // We mean it.
53 //
54 
55 #include <QtWidgets/private/qtwidgetsglobal_p.h>
56 #include "private/qobject_p.h"
57 
58 #include "QtWidgets/qabstractitemview.h"
59 #include "QtCore/qabstractproxymodel.h"
60 #include "qcompleter.h"
61 #include "QtWidgets/qitemdelegate.h"
62 #include "QtGui/qpainter.h"
63 #include "private/qabstractproxymodel_p.h"
64 
65 QT_REQUIRE_CONFIG(completer);
66 
67 QT_BEGIN_NAMESPACE
68 
69 class QCompletionModel;
70 
71 class QCompleterPrivate : public QObjectPrivate
72 {
73     Q_DECLARE_PUBLIC(QCompleter)
74 
75 public:
76     QCompleterPrivate();
~QCompleterPrivate()77     ~QCompleterPrivate() { delete popup; }
78     void init(QAbstractItemModel *model = nullptr);
79 
80     QPointer<QWidget> widget;
81     QCompletionModel *proxy;
82     QAbstractItemView *popup;
83     QCompleter::CompletionMode mode;
84     Qt::MatchFlags filterMode;
85 
86     QString prefix;
87     Qt::CaseSensitivity cs;
88     int role;
89     int column;
90     int maxVisibleItems;
91     QCompleter::ModelSorting sorting;
92     bool wrap;
93 
94     bool eatFocusOut;
95     QRect popupRect;
96     bool hiddenBecauseNoMatch;
97 
98     void showPopup(const QRect&);
99     void _q_complete(QModelIndex, bool = false);
100     void _q_completionSelected(const QItemSelection&);
101     void _q_autoResizePopup();
102     void _q_fileSystemModelDirectoryLoaded(const QString &path);
103     void setCurrentIndex(QModelIndex, bool = true);
104 
get(QCompleter * o)105     static QCompleterPrivate *get(QCompleter *o) { return o->d_func(); }
get(const QCompleter * o)106     static const QCompleterPrivate *get(const QCompleter *o) { return o->d_func(); }
107 };
108 
109 class QIndexMapper
110 {
111 public:
QIndexMapper()112     QIndexMapper() : v(false), f(0), t(-1) { }
QIndexMapper(int f,int t)113     QIndexMapper(int f, int t) : v(false), f(f), t(t) { }
QIndexMapper(const QVector<int> & vec)114     QIndexMapper(const QVector<int> &vec) : v(true), vector(vec), f(-1), t(-1) { }
115 
count()116     inline int count() const { return v ? vector.count() : t - f + 1; }
117     inline int operator[] (int index) const { return v ? vector[index] : f + index; }
indexOf(int x)118     inline int indexOf(int x) const { return v ? vector.indexOf(x) : ((t < f) ? -1 : x - f); }
isValid()119     inline bool isValid() const { return !isEmpty(); }
isEmpty()120     inline bool isEmpty() const { return v ? vector.isEmpty() : (t < f); }
append(int x)121     inline void append(int x) { Q_ASSERT(v); vector.append(x); }
first()122     inline int first() const { return v ? vector.first() : f; }
last()123     inline int last() const { return v ? vector.last() : t; }
from()124     inline int from() const { Q_ASSERT(!v); return f; }
to()125     inline int to() const { Q_ASSERT(!v); return t; }
cost()126     inline int cost() const { return vector.count()+2; }
127 
128 private:
129     bool v;
130     QVector<int> vector;
131     int f, t;
132 };
133 
134 struct QMatchData {
QMatchDataQMatchData135     QMatchData() : exactMatchIndex(-1), partial(false) { }
QMatchDataQMatchData136     QMatchData(const QIndexMapper& indices, int em, bool p) :
137         indices(indices), exactMatchIndex(em), partial(p) { }
138     QIndexMapper indices;
isValidQMatchData139     inline bool isValid() const { return indices.isValid(); }
140     int  exactMatchIndex;
141     bool partial;
142 };
143 
144 class QCompletionEngine
145 {
146 public:
147     typedef QMap<QString, QMatchData> CacheItem;
148     typedef QMap<QModelIndex, CacheItem> Cache;
149 
QCompletionEngine(QCompleterPrivate * c)150     QCompletionEngine(QCompleterPrivate *c) : c(c), curRow(-1), cost(0) { }
~QCompletionEngine()151     virtual ~QCompletionEngine() { }
152 
153     void filter(const QStringList &parts);
154 
155     QMatchData filterHistory();
156     bool matchHint(const QString &part, const QModelIndex &parent, QMatchData *m) const;
157 
158     void saveInCache(QString, const QModelIndex&, const QMatchData&);
159     bool lookupCache(const QString &part, const QModelIndex &parent, QMatchData *m) const;
160 
filterOnDemand(int)161     virtual void filterOnDemand(int) { }
162     virtual QMatchData filter(const QString&, const QModelIndex&, int) = 0;
163 
matchCount()164     int matchCount() const { return curMatch.indices.count() + historyMatch.indices.count(); }
165 
166     QMatchData curMatch, historyMatch;
167     QCompleterPrivate *c;
168     QStringList curParts;
169     QModelIndex curParent;
170     int curRow;
171 
172     Cache cache;
173     int cost;
174 };
175 
176 class QSortedModelEngine : public QCompletionEngine
177 {
178 public:
QSortedModelEngine(QCompleterPrivate * c)179     QSortedModelEngine(QCompleterPrivate *c) : QCompletionEngine(c) { }
180     QMatchData filter(const QString&, const QModelIndex&, int) override;
181     QIndexMapper indexHint(QString, const QModelIndex&, Qt::SortOrder);
182     Qt::SortOrder sortOrder(const QModelIndex&) const;
183 };
184 
185 class QUnsortedModelEngine : public QCompletionEngine
186 {
187 public:
QUnsortedModelEngine(QCompleterPrivate * c)188     QUnsortedModelEngine(QCompleterPrivate *c) : QCompletionEngine(c) { }
189 
190     void filterOnDemand(int) override;
191     QMatchData filter(const QString&, const QModelIndex&, int) override;
192 private:
193     int buildIndices(const QString& str, const QModelIndex& parent, int n,
194                      const QIndexMapper& iv, QMatchData* m);
195 };
196 
197 // ### Qt6: QStyledItemDelegate
198 class QCompleterItemDelegate : public QItemDelegate
199 {
200 public:
QCompleterItemDelegate(QAbstractItemView * view)201     QCompleterItemDelegate(QAbstractItemView *view)
202         : QItemDelegate(view), view(view) { }
paint(QPainter * p,const QStyleOptionViewItem & opt,const QModelIndex & idx)203     void paint(QPainter *p, const QStyleOptionViewItem& opt, const QModelIndex& idx) const override {
204         QStyleOptionViewItem optCopy = opt;
205         optCopy.showDecorationSelected = true;
206         if (view->currentIndex() == idx)
207             optCopy.state |= QStyle::State_HasFocus;
208         QItemDelegate::paint(p, optCopy, idx);
209     }
210 
211 private:
212     QAbstractItemView *view;
213 };
214 
215 class QCompletionModelPrivate;
216 
217 class QCompletionModel : public QAbstractProxyModel
218 {
219     Q_OBJECT
220 
221 public:
222     QCompletionModel(QCompleterPrivate *c, QObject *parent);
223 
224     void createEngine();
225     void setFiltered(bool);
226     void filter(const QStringList& parts);
227     int completionCount() const;
currentRow()228     int currentRow() const { return engine->curRow; }
229     bool setCurrentRow(int row);
230     QModelIndex currentIndex(bool) const;
231 
232     QModelIndex index(int row, int column, const QModelIndex & = QModelIndex()) const override;
233     int rowCount(const QModelIndex &index = QModelIndex()) const override;
234     int columnCount(const QModelIndex &index = QModelIndex()) const override;
235     bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
236     QModelIndex parent(const QModelIndex & = QModelIndex()) const override { return QModelIndex(); }
237     QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
238 
239     void setSourceModel(QAbstractItemModel *sourceModel) override;
240     QModelIndex mapToSource(const QModelIndex& proxyIndex) const override;
241     QModelIndex mapFromSource(const QModelIndex& sourceIndex) const override;
242 
243     QCompleterPrivate *c;
244     QScopedPointer<QCompletionEngine> engine;
245     bool showAll;
246 
247     Q_DECLARE_PRIVATE(QCompletionModel)
248 
249 signals:
250     void rowsAdded();
251 
252 public Q_SLOTS:
253     void invalidate();
254     void rowsInserted();
255     void modelDestroyed();
256 };
257 
258 class QCompletionModelPrivate : public QAbstractProxyModelPrivate
259 {
260     Q_DECLARE_PUBLIC(QCompletionModel)
261 };
262 
263 QT_END_NAMESPACE
264 
265 #endif // QCOMPLETER_P_H
266