// -------------------------------------------------------------------------------------------------------------------- // // Copyright (C) 2009 Jakob Christensen // // // Represents the base of a context action. // // -------------------------------------------------------------------------------------------------------------------- namespace AgentJohnson { using System; using JetBrains.Annotations; using JetBrains.Application; using JetBrains.DocumentModel; using JetBrains.ProjectModel; using JetBrains.ReSharper.Feature.Services.Bulbs; using JetBrains.ReSharper.Intentions.CSharp.DataProviders; using JetBrains.ReSharper.Psi; using JetBrains.ReSharper.Psi.Tree; using JetBrains.TextControl; using JetBrains.Util; /// Represents the base of a context action. public abstract class ContextActionBase : IBulbItem, IContextAction { #region Constants and Fields /// /// The current provider. /// private readonly IContextActionDataProvider provider; /// /// Indicates if transactions should be started. /// private bool startTransaction = true; #endregion #region Constructors and Destructors /// Initializes a new instance of the class. /// The provider. protected ContextActionBase([NotNull] ICSharpContextActionDataProvider provider) { this.provider = provider; } #endregion #region Implemented Interfaces #region IBulbAction /// /// Gets the items. /// /// The items. public IBulbItem[] Items { get { return new[] { this }; } } #endregion #region IBulbItem /// /// Gets the text. /// /// The bulb text. string IBulbItem.Text { get { return this.GetText(); } } #endregion #endregion #region Properties /// /// Gets the provider. /// /// The provider. [NotNull] public IContextActionDataProvider Provider { get { return this.provider; } } /// /// Gets the solution. /// /// The solution. protected ISolution Solution { get { return this.provider.Solution; } } /// /// Gets or sets a value indicating whether [start transaction]. /// /// true if [start transaction]; otherwise, false. protected bool StartTransaction { get { return this.startTransaction; } set { this.startTransaction = value; } } /// /// Gets the text control. /// /// The text control. protected ITextControl TextControl { get { return this.provider.TextControl; } } #endregion #region Public Methods /// Determines whether this instance is available. /// The element. /// true if this instance is available; otherwise, false. public abstract bool IsAvailable(IElement element); #endregion #region Implemented Interfaces #region IBulbAction /// /// Check if this action is available at the constructed context. /// Actions could store precalculated info in to share it between different actions /// /// The cache. /// The is available. public bool IsAvailable(IUserDataHolder cache) { return this.IsAvailableInternal(); } #endregion #region IBulbItem /// Executes the specified solution. /// The solution. /// The text control. void IBulbItem.Execute(ISolution solution, ITextControl textControl) { if (this.Solution != solution || this.TextControl != textControl) { throw new InvalidOperationException(); } var element = this.provider.SelectedElement; if (element == null) { return; } if (this.StartTransaction) { this.Modify(() => this.Execute(element)); } else { this.Execute(element); } this.PostExecute(); } #endregion #endregion #region Methods /// Returns the Modification Cookie. /// The cookie. [NotNull] protected ModificationCookie EnsureWritable() { if (this.Solution != null) { return DocumentManager.GetInstance(this.Solution).EnsureWritable(this.TextControl.Document); } return new ModificationCookie(EnsureWritableResult.FAILURE); } /// Executes this instance. /// The element. protected abstract void Execute(IElement element); /// Called to apply context action. No locks is taken before call /// The parameters. protected void ExecuteInternal(params object[] param) { var element = param[0] as IElement; if (this.startTransaction) { this.Modify(() => this.Execute(element)); } else { this.Execute(element); } this.PostExecute(); } /// Gets the text. /// The context action text. protected abstract string GetText(); /// Called to check if ContextAction is available. /// ReadLock is taken /// Will not be called if PsiManager, ProjectFile of Solution == null /// The is available internal. protected bool IsAvailableInternal() { var element = this.provider.SelectedElement; if (element == null) { return false; } return this.IsAvailable(element); } /// Posts the execute. protected virtual void PostExecute() { } /// Modifies the specified handler. /// The handler. private void Modify(Action handler) { var psiManager = PsiManager.GetInstance(this.Solution); if (psiManager == null) { return; } using (var cookie = this.EnsureWritable()) { if (cookie.EnsureWritableResult != EnsureWritableResult.SUCCESS) { return; } using (CommandCookie.Create(string.Format("Context Action {0}", this.GetText()))) { psiManager.DoTransaction(handler); } } } #endregion } }