annotate data/model/ModelDataTableModel.cpp @ 417:12b7bf0c3915

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