realXtend / tundra

realXtend Tundra SDK, a 3D virtual world application platform.
www.realxtend.org
Apache License 2.0
84 stars 70 forks source link

Maintaining Undo / Redo stack for EC editor and Scene editor #615

Closed cvetan5 closed 11 years ago

cvetan5 commented 11 years ago

An Undo / Redo stack manager for EC / Scene editor. It utilizes the Undo framework classes by Qt that implement the command pattern. All actions i.e. commands from EC / Scene editor (excluding pasting content, importing scene(s) and converting local entity to replicated and vice-versa) are represented by a QUndoCommand-derived class. The undo manager manipulates the QUndoStack and the UI elements i.e. undo and redo tool buttons with two QMenus which contain 5 recent commands that had been done (Undo menu) or undone (Redo menu). A QUndoView is provided to view the contents of QUndoStack, and to walk through them if needed. A helper class called EntityIdChangeTracker is used to track IDs of entities that had been deleted / re-added in an EC / Scene editor lifetime, and also to track acknowledging of new created entities so it can keep their valid replicated ID. The reason I did this is that I don't think it is smart to use old entity IDs to redo a "delete entity" action (and for some reason it does not work for replicated entities).

Workflow:

  1. When a command is executed, a new instance of the appropriate QUndoCommand-derived class is pushed onto the stack;
  2. QUndoStack calls QUndoCommand::redo() of the QUndoCommand that had been pushed, except when EditAttributeCommand<T> is pushed, where the old attribute value must be stored before setting it to the new value (there is a workaround there to avoid calling redo() upon pushing). The UI is updated;

    2.1. If for example, a command that will cause a change in the target entity's ID has been pushed, its ID is tracked with EntityIdChangeTracker;

  3. When UndoManager::Undo() is called, QUndoStack calls QUndoCommand::undo() of the topmost command from the stack. The index is changed to point to the next command that will be undone on the next undo() call. The UI is updated;
  4. If, for example. 4 commands are undone i.e. the index is changed back by 4, QUndoStack calls QUndoCommand::undo() repeatedly until the desired index is reached. The UI is updated;

    4.1. In the event that a new command is pushed onto the stack, commands that can be redone are removed from the stack and destroyed; 4.2. Entity IDs are retrieved by recursively walking through EntityIdChangeTracker's maps

  5. When "unsupported commands" are executed, it results in clearing the undo stack (removing and destroying all QUndoCommands)

Known drawbacks:

Possible drawbacks:

Most of the code for the commands is reused and moved to the appropriate QUndoCommand::redo() method. I would greatly appreciate if you guys test this and give me any notes on this.

jonnenauha commented 11 years ago

@cadaver could you give @cvetan5 a shout when you will be cheking this out so he can merge rex/tundra2 to it.

cadaver commented 11 years ago

Should be next week, after checking the noboost pull request.

cadaver commented 11 years ago

Looks good. After merging, I'll file an enhancement ticket for also recording transform gizmo actions as undo commands.