Qt Utilities 6.14.0
Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models
Loading...
Searching...
No Matches
checklistmodel.cpp
Go to the documentation of this file.
1#include "./checklistmodel.h"
2
3#include <QSettings>
4
10namespace QtUtilities {
11
28 : QAbstractListModel(parent)
29{
30}
31
32int ChecklistModel::rowCount(const QModelIndex &parent) const
33{
34 if (!parent.isValid()) {
35 return static_cast<int>(m_items.size());
36 }
37 return 0;
38}
39
40Qt::ItemFlags ChecklistModel::flags(const QModelIndex &index) const
41{
42 if (!index.isValid() || index.row() >= m_items.count() || index.model() != this) {
43 return Qt::ItemIsDropEnabled; // allows drops outside the items
44 }
45 return QAbstractListModel::flags(index) | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
46}
47
48QVariant ChecklistModel::data(const QModelIndex &index, int role) const
49{
50 if (index.isValid() && index.row() < m_items.size()) {
51 switch (role) {
52 case Qt::DisplayRole:
53 return m_items.at(index.row()).label();
54 case Qt::CheckStateRole:
55 return m_items.at(index.row()).checkState();
56 case idRole():
57 return m_items.at(index.row()).id();
58 default:;
59 }
60 }
61 return QVariant();
62}
63
64QMap<int, QVariant> ChecklistModel::itemData(const QModelIndex &index) const
65{
66 QMap<int, QVariant> roles;
67 roles.insert(Qt::DisplayRole, data(index, Qt::DisplayRole));
68 roles.insert(Qt::CheckStateRole, data(index, Qt::CheckStateRole));
69 roles.insert(idRole(), data(index, idRole()));
70 return roles;
71}
72
73bool ChecklistModel::setData(const QModelIndex &index, const QVariant &value, int role)
74{
75 bool success = false;
76 QVector<int> roles{ role };
77 if (index.isValid() && index.row() < m_items.size()) {
78 switch (role) {
79 case Qt::DisplayRole:
80 m_items[index.row()].m_label = value.toString();
81 success = true;
82 break;
83 case Qt::CheckStateRole:
84 if (value.canConvert(
85#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
86 QMetaType::Int
87#else
88 QMetaType::fromType<int>()
89#endif
90 )) {
91 m_items[index.row()].m_checkState = static_cast<Qt::CheckState>(value.toInt());
92 success = true;
93 }
94 break;
95 case idRole(): {
96 m_items[index.row()].m_id = value;
97 success = true;
98 auto label = labelForId(value);
99 if (!label.isEmpty()) {
100 m_items[index.row()].m_label = std::move(label);
101 roles << Qt::DisplayRole;
102 }
103 break;
104 }
105 default:;
106 }
107 }
108 if (success) {
109 emit dataChanged(index, index, roles);
110 }
111 return success;
112}
113
114bool ChecklistModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
115{
116 for (QMap<int, QVariant>::ConstIterator it = roles.constBegin(); it != roles.constEnd(); ++it) {
117 setData(index, it.value(), it.key());
118 }
119 return true;
120}
121
125bool ChecklistModel::setChecked(int row, Qt::CheckState checked)
126{
127 if (row < 0 || row >= m_items.size()) {
128 return false;
129 }
130 m_items[row].m_checkState = checked ? Qt::Checked : Qt::Unchecked;
131 const auto index(this->index(row));
132 emit dataChanged(index, index, QVector<int>{ Qt::CheckStateRole });
133 return true;
134}
135
149QString ChecklistModel::labelForId(const QVariant &) const
150{
151 return QString();
152}
153
155{
156 return Qt::MoveAction;
157}
158
159bool ChecklistModel::insertRows(int row, int count, const QModelIndex &parent)
160{
161 if (count < 1 || row < 0 || row > rowCount() || parent.isValid()) {
162 return false;
163 }
164 beginInsertRows(QModelIndex(), row, row + count - 1);
165 for (int index = row, end = row + count; index < end; ++index) {
166 m_items.insert(index, ChecklistItem());
167 }
168 endInsertRows();
169 return true;
170}
171
172bool ChecklistModel::removeRows(int row, int count, const QModelIndex &parent)
173{
174 if (count < 1 || row < 0 || (row + count) > rowCount() || parent.isValid()) {
175 return false;
176 }
177 beginRemoveRows(QModelIndex(), row, row + count - 1);
178 for (int index = row, end = row + count; index < end; ++index) {
179 m_items.removeAt(index);
180 }
181 endRemoveRows();
182 return true;
183}
184
188void ChecklistModel::setItems(const QList<ChecklistItem> &items)
189{
190 beginResetModel();
191 m_items = items;
192 for (auto &item : m_items) {
193 if (item.m_label.isEmpty()) {
194 item.m_label = labelForId(item.id());
195 }
196 }
197 endResetModel();
198}
199
210void ChecklistModel::restore(QSettings &settings, const QString &name)
211{
212 beginResetModel();
213 auto currentItems = m_items;
214 QList<QVariant> restoredIds;
215 m_items.clear();
216 int rows = settings.beginReadArray(name);
217 m_items.reserve(rows);
218 for (int i = 0; i < rows; ++i) {
219 settings.setArrayIndex(i);
220 const auto id = settings.value(QStringLiteral("id"));
221 const auto isIdValid = [&] {
222 for (const auto &item : currentItems) {
223 if (item.id() == id) {
224 return true;
225 }
226 }
227 return false;
228 }();
229 if (!isIdValid) {
230 continue;
231 }
232 const auto selected = settings.value(QStringLiteral("selected"));
233 if (!id.isNull() && !selected.isNull()
234 && selected.canConvert(
235#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
236 QMetaType::Bool
237#else
238 QMetaType::fromType<bool>()
239#endif
240 )
241 && !restoredIds.contains(id)) {
242 m_items << ChecklistItem(id, labelForId(id), selected.toBool() ? Qt::Checked : Qt::Unchecked);
243 restoredIds << id;
244 }
245 }
246 settings.endArray();
247 for (const ChecklistItem &item : currentItems) {
248 if (!restoredIds.contains(item.id())) {
249 m_items << item;
250 }
251 }
252 endResetModel();
253}
254
262void ChecklistModel::save(QSettings &settings, const QString &name) const
263{
264 settings.beginWriteArray(name, static_cast<int>(m_items.size()));
265 int index = 0;
266 for (const ChecklistItem &item : m_items) {
267 settings.setArrayIndex(index);
268 settings.setValue(QStringLiteral("id"), item.id());
269 settings.setValue(QStringLiteral("selected"), item.isChecked());
270 ++index;
271 }
272 settings.endArray();
273}
274
279{
280 QVariantList checkedIds;
281 checkedIds.reserve(m_items.size());
282 for (const auto &item : m_items) {
283 if (item.isChecked()) {
284 checkedIds << item.id();
285 }
286 }
287 return checkedIds;
288}
289
293void ChecklistModel::applyVariantList(const QVariantList &checkedIds)
294{
295 for (auto &item : m_items) {
296 item.m_checkState = checkedIds.contains(item.id()) ? Qt::Checked : Qt::Unchecked;
297 }
298 emit dataChanged(index(0), index(static_cast<int>(m_items.size())), { Qt::CheckStateRole });
299}
300
301} // namespace QtUtilities
void setItems(const QList< ChecklistItem > &items)
Sets the items.
ChecklistModel(QObject *parent=nullptr)
Constructs a new checklist model.
bool removeRows(int row, int count, const QModelIndex &parent) override
bool setChecked(int row, bool checked)
Sets the checked state of the specified item.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::DisplayRole) override
void save(QSettings &settings, const QString &name) const
Saves the IDs and checkstates to the specified settings object.
virtual QString labelForId(const QVariant &id) const
Returns the label for the specified id.
void applyVariantList(const QVariantList &checkedIds)
Checks all items contained by checkedIds and unchecks other items.
bool insertRows(int row, int count, const QModelIndex &parent) override
Qt::DropActions supportedDropActions() const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void restore(QSettings &settings, const QString &name)
Restores the IDs and checkstates read from the specified settings object.
QMap< int, QVariant > itemData(const QModelIndex &index) const override
const QList< ChecklistItem > & items() const
Returns the items.
QVariantList toVariantList() const
Returns the checked IDs.
static constexpr int idRole()
Returns the role used to get or set the item ID.
bool setItemData(const QModelIndex &index, const QMap< int, QVariant > &roles) override
Qt::ItemFlags flags(const QModelIndex &index) const override