changeset 1662:628ffbb05856 single-point

Update PathModel - doesn't use new EventSeries, but doesn't use SparseModel either - it's simpler than that
author Chris Cannam
date Fri, 22 Mar 2019 13:32:09 +0000
parents 353a2d15f213
children a77a7e8c085c
files data/model/AlignmentModel.cpp data/model/PathModel.h data/model/SparseModel.h data/model/test/TestSparseModels.h
diffstat 4 files changed, 170 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/data/model/AlignmentModel.cpp	Fri Mar 22 11:04:51 2019 +0000
+++ b/data/model/AlignmentModel.cpp	Fri Mar 22 13:32:09 2019 +0000
@@ -244,7 +244,7 @@
         sv_frame_t frame = p.getFrame();
         double value = p.getValue();
         sv_frame_t rframe = lrint(value * m_aligned->getSampleRate());
-        m_path->addPoint(PathPoint(frame, rframe));
+        m_path->add(PathPoint(frame, rframe));
     }
 
 #ifdef DEBUG_ALIGNMENT_MODEL
@@ -275,7 +275,7 @@
          i != points.end(); ++i) {
         sv_frame_t frame = i->frame;
         sv_frame_t rframe = i->mapframe;
-        m_reversePath->addPoint(PathPoint(rframe, frame));
+        m_reversePath->add(PathPoint(rframe, frame));
     }
 
 #ifdef DEBUG_ALIGNMENT_MODEL
@@ -306,7 +306,7 @@
     cerr << "AlignmentModel::align: frame " << frame << " requested" << endl;
 #endif
 
