Chris@413
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@413
|
2
|
Chris@413
|
3 /*
|
Chris@413
|
4 Sonic Visualiser
|
Chris@413
|
5 An audio file viewer and annotation editor.
|
Chris@413
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@413
|
7 This file copyright 2008 QMUL.
|
Chris@413
|
8
|
Chris@413
|
9 This program is free software; you can redistribute it and/or
|
Chris@413
|
10 modify it under the terms of the GNU General Public License as
|
Chris@413
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@413
|
12 License, or (at your option) any later version. See the file
|
Chris@413
|
13 COPYING included with this distribution for more information.
|
Chris@413
|
14 */
|
Chris@413
|
15
|
Chris@413
|
16 #include "ModelDataTableModel.h"
|
Chris@413
|
17
|
Chris@420
|
18 #include "TabularModel.h"
|
Chris@420
|
19 #include "Model.h"
|
Chris@413
|
20
|
Chris@422
|
21 #include <map>
|
Chris@417
|
22 #include <algorithm>
|
Chris@420
|
23 #include <iostream>
|
Chris@417
|
24
|
Chris@420
|
25 ModelDataTableModel::ModelDataTableModel(TabularModel *m) :
|
Chris@421
|
26 m_model(m),
|
Chris@421
|
27 m_sortColumn(0),
|
Chris@428
|
28 m_sortOrdering(Qt::AscendingOrder),
|
Chris@428
|
29 m_currentRow(0)
|
Chris@413
|
30 {
|
Chris@420
|
31 Model *baseModel = dynamic_cast<Model *>(m);
|
Chris@420
|
32
|
Chris@420
|
33 connect(baseModel, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
|
Chris@420
|
34 connect(baseModel, SIGNAL(modelChanged(size_t, size_t)),
|
Chris@413
|
35 this, SLOT(modelChanged(size_t, size_t)));
|
Chris@454
|
36 connect(baseModel, SIGNAL(aboutToBeDeleted()),
|
Chris@454
|
37 this, SLOT(modelAboutToBeDeleted()));
|
Chris@413
|
38 }
|
Chris@413
|
39
|
Chris@413
|
40 ModelDataTableModel::~ModelDataTableModel()
|
Chris@413
|
41 {
|
Chris@413
|
42 }
|
Chris@413
|
43
|
Chris@413
|
44 QVariant
|
Chris@413
|
45 ModelDataTableModel::data(const QModelIndex &index, int role) const
|
Chris@413
|
46 {
|
Chris@454
|
47 if (!m_model) return QVariant();
|
Chris@424
|
48 if (role != Qt::EditRole && role != Qt::DisplayRole) return QVariant();
|
Chris@413
|
49 if (!index.isValid()) return QVariant();
|
Chris@420
|
50 return m_model->getData(getUnsorted(index.row()), index.column(), role);
|
Chris@413
|
51 }
|
Chris@413
|
52
|
Chris@413
|
53 bool
|
Chris@413
|
54 ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
Chris@413
|
55 {
|
Chris@454
|
56 if (!m_model) return false;
|
Chris@420
|
57 if (!index.isValid()) return false;
|
Chris@421
|
58 Command *command = m_model->getSetDataCommand(getUnsorted(index.row()),
|
Chris@421
|
59 index.column(),
|
Chris@421
|
60 value, role);
|
Chris@420
|
61 if (command) {
|
Chris@427
|
62 emit addCommand(command);
|
Chris@420
|
63 return true;
|
Chris@420
|
64 } else {
|
Chris@416
|
65 return false;
|
Chris@416
|
66 }
|
Chris@413
|
67 }
|
Chris@413
|
68
|
Chris@427
|
69 bool
|
Chris@427
|
70 ModelDataTableModel::insertRow(int row, const QModelIndex &parent)
|
Chris@427
|
71 {
|
Chris@454
|
72 if (!m_model) return false;
|
Chris@427
|
73 if (parent.isValid()) return false;
|
Chris@427
|
74
|
Chris@427
|
75 emit beginInsertRows(parent, row, row);
|
Chris@427
|
76
|
Chris@427
|
77 Command *command = m_model->getInsertRowCommand(getUnsorted(row));
|
Chris@427
|
78
|
Chris@427
|
79 if (command) {
|
Chris@427
|
80 emit addCommand(command);
|
Chris@427
|
81 }
|
Chris@427
|
82
|
Chris@427
|
83 emit endInsertRows();
|
Chris@427
|
84
|
Chris@427
|
85 return (command ? true : false);
|
Chris@427
|
86 }
|
Chris@427
|
87
|
Chris@427
|
88 bool
|
Chris@427
|
89 ModelDataTableModel::removeRow(int row, const QModelIndex &parent)
|
Chris@427
|
90 {
|
Chris@454
|
91 if (!m_model) return false;
|
Chris@427
|
92 if (parent.isValid()) return false;
|
Chris@427
|
93
|
Chris@427
|
94 emit beginRemoveRows(parent, row, row);
|
Chris@427
|
95
|
Chris@427
|
96 Command *command = m_model->getRemoveRowCommand(getUnsorted(row));
|
Chris@427
|
97
|
Chris@427
|
98 if (command) {
|
Chris@427
|
99 emit addCommand(command);
|
Chris@427
|
100 }
|
Chris@427
|
101
|
Chris@427
|
102 emit endRemoveRows();
|
Chris@427
|
103
|
Chris@427
|
104 return (command ? true : false);
|
Chris@427
|
105 }
|
Chris@427
|
106
|
Chris@413
|
107 Qt::ItemFlags
|
Chris@413
|
108 ModelDataTableModel::flags(const QModelIndex &index) const
|
Chris@413
|
109 {
|
Chris@416
|
110 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable |
|
Chris@416
|
111 Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsSelectable;
|
Chris@416
|
112 return flags;
|
Chris@413
|
113 }
|
Chris@413
|
114
|
Chris@413
|
115 QVariant
|
Chris@413
|
116 ModelDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
Chris@413
|
117 {
|
Chris@454
|
118 if (!m_model) return QVariant();
|
Chris@454
|
119
|
Chris@425
|
120 if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
|
Chris@425
|
121 return section + 1;
|
Chris@425
|
122 }
|
Chris@413
|
123 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
Chris@420
|
124 return m_model->getHeading(section);
|
Chris@425
|
125 }
|
Chris@413
|
126 return QVariant();
|
Chris@413
|
127 }
|
Chris@413
|
128
|
Chris@413
|
129 QModelIndex
|
Chris@413
|
130 ModelDataTableModel::index(int row, int column, const QModelIndex &parent) const
|
Chris@413
|
131 {
|
Chris@413
|
132 return createIndex(row, column, 0);
|
Chris@413
|
133 }
|
Chris@413
|
134
|
Chris@413
|
135 QModelIndex
|
Chris@413
|
136 ModelDataTableModel::parent(const QModelIndex &index) const
|
Chris@413
|
137 {
|
Chris@413
|
138 return QModelIndex();
|
Chris@413
|
139 }
|
Chris@413
|
140
|
Chris@413
|
141 int
|
Chris@413
|
142 ModelDataTableModel::rowCount(const QModelIndex &parent) const
|
Chris@413
|
143 {
|
Chris@454
|
144 if (!m_model) return 0;
|
Chris@413
|
145 if (parent.isValid()) return 0;
|
Chris@420
|
146 return m_model->getRowCount();
|
Chris@413
|
147 }
|
Chris@413
|
148
|
Chris@413
|
149 int
|
Chris@413
|
150 ModelDataTableModel::columnCount(const QModelIndex &parent) const
|
Chris@413
|
151 {
|
Chris@454
|
152 if (!m_model) return 0;
|
Chris@413
|
153 if (parent.isValid()) return 0;
|
Chris@420
|
154 return m_model->getColumnCount();
|
Chris@416
|
155 }
|
Chris@416
|
156
|
Chris@416
|
157 QModelIndex
|
Chris@416
|
158 ModelDataTableModel::getModelIndexForFrame(size_t frame) const
|
Chris@416
|
159 {
|
Chris@454
|
160 if (!m_model) return createIndex(0, 0);
|
Chris@420
|
161 int row = m_model->getRowForFrame(frame);
|
Chris@420
|
162 return createIndex(getSorted(row), 0, 0);
|
Chris@413
|
163 }
|
Chris@413
|
164
|
Chris@419
|
165 size_t
|
Chris@419
|
166 ModelDataTableModel::getFrameForModelIndex(const QModelIndex &index) const
|
Chris@419
|
167 {
|
Chris@454
|
168 if (!m_model) return 0;
|
Chris@420
|
169 return m_model->getFrameForRow(getUnsorted(index.row()));
|
Chris@420
|
170 }
|
Chris@420
|
171
|
Chris@420
|
172 void
|
Chris@420
|
173 ModelDataTableModel::sort(int column, Qt::SortOrder sortOrder)
|
Chris@420
|
174 {
|
Chris@437
|
175 // std::cerr << "ModelDataTableModel::sort(" << column << ", " << sortOrder
|
Chris@437
|
176 // << ")" << std::endl;
|
Chris@428
|
177 int prevCurrent = getCurrentRow();
|
Chris@422
|
178 if (m_sortColumn != column) {
|
Chris@428
|
179 clearSort();
|
Chris@422
|
180 }
|
Chris@420
|
181 m_sortColumn = column;
|
Chris@420
|
182 m_sortOrdering = sortOrder;
|
Chris@428
|
183 int current = getCurrentRow();
|
Chris@428
|
184 if (current != prevCurrent) {
|
Chris@437
|
185 // std::cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << std::endl;
|
Chris@428
|
186 emit currentChanged(createIndex(current, 0, 0));
|
Chris@428
|
187 }
|
Chris@420
|
188 emit layoutChanged();
|
Chris@419
|
189 }
|
Chris@419
|
190
|
Chris@413
|
191 void
|
Chris@413
|
192 ModelDataTableModel::modelChanged()
|
Chris@413
|
193 {
|
Chris@428
|
194 clearSort();
|
Chris@413
|
195 emit layoutChanged();
|
Chris@413
|
196 }
|
Chris@413
|
197
|
Chris@413
|
198 void
|
Chris@416
|
199 ModelDataTableModel::modelChanged(size_t f0, size_t f1)
|
Chris@416
|
200 {
|
Chris@420
|
201 //!!! inefficient
|
Chris@428
|
202 clearSort();
|
Chris@416
|
203 emit layoutChanged();
|
Chris@416
|
204 }
|
Chris@413
|
205
|
Chris@454
|
206 void
|
Chris@454
|
207 ModelDataTableModel::modelAboutToBeDeleted()
|
Chris@454
|
208 {
|
Chris@454
|
209 m_model = 0;
|
Chris@454
|
210 emit modelRemoved();
|
Chris@454
|
211 }
|
Chris@454
|
212
|
Chris@420
|
213 int
|
Chris@426
|
214 ModelDataTableModel::getSorted(int row) const
|
Chris@413
|
215 {
|
Chris@454
|
216 if (!m_model) return row;
|
Chris@454
|
217
|
Chris@420
|
218 if (m_model->isColumnTimeValue(m_sortColumn)) {
|
Chris@420
|
219 if (m_sortOrdering == Qt::AscendingOrder) {
|
Chris@420
|
220 return row;
|
Chris@420
|
221 } else {
|
Chris@420
|
222 return rowCount() - row - 1;
|
Chris@420
|
223 }
|
Chris@420
|
224 }
|
Chris@413
|
225
|
Chris@420
|
226 if (m_sort.empty()) {
|
Chris@420
|
227 resort();
|
Chris@413
|
228 }
|
Chris@422
|
229 int result = 0;
|
Chris@422
|
230 if (row >= 0 && row < m_sort.size()) {
|
Chris@422
|
231 result = m_sort[row];
|
Chris@422
|
232 }
|
Chris@422
|
233 if (m_sortOrdering == Qt::DescendingOrder) {
|
Chris@422
|
234 result = rowCount() - result - 1;
|
Chris@422
|
235 }
|
Chris@422
|
236
|
Chris@422
|
237 return result;
|
Chris@413
|
238 }
|
Chris@413
|
239
|
Chris@420
|
240 int
|
Chris@426
|
241 ModelDataTableModel::getUnsorted(int row) const
|
Chris@413
|
242 {
|
Chris@454
|
243 if (!m_model) return row;
|
Chris@454
|
244
|
Chris@420
|
245 if (m_model->isColumnTimeValue(m_sortColumn)) {
|
Chris@420
|
246 if (m_sortOrdering == Qt::AscendingOrder) {
|
Chris@420
|
247 return row;
|
Chris@420
|
248 } else {
|
Chris@420
|
249 return rowCount() - row - 1;
|
Chris@420
|
250 }
|
Chris@413
|
251 }
|
Chris@422
|
252
|
Chris@420
|
253 if (m_sort.empty()) {
|
Chris@420
|
254 resort();
|
Chris@420
|
255 }
|
Chris@422
|
256
|
Chris@422
|
257 int result = 0;
|
Chris@422
|
258 if (row >= 0 && row < m_sort.size()) {
|
Chris@422
|
259 if (m_sortOrdering == Qt::AscendingOrder) {
|
Chris@422
|
260 result = m_rsort[row];
|
Chris@422
|
261 } else {
|
Chris@422
|
262 result = m_rsort[rowCount() - row - 1];
|
Chris@422
|
263 }
|
Chris@422
|
264 }
|
Chris@422
|
265
|
Chris@422
|
266 return result;
|
Chris@413
|
267 }
|
Chris@413
|
268
|
Chris@420
|
269 void
|
Chris@426
|
270 ModelDataTableModel::resort() const
|
Chris@413
|
271 {
|
Chris@454
|
272 if (!m_model) return;
|
Chris@454
|
273
|
Chris@422
|
274 bool numeric = (m_model->getSortType(m_sortColumn) ==
|
Chris@422
|
275 TabularModel::SortNumeric);
|
Chris@422
|
276
|
Chris@422
|
277 m_sort.clear();
|
Chris@422
|
278 m_rsort.clear();
|
Chris@422
|
279
|
Chris@422
|
280 if (numeric) resortNumeric();
|
Chris@422
|
281 else resortAlphabetical();
|
Chris@422
|
282
|
Chris@422
|
283 std::map<int, int> tmp;
|
Chris@422
|
284
|
Chris@422
|
285 // rsort maps from sorted row number to original row number
|
Chris@422
|
286
|
Chris@422
|
287 for (int i = 0; i < m_rsort.size(); ++i) {
|
Chris@422
|
288 tmp[m_rsort[i]] = i;
|
Chris@422
|
289 }
|
Chris@422
|
290
|
Chris@422
|
291 // tmp now maps from original row number to sorted row number
|
Chris@422
|
292
|
Chris@422
|
293 for (std::map<int, int>::const_iterator i = tmp.begin(); i != tmp.end(); ++i) {
|
Chris@422
|
294 m_sort.push_back(i->second);
|
Chris@422
|
295 }
|
Chris@422
|
296
|
Chris@422
|
297 // and sort now maps from original row number to sorted row number
|
Chris@413
|
298 }
|
Chris@413
|
299
|
Chris@422
|
300 void
|
Chris@426
|
301 ModelDataTableModel::resortNumeric() const
|
Chris@422
|
302 {
|
Chris@454
|
303 if (!m_model) return;
|
Chris@454
|
304
|
Chris@422
|
305 typedef std::multimap<double, int> MapType;
|
Chris@422
|
306
|
Chris@422
|
307 MapType rowMap;
|
Chris@422
|
308 int rows = m_model->getRowCount();
|
Chris@422
|
309
|
Chris@422
|
310 for (int i = 0; i < rows; ++i) {
|
Chris@424
|
311 QVariant value = m_model->getData(i, m_sortColumn, TabularModel::SortRole);
|
Chris@422
|
312 rowMap.insert(MapType::value_type(value.toDouble(), i));
|
Chris@422
|
313 }
|
Chris@422
|
314
|
Chris@422
|
315 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
|
Chris@422
|
316 m_rsort.push_back(i->second);
|
Chris@422
|
317 }
|
Chris@422
|
318
|
Chris@422
|
319 // rsort now maps from sorted row number to original row number
|
Chris@422
|
320 }
|
Chris@422
|
321
|
Chris@422
|
322 void
|
Chris@426
|
323 ModelDataTableModel::resortAlphabetical() const
|
Chris@422
|
324 {
|
Chris@454
|
325 if (!m_model) return;
|
Chris@454
|
326
|
Chris@422
|
327 typedef std::multimap<QString, int> MapType;
|
Chris@422
|
328
|
Chris@422
|
329 MapType rowMap;
|
Chris@422
|
330 int rows = m_model->getRowCount();
|
Chris@422
|
331
|
Chris@422
|
332 for (int i = 0; i < rows; ++i) {
|
Chris@422
|
333 QVariant value =
|
Chris@422
|
334 m_model->getData(i, m_sortColumn, TabularModel::SortRole);
|
Chris@422
|
335 rowMap.insert(MapType::value_type(value.toString(), i));
|
Chris@422
|
336 }
|
Chris@422
|
337
|
Chris@422
|
338 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
|
Chris@422
|
339 m_rsort.push_back(i->second);
|
Chris@422
|
340 }
|
Chris@422
|
341
|
Chris@422
|
342 // rsort now maps from sorted row number to original row number
|
Chris@422
|
343 }
|
Chris@422
|
344
|
Chris@428
|
345 int
|
Chris@428
|
346 ModelDataTableModel::getCurrentRow()
|
Chris@428
|
347 {
|
Chris@428
|
348 return getSorted(m_currentRow);
|
Chris@428
|
349 }
|
Chris@428
|
350
|
Chris@428
|
351 void
|
Chris@428
|
352 ModelDataTableModel::setCurrentRow(int row)
|
Chris@428
|
353 {
|
Chris@428
|
354 m_currentRow = getUnsorted(row);
|
Chris@428
|
355 }
|
Chris@428
|
356
|
Chris@428
|
357 void
|
Chris@428
|
358 ModelDataTableModel::clearSort()
|
Chris@428
|
359 {
|
Chris@428
|
360 // int prevCurrent = getCurrentRow();
|
Chris@428
|
361 m_sort.clear();
|
Chris@428
|
362 // int current = getCurrentRow(); //!!! no -- not until the sort criteria have changed
|
Chris@428
|
363 // if (current != prevCurrent) {
|
Chris@428
|
364 // std::cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << std::endl;
|
Chris@428
|
365 // emit currentRowChanged(createIndex(current, 0, 0));
|
Chris@428
|
366 // }
|
Chris@428
|
367 }
|
Chris@428
|
368
|
Chris@428
|
369
|