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
|