- typedef std::set<UndoTracker*> Trackers;
- Trackers m_trackers;
-public:
- RadiantUndoSystem()
- : m_undo_levels(64)
- {
- }
- ~RadiantUndoSystem()
- {
- clear();
- }
- UndoObserver* observer(Undoable* undoable)
- {
- ASSERT_NOTNULL(undoable);
-
- return &m_undoables[undoable];
- }
- void release(Undoable* undoable)
- {
- ASSERT_NOTNULL(undoable);
-
- m_undoables.erase(undoable);
- }
- void setLevels(std::size_t levels)
- {
- if(levels > MAX_UNDO_LEVELS())
- {
- levels = MAX_UNDO_LEVELS();
- }
-
- while(m_undo_stack.size() > levels)
- {
- m_undo_stack.pop_front();
- }
- m_undo_levels = levels;
- }
- std::size_t getLevels() const
- {
- return m_undo_levels;
- }
- std::size_t size() const
- {
- return m_undo_stack.size();
- }
- void startUndo()
- {
- m_undo_stack.start("unnamedCommand");
- mark_undoables(&m_undo_stack);
- }
- bool finishUndo(const char* command)
- {
- bool changed = m_undo_stack.finish(command);
- mark_undoables(0);
- return changed;
- }
- void startRedo()
- {
- m_redo_stack.start("unnamedCommand");
- mark_undoables(&m_redo_stack);
- }
- bool finishRedo(const char* command)
- {
- bool changed = m_redo_stack.finish(command);
- mark_undoables(0);
- return changed;
- }
- void start()
- {
- m_redo_stack.clear();
- if(m_undo_stack.size() == m_undo_levels)
- {
- m_undo_stack.pop_front();
- }
- startUndo();
- trackersBegin();
- }
- void finish(const char* command)
- {
- if(finishUndo(command))
- {
- globalOutputStream() << command << '\n';
- }
- }
- void undo()
- {
- if(m_undo_stack.empty())
- {
- globalOutputStream() << "Undo: no undo available\n";
- }
- else
- {
- Operation* operation = m_undo_stack.back();
- globalOutputStream() << "Undo: " << operation->m_command.c_str() << "\n";
-
- startRedo();
- trackersUndo();
- operation->m_snapshot.restore();
- finishRedo(operation->m_command.c_str());
- m_undo_stack.pop_back();
- }
- }
- void redo()
- {
- if(m_redo_stack.empty())
- {
- globalOutputStream() << "Redo: no redo available\n";
- }
- else
- {
- Operation* operation = m_redo_stack.back();
- globalOutputStream() << "Redo: " << operation->m_command.c_str() << "\n";
-
- startUndo();
- trackersRedo();
- operation->m_snapshot.restore();
- finishUndo(operation->m_command.c_str());
- m_redo_stack.pop_back();
- }
- }
- void clear()
- {
- mark_undoables(0);
- m_undo_stack.clear();
- m_redo_stack.clear();
- trackersClear();
- }
- void trackerAttach(UndoTracker& tracker)
- {
- ASSERT_MESSAGE(m_trackers.find(&tracker) == m_trackers.end(), "undo tracker already attached");
- m_trackers.insert(&tracker);
- }
- void trackerDetach(UndoTracker& tracker)
- {
- ASSERT_MESSAGE(m_trackers.find(&tracker) != m_trackers.end(), "undo tracker cannot be detached");
- m_trackers.erase(&tracker);
- }
- void trackersClear() const
- {
- for(Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i)
- {
- (*i)->clear();
- }
- }
- void trackersBegin() const
- {
- for(Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i)
- {
- (*i)->begin();
- }
- }
- void trackersUndo() const
- {
- for(Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i)
- {
- (*i)->undo();
- }
- }
- void trackersRedo() const
- {
- for(Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i)
- {
- (*i)->redo();
- }
- }