00001 00031 #include "linden_common.h" 00032 #include "llundo.h" 00033 00034 00035 // TODO: 00036 // implement doubly linked circular list for ring buffer 00037 // this will allow us to easily change the size of an undo buffer on the fly 00038 00039 //----------------------------------------------------------------------------- 00040 // LLUndoBuffer() 00041 //----------------------------------------------------------------------------- 00042 LLUndoBuffer::LLUndoBuffer( LLUndoAction (*create_func()), S32 initial_count ) 00043 { 00044 mNextAction = 0; 00045 mLastAction = 0; 00046 mFirstAction = 0; 00047 mOperationID = 0; 00048 00049 mNumActions = initial_count; 00050 00051 mActions = new LLUndoAction *[initial_count]; 00052 00053 //initialize buffer with actions 00054 for (S32 i = 0; i < initial_count; i++) 00055 { 00056 mActions[i] = create_func(); 00057 if (!mActions[i]) 00058 { 00059 llerrs << "Unable to create action for undo buffer" << llendl; 00060 } 00061 } 00062 } 00063 00064 //----------------------------------------------------------------------------- 00065 // ~LLUndoBuffer() 00066 //----------------------------------------------------------------------------- 00067 LLUndoBuffer::~LLUndoBuffer() 00068 { 00069 for (S32 i = 0; i < mNumActions; i++) 00070 { 00071 delete mActions[i]; 00072 } 00073 00074 delete [] mActions; 00075 } 00076 00077 //----------------------------------------------------------------------------- 00078 // getNextAction() 00079 //----------------------------------------------------------------------------- 00080 LLUndoBuffer::LLUndoAction* LLUndoBuffer::getNextAction(BOOL setClusterBegin) 00081 { 00082 LLUndoAction *nextAction = mActions[mNextAction]; 00083 00084 if (setClusterBegin) 00085 { 00086 mOperationID++; 00087 } 00088 mActions[mNextAction]->mClusterID = mOperationID; 00089 00090 mNextAction = (mNextAction + 1) % mNumActions; 00091 mLastAction = mNextAction; 00092 00093 if (mNextAction == mFirstAction) 00094 { 00095 mActions[mFirstAction]->cleanup(); 00096 mFirstAction = (mFirstAction + 1) % mNumActions; 00097 } 00098 00099 return nextAction; 00100 } 00101 00102 //----------------------------------------------------------------------------- 00103 // undoAction() 00104 //----------------------------------------------------------------------------- 00105 BOOL LLUndoBuffer::undoAction() 00106 { 00107 if (!canUndo()) 00108 { 00109 return FALSE; 00110 } 00111 00112 S32 prevAction = (mNextAction + mNumActions - 1) % mNumActions; 00113 00114 while(mActions[prevAction]->mClusterID == mOperationID) 00115 { 00116 // go ahead and decrement action index 00117 mNextAction = prevAction; 00118 00119 // undo this action 00120 mActions[mNextAction]->undo(); 00121 00122 // we're at the first action, so we don't know if we've actually undid everything 00123 if (mNextAction == mFirstAction) 00124 { 00125 mOperationID--; 00126 return FALSE; 00127 } 00128 00129 // do wrap-around of index, but avoid negative numbers for modulo operator 00130 prevAction = (mNextAction + mNumActions - 1) % mNumActions; 00131 } 00132 00133 mOperationID--; 00134 00135 return TRUE; 00136 } 00137 00138 //----------------------------------------------------------------------------- 00139 // redoAction() 00140 //----------------------------------------------------------------------------- 00141 BOOL LLUndoBuffer::redoAction() 00142 { 00143 if (!canRedo()) 00144 { 00145 return FALSE; 00146 } 00147 00148 mOperationID++; 00149 00150 while(mActions[mNextAction]->mClusterID == mOperationID) 00151 { 00152 if (mNextAction == mLastAction) 00153 { 00154 return FALSE; 00155 } 00156 00157 mActions[mNextAction]->redo(); 00158 00159 // do wrap-around of index 00160 mNextAction = (mNextAction + 1) % mNumActions; 00161 } 00162 00163 return TRUE; 00164 } 00165 00166 //----------------------------------------------------------------------------- 00167 // flushActions() 00168 //----------------------------------------------------------------------------- 00169 void LLUndoBuffer::flushActions() 00170 { 00171 for (S32 i = 0; i < mNumActions; i++) 00172 { 00173 mActions[i]->cleanup(); 00174 } 00175 mNextAction = 0; 00176 mLastAction = 0; 00177 mFirstAction = 0; 00178 mOperationID = 0; 00179 }