changeset 416:a00902d5f0ab

* basics of data editing in data table view
author Chris Cannam
date Mon, 09 Jun 2008 16:01:50 +0000
parents e37e44681720
children 12b7bf0c3915
files data/model/ModelDataTableModel.cpp data/model/ModelDataTableModel.h data/model/SparseModel.h
diffstat 3 files changed, 147 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/data/model/ModelDataTableModel.cpp	Mon Jun 09 16:01:22 2008 +0000
+++ b/data/model/ModelDataTableModel.cpp	Mon Jun 09 16:01:50 2008 +0000
@@ -35,10 +35,12 @@
 QVariant
 ModelDataTableModel::data(const QModelIndex &index, int role) const
 {
-    if (role != Qt::DisplayRole) {
+    if (role != Qt::DisplayRole && role != Qt::EditRole) {
         return QVariant();
     }
 
+    bool withUnit = (role == Qt::DisplayRole);
+
     if (!index.isValid()) return QVariant();
 
     int row = index.row(), col = index.column();
@@ -46,9 +48,9 @@
     if (row < 0 || row >= m_rows.size()) return QVariant();
 
     if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
-        return dataSparse<SparseOneDimensionalModel::Point>(row, col);
+        return dataSparse<SparseOneDimensionalModel::Point>(row, col, withUnit);
     } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
-        return dataSparse<SparseTimeValueModel::Point>(row, col);
+        return dataSparse<SparseTimeValueModel::Point>(row, col, withUnit);
     }
 
     return QVariant();
@@ -56,7 +58,7 @@
 
 template <typename PointType>
 QVariant
-ModelDataTableModel::dataSparse(int row, int col) const
+ModelDataTableModel::dataSparse(int row, int col, bool withUnit) const
 {
     size_t frame = m_rows[row];
     
@@ -89,10 +91,17 @@
         switch (col) {
 
         case 0:
+        {
+            RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate());
+            std::cerr << "Returning time " << rt << std::endl;
+            return QVariant(rt.toText().c_str());
+        }
+
+        case 1:
             std::cerr << "Returning frame " << frame << std::endl;
             return QVariant(frame); //!!! RealTime
 
-        case 1:
+        case 2:
             if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
                 const SparseOneDimensionalModel::Point *cp = 
                     reinterpret_cast<const SparseOneDimensionalModel::Point *>(point);
@@ -102,10 +111,15 @@
                 const SparseTimeValueModel::Point *cp = 
                     reinterpret_cast<const SparseTimeValueModel::Point *>(point);
                 std::cerr << "Returning value " << cp->value << std::endl;
-                return cp->value;
+                if (withUnit) {
+                    return QVariant(QString("%1 %2").arg(cp->value)
+                                    .arg(dynamic_cast<const SparseTimeValueModel *>(m_model)->getScaleUnits()));
+                } else {
+                    return cp->value;
+                }
             } else return QVariant();
 
-        case 2: 
+        case 3: 
             if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
                 return QVariant();
             } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
@@ -120,27 +134,115 @@
 bool
 ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
 {
+    if (role != Qt::EditRole) {
+        std::cerr << "setData: ignoring role " << role << std::endl;
+        return false;
+    }
+
+    //!!! see comment about disgustuality of this whole process, in
+    //dataSparse above
+
+    if (!index.isValid()) return false;
+
+    int row = index.row(), col = index.column();
+
+    if (row < 0 || row >= m_rows.size()) return false;
+
+    if (dynamic_cast<const SparseOneDimensionalModel *>(m_model)) {
+        return setDataSparse<SparseOneDimensionalModel::Point>(row, col, value);
+    } else if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
+        return setDataSparse<SparseTimeValueModel::Point>(row, col, value);
+    }
+
+    return false;
+}
+
+template <typename PointType>
+bool
+ModelDataTableModel::setDataSparse(int row, int col, QVariant value)
+{
+    size_t frame = m_rows[row];
+    
+    typedef SparseModel<PointType> ModelType;
+    typedef std::multiset<PointType, typename PointType::OrderComparator> 
+        PointListType;
+    typedef typename ModelType::EditCommand EditCommandType;
+
+    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 false;
+        if (indexAtFrame > 0) { --indexAtFrame; continue; }
+
+        switch (col) {
+
+        case 0:
+        {
+/*
+            RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate());
+            std::cerr << "Returning time " << rt << std::endl;
+            return QVariant(rt.toText().c_str());
+*/
+        }
+
+        case 1:
+        {
+            EditCommandType *command = 
+                new EditCommandType(sm, tr("Edit point time"));
+            PointType newPoint(*point);
+            newPoint.frame = value.toInt(); //!!! check validity
+            command->deletePoint(*point);
+            command->addPoint(newPoint);
+            command = command->finish();
+            if (command) emit executeCommand(command);
+            return true;
+        }
+//            std::cerr << "Returning frame " << frame << std::endl;
+//            return QVariant(frame); //!!! RealTime
+
+        case 2:
+            break;
+
+        case 3: 
+            break;
+        }
+    }
+
     return false;
 }
 
 Qt::ItemFlags
 ModelDataTableModel::flags(const QModelIndex &index) const
 {
-    return Qt::ItemFlags();
+    Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable |
+        Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsSelectable;
+    return flags;
 }
 
 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 (section == 0) return QVariant(tr("Time"));
