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