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