annotate data/model/ModelDataTableModel.cpp @ 413:0b274e1aaf10

* Start adding a spreadsheet-style editor window for model data
author Chris Cannam
date Fri, 06 Jun 2008 15:26:27 +0000
parents
children a00902d5f0ab
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@413 22 ModelDataTableModel::ModelDataTableModel(Model *m) :
Chris@413 23 m_model(m)
Chris@413 24 {
Chris@413 25 connect(m, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
Chris@413 26 connect(m, SIGNAL(modelChanged(size_t, size_t)),
Chris@413 27 this, SLOT(modelChanged(size_t, size_t)));
Chris@413 28 rebuildRowVector();
Chris@413 29 }
Chris@413 30
Chris@413 31 ModelDataTableModel::~ModelDataTableModel()
Chris@413 32 {
Chris@413 33 }
Chris@413 34
Chris@413 35 QVariant
Chris@413 36 ModelDataTableModel::data(const QModelIndex &index, int role) const
Chris@413 37 {
Chris@413 38 if (role != Qt::DisplayRole) {
Chris@413 39 return QVariant();
Chris@413 40 }
Chris@413 41
Chris@413 42 if (!index.isValid()) return QVariant();
Chris@413 43
Chris@413 44 int row = index.row(), col = index.column();
Chris@413 45
Chris@413 46 if (row < 0 || row >= m_rows.size()) return QVariant();
Chris@413 47
Chris@413 48 if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
Chris@413 49 return dataSparse<SparseOneDimensionalModel::Point>(row, col);
Chris@413 50 } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
Chris@413 51 return dataSparse<SparseTimeValueModel::Point>(row, col);
Chris@413 52 }
Chris@413 53
Chris@413 54 return QVariant();
Chris@413 55 }
Chris@413 56
Chris@413 57 template <typename PointType>
Chris@413 58 QVariant
Chris@413 59 ModelDataTableModel::dataSparse(int row, int col) const
Chris@413 60 {
Chris@413 61 size_t frame = m_rows[row];
Chris@413 62
Chris@413 63 // This is just garbage. This would be a reasonable enough way to
Chris@413 64 // handle this in a dynamically typed language but it's hopeless
Chris@413 65 // in C++. The design is simply wrong. We need virtual helper
Chris@413 66 // methods in the model itself.
Chris@413 67
Chris@413 68 typedef SparseModel<PointType> ModelType;
Chris@413 69 typedef std::multiset<PointType, typename PointType::OrderComparator>
Chris@413 70 PointListType;
Chris@413 71
Chris@413 72 const ModelType *sm = dynamic_cast<const ModelType *>(m_model);
Chris@413 73 const PointListType &points = sm->getPoints(frame);
Chris@413 74
Chris@413 75 // it is possible to have more than one point at the same frame
Chris@413 76
Chris@413 77 int indexAtFrame = 0;
Chris@413 78 int ri = row;
Chris@413 79 while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; }
Chris@413 80
Chris@413 81 for (typename PointListType::const_iterator i = points.begin();
Chris@413 82 i != points.end(); ++i) {
Chris@413 83
Chris@413 84 const PointType *point = &(*i);
Chris@413 85 if (point->frame < frame) continue;
Chris@413 86 if (point->frame > frame) return QVariant();
Chris@413 87 if (indexAtFrame > 0) { --indexAtFrame; continue; }
Chris@413 88
Chris@413 89 switch (col) {
Chris@413 90
Chris@413 91 case 0:
Chris@413 92 std::cerr << "Returning frame " << frame << std::endl;
Chris@413 93 return QVariant(frame); //!!! RealTime
Chris@413 94
Chris@413 95 case 1:
Chris@413 96 if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
Chris@413 97 const SparseOneDimensionalModel::Point *cp =
Chris@413 98 reinterpret_cast<const SparseOneDimensionalModel::Point *>(point);
Chris@413 99 std::cerr << "Returning label \"" << cp->label.toStdString() << "\"" << std::endl;
Chris@413 100 return QVariant(cp->label);
Chris@413 101 } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
Chris@413 102 const SparseTimeValueModel::Point *cp =
Chris@413 103 reinterpret_cast<const SparseTimeValueModel::Point *>(point);
Chris@413 104 std::cerr << "Returning value " << cp->value << std::endl;
Chris@413 105 return cp->value;
Chris@413 106 } else return QVariant();
Chris@413 107
Chris@413 108 case 2:
Chris@413 109 if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
Chris@413 110 return QVariant();
Chris@413 111 } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
Chris@413 112 return reinterpret_cast<const SparseTimeValueModel::Point *>(point)->label;
Chris@413 113 } else return QVariant();
Chris@413 114 }
Chris@413 115 }
Chris@413 116
Chris@413 117 return QVariant();
Chris@413 118 }
Chris@413 119
Chris@413 120 bool
Chris@413 121 ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
Chris@413 122 {
Chris@413 123 return false;
Chris@413 124 }
Chris@413 125
Chris@413 126 Qt::ItemFlags
Chris@413 127 ModelDataTableModel::flags(const QModelIndex &index) const
Chris@413 128 {
Chris@413 129 return Qt::ItemFlags();
Chris@413 130 }
Chris@413 131
Chris@413 132 QVariant
Chris@413 133 ModelDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const
Chris@413 134 {
Chris@413 135 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
Chris@413 136 if (section == 0) return QVariant(tr("Frame"));
Chris@413 137 else if (section == 1) {
Chris@413 138 if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
Chris@413 139 return QVariant(tr("Label"));
Chris@413 140 } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
Chris@413 141 return QVariant(tr("Value"));
Chris@413 142 }
Chris@413 143 } else if (section == 2) {
Chris@413 144 if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
Chris@413 145 return QVariant(tr("Label"));
Chris@413 146 }
Chris@413 147 }
Chris@413 148 }
Chris@413 149 return QVariant();
Chris@413 150 }
Chris@413 151
Chris@413 152 QModelIndex
Chris@413 153 ModelDataTableModel::index(int row, int column, const QModelIndex &parent) const
Chris@413 154 {
Chris@413 155 return createIndex(row, column, 0);
Chris@413 156 }
Chris@413 157
Chris@413 158 QModelIndex
Chris@413 159 ModelDataTableModel::parent(const QModelIndex &index) const
Chris@413 160 {
Chris@413 161 return QModelIndex();
Chris@413 162 }
Chris@413 163
Chris@413 164 int
Chris@413 165 ModelDataTableModel::rowCount(const QModelIndex &parent) const
Chris@413 166 {
Chris@413 167 if (parent.isValid()) return 0;
Chris@413 168 return m_rows.size();
Chris@413 169 }
Chris@413 170
Chris@413 171 int
Chris@413 172 ModelDataTableModel::columnCount(const QModelIndex &parent) const
Chris@413 173 {
Chris@413 174 if (parent.isValid()) return 0;
Chris@413 175 if (!canHandleModelType(m_model)) return 0;
Chris@413 176
Chris@413 177 if (dynamic_cast<SparseOneDimensionalModel *>(m_model)) {
Chris@413 178 return 2;
Chris@413 179 } else if (dynamic_cast<SparseTimeValueModel *>(m_model)) {
Chris@413 180 return 3;
Chris@413 181 }
Chris@413 182
Chris@413 183 return 1;
Chris@413 184 }
Chris@413 185
Chris@413 186 void
Chris@413 187 ModelDataTableModel::modelChanged()
Chris@413 188 {
Chris@413 189 rebuildRowVector();
Chris@413 190 emit layoutChanged();
Chris@413 191 }
Chris@413 192
Chris@413 193 void
Chris@413 194 ModelDataTableModel::modelChanged(size_t, size_t)
Chris@413 195 {}
Chris@413 196
Chris@413 197 void
Chris@413 198 ModelDataTableModel::rebuildRowVector()
Chris@413 199 {
Chris@413 200 if (!canHandleModelType(m_model)) return;
Chris@413 201
Chris@413 202 m_rows.clear();
Chris@413 203
Chris@413 204 if (dynamic_cast<SparseOneDimensionalModel *>(m_model)) {
Chris@413 205 rebuildRowVectorSparse<SparseOneDimensionalModel::Point>();
Chris@413 206 } else if (dynamic_cast<SparseTimeValueModel *>(m_model)) {
Chris@413 207 rebuildRowVectorSparse<SparseTimeValueModel::Point>();
Chris@413 208 }
Chris@413 209 }
Chris@413 210
Chris@413 211 template <typename PointType>
Chris@413 212 void
Chris@413 213 ModelDataTableModel::rebuildRowVectorSparse()
Chris@413 214 {
Chris@413 215 // gah
Chris@413 216
Chris@413 217 typedef SparseModel<PointType> ModelType;
Chris@413 218 typedef std::multiset<PointType, typename PointType::OrderComparator>
Chris@413 219 PointListType;
Chris@413 220
Chris@413 221 ModelType *sm = dynamic_cast<ModelType *>(m_model);
Chris@413 222 const PointListType &points = sm->getPoints();
Chris@413 223
Chris@413 224 for (typename PointListType::const_iterator i = points.begin();
Chris@413 225 i != points.end(); ++i) {
Chris@413 226 m_rows.push_back(i->frame);
Chris@413 227 }
Chris@413 228 }
Chris@413 229
Chris@413 230 bool
Chris@413 231 ModelDataTableModel::canHandleModelType(Model *m)
Chris@413 232 {
Chris@413 233 if (dynamic_cast<SparseOneDimensionalModel *>(m)) return true;
Chris@413 234 if (dynamic_cast<SparseTimeValueModel *>(m)) return true;
Chris@413 235 return false;
Chris@413 236 }
Chris@413 237
Chris@413 238