Qt Utilities  6.4.1
Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models
checklistmodel.cpp
Go to the documentation of this file.
1 #include "./checklistmodel.h"
2 
3 #include <QSettings>
4 
10 namespace QtUtilities {
11 
28  : QAbstractListModel(parent)
29 {
30 }
31 
32 int ChecklistModel::rowCount(const QModelIndex &parent) const
33 {
34  if (!parent.isValid()) {
35  return m_items.size();
36  }
37  return 0;
38 }
39 
40 Qt::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 
48 QVariant 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 
64 QMap<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 
73 bool 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 
114 bool 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 
125 bool 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 
149 QString ChecklistModel::labelForId(const QVariant &) const
150 {
151  return QString();
152 }
153 
155 {
156  return Qt::MoveAction;
157 }
158 
159 bool 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 
172 bool 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 
188 void 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 
210 void 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 
262 void ChecklistModel::save(QSettings &settings, const QString &name) const
263 {
264  settings.beginWriteArray(name, 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 
278 QVariantList ChecklistModel::toVariantList() const
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 
293 void 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(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