/** * @file llundo.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llundo.h" // TODO: // implement doubly linked circular list for ring buffer // this will allow us to easily change the size of an undo buffer on the fly //----------------------------------------------------------------------------- // LLUndoBuffer() //----------------------------------------------------------------------------- LLUndoBuffer::LLUndoBuffer( LLUndoAction (*create_func()), S32 initial_count ) { mNextAction = 0; mLastAction = 0; mFirstAction = 0; mOperationID = 0; mNumActions = initial_count; mActions = new LLUndoAction *[initial_count]; //initialize buffer with actions for (S32 i = 0; i < initial_count; i++) { mActions[i] = create_func(); if (!mActions[i]) { LL_ERRS() << "Unable to create action for undo buffer" << LL_ENDL; } } } //----------------------------------------------------------------------------- // ~LLUndoBuffer() //----------------------------------------------------------------------------- LLUndoBuffer::~LLUndoBuffer() { for (S32 i = 0; i < mNumActions; i++) { delete mActions[i]; } delete [] mActions; } //----------------------------------------------------------------------------- // getNextAction() //----------------------------------------------------------------------------- LLUndoBuffer::LLUndoAction* LLUndoBuffer::getNextAction(bool setClusterBegin) { LLUndoAction *nextAction = mActions[mNextAction]; if (setClusterBegin) { mOperationID++; } mActions[mNextAction]->mClusterID = mOperationID; mNextAction = (mNextAction + 1) % mNumActions; mLastAction = mNextAction; if (mNextAction == mFirstAction) { mActions[mFirstAction]->cleanup(); mFirstAction = (mFirstAction + 1) % mNumActions; } return nextAction; } //----------------------------------------------------------------------------- // undoAction() //----------------------------------------------------------------------------- bool LLUndoBuffer::undoAction() { if (!canUndo()) { return false; } S32 prevAction = (mNextAction + mNumActions - 1) % mNumActions; while(mActions[prevAction]->mClusterID == mOperationID) { // go ahead and decrement action index mNextAction = prevAction; // undo this action mActions[mNextAction]->undo(); // we're at the first action, so we don't know if we've actually undid everything if (mNextAction == mFirstAction) { mOperationID--; return false; } // do wrap-around of index, but avoid negative numbers for modulo operator prevAction = (mNextAction + mNumActions - 1) % mNumActions; } mOperationID--; return true; } //----------------------------------------------------------------------------- // redoAction() //----------------------------------------------------------------------------- bool LLUndoBuffer::redoAction() { if (!canRedo()) { return false; } mOperationID++; while(mActions[mNextAction]->mClusterID == mOperationID) { if (mNextAction == mLastAction) { return false; } mActions[mNextAction]->redo(); // do wrap-around of index mNextAction = (mNextAction + 1) % mNumActions; } return true; } //----------------------------------------------------------------------------- // flushActions() //----------------------------------------------------------------------------- void LLUndoBuffer::flushActions() { for (S32 i = 0; i < mNumActions; i++) { mActions[i]->cleanup(); } mNextAction = 0; mLastAction = 0; mFirstAction = 0; mOperationID = 0; }