From ab235abc46e3d902a7aaf61e589b81f826a2d7a5 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 11 Mar 2012 00:36:34 +0000 Subject: [PATCH] Changed undo redo internals. moved exec code to UndoState.cs from sop that now only sees a unified UndoRedoStore class, added size limit on buffers so only last 5 undo/redo are kept. (5 is hardcode like it was ) ***UNTESTED*** --- .../Framework/Scenes/SceneObjectPart.cs | 155 +++------------ OpenSim/Region/Framework/Scenes/UndoState.cs | 176 +++++++++++++++++- 2 files changed, 195 insertions(+), 136 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index c806fda5cc..f70b2597c6 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -263,8 +263,7 @@ namespace OpenSim.Region.Framework.Scenes private bool m_occupied; // KF if any av is sitting on this prim private string m_text = String.Empty; private string m_touchName = String.Empty; - private Stack m_undo = new Stack(5); - private Stack m_redo = new Stack(5); + private UndoRedoState m_UndoRedo = new UndoRedoState(5); private bool m_passTouches; @@ -1709,8 +1708,8 @@ namespace OpenSim.Region.Framework.Scenes dupe.Category = Category; dupe.m_rezzed = m_rezzed; - dupe.m_undo = new Stack(5); - dupe.m_redo = new Stack(5); + dupe.m_UndoRedo = new UndoRedoState(5); + dupe.IgnoreUndoUpdate = false; dupe.Undoing = false; @@ -3657,82 +3656,14 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.ScheduleGroupForTerseUpdate(); //ParentGroup.ScheduleGroupForFullUpdate(); } -/* - public void StoreUndoState() - { - StoreUndoState(false); - } - - public void StoreUndoState(bool forGroup) - { - if (!Undoing && !IgnoreUndoUpdate) // just to read better - undo is in progress, or suspended - { - if (ParentGroup != null) - { - lock (m_undo) - { - if (m_undo.Count > 0) - { - // see if we had a change - - UndoState last = m_undo.Peek(); - if (last != null) - { - if (last.Compare(this, forGroup)) - { - return; - } - } - } - - if (ParentGroup.GetSceneMaxUndo() > 0) - { - UndoState nUndo = new UndoState(this, forGroup); - - m_undo.Push(nUndo); - - if (m_redo.Count > 0) - m_redo.Clear(); - } - } - } - } - } -*/ - public void StoreUndoState(ObjectChangeWhat what) { - if (!Undoing && !IgnoreUndoUpdate) // just to read better - undo is in progress, or suspended + lock (m_UndoRedo) { - if (ParentGroup != null) + if (!Undoing && !IgnoreUndoUpdate && ParentGroup != null) // just to read better - undo is in progress, or suspended { - lock (m_undo) - { - if (m_undo.Count > 0) - { - // see if we had a change - - UndoState last = m_undo.Peek(); - if (last != null) - { - if (last.Compare(this, what)) - { - return; - } - } - } - - if (ParentGroup.GetSceneMaxUndo() > 0) - { - UndoState nUndo = new UndoState(this, what); - - m_undo.Push(nUndo); - - if (m_redo.Count > 0) - m_redo.Clear(); - } - } + m_UndoRedo.StoreUndo(this, what); } } } @@ -3744,84 +3675,42 @@ namespace OpenSim.Region.Framework.Scenes { get { - lock (m_undo) - return m_undo.Count; + lock (m_UndoRedo) + return m_UndoRedo.Count; } } public void Undo() { - lock (m_undo) + lock (m_UndoRedo) { -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handling undo request for {0} {1}, stack size {2}", -// Name, LocalId, m_undo.Count); + if (Undoing || ParentGroup == null) + return; - if (m_undo.Count > 0) - { - UndoState goback = m_undo.Pop(); - - if (goback != null) - { - UndoState nUndo = null; - - if (ParentGroup.GetSceneMaxUndo() > 0) - { - nUndo = new UndoState(this, goback.data.what); - } - - goback.PlayState(this); - - if (nUndo != null) - m_redo.Push(nUndo); - } - } - -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handled undo request for {0} {1}, stack size now {2}", -// Name, LocalId, m_undo.Count); + Undoing = true; + m_UndoRedo.Undo(this); + Undoing = false; } } public void Redo() { - lock (m_undo) + lock (m_UndoRedo) { -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handling redo request for {0} {1}, stack size {2}", -// Name, LocalId, m_redo.Count); + if (Undoing || ParentGroup == null) + return; - if (m_redo.Count > 0) - { - UndoState gofwd = m_redo.Pop(); - - if (gofwd != null) - { - if (ParentGroup.GetSceneMaxUndo() > 0) - { - UndoState nUndo = new UndoState(this, gofwd.data.what); - - m_undo.Push(nUndo); - } - - gofwd.PlayState(this); - } - -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handled redo request for {0} {1}, stack size now {2}", -// Name, LocalId, m_redo.Count); - } + Undoing = true; + m_UndoRedo.Redo(this); + Undoing = false; } } public void ClearUndoState() { -// m_log.DebugFormat("[SCENE OBJECT PART]: Clearing undo and redo stacks in {0} {1}", Name, LocalId); - - lock (m_undo) + lock (m_UndoRedo) { - m_undo.Clear(); - m_redo.Clear(); + m_UndoRedo.Clear(); } } diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs index eb76ca5bba..668b53b5bb 100644 --- a/OpenSim/Region/Framework/Scenes/UndoState.cs +++ b/OpenSim/Region/Framework/Scenes/UndoState.cs @@ -27,6 +27,7 @@ using System; using System.Reflection; +using System.Collections.Generic; using log4net; using OpenMetaverse; using OpenSim.Region.Framework.Interfaces; @@ -34,6 +35,8 @@ using System; namespace OpenSim.Region.Framework.Scenes { + +/* [Flags] public enum UndoType { @@ -48,7 +51,7 @@ namespace OpenSim.Region.Framework.Scenes STATE_ALL = 63 } -/* + public class UndoState { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -194,7 +197,10 @@ namespace OpenSim.Region.Framework.Scenes */ public class UndoState { + const int UNDOEXPIRESECONDS = 300; // undo expire time (nice to have it came from a ini later) + public ObjectChangeData data; + public DateTime creationtime; /// /// Constructor. /// @@ -204,8 +210,8 @@ namespace OpenSim.Region.Framework.Scenes public UndoState(SceneObjectPart part, ObjectChangeWhat what) { data = new ObjectChangeData(); - data.what = what; + creationtime = DateTime.UtcNow; if (part.ParentGroup.RootPart == part) { @@ -227,12 +233,25 @@ namespace OpenSim.Region.Framework.Scenes } } + public bool checkExpire() + { + TimeSpan t = DateTime.UtcNow - creationtime; + if (t.Seconds > UNDOEXPIRESECONDS) + return true; + return false; + } + + public void updateExpire() + { + creationtime = DateTime.UtcNow; + } + /// /// Compare the relevant state in the given part to this state. /// /// /// true if both the part's position, rotation and scale match those in this undo state. False otherwise. - public bool Compare(SceneObjectPart part, ObjectChangeWhat what) + public bool Compare(SceneObjectPart part, ObjectChangeWhat what) { if (data.what != what) // if diferent targets, then they are diferent return false; @@ -274,6 +293,157 @@ namespace OpenSim.Region.Framework.Scenes } } + public class UndoRedoState + { + int size; + public LinkedList m_redo = new LinkedList(); + public LinkedList m_undo = new LinkedList(); + + public UndoRedoState() + { + size = 5; + } + + public UndoRedoState(int _size) + { + if (_size < 3) + size = 3; + else + size = _size; + } + + public int Count + { + get { return m_undo.Count; } + } + + public void Clear() + { + m_undo.Clear(); + m_redo.Clear(); + } + + public void StoreUndo(SceneObjectPart part, ObjectChangeWhat what) + { + lock (m_undo) + { + UndoState last; + + if (m_redo.Count > 0) // last code seems to clear redo on every new undo + { + m_redo.Clear(); + } + + if (m_undo.Count > 0) + { + // check expired entry + last = m_undo.First.Value; + if (last != null && last.checkExpire()) + m_undo.Clear(); + else + { + // see if we actually have a change + if (last != null) + { + if (last.Compare(part, what)) + return; + } + } + } + + // limite size + while (m_undo.Count >= size) + m_undo.RemoveLast(); + + UndoState nUndo = new UndoState(part, what); + m_undo.AddFirst(nUndo); + } + } + + public void Undo(SceneObjectPart part) + { + lock (m_undo) + { + UndoState nUndo; + + // expire redo + if (m_redo.Count > 0) + { + nUndo = m_redo.First.Value; + if (nUndo != null && nUndo.checkExpire()) + m_redo.Clear(); + } + + if (m_undo.Count > 0) + { + UndoState goback = m_undo.First.Value; + // check expired + if (goback != null && goback.checkExpire()) + { + m_undo.Clear(); + return; + } + + if (goback != null) + { + m_undo.RemoveFirst(); + + // redo limite size + while (m_redo.Count >= size) + m_redo.RemoveLast(); + + nUndo = new UndoState(part, goback.data.what); // new value in part should it be full goback copy? + m_redo.AddFirst(nUndo); + + goback.PlayState(part); + } + } + } + } + + public void Redo(SceneObjectPart part) + { + lock (m_undo) + { + UndoState nUndo; + + // expire undo + if (m_undo.Count > 0) + { + nUndo = m_undo.First.Value; + if (nUndo != null && nUndo.checkExpire()) + m_undo.Clear(); + } + + if (m_redo.Count > 0) + { + UndoState gofwd = m_redo.First.Value; + // check expired + if (gofwd != null && gofwd.checkExpire()) + { + m_redo.Clear(); + return; + } + + if (gofwd != null) + { + m_redo.RemoveFirst(); + + // limite undo size + while (m_undo.Count >= size) + m_undo.RemoveLast(); + + nUndo = new UndoState(part, gofwd.data.what); // new value in part should it be full gofwd copy? + m_undo.AddFirst(nUndo); + + gofwd.PlayState(part); + } + } + } + } + + + } public class LandUndoState {