1 /* Copyright (C) 2010 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #include "precompiled.h"
20 #include "CommandProc.h"
25 //////////////////////////////////////////////////////////////////////////
27 template<typename T
> T
next_it(T x
) { T t
= x
; return ++t
; }
29 template<typename T
> void delete_fn(T
* v
) { delete v
; }
31 //////////////////////////////////////////////////////////////////////////
33 using namespace AtlasMessage
;
35 namespace AtlasMessage
{
37 CommandProc
& GetCommandProc()
39 static CommandProc commandProc
;
43 cmdHandlers
& GetCmdHandlers()
51 CommandProc::CommandProc()
53 // Start the list with a NULL, so m_CurrentCommand can point at
54 // something even when the command stack is empty
55 m_Commands
.push_back(NULL
);
57 m_CurrentCommand
= m_Commands
.begin();
60 CommandProc::~CommandProc()
62 // Make sure Destroy has been called before now (to avoid
63 // problems from the destruction order of static variables)
64 ENSURE(!m_Commands
.size());
67 void CommandProc::Destroy()
69 std::for_each(m_Commands
.begin(), m_Commands
.end(), delete_fn
<Command
>);
73 void CommandProc::Submit(Command
* cmd
)
75 // If some commands have been undone at the time we insert this new one,
76 // delete and remove them all.
77 std::for_each(next_it(m_CurrentCommand
), m_Commands
.end(), delete_fn
<Command
>);
78 m_Commands
.erase(next_it(m_CurrentCommand
), m_Commands
.end());
79 assert(next_it(m_CurrentCommand
) == m_Commands
.end());
81 m_CurrentCommand
= m_Commands
.insert(next_it(m_CurrentCommand
), cmd
);
83 (*m_CurrentCommand
)->Do();
86 void CommandProc::Undo()
88 if (m_CurrentCommand
!= m_Commands
.begin())
90 (*m_CurrentCommand
)->Undo();
95 void CommandProc::Redo()
97 if (next_it(m_CurrentCommand
) != m_Commands
.end())
100 (*m_CurrentCommand
)->Redo();
104 void CommandProc::Merge()
106 if (m_CurrentCommand
== m_Commands
.begin())
108 debug_warn(L
"Merge illogic: no commands");
112 if (next_it(m_CurrentCommand
) != m_Commands
.end())
114 debug_warn(L
"Merge illogic: not at stack top");
118 cmdIt prev
= m_CurrentCommand
;
121 if (prev
== m_Commands
.begin())
123 debug_warn(L
"Merge illogic: only 1 command");
127 if ((*prev
)->GetType() != (*m_CurrentCommand
)->GetType())
129 const char* a
= (*prev
)->GetType();
130 const char* b
= (*m_CurrentCommand
)->GetType();
131 debug_printf("[incompatible: %s -> %s]\n", a
, b
);
132 debug_warn(L
"Merge illogic: incompatible command");
136 (*m_CurrentCommand
)->Merge(*prev
);
138 delete *m_CurrentCommand
;
139 m_Commands
.erase(m_CurrentCommand
);
141 m_CurrentCommand
= prev
;