2006-04-24 01:14:18 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
|
|
|
#include "CommandProc.h"
|
|
|
|
|
2006-11-12 05:02:36 +01:00
|
|
|
#include <cassert>
|
2006-04-24 01:14:18 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
template<typename T> T next(T x) { T t = x; return ++t; }
|
|
|
|
|
|
|
|
template<typename T> void delete_fn(T* v) { delete v; }
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
using namespace AtlasMessage;
|
|
|
|
|
|
|
|
namespace AtlasMessage {
|
|
|
|
|
|
|
|
CommandProc& GetCommandProc()
|
|
|
|
{
|
|
|
|
static CommandProc commandProc;
|
|
|
|
return commandProc;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmdHandlers& GetCmdHandlers()
|
|
|
|
{
|
|
|
|
static cmdHandlers h;
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CommandProc::CommandProc()
|
|
|
|
{
|
|
|
|
// Start the list with a NULL, so m_CurrentCommand can point at
|
|
|
|
// something even when the command stack is empty
|
|
|
|
m_Commands.push_back(NULL);
|
|
|
|
|
|
|
|
m_CurrentCommand = m_Commands.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
CommandProc::~CommandProc()
|
|
|
|
{
|
|
|
|
// Make sure Destroy has been called before now (to avoid
|
|
|
|
// problems from the destruction order of static variables)
|
|
|
|
debug_assert(!m_Commands.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandProc::Destroy()
|
|
|
|
{
|
|
|
|
std::for_each(m_Commands.begin(), m_Commands.end(), delete_fn<Command>);
|
|
|
|
m_Commands.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandProc::Submit(Command* cmd)
|
|
|
|
{
|
2006-05-04 04:44:03 +02:00
|
|
|
// If some commands have been undone at the time we insert this new one,
|
|
|
|
// delete and remove them all.
|
|
|
|
std::for_each(next(m_CurrentCommand), m_Commands.end(), delete_fn<Command>);
|
|
|
|
m_Commands.erase(next(m_CurrentCommand), m_Commands.end());
|
|
|
|
assert(next(m_CurrentCommand) == m_Commands.end());
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
m_CurrentCommand = m_Commands.insert(next(m_CurrentCommand), cmd);
|
|
|
|
|
|
|
|
(*m_CurrentCommand)->Do();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandProc::Undo()
|
|
|
|
{
|
|
|
|
if (m_CurrentCommand != m_Commands.begin())
|
|
|
|
{
|
|
|
|
(*m_CurrentCommand)->Undo();
|
|
|
|
--m_CurrentCommand;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandProc::Redo()
|
|
|
|
{
|
|
|
|
if (next(m_CurrentCommand) != m_Commands.end())
|
|
|
|
{
|
|
|
|
++m_CurrentCommand;
|
|
|
|
(*m_CurrentCommand)->Redo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandProc::Merge()
|
|
|
|
{
|
|
|
|
if (m_CurrentCommand == m_Commands.begin())
|
|
|
|
{
|
|
|
|
debug_warn("Merge illogic: no commands");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (next(m_CurrentCommand) != m_Commands.end())
|
|
|
|
{
|
|
|
|
debug_warn("Merge illogic: not at stack top");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmdIt prev = m_CurrentCommand;
|
|
|
|
--prev;
|
|
|
|
|
|
|
|
if (prev == m_Commands.begin())
|
|
|
|
{
|
|
|
|
debug_warn("Merge illogic: only 1 command");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((*prev)->GetType() != (*m_CurrentCommand)->GetType())
|
|
|
|
{
|
|
|
|
const char* a = (*prev)->GetType();
|
|
|
|
const char* b = (*m_CurrentCommand)->GetType();
|
|
|
|
debug_printf("[incompatible: %s -> %s]\n", a, b);
|
|
|
|
debug_warn("Merge illogic: incompatible command");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*m_CurrentCommand)->Merge(*prev);
|
|
|
|
|
|
|
|
delete *m_CurrentCommand;
|
|
|
|
m_Commands.erase(m_CurrentCommand);
|
|
|
|
|
|
|
|
m_CurrentCommand = prev;
|
|
|
|
}
|