/* * * Copyright (c) 1996 * Knowledge Science Institute, University of Calgary * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. The Knowledge Science Institute makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * */ #define DONTDECLARECOMMANDLIBRARY 1 #include#undef DONTDECLARECOMMANDLIBRARY #include #include #if defined(__BORLANDC__) && defined(__MT__) #include //needed for __threadid #endif ObjectLibrary < Command, 0 > *CommandLibrary = new ObjectLibrary < Command, 0 > ( ); ObjectLibrary < ObjectLocator, 0 > *ObjectLocatorLibrary = new ObjectLibrary < ObjectLocator, 0 > ( ); /******************************************************************************* ******************************** Command *************************************** *******************************************************************************/ // Command::Command( const ObjectLocator & obj, unsigned int id ) { Locator = obj.clone( ); ID = id; User = ::getUser( ); ::time( &TimeStamp ); PID = getpid( ); #if defined(__BORLANDC__) && defined(__MT__) Thread = _threadid; #else //not sure how to get the thread on other platforms Thread = 0; #endif } Command::Command( ) // use only as an intermediate step!! { ID = 0; Locator = NULL; User = ::getUser( ); ::time( &TimeStamp ); PID = getpid( ); #if defined(__BORLANDC__) && defined(__MT__) Thread = _threadid; #else //not sure how to get the thread on other platforms Thread = 0; #endif } Command::Command( const Command & c ) { ID = c.ID; Locator = c.Locator ? c.Locator->clone( ) : NULL; User = c.User; TimeStamp = c.TimeStamp; PID = c.PID; Thread = c.Thread; } Command & Command::operator = ( const Command & c ) { ID = c.ID; if ( Locator ) delete Locator; Locator = c.Locator ? c.Locator->clone( ) : NULL; User = c.User; TimeStamp = c.TimeStamp; PID = c.PID; Thread = c.Thread; return *this; } int Command::operator < ( Command & c ) { int ret = ( TimeStamp < c.TimeStamp ); if ( ( !ret ) && !( c.TimeStamp < TimeStamp ) ) // tie-break equal times ret = ( User == c.User ) ? ( ( PID == c.PID ) ? ( Thread < c.Thread ) : ( PID < c.PID ) ) : ( User < c.User ); return ret; } int Command::operator == ( Command & c ) { return ( TimeStamp == c.TimeStamp ) && ( User == c.User ) && ( PID == c.PID ) && ( Thread == c.Thread ); } int Command::isMine( ) { return User == ::getUser( ) && PID == getpid( ) #if defined(__BORLANDC__) && defined(__MT__) && Thread == _threadid #endif ; } int Command::execute( ) { CommandReceiver *r = Locator->getObject( ); if ( r ) return r->execute( ( Command * ) this ); CommandReceiverContainer *c = Locator->getSuper( ); if ( c ) return c->executeOnBehalf( ( Command * ) this ); return -300; } int Command::undo( ) { CommandReceiver *r = Locator->getObject( ); if ( r ) return r->undo( ( Command * ) this ); CommandReceiverContainer *c = Locator->getSuper( ); if ( c ) return c->undoOnBehalf( ( Command * ) this ); return -300; } void Command::printOn( ostream & o ) { // this part can't have a counterpart in readFrom because we don't know all the types... Lexer::writeQuotedString( o, typeid( *this ).name( ) ); Lexer::writeDelim( o ); Lexer::writeUnsigned( o, ID ); Lexer::writeDelim( o ); MASSERT( Locator ); Lexer::writeQuotedString( o, typeid( *Locator ).name( ) ); Lexer::writeDelim( o ); Locator->printOn( o ); Lexer::writeDelim( o ); Lexer::writeQuotedString( o, User ); Lexer::writeDelim( o ); Lexer::writeUnsigned( o, TimeStamp ); Lexer::writeDelim( o ); Lexer::writeUnsigned( o, PID ); Lexer::writeDelim( o ); Lexer::writeUnsigned( o, Thread ); } void Command::readFrom( istream & i ) { unsigned long val; Lexer::readUnsigned( i, val ); ID = val; Lexer::readDelim( i ); string ltype; Lexer::readQuotedString( i, ltype ); Lexer::readDelim( i ); MASSERT( !Locator ); Locator = ObjectLocatorLibrary->makeCopy( ltype ); if ( !Locator ) { error( 0, 'E', "Command::readFrom: Can't find %s in ObjectLocatorLibrary", ltype.c_str( ) ); } else { Locator->readFrom( i ); Lexer::readDelim( i ); Lexer::readQuotedString( i, User ); Lexer::readDelim( i ); unsigned long t; Lexer::readUnsigned( i, t ); TimeStamp = t; Lexer::readDelim( i ); Lexer::readUnsigned( i, t ); PID = t; Lexer::readDelim( i ); Lexer::readUnsigned( i, t ); Thread = t; } } Command *Command::readCommand( istream & i ) { string type; Lexer::readQuotedString( i, type ); Lexer::readDelim( i ); Command *ret = CommandLibrary->makeCopy( type ); if ( !ret ) { error( 0, 'E', "Command::readCommand: Can't find %s in CommandLibrary", type.c_str( ) ); } else { ret->readFrom( i ); } return ret; } /******************************************************************************* **************************** CompositeCommand ********************************** *******************************************************************************/ // CompositeCommand::CompositeCommand( const CompositeCommand & c ):Command( c ) { for ( Commands_type::const_iterator i = c.Commands.begin( ); i != c.Commands.end( ); i++ ) Commands.push_back( ( *i )->clone( ) ); } CompositeCommand & CompositeCommand::operator = ( const CompositeCommand & c ) { emptyTheTrash( ); Command::operator = ( c ); for ( Commands_type::const_iterator i = c.Commands.begin( ); i != c.Commands.end( ); i++ ) Commands.push_back( ( *i )->clone( ) ); return *this; } int CompositeCommand::execute( ) { for ( Commands_type::iterator i = Commands.begin( ); i != Commands.end( ); i++ ) ( *i )->execute( ); return 0; } int CompositeCommand::undo( ) { for ( Commands_type::reverse_iterator i = Commands.rbegin( ); i != Commands.rend( ); i++ ) ( *i )->undo( ); return 0; } void CompositeCommand::emptyTheTrash( ) { for ( Commands_type::iterator i = Commands.begin( ); i != Commands.end( ); i++ ) { ( *i )->emptyTheTrash( ); delete( *i ); } Commands.erase( Commands.begin( ), Commands.end( ) ); } void CompositeCommand::printOn( ostream & o ) { Command::printOn( o ); char delim = '('; for ( Commands_type::iterator i = Commands.begin( ); i != Commands.end( ); i++ ) { Lexer::writeDelim( o, delim ); delim = ','; ( *i )->printOn( o ); } Lexer::writeDelim( o, ')' ); } void CompositeCommand::readFrom( istream & i ) { Command::readFrom( i ); char delim = '('; while ( !Lexer::readDelim( i, delim ) ) { delim = ','; string type; Lexer::readQuotedString( i, type ); Lexer::readDelim( i ); Command *com = CommandLibrary->makeCopy( type ); if ( !com ) { error( 0, 'E', "CompositeCommand::readFrom: Can't find %s in CommandLibrary", type.c_str( ) ); Lexer::scanPastDelim( i, ')' ); } else { com->readFrom( i ); Commands.push_back( com ); Lexer::readDelim( i, ')' ); } } } void CompositeCommand::setLocatorRoot( void *p ) { Command::setLocatorRoot( p ); for ( Commands_type::iterator i = Commands.begin( ); i != Commands.end( ); i++ ) ( *i )->setLocatorRoot( p ); } /******************************************************************************* **************************** CommandHandler ************************************ *******************************************************************************/ // int CommandHandler::undo( void ) { int ret = -589; if ( HistoryPtr ) { ret = HistoryList[--HistoryPtr]->undo( ); } return ret; } CommandHandler::~CommandHandler( ) { resetHistoryList( ); } int CommandHandler::resetHistoryList( void ) { while ( HistoryList.size( ) ) { HistoryList.back( )->emptyTheTrash( ); delete HistoryList.back( ); HistoryList.pop_back( ); } HistoryPtr = 0; } int CommandHandler::handleCommand( Command * c ) { int ret = -787; MASSERT( c ); ret = c->execute( ); if ( ret >= 0 ) { // only put the command on the history list or batchStack if the command succeeded. if (BatchStack.size()) { BatchStack.top()->append(c); } else { doPostCommandProcessing(c); } } return ret; } int CommandHandler::doPostCommandProcessing(Command* c) { int ret = AppendToHistoryList(c); return ret; } int CommandHandler::AppendToHistoryList(Command* c) { int ret = 0; while ( HistoryPtr < HistoryList.size( ) ) {// HistoryPtr always points one PAST the 'current place' in HistoryList HistoryList.back( )->emptyTheTrash( ); delete HistoryList.back( ); HistoryList.pop_back( ); } HistoryList.push_back( c ); HistoryPtr++; return ret; } int CommandHandler::redo( void ) { int ret = -589; if (HistoryPtr < HistoryList.size()) { ret = HistoryList[HistoryPtr++]->execute( ); } return ret; } int CommandHandler::beginBatch( unsigned int id ) { int ret = -589; BatchStack.push(new CompositeCommand(id)); return ret; } int CommandHandler::endBatch( void ) { int ret = -589; if (BatchStack.size()) { CompositeCommand* c = BatchStack.top(); BatchStack.pop(); doPostCommandProcessing(c); } return ret; } int CommandHandler::AbortBatch(int undoIt) { int ret = -589; while (BatchStack.size()) { CompositeCommand* c = BatchStack.top(); BatchStack.pop(); if (undoIt) c->undo(); delete c; } return ret; }