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 template <typename Base>
|
Chris@1741
|
34 class WithEditable
|
Chris@1741
|
35 {
|
Chris@1741
|
36 typedef typename Base::Id Id;
|
Chris@1741
|
37 Id m_id;
|
Chris@1741
|
38
|
Chris@1741
|
39 protected:
|
Chris@1741
|
40 WithEditable(Id id) : m_id(id) { }
|
Chris@1741
|
41
|
Chris@1741
|
42 std::shared_ptr<EventEditable> getEditable() {
|
Chris@1741
|
43 auto base = StaticById<Base, Id>::get(m_id);
|
Chris@1741
|
44 if (!base) return {}; // acceptable - item has expired
|
Chris@1741
|
45 auto editable = std::dynamic_pointer_cast<EventEditable>(base);
|
Chris@1741
|
46 if (!editable) {
|
Chris@1741
|
47 SVCERR << "WARNING: Id passed to EventEditable command is not that of an EventEditable" << endl;
|
Chris@1741
|
48 }
|
Chris@1741
|
49 return editable;
|
Chris@1741
|
50 }
|
Chris@1741
|
51 };
|
Chris@1741
|
52
|
Chris@1648
|
53 /**
|
Chris@1741
|
54 * Command to add an event to an editable containing events, with
|
Chris@1741
|
55 * undo. The template parameter must be a type that can be
|
Chris@1741
|
56 * dynamic_cast to EventEditable and that has a ById store.
|
Chris@1648
|
57 */
|
Chris@1741
|
58 template <typename Base>
|
Chris@1741
|
59 class AddEventCommand : public Command,
|
Chris@1741
|
60 public WithEditable<Base>
|
Chris@1648
|
61 {
|
Chris@1648
|
62 public:
|
Chris@1741
|
63 AddEventCommand(typename Base::Id editable, const Event &e, QString name) :
|
Chris@1741
|
64 WithEditable<Base>(editable), m_event(e), m_name(name) { }
|
Chris@1648
|
65
|
Chris@1648
|
66 QString getName() const override { return m_name; }
|
Chris@1648
|
67 Event getEvent() const { return m_event; }
|
Chris@1648
|
68
|
Chris@1741
|
69 void execute() override {
|
Chris@1741
|
70 auto editable = getEditable();
|
Chris@1741
|
71 if (editable) editable->add(m_event);
|
Chris@1741
|
72 }
|
Chris@1741
|
73 void unexecute() override {
|
Chris@1741
|
74 auto editable = getEditable();
|
Chris@1741
|
75 if (editable) editable->remove(m_event);
|
Chris@1741
|
76 }
|
Chris@1648
|
77
|
Chris@1648
|
78 private:
|
Chris@1648
|
79 Event m_event;
|
Chris@1648
|
80 QString m_name;
|
Chris@1741
|
81 using WithEditable<Base>::getEditable;
|
Chris@1648
|
82 };
|
Chris@1648
|
83
|
Chris@1648
|
84 /**
|
Chris@1648
|
85 * Command to remove an event from an editable containing events, with
|
Chris@1741
|
86 * undo. The template parameter must be a type that implements
|
Chris@1741
|
87 * EventBase and that has a ById store.
|
Chris@1648
|
88 */
|
Chris@1741
|
89 template <typename Base>
|
Chris@1741
|
90 class RemoveEventCommand : public Command,
|
Chris@1741
|
91 public WithEditable<Base>
|
Chris@1648
|
92 {
|
Chris@1648
|
93 public:
|
Chris@1741
|
94 RemoveEventCommand(typename Base::Id editable, const Event &e, QString name) :
|
Chris@1741
|
95 WithEditable<Base>(editable), m_event(e), m_name(name) { }
|
Chris@1648
|
96
|
Chris@1648
|
97 QString getName() const override { return m_name; }
|
Chris@1648
|
98 Event getEvent() const { return m_event; }
|
Chris@1648
|
99
|
Chris@1741
|
100 void execute() override {
|
Chris@1741
|
101 auto editable = getEditable();
|
Chris@1741
|
102 if (editable) editable->remove(m_event);
|
Chris@1741
|
103 }
|
Chris@1741
|
104 void unexecute() override {
|
Chris@1741
|
105 auto editable = getEditable();
|
Chris@1741
|
106 if (editable) editable->add(m_event);
|
Chris@1741
|
107 }
|
Chris@1648
|
108
|
Chris@1648
|
109 private:
|
Chris@1648
|
110 Event m_event;
|
Chris@1648
|
111 QString m_name;
|
Chris@1741
|
112 using WithEditable<Base>::getEditable;
|
Chris@1648
|
113 };
|
Chris@1648
|
114
|
Chris@1648
|
115 /**
|
Chris@1648
|
116 * Command to add or remove a series of events to or from an editable,
|
Chris@1648
|
117 * with undo. Creates and immediately executes a sub-command for each
|
Chris@1648
|
118 * add/remove requested. Consecutive add/remove pairs for the same
|
Chris@1741
|
119 * point are collapsed. The template parameter must be a type that
|
Chris@1741
|
120 * implements EventBase and that has a ById store.
|
Chris@1648
|
121 */
|
Chris@1741
|
122 template <typename Base>
|
Chris@1648
|
123 class ChangeEventsCommand : public MacroCommand
|
Chris@1648
|
124 {
|
Chris@1741
|
125 typedef typename Base::Id Id;
|
Chris@1741
|
126
|
Chris@1648
|
127 public:
|
Chris@1741
|
128 ChangeEventsCommand(Id editable, QString name) :
|
Chris@1648
|
129 MacroCommand(name), m_editable(editable) { }
|
Chris@1648
|
130
|
Chris@1648
|
131 void add(Event e) {
|
Chris@1741
|
132 addCommand(new AddEventCommand<Base>(m_editable, e, getName()),
|
Chris@1741
|
133 true);
|
Chris@1648
|
134 }
|
Chris@1648
|
135 void remove(Event e) {
|
Chris@1741
|
136 addCommand(new RemoveEventCommand<Base>(m_editable, e, getName()),
|
Chris@1741
|
137 true);
|
Chris@1648
|
138 }
|
Chris@1648
|
139
|
Chris@1648
|
140 /**
|
Chris@1648
|
141 * Stack an arbitrary other command in the same sequence.
|
Chris@1648
|
142 */
|
Chris@1648
|
143 void addCommand(Command *command) override { addCommand(command, true); }
|
Chris@1648
|
144
|
Chris@1648
|
145 /**
|
Chris@1648
|
146 * If any points have been added or deleted, return this
|
Chris@1648
|
147 * command (so the caller can add it to the command history).
|
Chris@1648
|
148 * Otherwise delete the command and return NULL.
|
Chris@1648
|
149 */
|
Chris@1648
|
150 ChangeEventsCommand *finish() {
|
Chris@1648
|
151 if (!m_commands.empty()) {
|
Chris@1648
|
152 return this;
|
Chris@1648
|
153 } else {
|
Chris@1648
|
154 delete this;
|
Chris@1648
|
155 return nullptr;
|
Chris@1648
|
156 }
|
Chris@1648
|
157 }
|
Chris@1648
|
158
|
Chris@1648
|
159 protected:
|
Chris@1648
|
160 virtual void addCommand(Command *command, bool executeFirst) {
|
Chris@1648
|
161
|
Chris@1648
|
162 if (executeFirst) command->execute();
|
Chris@1648
|
163
|
Chris@1648
|
164 if (m_commands.empty()) {
|
Chris@1648
|
165 MacroCommand::addCommand(command);
|
Chris@1648
|
166 return;
|
Chris@1648
|
167 }
|
Chris@1648
|
168
|
Chris@1741
|
169 RemoveEventCommand<Base> *r =
|
Chris@1741
|
170 dynamic_cast<RemoveEventCommand<Base> *>(command);
|
Chris@1741
|
171 AddEventCommand<Base> *a =
|
Chris@1741
|
172 dynamic_cast<AddEventCommand<Base> *>(*m_commands.rbegin());
|
Chris@1648
|
173 if (r && a) {
|
Chris@1648
|
174 if (a->getEvent() == r->getEvent()) {
|
Chris@1648
|
175 deleteCommand(a);
|
Chris@1648
|
176 return;
|
Chris@1648
|
177 }
|
Chris@1648
|
178 }
|
Chris@1648
|
179
|
Chris@1648
|
180 MacroCommand::addCommand(command);
|
Chris@1648
|
181 }
|
Chris@1648
|
182
|
Chris@1741
|
183 Id m_editable;
|
Chris@1648
|
184 };
|
Chris@1648
|
185
|
Chris@1648
|
186 #endif
|