Explorar o código

2008-01-04 Ivan N. Zlatev <[email protected]>

        * UndoEngine.cs: implemented.


svn path=/trunk/mcs/; revision=92222
Ivan Zlatev %!s(int64=18) %!d(string=hai) anos
pai
achega
a68d302aaf

+ 4 - 0
mcs/class/System.Design/System.ComponentModel.Design/ChangeLog

@@ -1,3 +1,7 @@
+2008-01-04  Ivan N. Zlatev  <[email protected]>
+
+	* UndoEngine.cs: implemented.
+
 2008-01-04  Ivan N. Zlatev  <[email protected]>
 	
 	* DesignerHost.cs: Fix lastTransaction to be set properly.

+ 363 - 71
mcs/class/System.Design/System.ComponentModel.Design/UndoEngine.cs

@@ -2,9 +2,9 @@
 // System.ComponentModel.Design.UndoEngine.cs
 //
 // Author:
-//      Atsushi Enomoto  <[email protected]>
+// 	Ivan N. Zlatev  <[email protected]>
 //
-// Copyright (C) 2007 Novell, Inc
+// Copyright (C) 2007 Ivan N. Zlatev <[email protected]>
 //
 
 //
@@ -31,43 +31,193 @@
 
 using System;
 using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.Collections.Generic;
