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