undo.cpp

Engine/source/util/undo.cpp

More...

Public Functions

ConsoleDocClass(CompoundUndoAction , "@brief An undo action that is comprised of other undo <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">actions.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )
ConsoleDocClass(UndoAction , "@brief An event which signals the editors <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> undo the last <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">action\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )
ConsoleDocClass(UndoManager , "@brief <a href="/coding/class/classsimobject/">SimObject</a> which adds, tracks , and deletes <a href="/coding/class/classundoaction/">UndoAction</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )
ConsoleDocClass(UndoScriptAction , "@brief Undo actions which can be created as script <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )
DefineEngineMethod(CompoundUndoAction , addAction , void , (const char *objName) , "addAction( <a href="/coding/class/classundoaction/">UndoAction</a> )" )
DefineEngineMethod(UndoAction , addToManager , void , (const char *undoManager) , ("") , "action.addToManager([undoManager])" )
DefineEngineMethod(UndoAction , redo , void , () , "() - Reo action contained in undo." )
DefineEngineMethod(UndoAction , undo , void , () , "() - Undo action contained in undo." )
DefineEngineMethod(UndoManager , clearAll , void , () , "Clears the undo manager." )
DefineEngineMethod(UndoManager , getNextRedoName , const char * , () , "UndoManager.getNextRedoName();" )
DefineEngineMethod(UndoManager , getNextUndoName , const char * , () , "UndoManager.getNextUndoName();" )
DefineEngineMethod(UndoManager , getRedoAction , S32 , (S32 index) , "(index)" )
DefineEngineMethod(UndoManager , getRedoCount , S32 , () , "" )
DefineEngineMethod(UndoManager , getRedoName , const char * , (S32 index) , "(index)" )
DefineEngineMethod(UndoManager , getUndoAction , S32 , (S32 index) , "(index)" )
DefineEngineMethod(UndoManager , getUndoCount , S32 , () , "" )
DefineEngineMethod(UndoManager , getUndoName , const char * , (S32 index) , "(index)" )
DefineEngineMethod(UndoManager , popCompound , void , (bool discard) , (false) , "( bool discard=false ) - Pop the current <a href="/coding/class/classcompoundundoaction/">CompoundUndoAction</a> off the stack." )
DefineEngineMethod(UndoManager , pushCompound , const char * , (String name) , ("") , "( string name=\"\" ) - Push <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classcompoundundoaction/">CompoundUndoAction</a> onto the compound stack <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> assembly." )
DefineEngineMethod(UndoManager , redo , void , () , "UndoManager.redo();" )
DefineEngineMethod(UndoManager , undo , void , () , "UndoManager.undo();" )

Detailed Description

Public Functions

ConsoleDocClass(CompoundUndoAction , "@brief An undo action that is comprised of other undo <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">actions.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )

ConsoleDocClass(UndoAction , "@brief An event which signals the editors <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> undo the last <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">action\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )

ConsoleDocClass(UndoManager , "@brief <a href="/coding/class/classsimobject/">SimObject</a> which adds, tracks , and deletes <a href="/coding/class/classundoaction/">UndoAction</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )

ConsoleDocClass(UndoScriptAction , "@brief Undo actions which can be created as script <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n\n</a>" "Not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> game development, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> editors or internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a> " " @internal" )

DefineEngineMethod(CompoundUndoAction , addAction , void , (const char *objName) , "addAction( <a href="/coding/class/classundoaction/">UndoAction</a> )" )

DefineEngineMethod(UndoAction , addToManager , void , (const char *undoManager) , ("") , "action.addToManager([undoManager])" )

DefineEngineMethod(UndoAction , redo , void , () , "() - Reo action contained in undo." )

DefineEngineMethod(UndoAction , undo , void , () , "() - Undo action contained in undo." )

DefineEngineMethod(UndoManager , clearAll , void , () , "Clears the undo manager." )

DefineEngineMethod(UndoManager , getNextRedoName , const char * , () , "UndoManager.getNextRedoName();" )

DefineEngineMethod(UndoManager , getNextUndoName , const char * , () , "UndoManager.getNextUndoName();" )

DefineEngineMethod(UndoManager , getRedoAction , S32 , (S32 index) , "(index)" )

DefineEngineMethod(UndoManager , getRedoCount , S32 , () , "" )

DefineEngineMethod(UndoManager , getRedoName , const char * , (S32 index) , "(index)" )

DefineEngineMethod(UndoManager , getUndoAction , S32 , (S32 index) , "(index)" )

DefineEngineMethod(UndoManager , getUndoCount , S32 , () , "" )

DefineEngineMethod(UndoManager , getUndoName , const char * , (S32 index) , "(index)" )

DefineEngineMethod(UndoManager , popCompound , void , (bool discard) , (false) , "( bool discard=false ) - Pop the current <a href="/coding/class/classcompoundundoaction/">CompoundUndoAction</a> off the stack." )

DefineEngineMethod(UndoManager , pushCompound , const char * , (String name) , ("") , "( string name=\"\" ) - Push <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classcompoundundoaction/">CompoundUndoAction</a> onto the compound stack <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> assembly." )

DefineEngineMethod(UndoManager , redo , void , () , "UndoManager.redo();" )

DefineEngineMethod(UndoManager , undo , void , () , "UndoManager.undo();" )

IMPLEMENT_CONOBJECT(CompoundUndoAction )

IMPLEMENT_CONOBJECT(UndoAction )

IMPLEMENT_CONOBJECT(UndoManager )

IMPLEMENT_CONOBJECT(UndoScriptAction )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "util/undo.h"
 26
 27#include "console/console.h"
 28#include "console/consoleTypes.h"
 29#include "console/engineAPI.h"
 30
 31//-----------------------------------------------------------------------------
 32// UndoAction
 33//-----------------------------------------------------------------------------
 34IMPLEMENT_CONOBJECT(UndoAction);
 35IMPLEMENT_CONOBJECT(UndoScriptAction);
 36
 37ConsoleDocClass( UndoAction,
 38            "@brief An event which signals the editors to undo the last action\n\n"
 39            "Not intended for game development, for editors or internal use only.\n\n "
 40            "@internal");
 41
 42ConsoleDocClass( UndoScriptAction,
 43            "@brief Undo actions which can be created as script objects.\n\n"
 44            "Not intended for game development, for editors or internal use only.\n\n "
 45            "@internal");
 46
 47UndoAction::UndoAction(const UTF8 *actionName)
 48{
 49   mActionName = actionName;
 50   mUndoManager = NULL;
 51}
 52
 53UndoAction::~UndoAction()
 54{
 55   // If we are registered to an undo manager, make sure
 56   // we get off its lists.
 57   if( mUndoManager )
 58      mUndoManager->removeAction( this, true );
 59
 60   clearAllNotifications();
 61}
 62
 63//-----------------------------------------------------------------------------
 64void UndoAction::initPersistFields()
 65{
 66   addField("actionName", TypeRealString, Offset(mActionName, UndoAction), 
 67      "A brief description of the action, for UI representation of this undo/redo action.");
 68
 69   Parent::initPersistFields();
 70}
 71
 72//-----------------------------------------------------------------------------
 73void UndoAction::addToManager(UndoManager* theMan)
 74{
 75   if(theMan)
 76   {
 77      mUndoManager = theMan;
 78      (*theMan).addAction(this);
 79   }
 80   else
 81   {
 82      mUndoManager = &UndoManager::getDefaultManager();
 83      mUndoManager->addAction(this);
 84   }
 85}
 86
 87//-----------------------------------------------------------------------------
 88// CompoundUndoAction
 89//-----------------------------------------------------------------------------
 90IMPLEMENT_CONOBJECT( CompoundUndoAction );
 91
 92ConsoleDocClass( CompoundUndoAction,
 93            "@brief An undo action that is comprised of other undo actions.\n\n"
 94            "Not intended for game development, for editors or internal use only.\n\n "
 95            "@internal");
 96
 97CompoundUndoAction::CompoundUndoAction( const UTF8 *actionName )
 98 : Parent( actionName )
 99{
100}
101
102CompoundUndoAction::~CompoundUndoAction()
103{
104   while( !mChildren.empty() )
105   {
106      UndoAction* action = mChildren.last();
107      if( action->isProperlyAdded() )
108         action->deleteObject();
109      else
110      {
111         clearNotify( action );  // need to clear the delete notification manually in this case
112         delete action;
113      }
114
115      mChildren.pop_back();
116   }
117}
118
119void CompoundUndoAction::addAction( UndoAction *action )
120{
121   //AssertFatal( action->mUndoManager == NULL, "CompoundUndoAction::addAction, action already had an UndoManager." );
122   mChildren.push_back( action );
123   deleteNotify( action );
124}
125
126void CompoundUndoAction::undo()
127{
128   Vector<UndoAction*>::iterator itr = mChildren.end() - 1;
129   for ( ; itr != mChildren.begin() - 1; itr-- )   
130      (*itr)->undo();
131}
132
133void CompoundUndoAction::redo()
134{
135   Vector<UndoAction*>::iterator itr = mChildren.begin();
136   for ( ; itr != mChildren.end(); itr++ )   
137      (*itr)->redo();   
138}
139
140void CompoundUndoAction::onDeleteNotify( SimObject* object )
141{      
142   for( U32 i = 0; i < mChildren.size(); ++ i )
143      if( mChildren[ i ] == object )
144         mChildren.erase( i );
145
146   Parent::onDeleteNotify( object );
147}
148
149DefineEngineMethod( CompoundUndoAction, addAction, void, (const char * objName), , "addAction( UndoAction )" )
150{
151   UndoAction *action;
152   if ( Sim::findObject( objName, action ) )
153      object->addAction( action );
154}
155
156//-----------------------------------------------------------------------------
157// UndoManager
158//-----------------------------------------------------------------------------
159IMPLEMENT_CONOBJECT(UndoManager);
160
161ConsoleDocClass( UndoManager,
162            "@brief SimObject which adds, tracks, and deletes UndoAction objects.\n\n"
163            "Not intended for game development, for editors or internal use only.\n\n "
164            "@internal")
165
166UndoManager::UndoManager(U32 levels)
167{
168   VECTOR_SET_ASSOCIATION( mUndoStack );
169   VECTOR_SET_ASSOCIATION( mRedoStack );
170   VECTOR_SET_ASSOCIATION( mCompoundStack );
171
172   mNumLevels = levels;
173   // levels can be arbitrarily high, so we don't really want to reserve(levels).
174   mUndoStack.reserve(10);
175   mRedoStack.reserve(10);
176}
177
178//-----------------------------------------------------------------------------
179UndoManager::~UndoManager()
180{
181   clearStack(mUndoStack);
182   clearStack(mRedoStack);
183   clearStack( *( ( Vector< UndoAction*>* ) &mCompoundStack ) );
184}
185
186//-----------------------------------------------------------------------------
187void UndoManager::initPersistFields()
188{
189   addField("numLevels", TypeS32, Offset(mNumLevels, UndoManager), "Number of undo & redo levels.");
190   // arrange for the default undo manager to exist.
191//   UndoManager &def = getDefaultManager();
192//   Con::printf("def = %s undo manager created", def.getName());
193   
194}
195
196//-----------------------------------------------------------------------------
197UndoManager& UndoManager::getDefaultManager()
198{
199   // the default manager is created the first time it is asked for.
200   static UndoManager *defaultMan = NULL;
201   if(!defaultMan)
202   {
203      defaultMan = new UndoManager();
204      defaultMan->assignName("DefaultUndoManager");
205      defaultMan->registerObject();
206   }
207   return *defaultMan;
208}
209
210DefineEngineMethod(UndoManager, clearAll, void, (),, "Clears the undo manager.")
211{
212   object->clearAll();
213}
214
215void UndoManager::clearAll()
216{
217   clearStack(mUndoStack);
218   clearStack(mRedoStack);
219   
220   Con::executef(this, "onClear");
221}
222
223//-----------------------------------------------------------------------------
224void UndoManager::clearStack(Vector<UndoAction*> &stack)
225{
226   Vector<UndoAction*>::iterator itr = stack.begin();
227   while (itr != stack.end())
228   {
229      UndoAction* undo = stack.first();
230      stack.pop_front();
231
232      // Call deleteObject() if the action was registered.
233      if ( undo->isProperlyAdded() )
234         undo->deleteObject();
235      else
236         delete undo;
237   }
238   stack.clear();
239}
240
241//-----------------------------------------------------------------------------
242void UndoManager::clampStack(Vector<UndoAction*> &stack)
243{
244   while(stack.size() > mNumLevels)
245   {
246      UndoAction *act = stack.front();
247      stack.pop_front();
248
249      // Call deleteObject() if the action was registered.
250      if ( act->isProperlyAdded() )
251         act->deleteObject();
252      else
253         delete act;
254   }
255}
256
257void UndoManager::removeAction(UndoAction *action, bool noDelete)
258{
259   Vector<UndoAction*>::iterator itr = mUndoStack.begin();
260   while (itr != mUndoStack.end())
261   {
262      if ((*itr) == action)
263      {
264         UndoAction* deleteAction = *itr;
265         mUndoStack.erase(itr);
266         doRemove( deleteAction, noDelete );
267         return;
268      }
269     itr++;
270   }
271
272   itr = mRedoStack.begin();
273   while (itr != mRedoStack.end())
274   {
275      if ((*itr) == action)
276      {
277         UndoAction* deleteAction = *itr;
278         mRedoStack.erase(itr);
279         doRemove( deleteAction, noDelete );
280         return;
281      }
282     itr++;
283   }
284}
285
286void UndoManager::doRemove( UndoAction* action, bool noDelete )
287{
288   if( action->mUndoManager == this )
289      action->mUndoManager = NULL;
290
291   if( !noDelete )
292   {
293      // Call deleteObject() if the action was registered.
294      if ( action->isProperlyAdded() )
295         action->deleteObject();
296      else
297         delete action;
298   }
299
300   if( isProperlyAdded() )
301      Con::executef(this, "onRemoveUndo");
302}
303
304//-----------------------------------------------------------------------------
305void UndoManager::undo()
306{
307   // make sure we have an action available
308   if(mUndoStack.size() < 1)
309      return;
310
311   // pop the action off the undo stack
312   UndoAction *act = mUndoStack.last();
313   mUndoStack.pop_back();
314   
315   // add it to the redo stack
316   mRedoStack.push_back(act);
317   if(mRedoStack.size() > mNumLevels)
318      mRedoStack.pop_front();
319   
320   Con::executef(this, "onUndo");
321
322   // perform the undo, whatever it may be.
323   (*act).undo();
324}
325
326//-----------------------------------------------------------------------------
327void UndoManager::redo()
328{
329   // make sure we have an action available
330   if(mRedoStack.size() < 1)
331      return;
332
333   // pop the action off the redo stack
334   UndoAction *react = mRedoStack.last();
335   mRedoStack.pop_back();
336   
337   // add it to the undo stack
338   mUndoStack.push_back(react);
339   if(mUndoStack.size() > mNumLevels)
340      mUndoStack.pop_front();
341   
342   Con::executef(this, "onRedo");
343   
344   // perform the redo, whatever it may be.
345   (*react).redo();
346}
347
348DefineEngineMethod(UndoManager, getUndoCount, S32, (),, "")
349{
350   return object->getUndoCount();
351}
352
353S32 UndoManager::getUndoCount()
354{
355   return mUndoStack.size();
356}
357
358DefineEngineMethod(UndoManager, getUndoName, const char*, (S32 index), , "(index)")
359{
360   return object->getUndoName(index);
361}
362
363const char* UndoManager::getUndoName(S32 index)
364{
365   if ((index < getUndoCount()) && (index >= 0))
366      return mUndoStack[index]->mActionName;
367
368   return NULL;
369}
370
371DefineEngineMethod(UndoManager, getUndoAction, S32, (S32 index), , "(index)")
372{
373   UndoAction * action = object->getUndoAction(index);
374   if ( !action )
375      return -1;
376   
377   if ( !action->isProperlyAdded() )
378      action->registerObject();
379
380   return action->getId();
381}
382
383UndoAction* UndoManager::getUndoAction(S32 index)
384{
385   if ((index < getUndoCount()) && (index >= 0))
386      return mUndoStack[index];
387   return NULL;
388}
389
390DefineEngineMethod(UndoManager, getRedoCount, S32, (),, "")
391{
392   return object->getRedoCount();
393}
394
395S32 UndoManager::getRedoCount()
396{
397   return mRedoStack.size();
398}
399
400DefineEngineMethod(UndoManager, getRedoName, const char*, (S32 index), , "(index)")
401{
402   return object->getRedoName(index);
403}
404
405const char* UndoManager::getRedoName(S32 index)
406{
407   if ((index < getRedoCount()) && (index >= 0))
408      return mRedoStack[getRedoCount() - index - 1]->mActionName;
409
410   return NULL;
411}
412
413DefineEngineMethod(UndoManager, getRedoAction, S32, (S32 index), , "(index)")
414{
415   UndoAction * action = object->getRedoAction(index);
416
417   if ( !action )
418      return -1;
419
420   if ( !action->isProperlyAdded() )
421      action->registerObject();
422
423   return action->getId();
424}
425
426UndoAction* UndoManager::getRedoAction(S32 index)
427{
428   if ((index < getRedoCount()) && (index >= 0))
429      return mRedoStack[index];
430   return NULL;
431}
432
433//-----------------------------------------------------------------------------
434const char* UndoManager::getNextUndoName()
435{
436   if(mUndoStack.size() < 1)
437      return NULL;
438      
439   UndoAction *act = mUndoStack.last();
440   return (*act).mActionName;
441}
442
443//-----------------------------------------------------------------------------
444const char* UndoManager::getNextRedoName()
445{
446   if(mRedoStack.size() < 1)
447      return NULL;
448
449   UndoAction *act = mRedoStack.last();
450   return (*act).mActionName;
451}
452
453//-----------------------------------------------------------------------------
454void UndoManager::addAction(UndoAction* action)
455{
456   // If we are assembling a compound, redirect the action to it
457   // and don't modify our current undo/redo state.
458   
459   if( mCompoundStack.size() )
460   {
461      mCompoundStack.last()->addAction( action );
462      return;
463   }
464   
465   // clear the redo stack
466   clearStack(mRedoStack);
467
468   // push the incoming action onto the stack, move old data off the end if necessary.
469   mUndoStack.push_back(action);
470   if(mUndoStack.size() > mNumLevels)
471      mUndoStack.pop_front();
472
473   Con::executef(this, "onAddUndo");
474}
475
476//-----------------------------------------------------------------------------
477
478CompoundUndoAction* UndoManager::pushCompound( const String& name )
479{
480   mCompoundStack.push_back( new CompoundUndoAction( name ) );
481   return mCompoundStack.last();
482}
483
484//-----------------------------------------------------------------------------
485
486void UndoManager::popCompound( bool discard )
487{
488   AssertFatal( getCompoundStackDepth() > 0, "UndoManager::popCompound - no compound on stack!" );
489   
490   CompoundUndoAction* undo = mCompoundStack.last();
491   mCompoundStack.pop_back();
492   
493   if( discard || undo->getNumChildren() == 0 )
494   {
495      if( undo->isProperlyAdded() )
496         undo->deleteObject();
497      else
498         delete undo;
499   }
500   else
501      addAction( undo );
502}
503
504//-----------------------------------------------------------------------------
505DefineEngineMethod(UndoAction, addToManager, void, (const char * undoManager), (""), "action.addToManager([undoManager])")
506{
507   UndoManager *theMan = NULL;
508   if (!String::isEmpty(undoManager))
509   {
510      SimObject *obj = Sim::findObject(undoManager);
511      if(obj)
512         theMan = dynamic_cast<UndoManager*> (obj);
513   }
514   object->addToManager(theMan);
515}
516
517//-----------------------------------------------------------------------------
518
519DefineEngineMethod( UndoAction, undo, void, (),, "() - Undo action contained in undo." )
520{
521   object->undo();
522}
523
524//-----------------------------------------------------------------------------
525
526DefineEngineMethod( UndoAction, redo, void, (),, "() - Reo action contained in undo." )
527{
528   object->redo();
529}
530
531//-----------------------------------------------------------------------------
532DefineEngineMethod(UndoManager, undo, void, (),, "UndoManager.undo();")
533{
534   object->undo();
535}
536
537//-----------------------------------------------------------------------------
538DefineEngineMethod(UndoManager, redo, void, (),, "UndoManager.redo();")
539{
540   object->redo();
541}
542
543//-----------------------------------------------------------------------------
544DefineEngineMethod(UndoManager, getNextUndoName, const char *, (),, "UndoManager.getNextUndoName();")
545{
546   const char *name = object->getNextUndoName();
547   if(!name)
548      return NULL;
549   dsize_t retLen = dStrlen(name) + 1;
550   char *ret = Con::getReturnBuffer(retLen);
551   dStrcpy(ret, name, retLen);
552   return ret;
553}
554
555//-----------------------------------------------------------------------------
556DefineEngineMethod(UndoManager, getNextRedoName, const char *, (),, "UndoManager.getNextRedoName();")
557{
558   const char *name = object->getNextRedoName();
559   if(!name)
560      return NULL;
561   dsize_t retLen = dStrlen(name) + 1;
562   char *ret = Con::getReturnBuffer(retLen);
563   dStrcpy(ret, name, retLen);
564   return ret;
565}
566
567//-----------------------------------------------------------------------------
568
569DefineEngineMethod( UndoManager, pushCompound, const char*, ( String name ), (""), "( string name=\"\" ) - Push a CompoundUndoAction onto the compound stack for assembly." )
570{
571      
572   CompoundUndoAction* action = object->pushCompound( name );
573   if( !action )
574      return "";
575      
576   if( !action->isProperlyAdded() )
577      action->registerObject();
578      
579   return action->getIdString();
580}
581
582//-----------------------------------------------------------------------------
583
584DefineEngineMethod( UndoManager, popCompound, void, ( bool discard ), (false), "( bool discard=false ) - Pop the current CompoundUndoAction off the stack." )
585{
586   if( !object->getCompoundStackDepth() )
587   {
588      Con::errorf( "UndoManager::popCompound - no compound on stack (%s) ",object->getName() );
589      return;
590   }
591   
592   
593   object->popCompound( discard );
594}
595