// // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. // // This file contain implementations details that are subject to change without notice. // Use at your own risk. // using System; using System.Collections.Generic; using System.Globalization; using System.ComponentModel.Composition; using System.ComponentModel; namespace Microsoft.VisualStudio.Text.Operations.Standalone { [Export(typeof(ITextUndoHistoryRegistry))] [Export(typeof(UndoHistoryRegistryImpl))] internal class UndoHistoryRegistryImpl : ITextUndoHistoryRegistry { #region Private Fields internal Dictionary histories; private Dictionary weakContextMapping; private Dictionary strongContextMapping; #endregion // Private Fields public UndoHistoryRegistryImpl() { // set up the list of histories histories = new Dictionary(); // set up the mappings from contexts to histories weakContextMapping = new Dictionary(); strongContextMapping = new Dictionary(); } /// /// /// public IEnumerable Histories { get { return histories.Keys; } } /// /// /// /// /// public ITextUndoHistory RegisterHistory(object context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } return RegisterHistory(context, false); } /// /// /// /// /// /// public ITextUndoHistory RegisterHistory(object context, bool keepAlive) { if (context == null) { throw new ArgumentNullException(nameof(context)); } ITextUndoHistory result; if (strongContextMapping.ContainsKey(context)) { result = strongContextMapping[context]; if (!keepAlive) { strongContextMapping.Remove(context); weakContextMapping.Add(new WeakReferenceForDictionaryKey(context), result); } } else if (weakContextMapping.ContainsKey(new WeakReferenceForDictionaryKey(context))) { result = weakContextMapping[new WeakReferenceForDictionaryKey(context)]; if (keepAlive) { weakContextMapping.Remove(new WeakReferenceForDictionaryKey(context)); strongContextMapping.Add(context, result); } } else { result = new UndoHistoryImpl(this); histories.Add(result, 1); if (keepAlive) { strongContextMapping.Add(context, result); } else { weakContextMapping.Add(new WeakReferenceForDictionaryKey(context), result); } } return result; } /// /// /// /// /// public ITextUndoHistory GetHistory(object context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } ITextUndoHistory result; if (strongContextMapping.ContainsKey(context)) { result = strongContextMapping[context]; } else if (weakContextMapping.ContainsKey(new WeakReferenceForDictionaryKey(context))) { result = weakContextMapping[new WeakReferenceForDictionaryKey(context)]; } else { throw new InvalidOperationException("Strings.GetHistoryCannotFindContextInRegistry"); } return result; } /// /// /// /// /// /// public bool TryGetHistory(object context, out ITextUndoHistory history) { if (context == null) { throw new ArgumentNullException(nameof(context)); } ITextUndoHistory result = null; if (strongContextMapping.ContainsKey(context)) { result = strongContextMapping[context]; } else if (weakContextMapping.ContainsKey(new WeakReferenceForDictionaryKey(context))) { result = weakContextMapping[new WeakReferenceForDictionaryKey(context)]; } history = result; return (result != null); } /// /// /// /// /// public void AttachHistory(object context, ITextUndoHistory history) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (history == null) { throw new ArgumentNullException(nameof(history)); } AttachHistory(context, history, false); } /// /// /// /// /// /// public void AttachHistory(object context, ITextUndoHistory history, bool keepAlive) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (history == null) { throw new ArgumentNullException(nameof(history)); } if (strongContextMapping.ContainsKey(context) || weakContextMapping.ContainsKey(new WeakReferenceForDictionaryKey(context))) { throw new InvalidOperationException("Strings.AttachHistoryAlreadyContainsContextInRegistry"); } if (!histories.ContainsKey(history)) { histories.Add(history, 1); } else { ++histories[history]; } if (keepAlive) { strongContextMapping.Add(context, history); } else { weakContextMapping.Add(new WeakReferenceForDictionaryKey(context), history); } } /// /// /// /// public void RemoveHistory(ITextUndoHistory history) { if (history == null) { throw new ArgumentNullException(nameof(history)); } if (!histories.ContainsKey(history)) { return; } histories.Remove(history); List strongToRemove = new List(); foreach (object o in strongContextMapping.Keys) { if (Object.ReferenceEquals(strongContextMapping[o], history)) { strongToRemove.Add(o); } } strongToRemove.ForEach(delegate(object o) { strongContextMapping.Remove(o); }); List weakToRemove = new List(); foreach (WeakReferenceForDictionaryKey o in weakContextMapping.Keys) { if (Object.ReferenceEquals(weakContextMapping[o], history)) { weakToRemove.Add(o); } } weakToRemove.ForEach(delegate(WeakReferenceForDictionaryKey o) { weakContextMapping.Remove(o); }); return; } } }