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@421
|
28 m_sortOrdering(Qt::AscendingOrder)
|
Chris@413
|
29 {
|
Chris@420
|
30 Model *baseModel = dynamic_cast<Model *>(m);
|
Chris@420
|
31
|
Chris@420
|
32 connect(baseModel, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
|
Chris@420
|
33 connect(baseModel, SIGNAL(modelChanged(size_t, size_t)),
|
Chris@413
|
34 this, SLOT(modelChanged(size_t, size_t)));
|
Chris@413
|
35 }
|
Chris@413
|
36
|
Chris@413
|
37 ModelDataTableModel::~ModelDataTableModel()
|
Chris@413
|
38 {
|
Chris@413
|
39 }
|
Chris@413
|
40
|
Chris@413
|
41 QVariant
|
Chris@413
|
42 ModelDataTableModel::data(const QModelIndex &index, int role) const
|
Chris@413
|
43 {
|
Chris@424
|
44 if (role != Qt::EditRole && role != Qt::DisplayRole) return QVariant();
|
Chris@413
|
45 if (!index.isValid()) return QVariant();
|
Chris@420
|
46 return m_model->getData(getUnsorted(index.row()), index.column(), role);
|
Chris@413
|
47 }
|
Chris@413
|
48
|
Chris@413
|
49 bool
|
Chris@413
|
50 ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
Chris@413
|
51 {
|
Chris@420
|
52 if (!index.isValid()) return false;
|
Chris@421
|
53 std::cerr << "ModelDataTableModel::setData(" << index.row() << ", " << index.column() << ", " << value.toString().toStdString() << ", " << role << ")" << std::endl;
|
Chris@421
|
54 Command *command = m_model->getSetDataCommand(getUnsorted(index.row()),
|
Chris@421
|
55 index.column(),
|
Chris@421
|
56 value, role);
|
Chris@420
|
57 if (command) {
|
Chris@421
|
58 std::cerr << "emitting executeCommand" << std::endl;
|
Chris@420
|
59 emit executeCommand(command);
|
Chris@420
|
60 return true;
|
Chris@420
|
61 } else {
|
Chris@416
|
62 return false;
|
Chris@416
|
63 }
|
Chris@413
|
64 }
|
Chris@413
|
65
|
Chris@413
|
66 Qt::ItemFlags
|
Chris@413
|
67 ModelDataTableModel::flags(const QModelIndex &index) const
|
Chris@413
|
68 {
|
Chris@416
|
69 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable |
|
Chris@416
|
70 Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsSelectable;
|
Chris@416
|
71 return flags;
|
Chris@413
|
72 }
|
Chris@413
|
73
|
Chris@413
|
74 QVariant
|
Chris@413
|
75 ModelDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
Chris@413
|
76 {
|
Chris@425
|
77 if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
|
Chris@425
|
78 return section + 1;
|
Chris@425
|
79 }
|
Chris@413
|
80 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
Chris@420
|
81 return m_model->getHeading(section);
|
Chris@425
|
82 }
|
Chris@413
|
83 return QVariant();
|
Chris@413
|
84 }
|
Chris@413
|
85
|
Chris@413
|
86 QModelIndex
|
Chris@413
|
87 ModelDataTableModel::index(int row, int column, const QModelIndex &parent) const
|
Chris@413
|
88 {
|
Chris@413
|
89 return createIndex(row, column, 0);
|
Chris@413
|
90 }
|
Chris@413
|
91
|
Chris@413
|
92 QModelIndex
|
Chris@413
|
93 ModelDataTableModel::parent(const QModelIndex &index) const
|
Chris@413
|
94 {
|
Chris@413
|
95 return QModelIndex();
|
Chris@413
|
96 }
|
Chris@413
|
97
|
Chris@413
|
98 int
|
Chris@413
|
99 ModelDataTableModel::rowCount(const QModelIndex &parent) const
|
Chris@413
|
100 {
|
Chris@413
|
101 if (parent.isValid()) return 0;
|
Chris@420
|
102 return m_model->getRowCount();
|
Chris@413
|
103 }
|
Chris@413
|
104
|
Chris@413
|
105 int
|
Chris@413
|
106 ModelDataTableModel::columnCount(const QModelIndex &parent) const
|
Chris@413
|
107 {
|
Chris@413
|
108 if (parent.isValid()) return 0;
|
Chris@420
|
109 return m_model->getColumnCount();
|
Chris@416
|
110 }
|
Chris@416
|
111
|
Chris@416
|
112 QModelIndex
|
Chris@416
|
113 ModelDataTableModel::getModelIndexForFrame(size_t frame) const
|
Chris@416
|
114 {
|
Chris@420
|
115 int row = m_model->getRowForFrame(frame);
|
Chris@420
|
116 return createIndex(getSorted(row), 0, 0);
|
Chris@413
|
117 }
|
Chris@413
|
118
|
Chris@419
|
119 size_t
|
Chris@419
|
120 ModelDataTableModel::getFrameForModelIndex(const QModelIndex &index) const
|
Chris@419
|
121 {
|
Chris@420
|
122 return m_model->getFrameForRow(getUnsorted(index.row()));
|
Chris@420
|
123 }
|
Chris@420
|
124
|
Chris@420
|
125 void
|
Chris@420
|
126 ModelDataTableModel::sort(int column, Qt::SortOrder sortOrder)
|
Chris@420
|
127 {
|
Chris@420
|
128 std::cerr << "ModelDataTableModel::sort(" << column << ", " << sortOrder
|
Chris@420
|
129 << ")" << std::endl;
|
Chris@422
|
130 if (m_sortColumn != column) {
|
Chris@422
|
131 m_sort.clear();
|
Chris@422
|
132 }
|
Chris@420
|
133 m_sortColumn = column;
|
Chris@420
|
134 m_sortOrdering = sortOrder;
|
Chris@420
|
135 emit layoutChanged();
|
Chris@419
|
136 }
|
Chris@419
|
137
|
Chris@413
|
138 void
|
Chris@413
|
139 ModelDataTableModel::modelChanged()
|
Chris@413
|
140 {
|
Chris@420
|
141 m_sort.clear();
|
Chris@413
|
142 emit layoutChanged();
|
Chris@413
|
143 }
|
Chris@413
|
144
|
Chris@413
|
145 void
|
Chris@416
|
146 ModelDataTableModel::modelChanged(size_t f0, size_t f1)
|
Chris@416
|
147 {
|
Chris@420
|
148 //!!! inefficient
|
Chris@420
|
149 m_sort.clear();
|
Chris@416
|
150 emit layoutChanged();
|
Chris@416
|
151 }
|
Chris@413
|
152
|
Chris@420
|
153 int
|
Chris@426
|
154 ModelDataTableModel::getSorted(int row) const
|
Chris@413
|
155 {
|
Chris@420
|
156 if (m_model->isColumnTimeValue(m_sortColumn)) {
|
Chris@420
|
157 if (m_sortOrdering == Qt::AscendingOrder) {
|
Chris@420
|
158 return row;
|
Chris@420
|
159 } else {
|
Chris@420
|
160 return rowCount() - row - 1;
|
Chris@420
|
161 }
|
Chris@420
|
162 }
|
Chris@413
|
163
|
Chris@420
|
164 if (m_sort.empty()) {
|
Chris@420
|
165 resort();
|
Chris@413
|
166 }
|
Chris@422
|
167 int result = 0;
|
Chris@422
|
168 if (row >= 0 && row < m_sort.size()) {
|
Chris@422
|
169 result = m_sort[row];
|
Chris@422
|
170 }
|
Chris@422
|
171 if (m_sortOrdering == Qt::DescendingOrder) {
|
Chris@422
|
172 result = rowCount() - result - 1;
|
Chris@422
|
173 }
|
Chris@422
|
174
|
Chris@422
|
175 return result;
|
Chris@413
|
176 }
|
Chris@413
|
177
|
Chris@420
|
178 int
|
Chris@426
|
179 ModelDataTableModel::getUnsorted(int row) const
|
Chris@413
|
180 {
|
Chris@420
|
181 if (m_model->isColumnTimeValue(m_sortColumn)) {
|
Chris@420
|
182 if (m_sortOrdering == Qt::AscendingOrder) {
|
Chris@420
|
183 return row;
|
Chris@420
|
184 } else {
|
Chris@420
|
185 return rowCount() - row - 1;
|
Chris@420
|
186 }
|
Chris@413
|
187 }
|
Chris@422
|
188
|
Chris@420
|
189 if (m_sort.empty()) {
|
Chris@420
|
190 resort();
|
Chris@420
|
191 }
|
Chris@422
|
192
|
Chris@422
|
193 int result = 0;
|
Chris@422
|
194 if (row >= 0 && row < m_sort.size()) {
|
Chris@422
|
195 if (m_sortOrdering == Qt::AscendingOrder) {
|
Chris@422
|
196 result = m_rsort[row];
|
Chris@422
|
197 } else {
|
Chris@422
|
198 result = m_rsort[rowCount() - row - 1];
|
Chris@422
|
199 }
|
Chris@422
|
200 }
|
Chris@422
|
201
|
Chris@422
|
202 return result;
|
Chris@413
|
203 }
|
Chris@413
|
204
|
Chris@420
|
205 void
|
Chris@426
|
206 ModelDataTableModel::resort() const
|
Chris@413
|
207 {
|
Chris@422
|
208 bool numeric = (m_model->getSortType(m_sortColumn) ==
|
Chris@422
|
209 TabularModel::SortNumeric);
|
Chris@422
|
210
|
Chris@422
|
211 m_sort.clear();
|
Chris@422
|
212 m_rsort.clear();
|
Chris@422
|
213
|
Chris@422
|
214 if (numeric) resortNumeric();
|
Chris@422
|
215 else resortAlphabetical();
|
Chris@422
|
216
|
Chris@422
|
217 std::map<int, int> tmp;
|
Chris@422
|
218
|
Chris@422
|
219 // rsort maps from sorted row number to original row number
|
Chris@422
|
220
|
Chris@422
|
221 for (int i = 0; i < m_rsort.size(); ++i) {
|
Chris@422
|
222 tmp[m_rsort[i]] = i;
|
Chris@422
|
223 }
|
Chris@422
|
224
|
Chris@422
|
225 // tmp now maps from original row number to sorted row number
|
Chris@422
|
226
|
Chris@422
|
227 for (std::map<int, int>::const_iterator i = tmp.begin(); i != tmp.end(); ++i) {
|
Chris@422
|
228 m_sort.push_back(i->second);
|
Chris@422
|
229 }
|
Chris@422
|
230
|
Chris@422
|
231 // and sort now maps from original row number to sorted row number
|
Chris@413
|
232 }
|
Chris@413
|
233
|
Chris@422
|
234 void
|
Chris@426
|
235 ModelDataTableModel::resortNumeric() const
|
Chris@422
|
236 {
|
Chris@422
|
237 typedef std::multimap<double, int> MapType;
|
Chris@422
|
238
|
Chris@422
|
239 MapType rowMap;
|
Chris@422
|
240 int rows = m_model->getRowCount();
|
Chris@422
|
241
|
Chris@422
|
242 for (int i = 0; i < rows; ++i) {
|
Chris@424
|
243 QVariant value = m_model->getData(i, m_sortColumn, TabularModel::SortRole);
|
Chris@422
|
244 rowMap.insert(MapType::value_type(value.toDouble(), i));
|
Chris@422
|
245 }
|
Chris@422
|
246
|
Chris@422
|
247 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
|
Chris@422
|
248 m_rsort.push_back(i->second);
|
Chris@422
|
249 }
|
Chris@422
|
250
|
Chris@422
|
251 // rsort now maps from sorted row number to original row number
|
Chris@422
|
252 }
|
Chris@422
|
253
|
Chris@422
|
254 void
|
Chris@426
|
255 ModelDataTableModel::resortAlphabetical() const
|
Chris@422
|
256 {
|
Chris@422
|
257 typedef std::multimap<QString, int> MapType;
|
Chris@422
|
258
|
Chris@422
|
259 MapType rowMap;
|
Chris@422
|
260 int rows = m_model->getRowCount();
|
Chris@422
|
261
|
Chris@422
|
262 for (int i = 0; i < rows; ++i) {
|
Chris@422
|
263 QVariant value =
|
Chris@422
|
264 m_model->getData(i, m_sortColumn, TabularModel::SortRole);
|
Chris@422
|
265 rowMap.insert(MapType::value_type(value.toString(), i));
|
Chris@422
|
266 }
|
Chris@422
|
267
|
Chris@422
|
268 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
|
Chris@422
|
269 m_rsort.push_back(i->second);
|
Chris@422
|
270 }
|
Chris@422
|
271
|
Chris@422
|
272 // rsort now maps from sorted row number to original row number
|
Chris@422
|
273 }
|
Chris@422
|
274
|