comparison data/model/ModelDataTableModel.cpp @ 420:50a956688baa

* reorganise tabular data editor model support
author Chris Cannam
date Wed, 11 Jun 2008 16:13:25 +0000
parents 64e7bbb255d3
children 397fe91dc8e0
comparison
equal deleted inserted replaced
419:64e7bbb255d3 420:50a956688baa
13 COPYING included with this distribution for more information. 13 COPYING included with this distribution for more information.
14 */ 14 */
15 15
16 #include "ModelDataTableModel.h" 16 #include "ModelDataTableModel.h"
17 17
18 #include "SparseTimeValueModel.h" 18 #include "TabularModel.h"
19 #include "SparseOneDimensionalModel.h" 19 #include "Model.h"
20 #include "SparseModel.h"
21 20
22 #include <algorithm> 21 #include <algorithm>
22 #include <iostream>
23 23
24 ModelDataTableModel::ModelDataTableModel(Model *m) : 24 ModelDataTableModel::ModelDataTableModel(TabularModel *m) :
25 m_model(m) 25 m_model(m)
26 { 26 {
27 connect(m, SIGNAL(modelChanged()), this, SLOT(modelChanged())); 27 Model *baseModel = dynamic_cast<Model *>(m);
28 connect(m, SIGNAL(modelChanged(size_t, size_t)), 28
29 connect(baseModel, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
30 connect(baseModel, SIGNAL(modelChanged(size_t, size_t)),
29 this, SLOT(modelChanged(size_t, size_t))); 31 this, SLOT(modelChanged(size_t, size_t)));
30 rebuildRowVector();
31 } 32 }
32 33
33 ModelDataTableModel::~ModelDataTableModel() 34 ModelDataTableModel::~ModelDataTableModel()
34 { 35 {
35 } 36 }
36 37
37 QVariant 38 QVariant
38 ModelDataTableModel::data(const QModelIndex &index, int role) const 39 ModelDataTableModel::data(const QModelIndex &index, int role) const
39 { 40 {
40 if (role != Qt::DisplayRole && role != Qt::EditRole) {
41 return QVariant();
42 }
43
44 bool withUnit = (role == Qt::DisplayRole);
45
46 if (!index.isValid()) return QVariant(); 41 if (!index.isValid()) return QVariant();
47 42 return m_model->getData(getUnsorted(index.row()), index.column(), role);
48 int row = index.row(), col = index.column();
49
50 if (row < 0 || row >= m_rows.size()) return QVariant();
51
52 if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
53 return dataSparse<SparseOneDimensionalModel::Point>(row, col, withUnit);
54 } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
55 return dataSparse<SparseTimeValueModel::Point>(row, col, withUnit);
56 }
57
58 return QVariant();
59 }
60
61 template <typename PointType>
62 QVariant
63 ModelDataTableModel::dataSparse(int row, int col, bool withUnit) const
64 {
65 size_t frame = m_rows[row];
66
67 // This is just garbage. This would be a reasonable enough way to
68 // handle this in a dynamically typed language but it's hopeless
69 // in C++. The design is simply wrong. We need virtual helper
70 // methods in the model itself.
71
72 typedef SparseModel<PointType> ModelType;
73 typedef std::multiset<PointType, typename PointType::OrderComparator>
74 PointListType;
75
76 const ModelType *sm = dynamic_cast<const ModelType *>(m_model);
77 const PointListType &points = sm->getPoints(frame);
78
79 // it is possible to have more than one point at the same frame
80
81 int indexAtFrame = 0;
82 int ri = row;
83 while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; }
84
85 for (typename PointListType::const_iterator i = points.begin();
86 i != points.end(); ++i) {
87
88 const PointType *point = &(*i);
89 if (point->frame < frame) continue;
90 if (point->frame > frame) return QVariant();
91 if (indexAtFrame > 0) { --indexAtFrame; continue; }
92
93 switch (col) {
94
95 case 0:
96 {
97 RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate());
98 std::cerr << "Returning time " << rt << std::endl;
99 return QVariant(rt.toText().c_str());
100 }
101
102 case 1:
103 std::cerr << "Returning frame " << frame << std::endl;
104 return QVariant(int(frame));
105
106 case 2:
107 if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
108 const SparseOneDimensionalModel::Point *cp =
109 reinterpret_cast<const SparseOneDimensionalModel::Point *>(point);
110 std::cerr << "Returning label \"" << cp->label.toStdString() << "\"" << std::endl;
111 return QVariant(cp->label);
112 } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
113 const SparseTimeValueModel::Point *cp =
114 reinterpret_cast<const SparseTimeValueModel::Point *>(point);
115 std::cerr << "Returning value " << cp->value << std::endl;
116 if (withUnit) {
117 return QVariant(QString("%1 %2").arg(cp->value)
118 .arg(dynamic_cast<const SparseTimeValueModel *>(m_model)->getScaleUnits()));
119 } else {
120 return cp->value;
121 }
122 } else return QVariant();
123
124 case 3:
125 if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
126 return QVariant();
127 } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
128 return reinterpret_cast<const SparseTimeValueModel::Point *>(point)->label;
129 } else return QVariant();
130 }
131 }
132
133 return QVariant();
134 } 43 }
135 44
136 bool 45 bool
137 ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role) 46 ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
138 { 47 {
139 if (role != Qt::EditRole) { 48 if (!index.isValid()) return false;
140 std::cerr << "setData: ignoring role " << role << std::endl; 49 Command *command = m_model->setData(getUnsorted(index.row()),
50 index.column(), value, role);
51 if (command) {
52 emit executeCommand(command);
53 return true;
54 } else {
141 return false; 55 return false;
142 } 56 }
143
144 //!!! see comment about disgustuality of this whole process, in
145 //dataSparse above
146
147 if (!index.isValid()) return false;
148
149 int row = index.row(), col = index.column();
150
151 if (row < 0 || row >= m_rows.size()) return false;
152
153 if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
154 return setDataSparse<SparseOneDimensionalModel::Point>(row, col, value);
155 } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
156 return setDataSparse<SparseTimeValueModel::Point>(row, col, value);
157 }
158
159 return false;
160 }
161
162 template <typename PointType>
163 bool
164 ModelDataTableModel::setDataSparse(int row, int col, QVariant value)
165 {
166 size_t frame = m_rows[row];
167
168 typedef SparseModel<PointType> ModelType;
169 typedef std::multiset<PointType, typename PointType::OrderComparator>
170 PointListType;
171 typedef typename ModelType::EditCommand EditCommandType;
172
173 ModelType *sm = dynamic_cast<ModelType *>(m_model);
174 const PointListType &points = sm->getPoints(frame);
175
176 // it is possible to have more than one point at the same frame
177
178 int indexAtFrame = 0;
179 int ri = row;
180 while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; }
181
182 for (typename PointListType::const_iterator i = points.begin();
183 i != points.end(); ++i) {
184
185 const PointType *point = &(*i);
186 if (point->frame < frame) continue;
187 if (point->frame > frame) return false;
188 if (indexAtFrame > 0) { --indexAtFrame; continue; }
189
190 switch (col) {
191
192 case 0:
193 {
194 /*
195 RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate());
196 std::cerr << "Returning time " << rt << std::endl;
197 return QVariant(rt.toText().c_str());
198 */
199 }
200
201 case 1:
202 {
203 EditCommandType *command =
204 new EditCommandType(sm, tr("Edit point time"));
205 PointType newPoint(*point);
206 newPoint.frame = value.toInt(); //!!! check validity
207 command->deletePoint(*point);
208 command->addPoint(newPoint);
209 command = command->finish();
210 if (command) emit executeCommand(command);
211 return true;
212 }
213 // std::cerr << "Returning frame " << frame << std::endl;
214 // return QVariant(frame); //!!! RealTime
215
216 case 2:
217 break;
218
219 case 3:
220 break;
221 }
222 }
223
224 return false;
225 } 57 }
226 58
227 Qt::ItemFlags 59 Qt::ItemFlags
228 ModelDataTableModel::flags(const QModelIndex &index) const 60 ModelDataTableModel::flags(const QModelIndex &index) const
229 { 61 {
234 66
235 QVariant 67 QVariant
236 ModelDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const 68 ModelDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const
237 { 69 {
238 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { 70 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
239 if (section == 0) return QVariant(tr("Time")); 71 return m_model->getHeading(section);
240 if (section == 1) return QVariant(tr("Frame"));
241 else if (section == 2) {
242 if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
243 return QVariant(tr("Label"));
244 } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
245 return QVariant(tr("Value"));
246 }
247 } else if (section == 3) {
248 if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
249 return QVariant(tr("Label"));
250 }
251 }
252 } 72 }
253 return QVariant(); 73 return QVariant();
254 } 74 }
255 75
256 QModelIndex 76 QModelIndex
267 87
268 int 88 int
269 ModelDataTableModel::rowCount(const QModelIndex &parent) const 89 ModelDataTableModel::rowCount(const QModelIndex &parent) const
270 { 90 {
271 if (parent.isValid()) return 0; 91 if (parent.isValid()) return 0;
272 return m_rows.size(); 92 return m_model->getRowCount();
273 } 93 }
274 94
275 int 95 int
276 ModelDataTableModel::columnCount(const QModelIndex &parent) const 96 ModelDataTableModel::columnCount(const QModelIndex &parent) const
277 { 97 {
278 if (parent.isValid()) return 0; 98 if (parent.isValid()) return 0;
279 if (!canHandleModelType(m_model)) return 0; 99 return m_model->getColumnCount();
280
281 if (dynamic_cast<SparseOneDimensionalModel *>(m_model)) {
282 return 3;
283 } else if (dynamic_cast<SparseTimeValueModel *>(m_model)) {
284 return 4;
285 }
286
287 return 2;
288 } 100 }
289 101
290 QModelIndex 102 QModelIndex
291 ModelDataTableModel::getModelIndexForFrame(size_t frame) const 103 ModelDataTableModel::getModelIndexForFrame(size_t frame) const
292 { 104 {
293 std::vector<size_t>::const_iterator i = 105 int row = m_model->getRowForFrame(frame);
294 std::lower_bound(m_rows.begin(), m_rows.end(), frame); 106 return createIndex(getSorted(row), 0, 0);
295 size_t dist = std::distance(m_rows.begin(), i);
296 return createIndex(dist, 0, 0);
297 } 107 }
298 108
299 size_t 109 size_t
300 ModelDataTableModel::getFrameForModelIndex(const QModelIndex &index) const 110 ModelDataTableModel::getFrameForModelIndex(const QModelIndex &index) const
301 { 111 {
302 int row = index.row(); 112 return m_model->getFrameForRow(getUnsorted(index.row()));
303 if (m_rows.empty()) return 0; 113 }
304 if (row < 0) row == 0; 114
305 if (row > m_rows.size()-1) row = m_rows.size()-1; 115 void
306 return m_rows[row]; 116 ModelDataTableModel::sort(int column, Qt::SortOrder sortOrder)
117 {
118 std::cerr << "ModelDataTableModel::sort(" << column << ", " << sortOrder
119 << ")" << std::endl;
120 m_sortColumn = column;
121 m_sortOrdering = sortOrder;
122 m_sort.clear();
123 emit layoutChanged();
307 } 124 }
308 125
309 void 126 void
310 ModelDataTableModel::modelChanged() 127 ModelDataTableModel::modelChanged()
311 { 128 {
312 rebuildRowVector(); 129 m_sort.clear();
313 emit layoutChanged(); 130 emit layoutChanged();
314 } 131 }
315 132
316 void 133 void
317 ModelDataTableModel::modelChanged(size_t f0, size_t f1) 134 ModelDataTableModel::modelChanged(size_t f0, size_t f1)
318 { 135 {
319 std::cerr << "ModelDataTableModel::modelChanged(" << f0 << "," << f1 << ")" << std::endl; 136 //!!! inefficient
320 //!!! highly inefficient 137 m_sort.clear();
321 rebuildRowVector();
322 emit layoutChanged(); 138 emit layoutChanged();
323 } 139 }
324 140
325 void 141 int
326 ModelDataTableModel::rebuildRowVector() 142 ModelDataTableModel::getSorted(int row)
327 { 143 {
328 if (!canHandleModelType(m_model)) return; 144 if (m_model->isColumnTimeValue(m_sortColumn)) {
145 if (m_sortOrdering == Qt::AscendingOrder) {
146 return row;
147 } else {
148 return rowCount() - row - 1;
149 }
150 }
329 151
330 m_rows.clear(); 152 if (m_sort.empty()) {
331 153 resort();
332 if (dynamic_cast<SparseOneDimensionalModel *>(m_model)) {
333 rebuildRowVectorSparse<SparseOneDimensionalModel::Point>();
334 } else if (dynamic_cast<SparseTimeValueModel *>(m_model)) {
335 rebuildRowVectorSparse<SparseTimeValueModel::Point>();
336 } 154 }
155 if (row < 0 || row >= m_sort.size()) return 0;
156 return m_sort[row];
337 } 157 }
338 158
339 template <typename PointType> 159 int
340 void 160 ModelDataTableModel::getUnsorted(int row)
341 ModelDataTableModel::rebuildRowVectorSparse()
342 { 161 {
343 // gah 162 if (m_model->isColumnTimeValue(m_sortColumn)) {
344 163 if (m_sortOrdering == Qt::AscendingOrder) {
345 typedef SparseModel<PointType> ModelType; 164 return row;
346 typedef std::multiset<PointType, typename PointType::OrderComparator> 165 } else {
347 PointListType; 166 return rowCount() - row - 1;
348 167 }
349 ModelType *sm = dynamic_cast<ModelType *>(m_model);
350 const PointListType &points = sm->getPoints();
351
352 for (typename PointListType::const_iterator i = points.begin();
353 i != points.end(); ++i) {
354 m_rows.push_back(i->frame);
355 } 168 }
169 //!!! need the reverse of this
170 if (m_sort.empty()) {
171 resort();
172 }
173 if (row < 0 || row >= m_sort.size()) return 0;
174 return m_sort[row];
356 } 175 }
357 176
358 bool 177 void
359 ModelDataTableModel::canHandleModelType(Model *m) 178 ModelDataTableModel::resort()
360 { 179 {
361 if (dynamic_cast<SparseOneDimensionalModel *>(m)) return true; 180 //...
362 if (dynamic_cast<SparseTimeValueModel *>(m)) return true;
363 return false;
364 } 181 }
365 182
366