comparison data/model/EventCommands.h @ 1741:9d82b164f264 by-id

Work on commands, and some other model updates
author Chris Cannam
date Thu, 27 Jun 2019 13:08:10 +0100
parents 86bbccb79c9b
children 52705a328b34
comparison
equal deleted inserted replaced
1740:fe3f7f8df3a3 1741:9d82b164f264
16 #ifndef SV_EVENT_COMMANDS_H 16 #ifndef SV_EVENT_COMMANDS_H
17 #define SV_EVENT_COMMANDS_H 17 #define SV_EVENT_COMMANDS_H
18 18
19 #include "base/Event.h" 19 #include "base/Event.h"
20 #include "base/Command.h" 20 #include "base/Command.h"
21 #include "base/ById.h"
21 22
22 /** 23 /**
23 * Interface for classes that can be modified through these commands 24 * Interface for classes that can be modified through these commands
24 */ 25 */
25 class EventEditable 26 class EventEditable
27 public: 28 public:
28 virtual void add(Event e) = 0; 29 virtual void add(Event e) = 0;
29 virtual void remove(Event e) = 0; 30 virtual void remove(Event e) = 0;
30 }; 31 };
31 32
33 template <typename Base>
34 class WithEditable
35 {
36 typedef typename Base::Id Id;
37 Id m_id;
38
39 protected:
40 WithEditable(Id id) : m_id(id) { }
41
42 std::shared_ptr<EventEditable> getEditable() {
43 auto base = StaticById<Base, Id>::get(m_id);
44 if (!base) return {}; // acceptable - item has expired
45 auto editable = std::dynamic_pointer_cast<EventEditable>(base);
46 if (!editable) {
47 SVCERR << "WARNING: Id passed to EventEditable command is not that of an EventEditable" << endl;
48 }
49 return editable;
50 }
51 };
52
32 /** 53 /**
33 * Command to add an event to an editable containing events, with undo. 54 * Command to add an event to an editable containing events, with
55 * undo. The template parameter must be a type that can be
56 * dynamic_cast to EventEditable and that has a ById store.
34 */ 57 */
35 class AddEventCommand : public Command 58 template <typename Base>
59 class AddEventCommand : public Command,
60 public WithEditable<Base>
36 { 61 {
37 public: 62 public:
38 AddEventCommand(EventEditable *editable, const Event &e, QString name) : 63 AddEventCommand(typename Base::Id editable, const Event &e, QString name) :
39 m_editable(editable), m_event(e), m_name(name) { } 64 WithEditable<Base>(editable), m_event(e), m_name(name) { }
40 65
41 QString getName() const override { return m_name; } 66 QString getName() const override { return m_name; }
42 Event getEvent() const { return m_event; } 67 Event getEvent() const { return m_event; }
43 68
44 void execute() override { m_editable->add(m_event); } 69 void execute() override {
45 void unexecute() override { m_editable->remove(m_event); } 70 auto editable = getEditable();
71 if (editable) editable->add(m_event);
72 }
73 void unexecute() override {
74 auto editable = getEditable();
75 if (editable) editable->remove(m_event);
76 }
46 77
47 private: 78 private:
48 EventEditable *m_editable;
49 Event m_event; 79 Event m_event;
50 QString m_name; 80 QString m_name;
81 using WithEditable<Base>::getEditable;
51 }; 82 };
52 83
53 /** 84 /**
54 * Command to remove an event from an editable containing events, with 85 * Command to remove an event from an editable containing events, with
55 * undo. 86 * undo. The template parameter must be a type that implements
87 * EventBase and that has a ById store.
56 */ 88 */
57 class RemoveEventCommand : public Command 89 template <typename Base>
90 class RemoveEventCommand : public Command,
91 public WithEditable<Base>
58 { 92 {
59 public: 93 public:
60 RemoveEventCommand(EventEditable *editable, const Event &e, QString name) : 94 RemoveEventCommand(typename Base::Id editable, const Event &e, QString name) :
61 m_editable(editable), m_event(e), m_name(name) { } 95 WithEditable<Base>(editable), m_event(e), m_name(name) { }
62 96
63 QString getName() const override { return m_name; } 97 QString getName() const override { return m_name; }
64 Event getEvent() const { return m_event; } 98 Event getEvent() const { return m_event; }
65 99
66 void execute() override { m_editable->remove(m_event); } 100 void execute() override {
67 void unexecute() override { m_editable->add(m_event); } 101 auto editable = getEditable();
102 if (editable) editable->remove(m_event);
103 }
104 void unexecute() override {
105 auto editable = getEditable();
106 if (editable) editable->add(m_event);
107 }
68 108
69 private: 109 private:
70 EventEditable *m_editable;
71 Event m_event; 110 Event m_event;
72 QString m_name; 111 QString m_name;
112 using WithEditable<Base>::getEditable;
73 }; 113 };
74 114
75 /** 115 /**
76 * Command to add or remove a series of events to or from an editable, 116 * Command to add or remove a series of events to or from an editable,
77 * with undo. Creates and immediately executes a sub-command for each 117 * with undo. Creates and immediately executes a sub-command for each
78 * add/remove requested. Consecutive add/remove pairs for the same 118 * add/remove requested. Consecutive add/remove pairs for the same
79 * point are collapsed. 119 * point are collapsed. The template parameter must be a type that
120 * implements EventBase and that has a ById store.
80 */ 121 */
122 template <typename Base>
81 class ChangeEventsCommand : public MacroCommand 123 class ChangeEventsCommand : public MacroCommand
82 { 124 {
125 typedef typename Base::Id Id;
126
83 public: 127 public:
84 ChangeEventsCommand(EventEditable *editable, QString name) : 128 ChangeEventsCommand(Id editable, QString name) :
85 MacroCommand(name), m_editable(editable) { } 129 MacroCommand(name), m_editable(editable) { }
86 130
87 void add(Event e) { 131 void add(Event e) {
88 addCommand(new AddEventCommand(m_editable, e, getName()), true); 132 addCommand(new AddEventCommand<Base>(m_editable, e, getName()),
133 true);
89 } 134 }
90 void remove(Event e) { 135 void remove(Event e) {
91 addCommand(new RemoveEventCommand(m_editable, e, getName()), true); 136 addCommand(new RemoveEventCommand<Base>(m_editable, e, getName()),
137 true);
92 } 138 }
93 139
94 /** 140 /**
95 * Stack an arbitrary other command in the same sequence. 141 * Stack an arbitrary other command in the same sequence.
96 */ 142 */
118 if (m_commands.empty()) { 164 if (m_commands.empty()) {
119 MacroCommand::addCommand(command); 165 MacroCommand::addCommand(command);
120 return; 166 return;
121 } 167 }
122 168
123 RemoveEventCommand *r = 169 RemoveEventCommand<Base> *r =
124 dynamic_cast<RemoveEventCommand *>(command); 170 dynamic_cast<RemoveEventCommand<Base> *>(command);
125 AddEventCommand *a = 171 AddEventCommand<Base> *a =
126 dynamic_cast<AddEventCommand *>(*m_commands.rbegin()); 172 dynamic_cast<AddEventCommand<Base> *>(*m_commands.rbegin());
127 if (r && a) { 173 if (r && a) {
128 if (a->getEvent() == r->getEvent()) { 174 if (a->getEvent() == r->getEvent()) {
129 deleteCommand(a); 175 deleteCommand(a);
130 return; 176 return;
131 } 177 }
132 } 178 }
133 179
134 MacroCommand::addCommand(command); 180 MacroCommand::addCommand(command);
135 } 181 }
136 182
137 EventEditable *m_editable; 183 Id m_editable;
138 }; 184 };
139 185
140 #endif 186 #endif