changeset 1804:343ef2a866a4

Implement missing TabularModel editing methods. Also made these pure in TabularModel, since almost all subclasses want them and (clearly) forgetting to implement them is a problem!
author Chris Cannam
date Mon, 14 Oct 2019 14:17:37 +0100
parents 6eb3a76c74f7
children 3db9a9fc2612
files data/model/BoxModel.h data/model/DenseThreeDimensionalModel.h data/model/ImageModel.h data/model/NoteModel.h data/model/RegionModel.h data/model/SparseOneDimensionalModel.h data/model/SparseTimeValueModel.h data/model/TabularModel.h data/model/TextModel.h
diffstat 9 files changed, 221 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/data/model/BoxModel.h	Thu Oct 10 10:03:31 2019 +0100
+++ b/data/model/BoxModel.h	Mon Oct 14 14:17:37 2019 +0100
@@ -272,6 +272,8 @@
         }
     }
 
+    bool isEditable() const override { return true; }
+
     Command *getSetDataCommand(int row, int column, const QVariant &value,
                                int role) override {
         
@@ -298,6 +300,24 @@
         return command->finish();
     }
 
+    Command *getInsertRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Add Box"));
+        Event e = m_events.getEventByIndex(row);
+        command->add(e);
+        return command->finish();
+    }
+
+    Command *getRemoveRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Delete Box"));
+        Event e = m_events.getEventByIndex(row);
+        command->remove(e);
+        return command->finish();
+    }
+
     
     /**
      * XmlExportable methods.
--- a/data/model/DenseThreeDimensionalModel.h	Thu Oct 10 10:03:31 2019 +0100
+++ b/data/model/DenseThreeDimensionalModel.h	Mon Oct 14 14:17:37 2019 +0100
@@ -132,6 +132,11 @@
     int getRowCount() const override { return getWidth(); }
     int getColumnCount() const override { return getHeight() + 2; }
 
+    bool isEditable() const override { return false; }
+    Command *getSetDataCommand(int, int, const QVariant &, int) { return nullptr; }
+    Command *getInsertRowCommand(int) { return nullptr; }
+    Command *getRemoveRowCommand(int) { return nullptr; }
+    
     QString getHeading(int column) const override
     {
         switch (column) {
--- a/data/model/ImageModel.h	Thu Oct 10 10:03:31 2019 +0100
+++ b/data/model/ImageModel.h	Mon Oct 14 14:17:37 2019 +0100
@@ -230,6 +230,26 @@
         command->add(e1);
         return command->finish();
     }
+
+    bool isEditable() const override { return true; }
+
+    Command *getInsertRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Add Image"));
+        Event e = m_events.getEventByIndex(row);
+        command->add(e);
+        return command->finish();
+    }
+
+    Command *getRemoveRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Delete Image"));
+        Event e = m_events.getEventByIndex(row);
+        command->remove(e);
+        return command->finish();
+    }
     
     /**
      * XmlExportable methods.
--- a/data/model/NoteModel.h	Thu Oct 10 10:03:31 2019 +0100
+++ b/data/model/NoteModel.h	Mon Oct 14 14:17:37 2019 +0100
@@ -322,6 +322,26 @@
         return SortNumeric;
     }
 
+    bool isEditable() const override { return true; }
+
+    Command *getInsertRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Add Note"));
+        Event e = m_events.getEventByIndex(row);
+        command->add(e);
+        return command->finish();
+    }
+
+    Command *getRemoveRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Delete Note"));
+        Event e = m_events.getEventByIndex(row);
+        command->remove(e);
+        return command->finish();
+    }
+
     /**
      * NoteExportable methods.
      */
--- a/data/model/RegionModel.h	Thu Oct 10 10:03:31 2019 +0100
+++ b/data/model/RegionModel.h	Mon Oct 14 14:17:37 2019 +0100
@@ -268,6 +268,8 @@
         }
     }
 
+    bool isEditable() const override { return true; }
+
     Command *getSetDataCommand(int row, int column, const QVariant &value, int role) override {
         
         if (row < 0 || row >= m_events.count()) return nullptr;
@@ -291,6 +293,24 @@
         return command->finish();
     }
 
+    Command *getInsertRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Add Region"));
+        Event e = m_events.getEventByIndex(row);
+        command->add(e);
+        return command->finish();
+    }
+
+    Command *getRemoveRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Delete Region"));
+        Event e = m_events.getEventByIndex(row);
+        command->remove(e);
+        return command->finish();
+    }
+
     
     /**
      * XmlExportable methods.
--- a/data/model/SparseOneDimensionalModel.h	Thu Oct 10 10:03:31 2019 +0100
+++ b/data/model/SparseOneDimensionalModel.h	Mon Oct 14 14:17:37 2019 +0100
@@ -243,6 +243,26 @@
         return command->finish();
     }
 
+    bool isEditable() const override { return true; }
+
+    Command *getInsertRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Add Point"));
+        Event e = m_events.getEventByIndex(row);
+        command->add(e);
+        return command->finish();
+    }
+
+    Command *getRemoveRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Delete Point"));
+        Event e = m_events.getEventByIndex(row);
+        command->remove(e);
+        return command->finish();
+    }
+
     /**
      * NoteExportable methods.
      */
--- a/data/model/SparseTimeValueModel.h	Thu Oct 10 10:03:31 2019 +0100
+++ b/data/model/SparseTimeValueModel.h	Mon Oct 14 14:17:37 2019 +0100
@@ -279,7 +279,10 @@
         }
     }
 
