changeset 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 5e4238d08caa
children c8955c486340
files data/data.pro data/model/ModelDataTableModel.cpp data/model/ModelDataTableModel.h
diffstat 3 files changed, 307 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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 \
--- /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<const SparseOneDimensionalModel *>(m_model)) {
+        return dataSparse<SparseOneDimensionalModel::Point>(row, col);
+    } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
+        return dataSparse<SparseTimeValueModel::Point>(row, col);
+    }
+
+    return QVariant();
+}
+
+template <typename PointType>
+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<PointType> ModelType;
+    typedef std::multiset<PointType, typename PointType::OrderComparator> 
+        PointListType;
+
+    const ModelType *sm = dynamic_cast<const ModelType *>(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<const SparseOneDimensionalModel *>(m_model)) {
+                const SparseOneDimensionalModel::Point *cp = 
+                    reinterpret_cast<const SparseOneDimensionalModel::Point *>(point);
+                std::cerr << "Returning label \"" << cp->label.toStdString() << "\"" << std::endl;
+                return QVariant(cp->label);
+            } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
+                const SparseTimeValueModel::Point *cp = 
+                    reinterpret_cast<const SparseTimeValueModel::Point *>(point);
+                std::cerr << "Returning value " << cp->value << std::endl;
+                return cp->value;
+            } else return QVariant();
+
+        case 2: 
+            if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
+                return QVariant();
+            } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
+                return reinterpret_cast<const SparseTimeValueModel::Point *>(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<const SparseOneDimensionalModel *>(m_model)) {
+                return QVariant(tr("Label"));
+            } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
+                return QVariant(tr("Value"));
+            }
+        } else if (section == 2) {
+            if (dynamic_cast<const SparseTimeValueModel *>(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<SparseOneDimensionalModel *>(m_model)) {
+        return 2;
+    } else if (dynamic_cast<SparseTimeValueModel *>(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<SparseOneDimensionalModel *>(m_model)) {
+        rebuildRowVectorSparse<SparseOneDimensionalModel::Point>();
+    } else if (dynamic_cast<SparseTimeValueModel *>(m_model)) {
+        rebuildRowVectorSparse<SparseTimeValueModel::Point>();
+    }
+}
+
+template <typename PointType>
+void
+ModelDataTableModel::rebuildRowVectorSparse()
+{
+    // gah
+
+    typedef SparseModel<PointType> ModelType;
+    typedef std::multiset<PointType, typename PointType::OrderComparator> 
+        PointListType;
+
+    ModelType *sm = dynamic_cast<ModelType *>(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<SparseOneDimensionalModel *>(m)) return true;
+    if (dynamic_cast<SparseTimeValueModel *>(m)) return true;
+    return false;
+}
+
+
--- /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 <QAbstractItemModel>
+
+#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<size_t> m_rows; // contains sample frame
+
+    Model *m_model;
+
+    void rebuildRowVector();
+    template <typename PointType> void rebuildRowVectorSparse();
+    template <typename PointType> QVariant dataSparse(int row, int col) const;
+};
+
+#endif