# HG changeset patch # User Chris Cannam # Date 1561637290 -3600 # Node ID 9d82b164f2644ed5d0a2e88b5ab6bf4355b2b468 # Parent fe3f7f8df3a36bfbde638839935c51dfd3fe4e8b Work on commands, and some other model updates diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/EventCommands.h --- a/data/model/EventCommands.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/EventCommands.h Thu Jun 27 13:08:10 2019 +0100 @@ -18,6 +18,7 @@ #include "base/Event.h" #include "base/Command.h" +#include "base/ById.h" /** * Interface for classes that can be modified through these commands @@ -29,66 +30,111 @@ virtual void remove(Event e) = 0; }; +template +class WithEditable +{ + typedef typename Base::Id Id; + Id m_id; + +protected: + WithEditable(Id id) : m_id(id) { } + + std::shared_ptr getEditable() { + auto base = StaticById::get(m_id); + if (!base) return {}; // acceptable - item has expired + auto editable = std::dynamic_pointer_cast(base); + if (!editable) { + SVCERR << "WARNING: Id passed to EventEditable command is not that of an EventEditable" << endl; + } + return editable; + } +}; + /** - * Command to add an event to an editable containing events, with undo. + * Command to add an event to an editable containing events, with + * undo. The template parameter must be a type that can be + * dynamic_cast to EventEditable and that has a ById store. */ -class AddEventCommand : public Command +template +class AddEventCommand : public Command, + public WithEditable { public: - AddEventCommand(EventEditable *editable, const Event &e, QString name) : - m_editable(editable), m_event(e), m_name(name) { } + AddEventCommand(typename Base::Id editable, const Event &e, QString name) : + WithEditable(editable), m_event(e), m_name(name) { } QString getName() const override { return m_name; } Event getEvent() const { return m_event; } - void execute() override { m_editable->add(m_event); } - void unexecute() override { m_editable->remove(m_event); } + void execute() override { + auto editable = getEditable(); + if (editable) editable->add(m_event); + } + void unexecute() override { + auto editable = getEditable(); + if (editable) editable->remove(m_event); + } private: - EventEditable *m_editable; Event m_event; QString m_name; + using WithEditable::getEditable; }; /** * Command to remove an event from an editable containing events, with - * undo. + * undo. The template parameter must be a type that implements + * EventBase and that has a ById store. */ -class RemoveEventCommand : public Command +template +class RemoveEventCommand : public Command, + public WithEditable { public: - RemoveEventCommand(EventEditable *editable, const Event &e, QString name) : - m_editable(editable), m_event(e), m_name(name) { } + RemoveEventCommand(typename Base::Id editable, const Event &e, QString name) : + WithEditable(editable), m_event(e), m_name(name) { } QString getName() const override { return m_name; } Event getEvent() const { return m_event; } - void execute() override { m_editable->remove(m_event); } - void unexecute() override { m_editable->add(m_event); } + void execute() override { + auto editable = getEditable(); + if (editable) editable->remove(m_event); + } + void unexecute() override { + auto editable = getEditable(); + if (editable) editable->add(m_event); + } private: - EventEditable *m_editable; Event m_event; QString m_name; + using WithEditable::getEditable; }; /** * Command to add or remove a series of events to or from an editable, * with undo. Creates and immediately executes a sub-command for each * add/remove requested. Consecutive add/remove pairs for the same - * point are collapsed. + * point are collapsed. The template parameter must be a type that + * implements EventBase and that has a ById store. */ +template class ChangeEventsCommand : public MacroCommand { + typedef typename Base::Id Id; + public: - ChangeEventsCommand(EventEditable *editable, QString name) : + ChangeEventsCommand(Id editable, QString name) : MacroCommand(name), m_editable(editable) { } void add(Event e) { - addCommand(new AddEventCommand(m_editable, e, getName()), true); + addCommand(new AddEventCommand(m_editable, e, getName()), + true); } void remove(Event e) { - addCommand(new RemoveEventCommand(m_editable, e, getName()), true); + addCommand(new RemoveEventCommand(m_editable, e, getName()), + true); } /** @@ -120,10 +166,10 @@ return; } - RemoveEventCommand *r = - dynamic_cast(command); - AddEventCommand *a = - dynamic_cast(*m_commands.rbegin()); + RemoveEventCommand *r = + dynamic_cast *>(command); + AddEventCommand *a = + dynamic_cast *>(*m_commands.rbegin()); if (r && a) { if (a->getEvent() == r->getEvent()) { deleteCommand(a); @@ -134,7 +180,7 @@ MacroCommand::addCommand(command); } - EventEditable *m_editable; + Id m_editable; }; #endif diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/ImageModel.h --- a/data/model/ImageModel.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/ImageModel.h Thu Jun 27 13:08:10 2019 +0100 @@ -231,8 +231,7 @@ case 3: e1 = e0.withLabel(value.toString()); break; } - ChangeEventsCommand *command = - new ChangeEventsCommand(this, tr("Edit Data")); + auto command = new ChangeEventsCommand(getId(), tr("Edit Data")); command->remove(e0); command->add(e1); return command->finish(); diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/Labeller.h --- a/data/model/Labeller.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/Labeller.h Thu Jun 27 13:08:10 2019 +0100 @@ -225,13 +225,16 @@ * Relabel all events in the given event vector that lie within * the given multi-selection, according to the labelling * properties of this labeller. Return a command that has been - * executed but not yet added to the history. + * executed but not yet added to the history. The template + * parameter must be a type that can be dynamic_cast to + * EventEditable and that has a ById store. */ - Command *labelAll(EventEditable *editable, + template + Command *labelAll(typename EditableBase::Id editable, MultiSelection *ms, const EventVector &allEvents) { - ChangeEventsCommand *command = new ChangeEventsCommand + auto command = new ChangeEventsCommand (editable, tr("Label Points")); Event prev; @@ -270,14 +273,17 @@ * that event lies within the given multi-selection, add n-1 new * events at equally spaced intervals between it and the following * event. Return a command that has been executed but not yet - * added to the history. + * added to the history. The template parameter must be a type + * that can be dynamic_cast to EventEditable and that has a ById + * store. */ - Command *subdivide(EventEditable *editable, + template + Command *subdivide(typename EditableBase::Id editable, MultiSelection *ms, const EventVector &allEvents, int n) { - ChangeEventsCommand *command = new ChangeEventsCommand + auto command = new ChangeEventsCommand (editable, tr("Subdivide Points")); for (auto i = allEvents.begin(); i != allEvents.end(); ++i) { @@ -319,14 +325,17 @@ * multi-selection, and a number n, remove all but every nth event * from the vector within the extents of the multi-selection. * Return a command that has been executed but not yet added to - * the history. + * the history. The template parameter must be a type + * that can be dynamic_cast to EventEditable and that has a ById + * store. */ - Command *winnow(EventEditable *editable, + template + Command *winnow(typename EditableBase::Id editable, MultiSelection *ms, const EventVector &allEvents, int n) { - ChangeEventsCommand *command = new ChangeEventsCommand + auto command = new ChangeEventsCommand (editable, tr("Winnow Points")); int counter = 0; diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/Model.h --- a/data/model/Model.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/Model.h Thu Jun 27 13:08:10 2019 +0100 @@ -362,7 +362,7 @@ sv_frame_t m_extendTo; }; -typedef Model::ModelId ModelId; -typedef StaticById ModelById; +typedef Model::Id ModelId; +typedef StaticById ModelById; #endif diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/NoteModel.h --- a/data/model/NoteModel.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/NoteModel.h Thu Jun 27 13:08:10 2019 +0100 @@ -308,8 +308,7 @@ case 5: e1 = e0.withLabel(value.toString()); break; } - ChangeEventsCommand *command = - new ChangeEventsCommand(this, tr("Edit Data")); + auto command = new ChangeEventsCommand(getId(), tr("Edit Data")); command->remove(e0); command->add(e1); return command->finish(); diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/Path.h --- a/data/model/Path.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/Path.h Thu Jun 27 13:08:10 2019 +0100 @@ -96,6 +96,16 @@ // For historical reasons we serialise a Path as a model, // although the class itself no longer is. + + // We also write start and end frames - which our API no + // longer exposes - just for backward compatibility + + sv_frame_t start = 0; + sv_frame_t end = 0; + if (!m_points.empty()) { + start = m_points.begin()->frame; + end = m_points.rbegin()->frame + m_resolution; + } // Our dataset doesn't have its own export ID, we just use // ours. Actually any model could do that, since datasets @@ -104,11 +114,14 @@ out << indent; out << QString("\n") + "start=\"%3\" end=\"%4\" type=\"sparse\" " + "dimensions=\"2\" resolution=\"%5\" " + "notifyOnAdd=\"true\" dataset=\"%6\" " + "subtype=\"path\" %7/>\n") .arg(getExportId()) .arg(m_sampleRate) + .arg(start) + .arg(end) .arg(m_resolution) .arg(getExportId()) .arg(extraAttributes); diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/RegionModel.h --- a/data/model/RegionModel.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/RegionModel.h Thu Jun 27 13:08:10 2019 +0100 @@ -291,8 +291,7 @@ case 4: e1 = e0.withLabel(value.toString()); break; } - ChangeEventsCommand *command = - new ChangeEventsCommand(this, tr("Edit Data")); + auto command = new ChangeEventsCommand(getId(), tr("Edit Data")); command->remove(e0); command->add(e1); return command->finish(); diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/SparseOneDimensionalModel.h --- a/data/model/SparseOneDimensionalModel.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/SparseOneDimensionalModel.h Thu Jun 27 13:08:10 2019 +0100 @@ -239,8 +239,7 @@ case 2: e1 = e0.withLabel(value.toString()); break; } - ChangeEventsCommand *command = - new ChangeEventsCommand(this, tr("Edit Data")); + auto command = new ChangeEventsCommand(getId(), tr("Edit Data")); command->remove(e0); command->add(e1); return command->finish(); diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/SparseTimeValueModel.h --- a/data/model/SparseTimeValueModel.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/SparseTimeValueModel.h Thu Jun 27 13:08:10 2019 +0100 @@ -289,8 +289,7 @@ case 3: e1 = e0.withLabel(value.toString()); break; } - ChangeEventsCommand *command = - new ChangeEventsCommand(this, tr("Edit Data")); + auto command = new ChangeEventsCommand(getId(), tr("Edit Data")); command->remove(e0); command->add(e1); return command->finish(); diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/TextModel.h --- a/data/model/TextModel.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/TextModel.h Thu Jun 27 13:08:10 2019 +0100 @@ -226,8 +226,7 @@ case 3: e1 = e0.withLabel(value.toString()); break; } - ChangeEventsCommand *command = - new ChangeEventsCommand(this, tr("Edit Data")); + auto command = new ChangeEventsCommand(getId(), tr("Edit Data")); command->remove(e0); command->add(e1); return command->finish(); diff -r fe3f7f8df3a3 -r 9d82b164f264 data/model/test/TestSparseModels.h --- a/data/model/test/TestSparseModels.h Wed Jun 26 17:25:20 2019 +0100 +++ b/data/model/test/TestSparseModels.h Thu Jun 27 13:08:10 2019 +0100 @@ -18,7 +18,7 @@ #include "../SparseOneDimensionalModel.h" #include "../NoteModel.h" #include "../TextModel.h" -#include "../PathModel.h" +#include "../Path.h" #include "../ImageModel.h" #include @@ -252,7 +252,7 @@ } void path_xml() { - PathModel m(100, 10, false); + Path m(100, 10); PathPoint p1(20, 30); PathPoint p2(40, 60); PathPoint p3(50, 49);