Chris@1648: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1648: Chris@1648: /* Chris@1648: Sonic Visualiser Chris@1648: An audio file viewer and annotation editor. Chris@1648: Centre for Digital Music, Queen Mary, University of London. Chris@1648: This file copyright 2006 Chris Cannam. Chris@1648: Chris@1648: This program is free software; you can redistribute it and/or Chris@1648: modify it under the terms of the GNU General Public License as Chris@1648: published by the Free Software Foundation; either version 2 of the Chris@1648: License, or (at your option) any later version. See the file Chris@1648: COPYING included with this distribution for more information. Chris@1648: */ Chris@1648: Chris@1648: #ifndef SV_EVENT_COMMANDS_H Chris@1648: #define SV_EVENT_COMMANDS_H Chris@1648: Chris@1648: #include "base/Event.h" Chris@1648: #include "base/Command.h" Chris@1648: Chris@1648: /** Chris@1648: * Interface for classes that can be modified through these commands Chris@1648: */ Chris@1648: class EventEditable Chris@1648: { Chris@1648: public: Chris@1648: virtual void add(Event e) = 0; Chris@1648: virtual void remove(Event e) = 0; Chris@1648: }; Chris@1648: Chris@1648: /** Chris@1648: * Command to add an event to an editable containing events, with undo. Chris@1648: */ Chris@1648: class AddEventCommand : public Command Chris@1648: { Chris@1648: public: Chris@1648: AddEventCommand(EventEditable *editable, const Event &e, QString name) : Chris@1648: m_editable(editable), m_event(e), m_name(name) { } Chris@1648: Chris@1648: QString getName() const override { return m_name; } Chris@1648: Event getEvent() const { return m_event; } Chris@1648: Chris@1648: void execute() override { m_editable->add(m_event); } Chris@1648: void unexecute() override { m_editable->remove(m_event); } Chris@1648: Chris@1648: private: Chris@1648: EventEditable *m_editable; Chris@1648: Event m_event; Chris@1648: QString m_name; Chris@1648: }; Chris@1648: Chris@1648: /** Chris@1648: * Command to remove an event from an editable containing events, with Chris@1648: * undo. Chris@1648: */ Chris@1648: class RemoveEventCommand : public Command Chris@1648: { Chris@1648: public: Chris@1648: RemoveEventCommand(EventEditable *editable, const Event &e, QString name) : Chris@1648: m_editable(editable), m_event(e), m_name(name) { } Chris@1648: Chris@1648: QString getName() const override { return m_name; } Chris@1648: Event getEvent() const { return m_event; } Chris@1648: Chris@1648: void execute() override { m_editable->remove(m_event); } Chris@1648: void unexecute() override { m_editable->add(m_event); } Chris@1648: Chris@1648: private: Chris@1648: EventEditable *m_editable; Chris@1648: Event m_event; Chris@1648: QString m_name; Chris@1648: }; Chris@1648: Chris@1648: /** Chris@1648: * Command to add or remove a series of events to or from an editable, Chris@1648: * with undo. Creates and immediately executes a sub-command for each Chris@1648: * add/remove requested. Consecutive add/remove pairs for the same Chris@1648: * point are collapsed. Chris@1648: */ Chris@1648: class ChangeEventsCommand : public MacroCommand Chris@1648: { Chris@1648: public: Chris@1648: ChangeEventsCommand(EventEditable *editable, QString name) : Chris@1648: MacroCommand(name), m_editable(editable) { } Chris@1648: Chris@1648: void add(Event e) { Chris@1648: addCommand(new AddEventCommand(m_editable, e, getName()), true); Chris@1648: } Chris@1648: void remove(Event e) { Chris@1648: addCommand(new RemoveEventCommand(m_editable, e, getName()), true); Chris@1648: } Chris@1648: Chris@1648: /** Chris@1648: * Stack an arbitrary other command in the same sequence. Chris@1648: */ Chris@1648: void addCommand(Command *command) override { addCommand(command, true); } Chris@1648: Chris@1648: /** Chris@1648: * If any points have been added or deleted, return this Chris@1648: * command (so the caller can add it to the command history). Chris@1648: * Otherwise delete the command and return NULL. Chris@1648: */ Chris@1648: ChangeEventsCommand *finish() { Chris@1648: if (!m_commands.empty()) { Chris@1648: return this; Chris@1648: } else { Chris@1648: delete this; Chris@1648: return nullptr; Chris@1648: } Chris@1648: } Chris@1648: Chris@1648: protected: Chris@1648: virtual void addCommand(Command *command, bool executeFirst) { Chris@1648: Chris@1648: if (executeFirst) command->execute(); Chris@1648: Chris@1648: if (m_commands.empty()) { Chris@1648: MacroCommand::addCommand(command); Chris@1648: return; Chris@1648: } Chris@1648: Chris@1648: RemoveEventCommand *r = Chris@1648: dynamic_cast(command); Chris@1648: AddEventCommand *a = Chris@1648: dynamic_cast(*m_commands.rbegin()); Chris@1648: if (r && a) { Chris@1648: if (a->getEvent() == r->getEvent()) { Chris@1648: deleteCommand(a); Chris@1648: return; Chris@1648: } Chris@1648: } Chris@1648: Chris@1648: MacroCommand::addCommand(command); Chris@1648: } Chris@1648: Chris@1648: EventEditable *m_editable; Chris@1648: }; Chris@1648: Chris@1648: #endif