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 "../utilities/FangLogging.h"
11 :
12 70 : ListModel::ListModel(ListItem* prototype, QObject *parent) :
13 70 : QAbstractListModel(parent), m_prototype(prototype), _selected(nullptr)
14 : {
15 : // Populate our _roleNames reverse lookup map.
16 70 : QHash<int, QByteArray> roleNames = m_prototype->roleNames();
17 1470 : for (int roleIndex : roleNames.keys()) {
18 1400 : _roleNames[ roleNames[roleIndex] ] = roleIndex;
19 70 : }
20 70 : }
21 :
22 630 : int ListModel::rowCount(const QModelIndex &parent) const
23 : {
24 : Q_UNUSED(parent);
25 630 : 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 : qCCritical(logModel) << "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 : qCCritical(logModel) << "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, int count)
96 : {
97 : // From: https://qt.gitorious.org/qt-labs/qml-object-model/source/7c2207640a65dc59a420ebf71a45e38350840313:qobjectlistmodel.cpp
98 : // Move count items one at a time to match QML ListModel behavior.
99 0 : for (int i = 0; i < count; ++i) {
100 0 : int src = (to > from) ? from : from + i;
101 0 : int dst = (to > from) ? to + i : to + i;
102 0 : if (src < 0 || src >= m_list.size() || dst < 0 || dst >= m_list.size() || src == dst) {
103 0 : continue;
104 : }
105 :
106 0 : int dest = (dst > src) ? dst + 1 : dst;
107 0 : if (!beginMoveRows(QModelIndex(), src, src, QModelIndex(), dest)) {
108 0 : continue;
109 : }
110 :
111 0 : m_list.move(src, dst);
112 0 : endMoveRows();
113 : }
114 0 : }
115 :
116 0 : QVariantMap ListModel::get(int row) const
117 : {
118 0 : QVariantMap map;
119 0 : if (row < 0 || row >= m_list.size()) {
120 0 : return map;
121 : }
122 :
123 0 : const ListItem* item = m_list.at(row);
124 0 : QHash<int, QByteArray> roles = m_prototype->roleNames();
125 0 : for (auto it = roles.constBegin(); it != roles.constEnd(); ++it) {
126 0 : map[QString::fromUtf8(it.value())] = item->data(it.key());
127 : }
128 0 : return map;
129 0 : }
130 :
131 0 : void ListModel::setProperty(int row, const QString &name, QVariant value)
132 : {
133 0 : setData(row, name, value);
134 0 : }
135 :
136 0 : void ListModel::remove(int row, int count)
137 : {
138 0 : removeRows(row, count);
139 0 : }
140 :
141 132 : ListModel::~ListModel() {
142 70 : delete m_prototype;
143 70 : clear();
144 132 : }
145 :
146 54 : void ListModel::appendRow(ListItem *item)
147 : {
148 54 : appendRows(QList<ListItem*>() << item);
149 54 : }
150 :
151 54 : void ListModel::appendRows(const QList<ListItem *> &items)
152 : {
153 54 : beginInsertRows(QModelIndex(), rowCount(), rowCount()+items.size()-1);
154 108 : for (ListItem *item : items) {
155 54 : connect(item, &ListItem::dataChanged, this, &ListModel::handleItemChange);
156 54 : m_list.append(item);
157 : }
158 54 : endInsertRows();
159 :
160 108 : for (ListItem* item : items) {
161 54 : emit added(item);
162 : }
163 :
164 54 : emit countChanged(count());
165 54 : }
166 :
167 0 : void ListModel::insertRow(int row, ListItem *item)
168 : {
169 0 : beginInsertRows(QModelIndex(), row, row);
170 0 : connect(item, &ListItem::dataChanged, this, &ListModel::handleItemChange);
171 0 : m_list.insert(row, item);
172 0 : endInsertRows();
173 :
174 0 : emit added(item);
175 :
176 0 : emit countChanged(count());
177 0 : }
178 :
179 92 : void ListModel::handleItemChange()
180 : {
181 92 : ListItem* item = static_cast<ListItem*>(sender());
182 92 : QModelIndex index = indexFromItem(item);
183 92 : if(index.isValid()) {
184 88 : emit dataChanged(index, index);
185 : }
186 92 : }
187 :
188 0 : ListItem * ListModel::find(const QString &id) const
189 : {
190 0 : for (ListItem* item : m_list) {
191 0 : if(item->id() == id) return item;
192 : }
193 0 : return 0;
194 : }
195 :
196 96 : QModelIndex ListModel::indexFromItem(const ListItem *item) const
197 : {
198 96 : if (!item) {
199 0 : qCCritical(logModel) << "ListModel::indexFromItem: item is null";
200 0 : return QModelIndex();
201 : }
202 219 : for(int row=0; row<m_list.size(); ++row) {
203 215 : if(m_list.at(row) == item) return index(row);
204 : }
205 4 : return QModelIndex();
206 : }
207 :
208 70 : void ListModel::clear()
209 : {
210 120 : for (ListItem* item : m_list) {
211 50 : emit removed(item);
212 : }
213 :
214 70 : m_list.clear();
215 :
216 70 : emit countChanged(count());
217 70 : }
218 :
219 0 : void ListModel::setSelected(ListItem *selected)
220 : {
221 0 : _selected = selected;
222 0 : emit selectedChanged(_selected);
223 0 : emit selectedIndexChanged(selectedIndex());
224 0 : }
225 :
226 0 : int ListModel::selectedIndex()
227 : {
228 0 : return m_list.indexOf(_selected);
229 : }
230 :
231 0 : void ListModel::setSelectedIndex(int selectedIndex)
232 : {
233 0 : setSelected(m_list.at(selectedIndex));
234 0 : }
235 :
236 0 : int ListModel::roleNameToRole(const QString &field_name) const
237 : {
238 0 : return _roleNames.contains(field_name) ? _roleNames[field_name] : -1;
239 : }
240 :
241 4 : bool ListModel::removeRow(int row, const QModelIndex &parent)
242 : {
243 : Q_UNUSED(parent);
244 4 : ListItem* toRemove = nullptr;
245 4 : if(row < 0 || row >= m_list.size()) return false;
246 4 : beginRemoveRows(QModelIndex(), row, row);
247 4 : toRemove = m_list.takeAt(row);
248 4 : endRemoveRows();
249 :
250 4 : emit removed(toRemove);
251 4 : emit countChanged(count());
252 :
253 4 : return true;
254 : }
255 :
256 0 : bool ListModel::removeRows(int row, int count, const QModelIndex &parent)
257 : {
258 : Q_UNUSED(parent);
259 0 : QList<ListItem*> toRemove;
260 :
261 0 : if(row < 0 || (row+count) >= m_list.size()) return false;
262 0 : beginRemoveRows(QModelIndex(), row, row+count-1);
263 0 : for(int i=0; i<count; ++i) {
264 0 : toRemove.append(m_list.takeAt(row));
265 : }
266 0 : endRemoveRows();
267 :
268 0 : for (ListItem* item : toRemove) {
269 0 : emit removed(item);
270 : }
271 :
272 0 : emit countChanged(this->count());
273 :
274 0 : return true;
275 0 : }
276 :
277 4 : bool ListModel::removeItem(const ListItem *item)
278 : {
279 4 : QModelIndex index = indexFromItem(item);
280 4 : int row = index.row();
281 :
282 8 : qCDebug(logModel) << "Remove item at: " << row;
283 :
284 4 : if (row == -1) {
285 0 : return false; // Not found.
286 : }
287 :
288 4 : return removeRow(row);
289 : }
290 :
291 0 : ListItem * ListModel::takeRow(int row)
292 : {
293 0 : beginRemoveRows(QModelIndex(), row, row);
294 0 : ListItem* item = m_list.takeAt(row);
295 0 : endRemoveRows();
296 :
297 0 : emit removed(item);
298 0 : emit countChanged(count());
299 :
300 0 : return item;
301 : }
|