/* * Copyright (C) =USTC= Fu Li * * Author : Fu Li * Create : 2005-3-6 * Home : http://www.crazy-bit.com/ * Mail : crazybit@263.net * History : */ #ifndef __FOO_PCL_INTERFACE_UNDO_MANAGER_H__ #define __FOO_PCL_INTERFACE_UNDO_MANAGER_H__ #include #include template class PCL_Interface_Undo ; //============================================================================= /** * Undo/Redo manage. */ template class PCL_Interface_Undo { public: /** * @name Basic Undo/Redo operation. * you must implement PCL_Implement_Undo/PCL_Implement_Redo in your subclass. */ //@{ bool IsUndoEnable() const {return !m_UndoList.empty();} bool IsRedoEnable() const {return !m_RedoList.empty();} void Undo() { if (IsUndoEnable()) { T * p = m_UndoList.back() ; // get the latest undo-command this->PCL_Implement_Undo (p) ; m_UndoList.pop_back() ; m_RedoList.push_front(p) ; } } void Redo() { if (IsRedoEnable()) { T * p = m_RedoList.front() ; // get the first redo-command this->PCL_Implement_Redo (p) ; m_RedoList.pop_front() ; m_UndoList.push_back(p) ; } } //@} /** * @name Clear operation. * clear command object in list. */ //@{ void ClearRedoList() { while (IsRedoEnable()) { T * p = m_RedoList.back() ; m_RedoList.pop_back() ; delete p ; } } void ClearUndoList() { while (IsUndoEnable()) { T * p = m_UndoList.back() ; m_UndoList.pop_back() ; delete p ; } } //@} /** * @name Undo max level. * if the undo level ==0, it means undo disable. */ //@{ int GetUndoLevel() const {return m_nUndoLevel;} /** it will delete overflowed command. */ void SetUndoLevel (int nLevel) { if (nLevel < 0) { assert(false); return; } m_nUndoLevel = nLevel ; // >=0 // calculate current number of command in list int nRemove = (int)(m_UndoList.size() + m_RedoList.size()) - m_nUndoLevel ; if (nRemove <= 0) return ; // first : delete command from Redo-list back while (!m_RedoList.empty() && (nRemove > 0)) { T * p = m_RedoList.back() ; m_RedoList.pop_back() ; delete p ; nRemove-- ; } // then : delete command from Undo-list front while (!m_UndoList.empty() && (nRemove > 0)) { T * p = m_UndoList.front() ; m_UndoList.pop_front() ; delete p ; nRemove-- ; } } //@} protected: /// Undo's implementation. /// @param : pCmd is the last command in undo-list. virtual void PCL_Implement_Undo (T* pCmd) =0 ; /// Redo's implementation. /// @param : pCmd is the first command in redo-list. virtual void PCL_Implement_Redo (T* pCmd) =0 ; /** * Add a command object into undo-list. * 1) it will clear redo-list.
* 2) if the undo list is full, it will delete oldest undo command. */ bool AddCommand (T* pCmd) { if ((m_nUndoLevel <= 0) || !pCmd) { assert(false); return false; } // clear redo-list, ennnnnnn. this behavior like a bintree. ClearRedoList() ; // single command assert ((int)m_UndoList.size() <= m_nUndoLevel) ; if ((int)m_UndoList.size() >= m_nUndoLevel) // never '>' { T * p = m_UndoList.front() ; m_UndoList.pop_front() ; delete p ; } // add to undo list m_UndoList.push_back (pCmd) ; return true ; } T* GetLatestUndoCommand() const {return IsUndoEnable() ? m_UndoList.back() : 0;} /** * @name Constructor. * constructor/destructor. */ //@{ PCL_Interface_Undo (int nUndoLevel = 20) : m_nUndoLevel(nUndoLevel) {} virtual ~PCL_Interface_Undo() { ClearRedoList() ; ClearUndoList() ; } //@} private: std::deque m_UndoList ; std::deque m_RedoList ; // the level of undo operation. the ZERO means disable undo int m_nUndoLevel ; }; //============================================================================= // inline implement //============================================================================= #endif