# HG changeset patch # User Chris Cannam # Date 1212765987 0 # Node ID 0b274e1aaf103948b49b2267844de9d66955c6b0 # Parent 5e4238d08caa20ff69ff5512ae24cc8af11f6d54 * Start adding a spreadsheet-style editor window for model data diff -r 5e4238d08caa -r 0b274e1aaf10 data/data.pro --- a/data/data.pro Wed May 21 11:09:15 2008 +0000 +++ b/data/data.pro Fri Jun 06 15:26:27 2008 +0000 @@ -52,6 +52,7 @@ model/ImageModel.h \ model/Labeller.h \ model/Model.h \ + model/ModelDataTableModel.h \ model/NoteModel.h \ model/PathModel.h \ model/PowerOfSqrtTwoZoomConstraint.h \ @@ -97,6 +98,7 @@ model/EditableDenseThreeDimensionalModel.cpp \ model/FFTModel.cpp \ model/Model.cpp \ + model/ModelDataTableModel.cpp \ model/NoteModel.cpp \ model/PowerOfSqrtTwoZoomConstraint.cpp \ model/PowerOfTwoZoomConstraint.cpp \ diff -r 5e4238d08caa -r 0b274e1aaf10 data/model/ModelDataTableModel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/model/ModelDataTableModel.cpp Fri Jun 06 15:26:27 2008 +0000 @@ -0,0 +1,238 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "ModelDataTableModel.h" + +#include "SparseTimeValueModel.h" +#include "SparseOneDimensionalModel.h" +#include "SparseModel.h" + +ModelDataTableModel::ModelDataTableModel(Model *m) : + m_model(m) +{ + connect(m, SIGNAL(modelChanged()), this, SLOT(modelChanged())); + connect(m, SIGNAL(modelChanged(size_t, size_t)), + this, SLOT(modelChanged(size_t, size_t))); + rebuildRowVector(); +} + +ModelDataTableModel::~ModelDataTableModel() +{ +} + +QVariant +ModelDataTableModel::data(const QModelIndex &index, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + + if (!index.isValid()) return QVariant(); + + int row = index.row(), col = index.column(); + + if (row < 0 || row >= m_rows.size()) return QVariant(); + + if (dynamic_cast(m_model)) { + return dataSparse(row, col); + } else if (dynamic_cast(m_model)) { + return dataSparse(row, col); + } + + return QVariant(); +} + +template +QVariant +ModelDataTableModel::dataSparse(int row, int col) const +{ + size_t frame = m_rows[row]; + + // This is just garbage. This would be a reasonable enough way to + // handle this in a dynamically typed language but it's hopeless + // in C++. The design is simply wrong. We need virtual helper + // methods in the model itself. + + typedef SparseModel ModelType; + typedef std::multiset + PointListType; + + const ModelType *sm = dynamic_cast(m_model); + const PointListType &points = sm->getPoints(frame); + + // it is possible to have more than one point at the same frame + + int indexAtFrame = 0; + int ri = row; + while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; } + + for (typename PointListType::const_iterator i = points.begin(); + i != points.end(); ++i) { + + const PointType *point = &(*i); + if (point->frame < frame) continue; + if (point->frame > frame) return QVariant(); + if (indexAtFrame > 0) { --indexAtFrame; continue; } + + switch (col) { + + case 0: + std::cerr << "Returning frame " << frame << std::endl; + return QVariant(frame); //!!! RealTime + + case 1: + if (dynamic_cast(m_model)) { + const SparseOneDimensionalModel::Point *cp = + reinterpret_cast(point); + std::cerr << "Returning label \"" << cp->label.toStdString() << "\"" << std::endl; + return QVariant(cp->label); + } else if (dynamic_cast(m_model)) { + const SparseTimeValueModel::Point *cp = + reinterpret_cast(point); + std::cerr << "Returning value " << cp->value << std::endl; + return cp->value; + } else return QVariant(); + + case 2: + if (dynamic_cast(m_model)) { + return QVariant(); + } else if (dynamic_cast(m_model)) { + return reinterpret_cast(point)->label; + } else return QVariant(); + } + } + + return QVariant(); +} + +bool +ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + return false; +} + +Qt::ItemFlags +ModelDataTableModel::flags(const QModelIndex &index) const +{ + return Qt::ItemFlags(); +} + +QVariant +ModelDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + if (section == 0) return QVariant(tr("Frame")); + else if (section == 1) { + if (dynamic_cast(m_model)) { + return QVariant(tr("Label")); + } else if (dynamic_cast(m_model)) { + return QVariant(tr("Value")); + } + } else if (section == 2) { + if (dynamic_cast(m_model)) { + return QVariant(tr("Label")); + } + } + } + return QVariant(); +} + +QModelIndex +ModelDataTableModel::index(int row, int column, const QModelIndex &parent) const +{ + return createIndex(row, column, 0); +} + +QModelIndex +ModelDataTableModel::parent(const QModelIndex &index) const +{ + return QModelIndex(); +} + +int +ModelDataTableModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) return 0; + return m_rows.size(); +} + +int +ModelDataTableModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) return 0; + if (!canHandleModelType(m_model)) return 0; + + if (dynamic_cast(m_model)) { + return 2; + } else if (dynamic_cast(m_model)) { + return 3; + } + + return 1; +} + +void +ModelDataTableModel::modelChanged() +{ + rebuildRowVector(); + emit layoutChanged(); +} + +void +ModelDataTableModel::modelChanged(size_t, size_t) +{} + +void +ModelDataTableModel::rebuildRowVector() +{ + if (!canHandleModelType(m_model)) return; + + m_rows.clear(); + + if (dynamic_cast(m_model)) { + rebuildRowVectorSparse(); + } else if (dynamic_cast(m_model)) { + rebuildRowVectorSparse(); + } +} + +template +void +ModelDataTableModel::rebuildRowVectorSparse() +{ + // gah + + typedef SparseModel ModelType; + typedef std::multiset + PointListType; + + ModelType *sm = dynamic_cast(m_model); + const PointListType &points = sm->getPoints(); + + for (typename PointListType::const_iterator i = points.begin(); + i != points.end(); ++i) { + m_rows.push_back(i->frame); + } +} + +bool +ModelDataTableModel::canHandleModelType(Model *m) +{ + if (dynamic_cast(m)) return true; + if (dynamic_cast(m)) return true; + return false; +} + + diff -r 5e4238d08caa -r 0b274e1aaf10 data/model/ModelDataTableModel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/model/ModelDataTableModel.h Fri Jun 06 15:26:27 2008 +0000 @@ -0,0 +1,67 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2008 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _MODEL_DATA_TABLE_MODEL_H_ +#define _MODEL_DATA_TABLE_MODEL_H_ + +#include + +#include "Model.h" + +class ModelDataTableModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + ModelDataTableModel(Model *m); + virtual ~ModelDataTableModel(); + + QVariant data(const QModelIndex &index, int role) const; + + bool setData(const QModelIndex &index, const QVariant &value, int role); + + Qt::ItemFlags flags(const QModelIndex &index) const; + + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + + QModelIndex parent(const QModelIndex &index) const; + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + static bool canHandleModelType(Model *); + +protected slots: + void modelChanged(); + void modelChanged(size_t, size_t); + +protected: + // We need to have some sort of map between row and time in sample + // frames. I guess this will do for now. + + std::vector m_rows; // contains sample frame + + Model *m_model; + + void rebuildRowVector(); + template void rebuildRowVectorSparse(); + template QVariant dataSparse(int row, int col) const; +}; + +#endif