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 QtCore 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/*
41 A simple model that uses a QStringList as its data source.
42*/
43
44#include "qstringlistmodel.h"
45
46#include <QtCore/qvector.h>
47
48#include <algorithm>
49
50QT_BEGIN_NAMESPACE
51
52/*!
53 \class QStringListModel
54 \inmodule QtCore
55 \brief The QStringListModel class provides a model that supplies strings to views.
56
57 \ingroup model-view
58
59 QStringListModel is an editable model that can be used for simple
60 cases where you need to display a number of strings in a view
61 widget, such as a QListView or a QComboBox.
62
63 The model provides all the standard functions of an editable
64 model, representing the data in the string list as a model with
65 one column and a number of rows equal to the number of items in
66 the list.
67
68 Model indexes corresponding to items are obtained with the
69 \l{QAbstractListModel::index()}{index()} function, and item flags
70 are obtained with flags(). Item data is read with the data()
71 function and written with setData(). The number of rows (and
72 number of items in the string list) can be found with the
73 rowCount() function.
74
75 The model can be constructed with an existing string list, or
76 strings can be set later with the setStringList() convenience
77 function. Strings can also be inserted in the usual way with the
78 insertRows() function, and removed with removeRows(). The contents
79 of the string list can be retrieved with the stringList()
80 convenience function.
81
82 An example usage of QStringListModel:
83
84 \snippet qstringlistmodel/main.cpp 0
85
86 \sa QAbstractListModel, QAbstractItemModel, {Model Classes}
87*/
88
89/*!
90 Constructs a string list model with the given \a parent.
91*/
92
93QStringListModel::QStringListModel(QObject *parent)
94 : QAbstractListModel(parent)
95{
96}
97
98/*!
99 Constructs a string list model containing the specified \a strings
100 with the given \a parent.
101*/
102
103QStringListModel::QStringListModel(const QStringList &strings, QObject *parent)
104 : QAbstractListModel(parent), lst(strings)
105{
106}
107
108/*!
109 Returns the number of rows in the model. This value corresponds to the
110 number of items in the model's internal string list.
111
112 The optional \a parent argument is in most models used to specify
113 the parent of the rows to be counted. Because this is a list if a
114 valid parent is specified, the result will always be 0.
115
116 \sa insertRows(), removeRows(), QAbstractItemModel::rowCount()
117*/
118
119int QStringListModel::rowCount(const QModelIndex &parent) const
120{
121 if (parent.isValid())
122 return 0;
123
124 return lst.count();
125}
126
127/*!
128 \reimp
129*/
130QModelIndex QStringListModel::sibling(int row, int column, const QModelIndex &idx) const
131{
132 if (!idx.isValid() || column != 0 || row >= lst.count() || row < 0)
133 return QModelIndex();
134
135 return createIndex(arow: row, acolumn: 0);
136}
137
138/*!
139 \reimp
140 \since 5.13
141*/
142QMap<int, QVariant> QStringListModel::itemData(const QModelIndex &index) const
143{
144 if (!checkIndex(index, options: CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid))
145 return QMap<int, QVariant>{};
146 const QVariant displayData = lst.at(i: index.row());
147 return QMap<int, QVariant>{{
148 std::make_pair<int>(x: Qt::DisplayRole, y: displayData),
149 std::make_pair<int>(x: Qt::EditRole, y: displayData)
150 }};
151}
152
153/*!
154 \reimp
155 \since 5.13
156 If \a roles contains both Qt::DisplayRole and Qt::EditRole, the latter will take precedence
157*/
158bool QStringListModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
159{
160 if (roles.isEmpty())
161 return false;
162 if (std::any_of(first: roles.keyBegin(), last: roles.keyEnd(), pred: [](int role) -> bool {
163 return role != Qt::DisplayRole && role != Qt::EditRole;
164 })) {
165 return false;
166 }
167 auto roleIter = roles.constFind(akey: Qt::EditRole);
168 if (roleIter == roles.constEnd())
169 roleIter = roles.constFind(akey: Qt::DisplayRole);
170 Q_ASSERT(roleIter != roles.constEnd());
171 return setData(index, value: roleIter.value(), role: roleIter.key());
172}
173
174/*!
175 Returns data for the specified \a role, from the item with the
176 given \a index.
177
178 If the view requests an invalid index, an invalid variant is returned.
179
180 \sa setData()
181*/
182
183QVariant QStringListModel::data(const QModelIndex &index, int role) const
184{
185 if (index.row() < 0 || index.row() >= lst.size())
186 return QVariant();
187
188 if (role == Qt::DisplayRole || role == Qt::EditRole)
189 return lst.at(i: index.row());
190
191 return QVariant();
192}
193
194/*!
195 Returns the flags for the item with the given \a index.
196
197 Valid items are enabled, selectable, editable, drag enabled and drop enabled.
198
199 \sa QAbstractItemModel::flags()
200*/
201
202Qt::ItemFlags QStringListModel::flags(const QModelIndex &index) const
203{
204 if (!index.isValid())
205 return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled;
206
207 return QAbstractListModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
208}
209
210/*!
211 Sets the data for the specified \a role in the item with the given
212 \a index in the model, to the provided \a value.
213
214 The dataChanged() signal is emitted if the item is changed.
215 Returns \c true after emitting the dataChanged() signal.
216
217 \sa Qt::ItemDataRole, data()
218*/
219
220bool QStringListModel::setData(const QModelIndex &index, const QVariant &value, int role)
221{
222 if (index.row() >= 0 && index.row() < lst.size()
223 && (role == Qt::EditRole || role == Qt::DisplayRole)) {
224 const QString valueString = value.toString();
225 if (lst.at(i: index.row()) == valueString)
226 return true;
227 lst.replace(i: index.row(), t: valueString);
228 emit dataChanged(topLeft: index, bottomRight: index, roles: {Qt::DisplayRole, Qt::EditRole});
229 return true;
230 }
231 return false;
232}
233
234#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
235/*!
236 \reimp
237 \since 6.0
238 */
239bool QStringListModel::clearItemData(const QModelIndex &index)
240{
241 return setData(index, QVariant(), Qt::EditRole);
242}
243#endif
244
245/*!
246 Inserts \a count rows into the model, beginning at the given \a row.
247
248 The \a parent index of the rows is optional and is only used for
249 consistency with QAbstractItemModel. By default, a null index is
250 specified, indicating that the rows are inserted in the top level of
251 the model.
252
253 Returns \c true if the insertion was successful.
254
255 \sa QAbstractItemModel::insertRows()
256*/
257
258bool QStringListModel::insertRows(int row, int count, const QModelIndex &parent)
259{
260 if (count < 1 || row < 0 || row > rowCount(parent))
261 return false;
262
263 beginInsertRows(parent: QModelIndex(), first: row, last: row + count - 1);
264
265 for (int r = 0; r < count; ++r)
266 lst.insert(i: row, t: QString());
267
268 endInsertRows();
269
270 return true;
271}
272
273/*!
274 Removes \a count rows from the model, beginning at the given \a row.
275
276 The \a parent index of the rows is optional and is only used for
277 consistency with QAbstractItemModel. By default, a null index is
278 specified, indicating that the rows are removed in the top level of
279 the model.
280
281 Returns \c true if the row removal was successful.
282
283 \sa QAbstractItemModel::removeRows()
284*/
285
286bool QStringListModel::removeRows(int row, int count, const QModelIndex &parent)
287{
288 if (count <= 0 || row < 0 || (row + count) > rowCount(parent))
289 return false;
290
291 beginRemoveRows(parent: QModelIndex(), first: row, last: row + count - 1);
292
293 const auto it = lst.begin() + row;
294 lst.erase(afirst: it, alast: it + count);
295
296 endRemoveRows();
297
298 return true;
299}
300
301/*!
302 \since 5.13
303 \reimp
304*/
305bool QStringListModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
306{
307 if (sourceRow < 0
308 || sourceRow + count - 1 >= rowCount(parent: sourceParent)
309 || destinationChild < 0
310 || destinationChild > rowCount(parent: destinationParent)
311 || sourceRow == destinationChild
312 || sourceRow == destinationChild - 1
313 || count <= 0
314 || sourceParent.isValid()
315 || destinationParent.isValid()) {
316 return false;
317 }
318 if (!beginMoveRows(sourceParent: QModelIndex(), sourceFirst: sourceRow, sourceLast: sourceRow + count - 1, destinationParent: QModelIndex(), destinationRow: destinationChild))
319 return false;
320
321 int fromRow = sourceRow;
322 if (destinationChild < sourceRow)
323 fromRow += count - 1;
324 else
325 destinationChild--;
326 while (count--)
327 lst.move(from: fromRow, to: destinationChild);
328 endMoveRows();
329 return true;
330}
331
332static bool ascendingLessThan(const QPair<QString, int> &s1, const QPair<QString, int> &s2)
333{
334 return s1.first < s2.first;
335}
336
337static bool decendingLessThan(const QPair<QString, int> &s1, const QPair<QString, int> &s2)
338{
339 return s1.first > s2.first;
340}
341
342/*!
343 \reimp
344*/
345void QStringListModel::sort(int, Qt::SortOrder order)
346{
347 emit layoutAboutToBeChanged(parents: QList<QPersistentModelIndex>(), hint: VerticalSortHint);
348
349 QVector<QPair<QString, int> > list;
350 const int lstCount = lst.count();
351 list.reserve(asize: lstCount);
352 for (int i = 0; i < lstCount; ++i)
353 list.append(t: QPair<QString, int>(lst.at(i), i));
354
355 if (order == Qt::AscendingOrder)
356 std::sort(first: list.begin(), last: list.end(), comp: ascendingLessThan);
357 else
358 std::sort(first: list.begin(), last: list.end(), comp: decendingLessThan);
359
360 lst.clear();
361 QVector<int> forwarding(lstCount);
362 for (int i = 0; i < lstCount; ++i) {
363 lst.append(t: list.at(i).first);
364 forwarding[list.at(i).second] = i;
365 }
366
367 QModelIndexList oldList = persistentIndexList();
368 QModelIndexList newList;
369 const int numOldIndexes = oldList.count();
370 newList.reserve(alloc: numOldIndexes);
371 for (int i = 0; i < numOldIndexes; ++i)
372 newList.append(t: index(row: forwarding.at(i: oldList.at(i).row()), column: 0));
373 changePersistentIndexList(from: oldList, to: newList);
374
375 emit layoutChanged(parents: QList<QPersistentModelIndex>(), hint: VerticalSortHint);
376}
377
378/*!
379 Returns the string list used by the model to store data.
380*/
381QStringList QStringListModel::stringList() const
382{
383 return lst;
384}
385
386/*!
387 Sets the model's internal string list to \a strings. The model will
388 notify any attached views that its underlying data has changed.
389
390 \sa dataChanged()
391*/
392void QStringListModel::setStringList(const QStringList &strings)
393{
394 beginResetModel();
395 lst = strings;
396 endResetModel();
397}
398
399/*!
400 \reimp
401*/
402Qt::DropActions QStringListModel::supportedDropActions() const
403{
404 return QAbstractItemModel::supportedDropActions() | Qt::MoveAction;
405}
406
407QT_END_NAMESPACE
408
409#include "moc_qstringlistmodel.cpp"
410

source code of qtbase/src/corelib/itemmodels/qstringlistmodel.cpp