/** * @file llundo.cpp * * $LicenseInfo:firstyear=2001&license=viewergpl$ * * Copyright (c) 2001-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/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]) { llerrs << "Unable to create action for undo buffer" << llendl; } } } //----------------------------------------------------------------------------- // ~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; }