-    PathModel::Point point(frame);
+    PathPoint point(frame);
     PathModel::PointList::const_iterator i = points.lower_bound(point);
     if (i == points.end()) {
 #ifdef DEBUG_ALIGNMENT_MODEL
--- a/data/model/PathModel.h	Fri Mar 22 11:04:51 2019 +0000
+++ b/data/model/PathModel.h	Fri Mar 22 13:32:09 2019 +0000
@@ -17,26 +17,26 @@
 #define SV_PATH_MODEL_H
 
 #include "Model.h"
-#include "SparseModel.h"
+#include "DeferredNotifier.h"
 #include "base/RealTime.h"
 #include "base/BaseTypes.h"
 
+#include "base/XmlExportable.h"
+#include "base/RealTime.h"
+
 #include <QStringList>
-
+#include <set>
 
 struct PathPoint
 {
-    PathPoint(sv_frame_t _frame) : frame(_frame), mapframe(_frame) { }
+    PathPoint(sv_frame_t _frame) :
+        frame(_frame), mapframe(_frame) { }
     PathPoint(sv_frame_t _frame, sv_frame_t _mapframe) :
         frame(_frame), mapframe(_mapframe) { }
 
-    int getDimensions() const { return 2; }
-
     sv_frame_t frame;
     sv_frame_t mapframe;
 
-    QString getLabel() const { return ""; }
-
     void toXml(QTextStream &stream, QString indent = "",
                QString extraAttributes = "") const {
         stream << QString("%1<point frame=\"%2\" mapframe=\"%3\" %4/>\n")
@@ -51,44 +51,147 @@
         return list.join(delimiter);
     }
 
-    struct Comparator {
-        bool operator()(const PathPoint &p1, const PathPoint &p2) const {
-            if (p1.frame != p2.frame) return p1.frame < p2.frame;
-            return p1.mapframe < p2.mapframe;
-        }
-    };
-    
-    struct OrderComparator {
-        bool operator()(const PathPoint &p1, const PathPoint &p2) const {
-            return p1.frame < p2.frame;
-        }
-    };
+    bool operator<(const PathPoint &p2) const {
+        if (frame != p2.frame) return frame < p2.frame;
+        return mapframe < p2.mapframe;
+    }
 };
 
-class PathModel : public SparseModel<PathPoint>
+class PathModel : public Model
 {
 public:
-    PathModel(sv_samplerate_t sampleRate, int resolution, bool notify = true) :
-        SparseModel<PathPoint>(sampleRate, resolution, notify) { }
+    typedef std::set<PathPoint> PointList;
 
-    void toXml(QTextStream &out,
-                       QString indent = "",
-                       QString extraAttributes = "") const override
-    {
-        SparseModel<PathPoint>::toXml
-            (out, 
-             indent,
-             QString("%1 subtype=\"path\"")
-             .arg(extraAttributes));
+    PathModel(sv_samplerate_t sampleRate,
+              int resolution,
+              bool notifyOnAdd = true) :
+        m_sampleRate(sampleRate),
+        m_resolution(resolution),
+        m_notifier(this,
+                   notifyOnAdd ?
+                   DeferredNotifier::NOTIFY_ALWAYS :
+                   DeferredNotifier::NOTIFY_DEFERRED),
+        m_completion(100),
+        m_start(0),
+        m_end(0) {
+    }
+
+    QString getTypeName() const override { return tr("Text"); }
+    bool isSparse() const { return true; }
+    bool isOK() const override { return true; }
+
+    sv_frame_t getStartFrame() const override {
+        return m_start;
+    }
+    sv_frame_t getEndFrame() const override {
+        return m_end;
+    }
+    
+    sv_samplerate_t getSampleRate() const override { return m_sampleRate; }
+    int getResolution() const { return m_resolution; }
+    
+    int getCompletion() const { return m_completion; }
+
+    void setCompletion(int completion, bool update = true) {
+        
+        {   QMutexLocker locker(&m_mutex);
+            if (m_completion == completion) return;
+            m_completion = completion;
+        }
+
+        if (update) {
+            m_notifier.makeDeferredNotifications();
+        }
+        
+        emit completionChanged();
+
+        if (completion == 100) {
+            // henceforth:
+            m_notifier.switchMode(DeferredNotifier::NOTIFY_ALWAYS);
+            emit modelChanged();
+        }
     }
 
     /**
-     * TabularModel is inherited via SparseModel, but we don't need it here.
+     * Query methods.
      */
-    QString getHeading(int) const override { return ""; }
-    bool isColumnTimeValue(int) const override { return false; }
-    SortType getSortType(int) const override { return SortNumeric; }
+    const PointList &getPoints() const {
+        return m_points;
+    }
 
+    /**
+     * Editing methods.
+     */
+    void add(PathPoint p) {
+
+        {   QMutexLocker locker(&m_mutex);
+            m_points.insert(p);
+
+            if (m_start == m_end) {
+                m_start = p.frame;
+                m_end = m_start + m_resolution;
+            } else {
+                if (p.frame < m_start) {
+                    m_start = p.frame;
+                }
+                if (p.frame + m_resolution > m_end) {
+                    m_end = p.frame + m_resolution;
+                }
+            }
+        }
+        
+        m_notifier.update(p.frame, m_resolution);
+    }
+    
+    void remove(PathPoint p) {
+        {   QMutexLocker locker(&m_mutex);
+            m_points.erase(p);
+        }
+
+        emit modelChangedWithin(p.frame, p.frame + m_resolution);
+    }
+
+    void clear() {
+        {   QMutexLocker locker(&m_mutex);
+            m_start = m_end = 0;
+            m_points.clear();
+        }
+    }
+
+    /**
+     * XmlExportable methods.
+     */
+    void toXml(QTextStream &out,
+                       QString indent = "",
+                       QString extraAttributes = "") const override {
+        
+        Model::toXml
+            (out,
+             indent,
+             QString("type=\"sparse\" dimensions=\"2\" resolution=\"%1\" "
+                     "notifyOnAdd=\"%2\" dataset=\"%3\" subtype=\"path\" %4")
+             .arg(m_resolution)
+             .arg("true") // always true after model reaches 100% -
+                          // subsequent points are always notified
+             .arg(getObjectExportId(&m_points))
+             .arg(extraAttributes));
+
+        
+    }
+    
+
+protected:
+    sv_samplerate_t m_sampleRate;
+    int m_resolution;
+
+    DeferredNotifier m_notifier;
+    int m_completion;
+
+    sv_frame_t m_start;
+    sv_frame_t m_end;
+    PointList m_points;
+
+    mutable QMutex m_mutex;  
 };
 
 
--- a/data/model/SparseModel.h	Fri Mar 22 11:04:51 2019 +0000
+++ b/data/model/SparseModel.h	Fri Mar 22 13:32:09 2019 +0000
@@ -38,7 +38,6 @@
  * Model containing sparse data (points with some properties).  The
  * properties depend on the point type.
  */
-
 template <typename PointType>
 class SparseModel : public Model,
                     public TabularModel
@@ -996,7 +995,6 @@
     MacroCommand::addCommand(command);
 }
 
-
 #endif
 
 
--- a/data/model/test/TestSparseModels.h	Fri Mar 22 11:04:51 2019 +0000
+++ b/data/model/test/TestSparseModels.h	Fri Mar 22 13:32:09 2019 +0000
@@ -18,6 +18,7 @@
 #include "../SparseOneDimensionalModel.h"
 #include "../NoteModel.h"
 #include "../TextModel.h"
+#include "../PathModel.h"
 
 #include <QObject>
 #include <QtTest>
@@ -246,6 +247,34 @@
         }
         QCOMPARE(xml, expected);
     }
+    
+    void path_xml() {
+        PathModel m(100, 10, false);
+        PathPoint p1(20, 30);
+        PathPoint p2(40, 60);
+        PathPoint p3(50, 49);
+        m.addPoint(p1);
+        m.addPoint(p2);
+        m.addPoint(p3);
+        QString xml;
+        QTextStream str(&xml, QIODevice::WriteOnly);
+        m.toXml(str);
+        str.flush();
+
+        QString expected =
+            "<model id='7' name='' sampleRate='100' start='20' end='80' type='sparse' dimensions='2' resolution='10' notifyOnAdd='true' dataset='4' subtype='path' />\n"
+            "<dataset id='6' dimensions='2'>\n"
+            "  <point frame='20' mapframe='30' />\n"
+            "  <point frame='40' mapframe='60' />\n"
+            "  <point frame='50' mapframe='49' />\n"
+            "</dataset>\n";
+        expected.replace("\'", "\"");
+        if (xml != expected) {
+            cerr << "Obtained xml:\n" << xml
+                 << "\nExpected:\n" << expected << endl;
+        }
+        QCOMPARE(xml, expected);
+    }
         
 };