+using System.ComponentModel.Design.Serialization;
 
 namespace System.ComponentModel.Design
 {
 	public abstract class UndoEngine : IDisposable
 	{
-		[MonoTODO]
+		private bool _undoing;
+		private UndoUnit _currentUnit;
+		private IServiceProvider _provider;
+		private bool _enabled;
+
 		protected UndoEngine (IServiceProvider provider)
 		{
-			throw new NotImplementedException ();
+			if (provider == null)
+				throw new ArgumentNullException ("provider");
+
+			_provider = provider;
+			_currentUnit = null;
+			Enable ();
+		}
+
+		private void Enable ()
+		{
+			if (!_enabled) {
+				IComponentChangeService changeService = GetRequiredService (typeof (IComponentChangeService)) as IComponentChangeService;
+				changeService.ComponentAdding += new ComponentEventHandler (OnComponentAdding);
+				changeService.ComponentAdded += new ComponentEventHandler (OnComponentAdded);
+				changeService.ComponentRemoving += new ComponentEventHandler (OnComponentRemoving);
+				changeService.ComponentRemoved += new ComponentEventHandler (OnComponentRemoved);
+				changeService.ComponentChanging += new ComponentChangingEventHandler (OnComponentChanging);
+				changeService.ComponentChanged += new ComponentChangedEventHandler (OnComponentChanged);
+				changeService.ComponentRename += new ComponentRenameEventHandler (OnComponentRename);
+
+				IDesignerHost host = GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+				host.TransactionClosed += new DesignerTransactionCloseEventHandler (OnTransactionClosed);
+				host.TransactionOpened += new EventHandler (OnTransactionOpened);
+
+				_enabled = true;
+			}
+		}
+
+		private void Disable ()
+		{
+			if (_enabled) {
+				IComponentChangeService changeService = GetRequiredService (typeof (IComponentChangeService)) as IComponentChangeService;
+				changeService.ComponentAdding -= new ComponentEventHandler (OnComponentAdding);
+				changeService.ComponentAdded -= new ComponentEventHandler (OnComponentAdded);
+				changeService.ComponentRemoving -= new ComponentEventHandler (OnComponentRemoving);
+				changeService.ComponentRemoved -= new ComponentEventHandler (OnComponentRemoved);
+				changeService.ComponentChanging -= new ComponentChangingEventHandler (OnComponentChanging);
+				changeService.ComponentChanged -= new ComponentChangedEventHandler (OnComponentChanged);
+				changeService.ComponentRename -= new ComponentRenameEventHandler (OnComponentRename);
+
+				IDesignerHost host = GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+				host.TransactionClosed -= new DesignerTransactionCloseEventHandler (OnTransactionClosed);
+				host.TransactionOpened -= new EventHandler (OnTransactionOpened);
+
+				_enabled = false;
+			}
+		}
+
+		// FIXME: there could be more transactions opened and closed (but not commited) after the first one!!!
+		// This means that there should be multiple units. Only the top level transaction is commited though
+		// 
+		private void OnTransactionOpened (object sender, EventArgs args)
+		{
+			if (_currentUnit == null) {
+				IDesignerHost host = GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+				_currentUnit = CreateUndoUnit (host.TransactionDescription, true);
+			}
+		}
+
+
+		private void OnTransactionClosed (object sender, DesignerTransactionCloseEventArgs args)
+		{
+			IDesignerHost host = GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+			if (!host.InTransaction) { // the "top-most" transaction was closed (currentUnit one)
+				_currentUnit.Close ();
+				if (args.TransactionCommitted) {
+					AddUndoUnit (_currentUnit);
+				} else {
+					_currentUnit.Undo ();
+					DiscardUndoUnit (_currentUnit);
+				}
+				_currentUnit = null;
+			}
+		}
+
+		private void OnComponentAdding (object sender, ComponentEventArgs args)
+		{
+			if (_currentUnit == null)
+				_currentUnit = CreateUndoUnit ("Add " + args.Component.GetType ().Name, true);
+			_currentUnit.ComponentAdding (args);
+		}
+
+		private void OnComponentAdded (object sender, ComponentEventArgs args)
+		{
+			if (_currentUnit == null)
+				_currentUnit = CreateUndoUnit ("Add " + args.Component.Site.Name, true);
+			_currentUnit.ComponentAdded (args);
+
+			IDesignerHost host = GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+			if (!host.InTransaction) {
+				_currentUnit.Close ();
+				AddUndoUnit (_currentUnit);
+				_currentUnit = null;
+			}
+		}
+
+		private void OnComponentRemoving (object sender, ComponentEventArgs args)
+		{
+			if (_currentUnit == null)
+				_currentUnit = CreateUndoUnit ("Remove " + args.Component.Site.Name, true);
+			_currentUnit.ComponentRemoving (args);
+		}
+
+		private void OnComponentRemoved (object sender, ComponentEventArgs args)
+		{
+			if (_currentUnit == null)
+				_currentUnit = CreateUndoUnit ("Remove " + args.Component.GetType ().Name, true);
+			_currentUnit.ComponentRemoved (args);
+
+			IDesignerHost host = GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+			if (!host.InTransaction) {
+				_currentUnit.Close ();
+				AddUndoUnit (_currentUnit);
+				_currentUnit = null;
+			}
+		}
+
+		private void OnComponentChanging (object sender, ComponentChangingEventArgs args)
+		{
+			if (_currentUnit == null)
+				_currentUnit = CreateUndoUnit ("Modify " + ((IComponent)args.Component).Site.Name + "." + args.Member.Name, true);
+			_currentUnit.ComponentChanging (args);
+		}
+
+		private void OnComponentChanged (object sender, ComponentChangedEventArgs args)
+		{
+			if (_currentUnit == null)
+				_currentUnit = CreateUndoUnit ("Modify " + ((IComponent)args.Component).Site.Name + "." + args.Member.Name, true);
+			_currentUnit.ComponentChanged (args);
+
+			IDesignerHost host = GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+			if (!host.InTransaction) {
+				_currentUnit.Close ();
+				AddUndoUnit (_currentUnit);
+				_currentUnit = null;
+			}
+		}
+
+		private void OnComponentRename (object sender, ComponentRenameEventArgs args)
+		{
+			if (_currentUnit == null)
+				_currentUnit = CreateUndoUnit ("Rename " + ((IComponent)args.Component).Site.Name, true);
+			_currentUnit.ComponentRename (args);
+
+			IDesignerHost host = GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+			if (!host.InTransaction) {
+				_currentUnit.Close ();
+				AddUndoUnit (_currentUnit);
+				_currentUnit = null;
+			}
 		}
 
 		public event EventHandler Undoing;
 		public event EventHandler Undone;
 
-		[MonoTODO]
 		public bool Enabled {
-			get { throw new NotImplementedException (); }
-			set { throw new NotImplementedException (); }
+			get { return _enabled; }
+			set {
+				if (value)
+					Enable ();
+				else
+					Disable ();
+			}
 		}
 
-		[MonoTODO]
 		public bool UndoInProgress {
-			get { throw new NotImplementedException (); }
+			get { return _undoing; }
 		}
 
-		protected abstract void AddUndoUnit (UndoEngine.UndoUnit unit);
-
-		[MonoTODO]
 		protected virtual UndoEngine.UndoUnit CreateUndoUnit (string name, bool primary)
 		{
-			throw new NotImplementedException ();
-		}
-
-		[MonoTODO]
-		protected virtual void DiscardUndoUnit (UndoEngine.UndoUnit unit)
-		{
-			throw new NotImplementedException ();
+			return new UndoUnit (this, name);
 		}
 
 		public void Dispose ()
@@ -75,130 +225,272 @@ namespace System.ComponentModel.Design
 			Dispose (true);
 		}
 
-		[MonoTODO]
 		protected virtual void Dispose (bool disposing)
 		{
+			if (disposing) {
+				if (_currentUnit != null) {
+					_currentUnit.Close ();
+					_currentUnit = null;
+				}
+			}
 		}
 
-		[MonoTODO]
 		protected object GetRequiredService (Type serviceType)
 		{
-			throw new NotImplementedException ();
+			object service = this.GetService (serviceType);
+			if (service == null)
+				throw new NotSupportedException ("Service '" + serviceType.Name + "' missing");
+			return service;
 		}
 
-		[MonoTODO]
 		protected object GetService (Type serviceType)
 		{
-			throw new NotImplementedException ();
+			if (serviceType == null)
+				throw new ArgumentNullException ("serviceType");
+
+			if (_provider != null)
+				return _provider.GetService (serviceType);
+			return null;
 		}
 
-		[MonoTODO]
 		protected virtual void OnUndoing (EventArgs e)
 		{
-			throw new NotImplementedException ();
+			Disable ();
+			_undoing = true;
+			if (Undoing != null)
+				Undoing (this, e);
 		}
 
-		[MonoTODO]
 		protected virtual void OnUndone (EventArgs e)
 		{
-			throw new NotImplementedException ();
+			Enable ();
+			_undoing = false;
+			if (Undone != null)
+				Undone (this, e);
 		}
 
+
+		protected abstract void AddUndoUnit (UndoEngine.UndoUnit unit);
+
+		protected virtual void DiscardUndoUnit (UndoEngine.UndoUnit unit)
+		{
+		}
+
+
 		protected class UndoUnit
 		{
-			UndoEngine engine;
-			string name;
+			private class Action
+			{
+				public virtual void Undo (UndoEngine engine)
+				{
+				}
+			}
+
+			private class ComponentRenameAction : Action
+			{
+				private string _oldName;
+				private string _currentName;
+
+				public ComponentRenameAction (string currentName, string oldName)
+				{
+					_currentName = currentName;
+					_oldName = oldName;
+				}
+
+				public override void Undo (UndoEngine engine)
+				{
+					IComponentChangeService changeService = engine.GetRequiredService (typeof (IComponentChangeService)) as IComponentChangeService;
+					IDesignerHost host = engine.GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+
+					IComponent component = host.Container.Components[_currentName];
+					changeService.OnComponentChanging (component, null);
+					component.Site.Name = _oldName;
+					string tmp = _currentName;
+					_currentName = _oldName;
+					_oldName = tmp;
+					changeService.OnComponentChanged (component, null, null, null);
+				}
+			} // ComponentRenameAction
+
+			private class ComponentAddRemoveAction : Action
+			{
+				private string _componentName;
+				private SerializationStore _serializedComponent;
+				private bool _added;
+
+				public ComponentAddRemoveAction (UndoEngine engine, IComponent component, bool added)
+				{
+					if (component == null)
+						throw new ArgumentNullException ("component");
+					ComponentSerializationService serializationService = engine.GetRequiredService (
+						typeof (ComponentSerializationService)) as ComponentSerializationService;
+
+					_serializedComponent = serializationService.CreateStore ();
+					serializationService.Serialize (_serializedComponent, component);
+					_serializedComponent.Close ();
+
+					_added = added;
+					_componentName = component.Site.Name;
+				}
+
+				public override void Undo (UndoEngine engine)
+				{
+					IDesignerHost host = engine.GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+					if (_added) {
+						host.DestroyComponent (host.Container.Components[_componentName]);
+						_added = false;
+					} else {
+						ComponentSerializationService serializationService = engine.GetRequiredService (
+							typeof (ComponentSerializationService)) as ComponentSerializationService;
+
+						serializationService.DeserializeTo (_serializedComponent, host.Container);
+						_added = true;
+					}
+				}
+			} // ComponentAddRemoveAction
+
+
+			private class ComponentChangeAction : Action
+			{
+				private SerializationStore _currentState;
+				private SerializationStore _oldState;
+
+				public ComponentChangeAction ()
+				{
+				}
+
+				public void SetOriginalState (UndoEngine engine, IComponent component, MemberDescriptor member)
+				{
+					ComponentSerializationService serializationService = engine.GetRequiredService (
+						typeof (ComponentSerializationService)) as ComponentSerializationService;
+					_oldState = serializationService.CreateStore ();
+					serializationService.SerializeMember (_oldState, component, member);
+					_oldState.Close ();
+				}
+
+
+				public void SetModifiedState (UndoEngine engine, IComponent component, MemberDescriptor member)
+				{
+					ComponentSerializationService serializationService = engine.GetRequiredService (
+						typeof (ComponentSerializationService)) as ComponentSerializationService;
+					_currentState = serializationService.CreateStore ();
+					serializationService.SerializeMember (_currentState, component, member);
+					_currentState.Close ();
+				}
+
+				public override void Undo (UndoEngine engine)
+				{
+					ComponentSerializationService serializationService = engine.GetRequiredService (
+						typeof (ComponentSerializationService)) as ComponentSerializationService;
+					IDesignerHost host = engine.GetRequiredService (typeof (IDesignerHost)) as IDesignerHost;
+					serializationService.Deserialize (_oldState, host.Container);
+
+					SerializationStore tmp = _currentState;
+					_currentState = _oldState;
+					_oldState = tmp;
+				}
+			} // ComponentChangeAction
+
+			private UndoEngine _engine;
+			private string _name;
+			private bool _closed;
+			private Stack <Action> _actions;
 
-			[MonoTODO]
 			public UndoUnit (UndoEngine engine, string name)
 			{
-				this.engine = engine;
-				this.name = name;
+				if (engine == null)
+					throw new ArgumentNullException ("engine");
+				if (name == null)
+					throw new ArgumentNullException ("name");
+					//name = String.Empty;
+
+				_engine = engine;
+				_name = name;
+				_actions = new Stack <Action> ();
+			}
+
+			public void Undo ()
+			{
+				_engine.OnUndoing (EventArgs.Empty);
+				UndoCore ();
+				_engine.OnUndone (EventArgs.Empty);
+			}
+
+			protected virtual void UndoCore ()
+			{
+				foreach (Action action in _actions)
+					action.Undo (_engine);
 			}
 
 			protected UndoEngine UndoEngine {
-				get { return engine; }
+				get { return _engine; }
 			}
 
-			[MonoTODO]
 			public virtual bool IsEmpty {
-				get { throw new NotImplementedException (); }
+				get { return _actions.Count == 0; }
 			}
 
 			public virtual string Name {
-				get { return name; }
+				get { return _name; }
 			}
 
-			[MonoTODO]
 			public virtual void Close ()
 			{
-				throw new NotImplementedException ();
+				_closed = true;
 			}
 
-			[MonoTODO]
 			public virtual void ComponentAdded (ComponentEventArgs e)
 			{
-				throw new NotImplementedException ();
+				if (!_closed)
+					_actions.Push (new ComponentAddRemoveAction (_engine, (IComponent) e.Component, true));
 			}
 
-			[MonoTODO]
 			public virtual void ComponentAdding (ComponentEventArgs e)
 			{
-				throw new NotImplementedException ();
 			}
 
-			[MonoTODO]
-			public virtual void ComponentChanged (ComponentEventArgs e)
+			public virtual void ComponentChanged (ComponentChangedEventArgs e)
 			{
-				throw new NotImplementedException ();
+				if (!_closed) {
+					ComponentChangeAction action = _actions.Peek () as ComponentChangeAction;
+					if (action != null)
+						action.SetModifiedState (_engine, (IComponent) e.Component, e.Member);
+				}
 			}
 
-			[MonoTODO]
-			public virtual void ComponentChanging (ComponentEventArgs e)
+			public virtual void ComponentChanging (ComponentChangingEventArgs e)
 			{
-				throw new NotImplementedException ();
+				if (!_closed) {
+					ComponentChangeAction action = new ComponentChangeAction ();
+					action.SetOriginalState (_engine, (IComponent) e.Component, e.Member);
+					_actions.Push (action);
+				}
 			}
 
-			[MonoTODO]
 			public virtual void ComponentRemoved (ComponentEventArgs e)
 			{
-				throw new NotImplementedException ();
+				if (!_closed)
+					_actions.Push (new ComponentAddRemoveAction (_engine, e.Component, false));
 			}
 
-			[MonoTODO]
 			public virtual void ComponentRemoving (ComponentEventArgs e)
 			{
-				throw new NotImplementedException ();
 			}
 
-			[MonoTODO]
 			public virtual void ComponentRename (ComponentRenameEventArgs e)
 			{
-				throw new NotImplementedException ();
+				if (!_closed)
+					_actions.Push (new ComponentRenameAction (((IComponent)e.Component).Site.Name, e.OldName));
 			}
 
-			[MonoTODO]
 			protected object GetService (Type serviceType)
 			{
-				throw new NotImplementedException ();
+				return _engine.GetService (serviceType);
 			}
 
-			[MonoTODO]
 			public override string ToString ()
 			{
-				return base.ToString ();
-			}
-
-			[MonoTODO]
-			public void Undo ()
-			{
-				throw new NotImplementedException ();
-			}
-
-			[MonoTODO]
-			protected virtual void UndoCore ()
-			{
-				throw new NotImplementedException ();
+				return _name;
 			}
 		}
 	}