| 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 |