// actionmgr.cpp -- the action manager // // Written by Frederic Bouvier, started May 2002. // // Copyright (C) 2002 Frederic Bouvier - fredb@users.sourceforge.net // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // $Id: actionmgr.cpp,v 1.14 2005/05/09 07:01:47 fredb Exp $ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "actionmgr.hpp" #include #include "action.hpp" #include "actfact.hpp" static const size_t ACTION_MGR_INVALID = (size_t)-1; FGSD_ActionManager::FGSD_ActionManager() : _lastSaveSize( 0 ) { FGSD_ActionFactory *fact = FGSD_ActionFactory::_last; while ( fact ) { registerFactory( fact->getName(), fact ); fact = fact->_next; } SGTimeStamp current; current.stamp(); _lastNewAction = current; } void FGSD_ActionManager::registerFactory( const std::string &__name, FGSD_ActionFactory *__fact ) { _factoryMap[ __name ] = __fact; } bool FGSD_ActionManager::loadAndExecute( const char *__project, SGPropertyNode *__node ) { bool ret = false; std::vector cActions = __node->getChildren( "action" ); size_t nb = cActions.size(); for ( size_t i = 0; i < nb; i++ ) { SGPropertyNode *fm = cActions[ i ]->getChild( "family" ); if ( fm ) { std::string family = fm->getStringValue(); FactoryMap::iterator fi = _factoryMap.find( family ); if ( fi != _factoryMap.end() ) { FGSD_ActionFactory *fact = fi->second; FGSD_Action *action = fact->createAction( __project, cActions[ i ] ); action->redo( true ); action->_isUndoable = false; _undoable.push_back( action ); ret = true; } } } _lastSaveSize = _undoable.size(); return ret; } bool FGSD_ActionManager::save( const char *__project, SGPropertyNode *__node ) { size_t i = 0; for ( ActionList::iterator ai = _undoable.begin(); ai != _undoable.end(); ++ai ) { FGSD_Action *act = *ai; if ( act->savable() ) { SGPropertyNode *node = __node->getChild( "action", i++, true ); act->save( __project, node ); } } _lastSaveSize = _undoable.size(); return true; } size_t FGSD_ActionManager::getWeight( const char *__project, SGPropertyNode *__node ) const { size_t ret = 0; std::vector cActions = __node->getChildren( "action" ); size_t nb = cActions.size(); for ( size_t i = 0; i < nb; i++ ) { SGPropertyNode *fm = cActions[ i ]->getChild( "family" ); if ( fm ) { std::string family = fm->getStringValue(); FactoryMap::const_iterator fi = _factoryMap.find( family ); if ( fi != _factoryMap.end() ) { FGSD_ActionFactory *fact = fi->second; FGSD_Action *action = fact->createAction( __project, cActions[ i ] ); ret += action->weight( cActions[ i ] ); delete action; } } } return ret; } bool FGSD_ActionManager::getPosition( bool undo, double &lon, double &lat ) const { FGSD_Action *act = 0; if ( undo ) act = _redoable.front(); else act = _undoable.back(); return act ? act->getPosition( undo, lon, lat ) : false; } void FGSD_ActionManager::clear() { ActionList::iterator ai; for ( ai = _undoable.begin(); ai != _undoable.end(); ++ai ) delete *ai; _undoable.clear(); for ( ai = _redoable.begin(); ai != _redoable.end(); ++ai ) delete *ai; _redoable.clear(); _lastSaveSize = 0; } bool FGSD_ActionManager::undo() { bool ret = false; if ( _undoable.size() ) { FGSD_Action *action = _undoable.back(); if ( action->isUndoable() ) { ret = action->undo(); if ( ret ) { _undoable.pop_back(); _redoable.push_front( action ); } } } return ret; } bool FGSD_ActionManager::redo() { bool ret = false; if ( _redoable.size() ) { FGSD_Action *action = _redoable.front(); ret = action->redo(); if ( ret ) { _redoable.pop_front(); _undoable.push_back( action ); } } return ret; } void FGSD_ActionManager::newAction( FGSD_Action *__action ) { for ( ActionList::iterator i = _redoable.begin(); i != _redoable.end(); ++i ) delete *i; _redoable.clear(); SGTimeStamp current; current.stamp(); bool combined = false; if ( _undoable.size() && double( current - _lastNewAction ) < __action->timeoutForCombine() ) { FGSD_Action *action = _undoable.back(); if ( __action->combine( action ) ) { delete __action; combined = true; } else _undoable.push_back( __action ); } else _undoable.push_back( __action ); _lastNewAction = current; if ( _undoable.size() <= _lastSaveSize ) _lastSaveSize = ACTION_MGR_INVALID; } bool FGSD_ActionManager::undoable() { return !_undoable.empty() && _undoable.back()->isUndoable(); } bool FGSD_ActionManager::redoable() { return !_redoable.empty(); } FGSD_Action *FGSD_ActionManager::firstUndoable() { FGSD_Action *ret = 0; if ( undoable() ) ret = _undoable.back(); return ret; } FGSD_Action *FGSD_ActionManager::firstRedoable() { FGSD_Action *ret = 0; if ( redoable() ) ret = _redoable.front(); return ret; } bool FGSD_ActionManager::modified() const { return _lastSaveSize != _undoable.size(); } std::vector FGSD_ActionManager::getUndoDesc() const { std::vector ret; ActionList::const_reverse_iterator ri = _undoable.rbegin(); for ( ; ri != _undoable.rend(); ++ri ) { FGSD_Action *act = *ri; if ( act->isUndoable() ) { std::string desc = act->description(); ret.push_back( desc ); } else break; } return ret; } std::vector FGSD_ActionManager::getRedoDesc() const { std::vector ret; ActionList::const_iterator i = _redoable.begin(); for ( ; i != _redoable.end(); ++i ) { std::string desc = (*i)->description(); ret.push_back( desc ); } return ret; }