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:
QVirtualKeyboardSelectionListModelPrivate()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 
QVirtualKeyboardSelectionListModel(QObject * parent)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 */
~QVirtualKeyboardSelectionListModel()160 QVirtualKeyboardSelectionListModel::~QVirtualKeyboardSelectionListModel()
161 {
162 }
163 
164 /*!
165     \internal
166 */
setDataSource(QVirtualKeyboardAbstractInputMethod * dataSource,Type type)167 void QVirtualKeyboardSelectionListModel::setDataSource(QVirtualKeyboardAbstractInputMethod *dataSource, Type type)
168 {
169     Q_D(QVirtualKeyboardSelectionListModel);
170     if (d->dataSource) {
171         disconnect(this, SLOT(selectionListChanged(Type)));
172         disconnect(this, SLOT(selectionListActiveItemChanged(Type, int)));
173     }
174     d->type = type;
175     if (d->dataSource) {
176         d->dataSource = nullptr;
177         selectionListChanged(type);
178         selectionListActiveItemChanged(type, -1);
179     }
180     d->dataSource = dataSource;
181     if (d->dataSource) {
182         QObject::connect(d->dataSource.data(), &QVirtualKeyboardAbstractInputMethod::selectionListChanged, this, &QVirtualKeyboardSelectionListModel::selectionListChanged);
183         QObject::connect(d->dataSource.data(), &QVirtualKeyboardAbstractInputMethod::selectionListActiveItemChanged, this, &QVirtualKeyboardSelectionListModel::selectionListActiveItemChanged);
184     }
185 }
186 
187 /*!
188     \internal
189 */
dataSource() const190 QVirtualKeyboardAbstractInputMethod *QVirtualKeyboardSelectionListModel::dataSource() const
191 {
192     Q_D(const QVirtualKeyboardSelectionListModel);
193     return d->dataSource;
194 }
195 
196 /*!
197     \internal
198 */
rowCount(const QModelIndex & parent) const199 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 */
data(const QModelIndex & index,int role) const209 QVariant QVirtualKeyboardSelectionListModel::data(const QModelIndex &index, int role) const
210 {
211     Q_D(const QVirtualKeyboardSelectionListModel);
212     return d->dataSource ? d->dataSource->selectionListData(d->type, index.row(), static_cast<Role>(role)) : QVariant();
213 }
214 
215 /*!
216     \internal
217 */
roleNames() const218 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 */
count() const231 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 */
selectItem(int index)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(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 */
removeItem(int index)269 void QVirtualKeyboardSelectionListModel::removeItem(int index)
270 {
271     Q_D(QVirtualKeyboardSelectionListModel);
272     if (index >= 0 && index < d->rowCount && d->dataSource) {
273         d->dataSource->selectionListRemoveItem(d->type, index);
274     }
275 }
276 
277 /*!
278  * \internal
279  */
dataAt(int index,QVirtualKeyboardSelectionListModel::Role role) const280 QVariant QVirtualKeyboardSelectionListModel::dataAt(int index, QVirtualKeyboardSelectionListModel::Role role) const
281 {
282     return data(this->index(index, 0), static_cast<int>(role));
283 }
284 
285 /*!
286     \internal
287 */
selectionListChanged(QVirtualKeyboardSelectionListModel::Type type)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(d->type) : 0;
294         if (newCount) {
295             int changedCount = qMin(oldCount, newCount);
296             if (changedCount)
297                 emit dataChanged(index(0), index(changedCount - 1));
298             if (oldCount > newCount) {
299                 beginRemoveRows(QModelIndex(), newCount, oldCount - 1);
300                 d->rowCount = newCount;
301                 endRemoveRows();
302             } else if (oldCount < newCount) {
303                 beginInsertRows(QModelIndex(), oldCount, 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(0).toString().length() > 1);
316         if (d->rowCount != oldCount)
317             emit countChanged();
318     }
319 }
320 
321 /*!
322     \internal
323 */
selectionListActiveItemChanged(QVirtualKeyboardSelectionListModel::Type type,int index)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(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