From 53f53a33200cc9a80a98585b5564ddf0d03812e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kon=C3=AD=C4=8Dek?= Date: Tue, 27 Jul 2010 18:28:21 +0000 Subject: [PATCH] First implementation of GUI for editor context actions. A WPF Popup is shown over the editor when some actions are available. Can be opened by mouse click (TODO open by shortcut). A Popup is probably not the best solution: it is not "tied" to current editor line anyhow so it stays open when region is collapsed, active ViewContent changes etc. (for active ViewContent change I added explicit handling). It should be probably part of editor's visual tree, in a special layer. Alternatively it could be displayed in the bookmark margin, but that would make it too small. This way it resembles ReSharper. Have to consult this with Daniel. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@6290 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/ContextActionsRenderer.cs | 40 +++++++++++++++++-- .../Project/Src/GenerateCode.cs | 2 +- .../ContextActionsHeaderedControl.xaml | 4 +- .../ContextActionsHeaderedControl.xaml.cs | 33 +++++++++++++++ .../ContextActions/ContextActionsPopup.cs | 4 ++ .../ContextActions/ContextActionsService.cs | 1 - .../ContextActionsHelper.cs | 6 +-- 7 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActionsRenderer.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActionsRenderer.cs index 8144ac5b12..8031bc157c 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActionsRenderer.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActionsRenderer.cs @@ -8,8 +8,10 @@ using System; using System.Collections.ObjectModel; using System.Linq; using System.Windows.Threading; +using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor.AvalonEdit; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Refactoring; namespace ICSharpCode.AvalonEdit.AddIn @@ -44,11 +46,34 @@ namespace ICSharpCode.AvalonEdit.AddIn this.delayMoveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMoveMilliseconds) }; this.delayMoveTimer.Stop(); this.delayMoveTimer.Tick += TimerMoveTick; + WorkbenchSingleton.Workbench.ViewClosed += WorkbenchSingleton_Workbench_ViewClosed; + WorkbenchSingleton.Workbench.ActiveViewContentChanged += WorkbenchSingleton_Workbench_ActiveViewContentChanged; + } + + void WorkbenchSingleton_Workbench_ViewClosed(object sender, ViewContentEventArgs e) + { + try { + // prevent memory leaks + if (e.Content.PrimaryFileName == this.Editor.FileName) { + WorkbenchSingleton.Workbench.ViewClosed -= WorkbenchSingleton_Workbench_ViewClosed; + WorkbenchSingleton.Workbench.ActiveViewContentChanged -= WorkbenchSingleton_Workbench_ActiveViewContentChanged; + } + } catch {} + } + + void WorkbenchSingleton_Workbench_ActiveViewContentChanged(object sender, EventArgs e) + { + ClosePopup(); + try { + // open the popup again if in current file + if (((IViewContent)WorkbenchSingleton.Workbench.ActiveContent).PrimaryFileName == this.Editor.FileName) + CaretPositionChanged(this, EventArgs.Empty); + } catch {} } void ScrollChanged(object sender, EventArgs e) { - this.popup.Close(); + ClosePopup(); } void TimerMoveTick(object sender, EventArgs e) @@ -62,7 +87,8 @@ namespace ICSharpCode.AvalonEdit.AddIn return; this.popup.Actions = new ContextActionsViewModel { - Title = "A", + Title = "#", + //Image = ClassBrowserIconService.Class.ImageSource, Actions = availableActionsVM }; this.popup.OpenAtLineStart(this.Editor); @@ -72,11 +98,17 @@ namespace ICSharpCode.AvalonEdit.AddIn { if (this.popup.IsOpen) { - this.popup.Close(); - this.popup.Actions = null; + ClosePopup(); } this.delayMoveTimer.Stop(); this.delayMoveTimer.Start(); } + + void ClosePopup() + { + this.popup.Close(); + this.popup.IsDropdownOpen = false; + this.popup.Actions = null; + } } } diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/GenerateCode.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/GenerateCode.cs index 98c376e6ae..9e2bab57c4 100644 --- a/src/AddIns/Misc/SharpRefactoring/Project/Src/GenerateCode.cs +++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/GenerateCode.cs @@ -330,4 +330,4 @@ namespace SharpRefactoring } } #endregion -} +} \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml index 2073629bc4..fdca32c814 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml @@ -18,8 +18,8 @@ - + diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml.cs index b8fe260a35..95d51890c8 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml.cs @@ -24,6 +24,31 @@ namespace ICSharpCode.SharpDevelop.Refactoring public ContextActionsHeaderedControl() { InitializeComponent(); + this.IsAlwaysOpen = false; + this.IsOpen = false; + } + + bool isAlwaysOpen; + public bool IsAlwaysOpen { + get { return isAlwaysOpen; } + set { + isAlwaysOpen = value; + if (value) + IsOpen = true; + } + } + + bool isOpen; + public bool IsOpen { + get { return isOpen; } + set { + if (IsAlwaysOpen && !value) + throw new InvalidOperationException("Cannot set IsOpen to false when IsAlwaysOpen is true"); + isOpen = value; + this.Header.Opacity = isOpen ? 1.0 : 0.5; + this.Header.BorderThickness = isOpen ? new Thickness(1, 1, 1, 0) : new Thickness(1); + this.ActionsTreeView.Visibility = isOpen ? Visibility.Visible : Visibility.Collapsed; + } } public event EventHandler ActionExecuted @@ -37,5 +62,13 @@ namespace ICSharpCode.SharpDevelop.Refactoring if (this.ActionsTreeView != null) this.ActionsTreeView.Focus(); } + + void Header_MouseUp(object sender, MouseButtonEventArgs e) + { + if (!this.IsAlwaysOpen) + { + this.IsOpen = !this.IsOpen; + } + } } } \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsPopup.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsPopup.cs index d807ae755a..1b1c11329b 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsPopup.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsPopup.cs @@ -35,6 +35,9 @@ namespace ICSharpCode.SharpDevelop.Refactoring Close(); } + public bool IsDropdownOpen { get { return ActionsControl.IsOpen; } set {ActionsControl.IsOpen = value; } } + public bool IsDropdownAlwaysOpen { get { return ActionsControl.IsAlwaysOpen; } set {ActionsControl.IsAlwaysOpen = value; } } + ContextActionsHeaderedControl ActionsControl { get { return (ContextActionsHeaderedControl)this.Child; } @@ -73,6 +76,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring public void OpenAtLineStart(ITextEditor editor) { OpenAtPosition(editor, editor.Caret.Line, 1, false); + this.VerticalOffset -= 16; } void OpenAtPosition(ITextEditor editor, int line, int column, bool openAtWordStart) diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsService.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsService.cs index 9f7987a353..44f6a7812e 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsService.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsService.cs @@ -39,7 +39,6 @@ namespace ICSharpCode.SharpDevelop.Refactoring /// public IEnumerable GetAvailableActions(ITextEditor editor) { - yield break; var editorContext = new EditorContext(editor); // could run providers in parallel foreach (var provider in this.providers) { diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActionsHelper.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActionsHelper.cs index 08fe044ca6..c1889cb01d 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActionsHelper.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActionsHelper.cs @@ -27,7 +27,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring var popupViewModel = new ContextActionsViewModel { Title = MenuService.ConvertLabel(StringParser.Parse( "${res:SharpDevelop.Refactoring.ClassesDerivingFrom}", new StringTagPair("Name", baseClass.Name)))}; popupViewModel.Actions = new PopupTreeViewModelBuilder().BuildTreeViewModel(derivedClassesTree); - return new ContextActionsPopup { Actions = popupViewModel }; + return new ContextActionsPopup { Actions = popupViewModel, IsDropdownAlwaysOpen = true }; } public static ContextActionsPopup MakePopupWithBaseClasses(IClass @class) @@ -40,7 +40,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring var popupViewModel = new ContextActionsViewModel { Title = MenuService.ConvertLabel(StringParser.Parse( "${res:SharpDevelop.Refactoring.BaseClassesOf}", new StringTagPair("Name", @class.Name)))}; popupViewModel.Actions = new PopupListViewModelBuilder().BuildListViewModel(baseClassList); - return new ContextActionsPopup { Actions = popupViewModel }; + return new ContextActionsPopup { Actions = popupViewModel, IsDropdownAlwaysOpen = true }; } public static ContextActionsPopup MakePopupWithOverrides(IMember member) @@ -49,7 +49,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring var popupViewModel = new ContextActionsViewModel { Title = MenuService.ConvertLabel(StringParser.Parse( "${res:SharpDevelop.Refactoring.OverridesOf}", new string[,] {{ "Name", member.FullyQualifiedName }}))}; popupViewModel.Actions = new OverridesPopupTreeViewModelBuilder(member).BuildTreeViewModel(derivedClassesTree); - return new ContextActionsPopup { Actions = popupViewModel }; + return new ContextActionsPopup { Actions = popupViewModel, IsDropdownAlwaysOpen = true }; } class PopupViewModelBuilder