annotate data/model/EventCommands.h @ 1742:52705a328b34 by-id

Rejig ById so as to put everything in a single pool, so that at the core you can go from numeric id (untyped) to anything the object can be dynamic_cast to. Useful for building other abstractions like PlayParameter-type registrations that don't know about e.g. Models. Probably some more tweaking needed. Also add tests
author Chris Cannam
date Fri, 28 Jun 2019 17:36:30 +0100
parents 9d82b164f264
children
rev   line source
Chris@1648 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1648 2
Chris@1648 3 /*
Chris@1648 4 Sonic Visualiser
Chris@1648 5 An audio file viewer and annotation editor.
Chris@1648 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1648 7 This file copyright 2006 Chris Cannam.
Chris@1648 8
Chris@1648 9 This program is free software; you can redistribute it and/or
Chris@1648 10 modify it under the terms of the GNU General Public License as
Chris@1648 11 published by the Free Software Foundation; either version 2 of the
Chris@1648 12 License, or (at your option) any later version. See the file
Chris@1648 13 COPYING included with this distribution for more information.
Chris@1648 14 */
Chris@1648 15
Chris@1648 16 #ifndef SV_EVENT_COMMANDS_H
Chris@1648 17 #define SV_EVENT_COMMANDS_H
Chris@1648 18
Chris@1648 19 #include "base/Event.h"
Chris@1648 20 #include "base/Command.h"
Chris@1741 21 #include "base/ById.h"
Chris@1648 22
Chris@1648 23 /**
Chris@1648 24 * Interface for classes that can be modified through these commands
Chris@1648 25 */
Chris@1648 26 class EventEditable
Chris@1648 27 {
Chris@1648 28 public:
Chris@1648 29 virtual void add(Event e) = 0;
Chris@1648 30 virtual void remove(Event e) = 0;
Chris@1648 31 };
Chris@1648 32
Chris@1741 33 class WithEditable
Chris@1741 34 {
Chris@1741 35 protected:
Chris@1742 36 WithEditable(int editableId) : m_editableId(editableId) { }
Chris@1741 37
Chris@1741 38 std::shared_ptr<EventEditable> getEditable() {
Chris@1742 39 auto editable = AnyById::getAs<EventEditable>(m_editableId);
Chris@1741 40 if (!editable) {
Chris@1741 41 SVCERR << "WARNING: Id passed to EventEditable command is not that of an EventEditable" << endl;
Chris@1741 42 }
Chris@1741 43 return editable;
Chris@1741 44 }
Chris@1742 45
Chris@1742 46 private:
Chris@1742 47 int m_editableId;
Chris@1741 48 };
Chris@1741 49
Chris@1648 50 /**
Chris@1741 51 * Command to add an event to an editable containing events, with
Chris@1742 52 * undo. The id must be that of a type that can be retrieved from the
Chris@1742 53 * AnyById store and dynamic_cast to EventEditable.
Chris@1648 54 */
Chris@1741 55 class AddEventCommand : public Command,
Chris@1742 56 public WithEditable
Chris@1648 57 {
Chris@1648 58 public:
Chris@1742 59 AddEventCommand(int editableId, const Event &e, QString name) :
Chris@1742 60 WithEditable(editableId), m_event(e), m_name(name) { }
Chris@1648 61
Chris@1648 62 QString getName() const override { return m_name; }
Chris@1648 63 Event getEvent() const { return m_event; }
Chris@1648 64
Chris@1741 65 void execute() override {
Chris@1741 66 auto editable = getEditable();
Chris@1741 67 if (editable) editable->add(m_event);
Chris@1741 68 }
Chris@1741 69 void unexecute() override {
Chris@1741 70 auto editable = getEditable();
Chris@1741 71 if (editable) editable->remove(m_event);
Chris@1741 72 }
Chris@1648 73
Chris@1648 74 private:
Chris@1648 75 Event m_event;
Chris@1648 76 QString m_name;
Chris@1648 77 };
Chris@1648 78
Chris@1648 79 /**
Chris@1648 80 * Command to remove an event from an editable containing events, with
Chris@1742 81 * undo. The id must be that of a type that can be retrieved from the
Chris@1742 82 * AnyById store and dynamic_cast to EventEditable.
Chris@1648 83 */
Chris@1741 84 class RemoveEventCommand : public Command,
Chris@1742 85 public WithEditable
Chris@1648 86 {
Chris@1648 87 public:
Chris@1742 88 RemoveEventCommand(int editableId, const Event &e, QString name) :
Chris@1742 89 WithEditable(editableId), m_event(e), m_name(name) { }
Chris@1648 90
Chris@1648 91 QString getName() const override { return m_name; }
Chris@1648 92 Event getEvent() const { return m_event; }
Chris@1648 93
Chris@1741 94 void execute() override {
Chris@1741 95 auto editable = getEditable();
Chris@1741 96 if (editable) editable->remove(m_event);
Chris@1741 97 }
Chris@1741 98 void unexecute() override {
Chris@1741 99 auto editable = getEditable();
Chris@1741 100 if (editable) editable->add(m_event);
Chris@1741 101 }
Chris@1648 102
Chris@1648 103 private:
Chris@1648 104 Event m_event;
Chris@1648 105 QString m_name;
Chris@1648 106 };
Chris@1648 107
Chris@1648 108 /**
Chris@1648 109 * Command to add or remove a series of events to or from an editable,
Chris@1648 110 * with undo. Creates and immediately executes a sub-command for each
Chris@1648 111 * add/remove requested. Consecutive add/remove pairs for the same
Chris@1742 112 * point are collapsed. The id must be that of a type that can be
Chris@1742 113 * retrieved from the AnyById store and dynamic_cast to EventEditable.
Chris@1648 114 */
Chris@1648 115 class ChangeEventsCommand : public MacroCommand
Chris@1648 116 {
Chris@1648 117 public:
Chris@1742 118 ChangeEventsCommand(int editableId, QString name) :
Chris@1742 119 MacroCommand(name), m_editableId(editableId) { }
Chris@1648 120
Chris@1648 121 void add(Event e) {
Chris@1742 122 addCommand(new AddEventCommand(m_editableId, e, getName()), true);
Chris@1648 123 }
Chris@1648 124 void remove(Event e) {
Chris@1742 125 addCommand(new RemoveEventCommand(m_editableId, e, getName()), true);
Chris@1648 126 }
Chris@1648 127
Chris@1648 128 /**
Chris@1648 129 * Stack an arbitrary other command in the same sequence.
Chris@1648 130 */
Chris@1648 131 void addCommand(Command *command) override { addCommand(command, true); }
Chris@1648 132
Chris@1648 133 /**
Chris@1648 134 * If any points have been added or deleted, return this
Chris@1648 135 * command (so the caller can add it to the command history).
Chris@1648 136 * Otherwise delete the command and return NULL.
Chris@1648 137 */
Chris@1648 138 ChangeEventsCommand *finish() {
Chris@1648 139 if (!m_commands.empty()) {
Chris@1648 140 return this;
Chris@1648 141 } else {
Chris@1648 142 delete this;
Chris@1648 143 return nullptr;
Chris@1648 144 }
Chris@1648 145 }
Chris@1648 146
Chris@1648 147 protected:
Chris@1648 148 virtual void addCommand(Command *command, bool executeFirst) {
Chris@1648 149
Chris@1648 150 if (executeFirst) command->execute();
Chris@1648 151
Chris@1648 152 if (m_commands.empty()) {
Chris@1648 153 MacroCommand::addCommand(command);
Chris@1648 154 return;
Chris@1648 155 }
Chris@1648 156
Chris@1742 157 RemoveEventCommand *r =
Chris@1742 158 dynamic_cast<RemoveEventCommand *>(command);
Chris@1742 159 AddEventCommand *a =
Chris@1742 160 dynamic_cast<AddEventCommand *>(*m_commands.rbegin());
Chris@1648 161 if (r && a) {
Chris@1648 162 if (a->getEvent() == r->getEvent()) {
Chris@1648 163 deleteCommand(a);
Chris@1648 164 return;
Chris@1648 165 }
Chris@1648 166 }
Chris@1648 167
Chris@1648 168 MacroCommand::addCommand(command);
Chris@1648 169 }
Chris@1648 170
Chris@1742 171 int m_editableId;
Chris@1648 172 };
Chris@1648 173
Chris@1648 174 #endif