-    Command *getSetDataCommand(int row, int column, const QVariant &value, int role) override {
+    bool isEditable() const override { return true; }
+
+    Command *getSetDataCommand(int row, int column, const QVariant &value,
+                               int role) override {
         if (row < 0 || row >= m_events.count()) return nullptr;
         if (role != Qt::EditRole) return nullptr;
 
@@ -299,6 +302,24 @@
         command->add(e1);
         return command->finish();
     }
+
+    Command *getInsertRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Add Point"));
+        Event e = m_events.getEventByIndex(row);
+        command->add(e);
+        return command->finish();
+    }
+
+    Command *getRemoveRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Delete Point"));
+        Event e = m_events.getEventByIndex(row);
+        command->remove(e);
+        return command->finish();
+    }
     
     /**
      * XmlExportable methods.
--- a/data/model/TabularModel.h	Thu Oct 10 10:03:31 2019 +0100
+++ b/data/model/TabularModel.h	Mon Oct 14 14:17:37 2019 +0100
@@ -32,44 +32,107 @@
  * This is very like a cut-down QAbstractItemModel.  It assumes a
  * relationship between row number and frame time.
  */
-
 class TabularModel
 {
 public:
     virtual ~TabularModel() { }
 
+    /**
+     * Return the number of rows (items) in the model.
+     */
     virtual int getRowCount() const = 0;
+
+    /** 
+     * Return the number of columns (values/labels/etc per item).
+     */
     virtual int getColumnCount() const = 0;
 
+    /**
+     * Return the heading for a given column, e.g. "Time" or "Value".
+     * These are shown directly to the user, so must be translated
+     * already.
+     */
     virtual QString getHeading(int column) const = 0;
 
     enum { SortRole = Qt::UserRole };
     enum SortType { SortNumeric, SortAlphabetical };
 
+    /**
+     * Get the value in the given cell, for the given role. The role
+     * is actually a Qt::ItemDataRole.
+     */
     virtual QVariant getData(int row, int column, int role) const = 0;
+
+    /**
+     * Return true if the column is the frame time of the item, or an
+     * alternative representation of it (i.e. anything that has the
+     * same sort order). Duration is not a time value by this meaning.
+     */
     virtual bool isColumnTimeValue(int col) const = 0;
+
+    /**
+     * Return the sort type (numeric or alphabetical) for the column.
+     */
     virtual SortType getSortType(int col) const = 0;
 
+    /**
+     * Return the frame time for the given row.
+     */
     virtual sv_frame_t getFrameForRow(int row) const = 0;
+
+    /** 
+     * Return the number of the first row whose frame time is not less
+     * than the given one. If there is none, return getRowCount().
+     */
     virtual int getRowForFrame(sv_frame_t frame) const = 0;
 
-    virtual bool isEditable() const { return false; }
-    virtual Command *getSetDataCommand(int /* row */, int /* column */, const QVariant &, int /* role */) { return 0; }
-    virtual Command *getInsertRowCommand(int /* beforeRow */) { return 0; }
-    virtual Command *getRemoveRowCommand(int /* row */) { return 0; }
+    /**
+     * Return true if the model is user-editable, false otherwise.
+     */
+    virtual bool isEditable() const = 0;
 
-    QVariant adaptFrameForRole(sv_frame_t frame,
-                               sv_samplerate_t rate,
-                               int role) const {
+    /**
+     * Return a command to set the value in the given cell, for the
+     * given role, to the contents of the supplied variant.
+     *
+     * If the model is not editable or the cell or value is out of
+     * range, return nullptr.
+     */
+    virtual Command *getSetDataCommand(int row, int column,
+                                       const QVariant &, int role) = 0;
+
+    /**
+     * Return a command to insert a new row before the row with the
+     * given index.
+     *
+     * If the model is not editable or the index is out of range,
+     * return nullptr.
+     */
+    virtual Command *getInsertRowCommand(int beforeRow) = 0;
+
+    /**
+     * Return a command to delete the row with the given index.
+     *
+     * If the model is not editable or the index is out of range,
+     * return nullptr.
+     */
+    virtual Command *getRemoveRowCommand(int row) = 0;
+
+protected:
+    // Helpers
+    
+    static QVariant adaptFrameForRole(sv_frame_t frame,
+                                      sv_samplerate_t rate,
+                                      int role) {
         if (role == SortRole) return int(frame);
         RealTime rt = RealTime::frame2RealTime(frame, rate);
         if (role == Qt::EditRole) return rt.toString().c_str();
         else return rt.toText().c_str();
     }
 
-    QVariant adaptValueForRole(float value,
-                               QString unit,
-                               int role) const {
+    static QVariant adaptValueForRole(float value,
+                                      QString unit,
+                                      int role) {
         if (role == SortRole || role == Qt::EditRole) return value;
         else return QString("%1 %2").arg(value).arg(unit);
     }
--- a/data/model/TextModel.h	Thu Oct 10 10:03:31 2019 +0100
+++ b/data/model/TextModel.h	Mon Oct 14 14:17:37 2019 +0100
@@ -233,6 +233,26 @@
         command->add(e1);
         return command->finish();
     }
+
+    bool isEditable() const override { return true; }
+
+    Command *getInsertRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Add Label"));
+        Event e = m_events.getEventByIndex(row);
+        command->add(e);
+        return command->finish();
+    }
+
+    Command *getRemoveRowCommand(int row) override {
+        if (row < 0 || row >= m_events.count()) return nullptr;
+        auto command = new ChangeEventsCommand(getId().untyped,
+                                               tr("Delete Label"));
+        Event e = m_events.getEventByIndex(row);
+        command->remove(e);
+        return command->finish();
+    }
     
     /**
      * XmlExportable methods.