+        if (section == 1) return QVariant(tr("Frame"));
+        else if (section == 2) {
             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) {
+        } else if (section == 3) {
             if (dynamic_cast<const SparseTimeValueModel *>(m_model)) {
                 return QVariant(tr("Label"));
             }
@@ -175,12 +277,21 @@
     if (!canHandleModelType(m_model)) return 0;
 
     if (dynamic_cast<SparseOneDimensionalModel *>(m_model)) {
-        return 2;
+        return 3;
     } else if (dynamic_cast<SparseTimeValueModel *>(m_model)) {
-        return 3;
+        return 4;
     }
 
-    return 1;
+    return 2;
+}
+
+QModelIndex 
+ModelDataTableModel::getModelIndexForFrame(size_t frame) const
+{
+    std::vector<size_t>::const_iterator i =
+        std::lower_bound(m_rows.begin(), m_rows.end(), frame);
+    size_t dist = std::distance(m_rows.begin(), i);
+    return createIndex(dist, 0, 0);
 }
 
 void
@@ -191,8 +302,13 @@
 }
 
 void 
-ModelDataTableModel::modelChanged(size_t, size_t)
-{}
+ModelDataTableModel::modelChanged(size_t f0, size_t f1)
+{
+    std::cerr << "ModelDataTableModel::modelChanged(" << f0 << "," << f1 << ")" << std::endl;
+    //!!! highly inefficient
+    rebuildRowVector();
+    emit layoutChanged();
+}
 
 void
 ModelDataTableModel::rebuildRowVector()
--- a/data/model/ModelDataTableModel.h	Mon Jun 09 16:01:22 2008 +0000
+++ b/data/model/ModelDataTableModel.h	Mon Jun 09 16:01:50 2008 +0000
@@ -20,6 +20,8 @@
 
 #include "Model.h"
 
+class Command;
+
 class ModelDataTableModel : public QAbstractItemModel
 {
     Q_OBJECT
@@ -45,8 +47,14 @@
     int rowCount(const QModelIndex &parent = QModelIndex()) const;
     int columnCount(const QModelIndex &parent = QModelIndex()) const;
 
+    QModelIndex getModelIndexForFrame(size_t frame) const;
+
     static bool canHandleModelType(Model *);
 
+signals:
+    void frameSelected(size_t);
+    void executeCommand(Command *);
+
 protected slots:
     void modelChanged();
     void modelChanged(size_t, size_t);
@@ -61,7 +69,10 @@
 
     void rebuildRowVector();
     template <typename PointType> void rebuildRowVectorSparse();
-    template <typename PointType> QVariant dataSparse(int row, int col) const;
+    template <typename PointType> QVariant dataSparse(int row, int col,
+                                                      bool withUnit) const;
+    template <typename PointType> bool setDataSparse(int row, int col,
+                                                     QVariant value);
 };
 
 #endif
--- a/data/model/SparseModel.h	Mon Jun 09 16:01:22 2008 +0000
+++ b/data/model/SparseModel.h	Mon Jun 09 16:01:50 2008 +0000
@@ -218,9 +218,9 @@
 	/**
 	 * If any points have been added or deleted, return this
 	 * command (so the caller can add it to the command history).
-	 * Otherwise delete the command.
+	 * Otherwise delete the command and return NULL.
 	 */
-	virtual Command *finish();
+	virtual EditCommand *finish();
 
     protected:
 	virtual void addCommand(Command *command, bool executeFirst);
@@ -605,7 +605,7 @@
 }
 
 template <typename PointType>
-Command *
+typename SparseModel<PointType>::EditCommand *
 SparseModel<PointType>::EditCommand::finish()
 {
     if (!m_commands.empty()) {