Line data Source code
1 : /*
2 : * Author: Christophe Dumez <dchris@gmail.com>
3 : * License: Public domain (No attribution required)
4 : * Website: http://cdumez.blogspot.com/
5 : * Version: 1.0
6 : */
7 :
8 : #include "ListModel.h"
9 :
10 : #include <QDebug>
11 :
12 16 : ListModel::ListModel(ListItem* prototype, QObject *parent) :
13 16 : QAbstractListModel(parent), m_prototype(prototype), _selected(nullptr)
14 : {
15 : // Populate our _roleNames reverse lookup map.
16 16 : QHash<int, QByteArray> roleNames = m_prototype->roleNames();
17 320 : for (int roleIndex : roleNames.keys()) {
18 304 : _roleNames[ roleNames[roleIndex] ] = roleIndex;
19 16 : }
20 16 : }
21 :
22 267 : int ListModel::rowCount(const QModelIndex &parent) const
23 : {
24 : Q_UNUSED(parent);
25 267 : return m_list.size();
26 : }
27 :
28 0 : QVariant ListModel::data(const QModelIndex &index, int role) const
29 : {
30 0 : if(index.row() < 0 || index.row() >= m_list.size()) {
31 0 : return QVariant();
32 : }
33 :
34 0 : int indexRow = index.row();
35 0 : int maxRows = rowCount();
36 0 : return m_list.at(indexRow)->data(role);
37 : }
38 :
39 0 : QVariant ListModel::dataByField(int row, const QString &field_name) const
40 : {
41 0 : if(row < 0 || row >= m_list.size()) {
42 0 : return QVariant();
43 : }
44 :
45 0 : int roleIndex = roleNameToRole(field_name);
46 0 : if (roleIndex < 0) {
47 0 : qCritical() << "ListModel::dataByField: Invalid field name" << field_name;
48 0 : return QVariant();
49 : }
50 :
51 0 : return m_list.at(row)->data(roleIndex);
52 : }
53 :
54 0 : bool ListModel::setData(const QModelIndex &index, const QVariant &value, int role)
55 : {
56 0 : if(index.row() < 0 || index.row() >= m_list.size()) {
57 0 : return false;
58 : }
59 :
60 0 : return m_list.at(index.row())->setData(value, role);
61 : }
62 :
63 0 : void ListModel::setData(int row, const QString &field_name, QVariant new_value)
64 : {
65 0 : if (row < 0 || row >= m_list.size()) {
66 0 : return;
67 : }
68 :
69 0 : QHash<int, QByteArray> roleNames = m_list.at(row)->roleNames();
70 0 : for (int roleIndex : roleNames.keys()) {
71 0 : if (field_name == roleNames[roleIndex]) {
72 0 : m_list.at(row)->setData(new_value, roleIndex);
73 :
74 0 : return;
75 : }
76 0 : }
77 :
78 0 : int roleIndex = roleNameToRole(field_name);
79 0 : if (roleIndex < 0) {
80 0 : qCritical() << "ListModel::setData: Invalid field name" << field_name;
81 0 : return;
82 : }
83 0 : m_list.at(row)->setData(new_value, roleIndex);
84 0 : }
85 :
86 0 : Qt::ItemFlags ListModel::flags(const QModelIndex &index) const
87 : {
88 0 : if(index.row() < 0 || index.row() >= m_list.size()) {
89 0 : return Qt::NoItemFlags;
90 : }
91 :
92 0 : return m_list.at(index.row())->flags();
93 : }
94 :
95 0 : void ListModel::move(int from, int to)
96 : {
97 : // From: https://qt.gitorious.org/qt-labs/qml-object-model/source/7c2207640a65dc59a420ebf71a45e38350840313:qobjectlistmodel.cpp
98 0 : if (!beginMoveRows(QModelIndex(), from, from, QModelIndex(), to > from ? to+1 : to)) {
99 0 : return;
100 : }
101 :
102 0 : m_list.move(from, to);
103 0 : endMoveRows();
104 : }
105 :
106 24 : ListModel::~ListModel() {
107 16 : delete m_prototype;
108 16 : clear();
109 24 : }
110 :
111 30 : void ListModel::appendRow(ListItem *item)
112 : {
113 30 : appendRows(QList<ListItem*>() << item);
114 30 : }
115 :
116 30 : void ListModel::appendRows(const QList<ListItem *> &items)
117 : {
118 30 : beginInsertRows(QModelIndex(), rowCount(), rowCount()+items.size()-1);
119 60 : for (ListItem *item : items) {
120 30 : connect(item, &ListItem::dataChanged, this, &ListModel::handleItemChange);
121 30 : m_list.append(item);
122 : }
123 30 : endInsertRows();
124 :
125 60 : for (ListItem* item : items) {
126 30 : emit added(item);
127 : }
128 :
129 30 : emit countChanged(count());
130 30 : }
131 :
132 0 : void ListModel::insertRow(int row, ListItem *item)
133 : {
134 0 : beginInsertRows(QModelIndex(), row, row);
135 0 : connect(item, &ListItem::dataChanged, this, &ListModel::handleItemChange);
136 0 : m_list.insert(row, item);
137 0 : endInsertRows();
138 :
139 0 : emit added(item);
140 :
141 0 : emit countChanged(count());
142 0 : }
143 :
144 73 : void ListModel::handleItemChange()
145 : {
146 73 : ListItem* item = static_cast<ListItem*>(sender());
147 73 : QModelIndex index = indexFromItem(item);
148 73 : if(index.isValid()) {
149 73 : emit dataChanged(index, index);
150 : }
151 73 : }
152 :
153 0 : ListItem * ListModel::find(const QString &id) const
154 : {
155 0 : for (ListItem* item : m_list) {
156 0 : if(item->id() == id) return item;
157 : }
158 0 : return 0;
159 : }
160 :
161 73 : QModelIndex ListModel::indexFromItem(const ListItem *item) const
162 : {
163 73 : if (!item) {
164 0 : qCritical() << "ListModel::indexFromItem: item is null";
165 0 : return QModelIndex();
166 : }
167 185 : for(int row=0; row<m_list.size(); ++row) {
168 185 : if(m_list.at(row) == item) return index(row);
169 : }
170 0 : return QModelIndex();
171 : }
172 :
173 16 : void ListModel::clear()
174 : {
175 46 : for (ListItem* item : m_list) {
176 30 : emit removed(item);
177 : }
178 :
179 16 : m_list.clear();
180 :
181 16 : emit countChanged(count());
182 16 : }
183 :
184 0 : void ListModel::setSelected(ListItem *selected)
185 : {
186 0 : _selected = selected;
187 0 : emit selectedChanged(_selected);
188 0 : emit selectedIndexChanged(selectedIndex());
189 0 : }
190 :
191 0 : int ListModel::selectedIndex()
192 : {
193 0 : return m_list.indexOf(_selected);
194 : }
195 :
196 0 : void ListModel::setSelectedIndex(int selectedIndex)
197 : {
198 0 : setSelected(m_list.at(selectedIndex));
199 0 : }
200 :
201 0 : int ListModel::roleNameToRole(const QString &field_name) const
202 : {
203 0 : return _roleNames.contains(field_name) ? _roleNames[field_name] : -1;
204 : }
205 :
206 0 : bool ListModel::removeRow(int row, const QModelIndex &parent)
207 : {
208 : Q_UNUSED(parent);
209 0 : ListItem* toRemove = nullptr;
210 0 : if(row < 0 || row >= m_list.size()) return false;
211 0 : beginRemoveRows(QModelIndex(), row, row);
212 0 : toRemove = m_list.takeAt(row);
213 0 : endRemoveRows();
214 :
215 0 : emit removed(toRemove);
216 0 : emit countChanged(count());
217 :
218 0 : return true;
219 : }
220 :
221 0 : bool ListModel::removeRows(int row, int count, const QModelIndex &parent)
222 : {
223 : Q_UNUSED(parent);
224 0 : QList<ListItem*> toRemove;
225 :
226 0 : if(row < 0 || (row+count) >= m_list.size()) return false;
227 0 : beginRemoveRows(QModelIndex(), row, row+count-1);
228 0 : for(int i=0; i<count; ++i) {
229 0 : toRemove.append(m_list.takeAt(row));
230 : }
231 0 : endRemoveRows();
232 :
233 0 : for (ListItem* item : toRemove) {
234 0 : emit removed(item);
235 : }
236 :
237 0 : emit countChanged(this->count());
238 :
239 0 : return true;
240 0 : }
241 :
242 0 : bool ListModel::removeItem(const ListItem *item)
243 : {
244 0 : QModelIndex index = indexFromItem(item);
245 0 : int row = index.row();
246 :
247 0 : qDebug() << "Remove item at: " << row;
248 :
249 0 : if (row == -1) {
250 0 : return false; // Not found.
251 : }
252 :
253 0 : return removeRow(row);
254 : }
255 :
256 0 : ListItem * ListModel::takeRow(int row)
257 : {
258 0 : beginRemoveRows(QModelIndex(), row, row);
259 0 : ListItem* item = m_list.takeAt(row);
260 0 : endRemoveRows();
261 :
262 0 : emit removed(item);
263 0 : emit countChanged(count());
264 :
265 0 : return item;
266 : }
|