Loading...
Searching...
No Matches
MultiOngoingCommandDispatcher.hpp
1#pragma once
2#include <score/command/Dispatchers/ICommandDispatcher.hpp>
3#include <score/command/Dispatchers/SendStrategy.hpp>
4#include <score/selection/SelectionStack.hpp>
5
6// Creates commands on a list and keep updating the latest command
7// up to the next new command.
8namespace RollbackStrategy
9{
10struct Simple
11{
12 static void
13 rollback(const score::DocumentContext& ctx, const std::vector<score::Command*>& cmds)
14 {
15 if(cmds.empty())
16 return;
17
18 for(int i = cmds.size() - 1; i >= 0; --i)
19 {
20 cmds[i]->undo(ctx);
21 }
22 }
23};
24}
25
37{
38public:
40 : ICommandDispatcher{stack}
41 {
42 }
43
44 ~MultiOngoingCommandDispatcher() { cleanup(); }
45
46 void submit(score::Command* cmd)
47 {
48 stack().disableActions();
49 {
50 score::SelectionStack::Batch b{stack().selectionStack()};
51 cmd->redo(stack().context());
52 }
53 m_cmds.push_back(cmd);
54 }
55
56 void submitQuiet(score::Command* cmd)
57 {
58 stack().disableActions();
59 m_cmds.push_back(cmd);
60 }
61
62 template <typename TheCommand, typename... Args>
63 void submit(Args&&... args)
64 {
65 score::SelectionStack::Batch b{stack().selectionStack()};
66 if(m_cmds.empty())
67 {
68 stack().disableActions();
69 auto cmd = new TheCommand(std::forward<Args>(args)...);
70 cmd->redo(stack().context());
71 m_cmds.push_back(cmd);
72 }
73 else
74 {
75 score::Command* last = m_cmds.back();
76 if(last->key() == TheCommand::static_key())
77 {
78 auto cmd = safe_cast<TheCommand*>(last);
79 if constexpr(requires { bool(cmd->compatible(std::forward<Args>(args)...)); })
80 {
81 if(cmd->compatible(std::forward<Args>(args)...))
82 {
83 cmd->update(std::forward<Args>(args)...);
84 cmd->redo(stack().context());
85 }
86 else
87 {
88 auto cmd = new TheCommand(std::forward<Args>(args)...);
89 cmd->redo(stack().context());
90 m_cmds.push_back(cmd);
91 }
92 }
93 else
94 {
95 cmd->update(std::forward<Args>(args)...);
96 cmd->redo(stack().context());
97 }
98 }
99 else
100 {
101 auto cmd = new TheCommand(std::forward<Args>(args)...);
102 cmd->redo(stack().context());
103 m_cmds.push_back(cmd);
104 }
105 }
106 }
107
108 // Give it something that behaves like AggregateCommand
109 template <typename CommitCommand>
110 void commit()
111 {
112 if(!m_cmds.empty())
113 {
114 auto theCmd = new CommitCommand;
115 for(auto& cmd : m_cmds)
116 {
117 theCmd->addCommand(cmd);
118 }
119
120 SendStrategy::Quiet::send(stack(), theCmd);
121 m_cmds.clear();
122
123 stack().enableActions();
124 }
125 }
126
127 template <typename RollbackStrategy = RollbackStrategy::Simple>
128 void rollback()
129 {
130 {
131 score::SelectionStack::Batch b{stack().selectionStack()};
132 RollbackStrategy::rollback(stack().context(), m_cmds);
133 }
134
135 cleanup();
136 m_cmds.clear();
137
138 stack().enableActions();
139 }
140
141private:
142 void cleanup()
143 {
144 std::for_each(m_cmds.rbegin(), m_cmds.rend(), [](auto cmd) { delete cmd; });
145 }
146
147 std::vector<score::Command*> m_cmds;
148};
The ICommandDispatcher class.
Definition ICommandDispatcher.hpp:21
The MultiOngoingCommandDispatcher class.
Definition MultiOngoingCommandDispatcher.hpp:37
The Command class.
Definition Command.hpp:34
A small abstraction layer over the score::CommandStack.
Definition CommandStackFacade.hpp:21
Definition SelectionStack.hpp:72
Definition MultiOngoingCommandDispatcher.hpp:11
Definition DocumentContext.hpp:18