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 Qt Virtual Keyboard module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL$ |
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 General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 or (at your option) any later version |
20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by |
21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #include <QtVirtualKeyboard/qvirtualkeyboardselectionlistmodel.h> |
31 | #include <QtVirtualKeyboard/qvirtualkeyboardabstractinputmethod.h> |
32 | #include <QtVirtualKeyboard/private/settings_p.h> |
33 | #include <QtCore/private/qabstractitemmodel_p.h> |
34 | #include <QtCore/qpointer.h> |
35 | |
36 | QT_BEGIN_NAMESPACE |
37 | |
38 | using namespace QtVirtualKeyboard; |
39 | |
40 | class QVirtualKeyboardSelectionListModelPrivate : public QAbstractItemModelPrivate |
41 | { |
42 | public: |
43 | QVirtualKeyboardSelectionListModelPrivate() : |
44 | QAbstractItemModelPrivate(), |
45 | dataSource(nullptr), |
46 | type(QVirtualKeyboardSelectionListModel::Type::WordCandidateList), |
47 | rowCount(0), |
48 | wclAutoCommitWord(false) |
49 | { |
50 | } |
51 | |
52 | QHash<int, QByteArray> roles; |
53 | QPointer<QVirtualKeyboardAbstractInputMethod> dataSource; |
54 | QVirtualKeyboardSelectionListModel::Type type; |
55 | int rowCount; |
56 | bool wclAutoCommitWord; |
57 | }; |
58 | |
59 | /*! |
60 | \qmltype SelectionListModel |
61 | \instantiates QVirtualKeyboardSelectionListModel |
62 | \inqmlmodule QtQuick.VirtualKeyboard |
63 | \ingroup qtvirtualkeyboard-qml |
64 | \brief Provides a data model for the selection lists. |
65 | |
66 | The SelectionListModel is a data model for word candidates |
67 | provided by the input method. |
68 | |
69 | An instance of a SelectionListModel cannot be created directly. |
70 | Instead, the InputEngine manages the instances and provides |
71 | access to the model by InputEngine::wordCandidateListModel |
72 | property. |
73 | |
74 | The model exposes the following data roles for the list delegate: |
75 | \list |
76 | \li \c display Display text for item. |
77 | \li \c wordCompletionLength Word completion length for item. |
78 | \li \c dictionaryType Dictionary type of the word, see QVirtualKeyboardSelectionListModel::DictionaryType. |
79 | \li \c canRemoveSuggestion A boolean indicating if the word can be removed from the dictionary. |
80 | \endlist |
81 | |
82 | The activeItemChanged signal indicates which item is currently |
83 | highlighted by the input method. The view should respond to this |
84 | signal by highlighting the corresponding item in the list. |
85 | |
86 | The user selection is handled by the selectItem() method. The view |
87 | should be invoke this method when the user selects an item from the |
88 | list. |
89 | */ |
90 | |
91 | /*! |
92 | \class QVirtualKeyboardSelectionListModel |
93 | |
94 | \inmodule QtVirtualKeyboard |
95 | |
96 | \brief List model for selection lists. |
97 | |
98 | This class acts as a bridge between the UI and the |
99 | input method that provides the data for selection |
100 | lists. |
101 | */ |
102 | |
103 | /*! |
104 | \enum QVirtualKeyboardSelectionListModel::Type |
105 | |
106 | This enum specifies the type of selection list. |
107 | |
108 | \value WordCandidateList |
109 | Shows list of word candidates. |
110 | */ |
111 | |
112 | /*! |
113 | \enum QVirtualKeyboardSelectionListModel::Role |
114 | |
115 | This enum specifies a role of the data requested. |
116 | |
117 | \value Display |
118 | The data to be rendered in form of text. |
119 | \value DisplayRole |
120 | \c obsolete Use Role::Display. |
121 | \value WordCompletionLength |
122 | An integer specifying the length of the word |
123 | the completion part expressed as the |
124 | number of characters counted from the |
125 | end of the string. |
126 | \value WordCompletionLengthRole |
127 | \c obsolete Use Role::WordCompletionLength. |
128 | \value Dictionary |
129 | An integer specifying \ l {QVirtualKeyboardSelectionListModel::DictionaryType}{dictionary type}. |
130 | \value CanRemoveSuggestion |
131 | A boolean value indicating if the word candidate |
132 | can be removed from the dictionary. |
133 | */ |
134 | |
135 | /*! |
136 | \enum QVirtualKeyboardSelectionListModel::DictionaryType |
137 | |
138 | This enum specifies the dictionary type of a word. |
139 | |
140 | \value Default |
141 | The word candidate is from the default dictionary. |
142 | \value User |
143 | The word candidate is from the user dictionary. |
144 | */ |
145 | |
146 | QVirtualKeyboardSelectionListModel::QVirtualKeyboardSelectionListModel(QObject *parent) : |
147 | QAbstractListModel(*new QVirtualKeyboardSelectionListModelPrivate(), parent) |
148 | { |
149 | Q_D(QVirtualKeyboardSelectionListModel); |
150 | d->roles = |
151 | {{static_cast<int>(Role::Display), "display" }, |
152 | {static_cast<int>(Role::WordCompletionLength), "wordCompletionLength" }, |
153 | {static_cast<int>(Role::Dictionary), "dictionary" }, |
154 | {static_cast<int>(Role::CanRemoveSuggestion), "canRemoveSuggestion" }}; |
155 | } |
156 | |
157 | /*! |
158 | \internal |
159 | */ |
160 | QVirtualKeyboardSelectionListModel::~QVirtualKeyboardSelectionListModel() |
161 | { |
162 | } |
163 | |
164 | /*! |
165 | \internal |
166 | */ |
167 | void QVirtualKeyboardSelectionListModel::setDataSource(QVirtualKeyboardAbstractInputMethod *dataSource, Type type) |
168 | { |
169 | Q_D(QVirtualKeyboardSelectionListModel); |
170 | if (d->dataSource) { |
171 | disconnect(receiver: this, SLOT(selectionListChanged(Type))); |
172 | disconnect(receiver: this, SLOT(selectionListActiveItemChanged(Type, int))); |
173 | } |
174 | d->type = type; |
175 | if (d->dataSource) { |
176 | d->dataSource = nullptr; |
177 | selectionListChanged(type); |
178 | selectionListActiveItemChanged(type, index: -1); |
179 | } |
180 | d->dataSource = dataSource; |
181 | if (d->dataSource) { |
182 | QObject::connect(sender: d->dataSource.data(), signal: &QVirtualKeyboardAbstractInputMethod::selectionListChanged, receiver: this, slot: &QVirtualKeyboardSelectionListModel::selectionListChanged); |
183 | QObject::connect(sender: d->dataSource.data(), signal: &QVirtualKeyboardAbstractInputMethod::selectionListActiveItemChanged, receiver: this, slot: &QVirtualKeyboardSelectionListModel::selectionListActiveItemChanged); |
184 | } |
185 | } |
186 | |
187 | /*! |
188 | \internal |
189 | */ |
190 | QVirtualKeyboardAbstractInputMethod *QVirtualKeyboardSelectionListModel::dataSource() const |
191 | { |
192 | Q_D(const QVirtualKeyboardSelectionListModel); |
193 | return d->dataSource; |
194 | } |
195 | |
196 | /*! |
197 | \internal |
198 | */ |
199 | int QVirtualKeyboardSelectionListModel::rowCount(const QModelIndex &parent) const |
200 | { |
201 | Q_D(const QVirtualKeyboardSelectionListModel); |
202 | Q_UNUSED(parent) |
203 | return d->rowCount; |
204 | } |
205 | |
206 | /*! |
207 | \internal |
208 | */ |
209 | QVariant QVirtualKeyboardSelectionListModel::data(const QModelIndex &index, int role) const |
210 | { |
211 | Q_D(const QVirtualKeyboardSelectionListModel); |
212 | return d->dataSource ? d->dataSource->selectionListData(type: d->type, index: index.row(), role: static_cast<Role>(role)) : QVariant(); |
213 | } |
214 | |
215 | /*! |
216 | \internal |
217 | */ |
218 | QHash<int,QByteArray> QVirtualKeyboardSelectionListModel::roleNames() const |
219 | { |
220 | Q_D(const QVirtualKeyboardSelectionListModel); |
221 | return d->roles; |
222 | } |
223 | |
224 | /*! |
225 | \property QVirtualKeyboardSelectionListModel::count |
226 | \internal |
227 | */ |
228 | /* |
229 | \internal |
230 | */ |
231 | int QVirtualKeyboardSelectionListModel::count() const |
232 | { |
233 | Q_D(const QVirtualKeyboardSelectionListModel); |
234 | return d->rowCount; |
235 | } |
236 | |
237 | /*! \qmlmethod void SelectionListModel::selectItem(int index) |
238 | |
239 | This method should be called when the user selects an item at position |
240 | \a index from the list. |
241 | The selection is forwarded to the input method for further processing. |
242 | */ |
243 | /*! |
244 | This method should be called when the user selects an item at position |
245 | \a index from the list. |
246 | The selection is forwarded to the input method for further processing. |
247 | */ |
248 | void QVirtualKeyboardSelectionListModel::selectItem(int index) |
249 | { |
250 | Q_D(QVirtualKeyboardSelectionListModel); |
251 | if (index >= 0 && index < d->rowCount && d->dataSource) { |
252 | emit itemSelected(index); |
253 | d->dataSource->selectionListItemSelected(type: d->type, index); |
254 | } |
255 | } |
256 | |
257 | /*! |
258 | \qmlmethod void SelectionListModel::removeItem(int index) |
259 | |
260 | This method should be called when the user removes an item at position |
261 | \a index from the list. |
262 | The removal is forwarded to the input method for further processing. |
263 | */ |
264 | /*! |
265 | This method should be called when the user removes an item at position |
266 | \a index from the list. |
267 | The removal is forwarded to the input method for further processing. |
268 | */ |
269 | void QVirtualKeyboardSelectionListModel::removeItem(int index) |
270 | { |
271 | Q_D(QVirtualKeyboardSelectionListModel); |
272 | if (index >= 0 && index < d->rowCount && d->dataSource) { |
273 | d->dataSource->selectionListRemoveItem(type: d->type, index); |
274 | } |
275 | } |
276 | |
277 | /*! |
278 | * \internal |
279 | */ |
280 | QVariant QVirtualKeyboardSelectionListModel::dataAt(int index, QVirtualKeyboardSelectionListModel::Role role) const |
281 | { |
282 | return data(index: this->index(row: index, column: 0), role: static_cast<int>(role)); |
283 | } |
284 | |
285 | /*! |
286 | \internal |
287 | */ |
288 | void QVirtualKeyboardSelectionListModel::selectionListChanged(QVirtualKeyboardSelectionListModel::Type type) |
289 | { |
290 | Q_D(QVirtualKeyboardSelectionListModel); |
291 | if (static_cast<Type>(type) == d->type) { |
292 | int oldCount = d->rowCount; |
293 | int newCount = d->dataSource ? d->dataSource->selectionListItemCount(type: d->type) : 0; |
294 | if (newCount) { |
295 | int changedCount = qMin(a: oldCount, b: newCount); |
296 | if (changedCount) |
297 | emit dataChanged(topLeft: index(row: 0), bottomRight: index(row: changedCount - 1)); |
298 | if (oldCount > newCount) { |
299 | beginRemoveRows(parent: QModelIndex(), first: newCount, last: oldCount - 1); |
300 | d->rowCount = newCount; |
301 | endRemoveRows(); |
302 | } else if (oldCount < newCount) { |
303 | beginInsertRows(parent: QModelIndex(), first: oldCount, last: newCount - 1); |
304 | d->rowCount = newCount; |
305 | endInsertRows(); |
306 | } |
307 | } else { |
308 | beginResetModel(); |
309 | d->rowCount = 0; |
310 | endResetModel(); |
311 | } |
312 | if (static_cast<QVirtualKeyboardSelectionListModel::Type>(type) == QVirtualKeyboardSelectionListModel::Type::WordCandidateList) |
313 | d->wclAutoCommitWord = ((oldCount > 1 || (oldCount == 1 && d->wclAutoCommitWord)) && newCount == 1 && |
314 | Settings::instance()->wclAutoCommitWord() && |
315 | dataAt(index: 0).toString().length() > 1); |
316 | if (d->rowCount != oldCount) |
317 | emit countChanged(); |
318 | } |
319 | } |
320 | |
321 | /*! |
322 | \internal |
323 | */ |
324 | void QVirtualKeyboardSelectionListModel::selectionListActiveItemChanged(QVirtualKeyboardSelectionListModel::Type type, int index) |
325 | { |
326 | Q_D(QVirtualKeyboardSelectionListModel); |
327 | if (static_cast<Type>(type) == d->type && index < d->rowCount) { |
328 | emit activeItemChanged(index); |
329 | if (index == 0 && d->wclAutoCommitWord) |
330 | selectItem(index: 0); |
331 | } |
332 | } |
333 | |
334 | /*! |
335 | \qmlsignal void SelectionListModel::activeItemChanged(int index) |
336 | |
337 | This signal is emitted when the active item in the list changes. The |
338 | UI should react to this signal by highlighting the item at \a index in |
339 | the list. |
340 | */ |
341 | /*! |
342 | \fn void QVirtualKeyboardSelectionListModel::activeItemChanged(int index) |
343 | |
344 | This signal is emitted when the active item in the list changes. The |
345 | UI should react to this signal by highlighting the item at \a index in |
346 | the list. |
347 | */ |
348 | |
349 | /*! |
350 | \qmlsignal void SelectionListModel::itemSelected(int index) |
351 | |
352 | This signal is emitted when an item at \a index is selected by the user. |
353 | */ |
354 | /*! |
355 | \fn void QVirtualKeyboardSelectionListModel::itemSelected(int index) |
356 | |
357 | This signal is emitted when an item at \a index is selected by the user. |
358 | */ |
359 | |
360 | QT_END_NAMESPACE |
361 | |