Browse Source

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
pull/1/head
Martin Koníček 16 years ago
parent
commit
53f53a3320
  1. 40
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActionsRenderer.cs
  2. 2
      src/AddIns/Misc/SharpRefactoring/Project/Src/GenerateCode.cs
  3. 4
      src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml
  4. 33
      src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml.cs
  5. 4
      src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsPopup.cs
  6. 1
      src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsService.cs
  7. 6
      src/Main/Base/Project/Src/Services/RefactoringService/ContextActionsHelper.cs

40
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActionsRenderer.cs

@ -8,8 +8,10 @@ using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.AvalonEdit; using ICSharpCode.SharpDevelop.Editor.AvalonEdit;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Refactoring; using ICSharpCode.SharpDevelop.Refactoring;
namespace ICSharpCode.AvalonEdit.AddIn namespace ICSharpCode.AvalonEdit.AddIn
@ -44,11 +46,34 @@ namespace ICSharpCode.AvalonEdit.AddIn
this.delayMoveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMoveMilliseconds) }; this.delayMoveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMoveMilliseconds) };
this.delayMoveTimer.Stop(); this.delayMoveTimer.Stop();
this.delayMoveTimer.Tick += TimerMoveTick; 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) void ScrollChanged(object sender, EventArgs e)
{ {
this.popup.Close(); ClosePopup();
} }
void TimerMoveTick(object sender, EventArgs e) void TimerMoveTick(object sender, EventArgs e)
@ -62,7 +87,8 @@ namespace ICSharpCode.AvalonEdit.AddIn
return; return;
this.popup.Actions = new ContextActionsViewModel { this.popup.Actions = new ContextActionsViewModel {
Title = "A", Title = "#",
//Image = ClassBrowserIconService.Class.ImageSource,
Actions = availableActionsVM Actions = availableActionsVM
}; };
this.popup.OpenAtLineStart(this.Editor); this.popup.OpenAtLineStart(this.Editor);
@ -72,11 +98,17 @@ namespace ICSharpCode.AvalonEdit.AddIn
{ {
if (this.popup.IsOpen) if (this.popup.IsOpen)
{ {
this.popup.Close(); ClosePopup();
this.popup.Actions = null;
} }
this.delayMoveTimer.Stop(); this.delayMoveTimer.Stop();
this.delayMoveTimer.Start(); this.delayMoveTimer.Start();
} }
void ClosePopup()
{
this.popup.Close();
this.popup.IsDropdownOpen = false;
this.popup.Actions = null;
}
} }
} }

2
src/AddIns/Misc/SharpRefactoring/Project/Src/GenerateCode.cs

@ -330,4 +330,4 @@ namespace SharpRefactoring
} }
} }
#endregion #endregion
} }

4
src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml

@ -18,8 +18,8 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<!-- Header --> <!-- Header -->
<Border Grid.Row="0" Grid.Column="0" Padding="4" BorderThickness="1 1 1 0" <Border x:Name="Header" Grid.Row="0" Grid.Column="0" Padding="4" BorderThickness="1"
BorderBrush="{StaticResource OuterBorderBrush}" HorizontalAlignment="Left"> BorderBrush="{StaticResource OuterBorderBrush}" HorizontalAlignment="Left" MouseUp="Header_MouseUp">
<Border.Background> <Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#D6E9FF" Offset="0"/> <GradientStop Color="#D6E9FF" Offset="0"/>

33
src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHeaderedControl.xaml.cs

@ -24,6 +24,31 @@ namespace ICSharpCode.SharpDevelop.Refactoring
public ContextActionsHeaderedControl() public ContextActionsHeaderedControl()
{ {
InitializeComponent(); 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 public event EventHandler ActionExecuted
@ -37,5 +62,13 @@ namespace ICSharpCode.SharpDevelop.Refactoring
if (this.ActionsTreeView != null) if (this.ActionsTreeView != null)
this.ActionsTreeView.Focus(); this.ActionsTreeView.Focus();
} }
void Header_MouseUp(object sender, MouseButtonEventArgs e)
{
if (!this.IsAlwaysOpen)
{
this.IsOpen = !this.IsOpen;
}
}
} }
} }

4
src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsPopup.cs

@ -35,6 +35,9 @@ namespace ICSharpCode.SharpDevelop.Refactoring
Close(); 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 ContextActionsHeaderedControl ActionsControl
{ {
get { return (ContextActionsHeaderedControl)this.Child; } get { return (ContextActionsHeaderedControl)this.Child; }
@ -73,6 +76,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
public void OpenAtLineStart(ITextEditor editor) public void OpenAtLineStart(ITextEditor editor)
{ {
OpenAtPosition(editor, editor.Caret.Line, 1, false); OpenAtPosition(editor, editor.Caret.Line, 1, false);
this.VerticalOffset -= 16;
} }
void OpenAtPosition(ITextEditor editor, int line, int column, bool openAtWordStart) void OpenAtPosition(ITextEditor editor, int line, int column, bool openAtWordStart)

1
src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsService.cs

@ -39,7 +39,6 @@ namespace ICSharpCode.SharpDevelop.Refactoring
/// </summary> /// </summary>
public IEnumerable<IContextAction> GetAvailableActions(ITextEditor editor) public IEnumerable<IContextAction> GetAvailableActions(ITextEditor editor)
{ {
yield break;
var editorContext = new EditorContext(editor); var editorContext = new EditorContext(editor);
// could run providers in parallel // could run providers in parallel
foreach (var provider in this.providers) { foreach (var provider in this.providers) {

6
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( var popupViewModel = new ContextActionsViewModel { Title = MenuService.ConvertLabel(StringParser.Parse(
"${res:SharpDevelop.Refactoring.ClassesDerivingFrom}", new StringTagPair("Name", baseClass.Name)))}; "${res:SharpDevelop.Refactoring.ClassesDerivingFrom}", new StringTagPair("Name", baseClass.Name)))};
popupViewModel.Actions = new PopupTreeViewModelBuilder().BuildTreeViewModel(derivedClassesTree); popupViewModel.Actions = new PopupTreeViewModelBuilder().BuildTreeViewModel(derivedClassesTree);
return new ContextActionsPopup { Actions = popupViewModel }; return new ContextActionsPopup { Actions = popupViewModel, IsDropdownAlwaysOpen = true };
} }
public static ContextActionsPopup MakePopupWithBaseClasses(IClass @class) public static ContextActionsPopup MakePopupWithBaseClasses(IClass @class)
@ -40,7 +40,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
var popupViewModel = new ContextActionsViewModel { Title = MenuService.ConvertLabel(StringParser.Parse( var popupViewModel = new ContextActionsViewModel { Title = MenuService.ConvertLabel(StringParser.Parse(
"${res:SharpDevelop.Refactoring.BaseClassesOf}", new StringTagPair("Name", @class.Name)))}; "${res:SharpDevelop.Refactoring.BaseClassesOf}", new StringTagPair("Name", @class.Name)))};
popupViewModel.Actions = new PopupListViewModelBuilder().BuildListViewModel(baseClassList); popupViewModel.Actions = new PopupListViewModelBuilder().BuildListViewModel(baseClassList);
return new ContextActionsPopup { Actions = popupViewModel }; return new ContextActionsPopup { Actions = popupViewModel, IsDropdownAlwaysOpen = true };
} }
public static ContextActionsPopup MakePopupWithOverrides(IMember member) public static ContextActionsPopup MakePopupWithOverrides(IMember member)
@ -49,7 +49,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
var popupViewModel = new ContextActionsViewModel { Title = MenuService.ConvertLabel(StringParser.Parse( var popupViewModel = new ContextActionsViewModel { Title = MenuService.ConvertLabel(StringParser.Parse(
"${res:SharpDevelop.Refactoring.OverridesOf}", new string[,] {{ "Name", member.FullyQualifiedName }}))}; "${res:SharpDevelop.Refactoring.OverridesOf}", new string[,] {{ "Name", member.FullyQualifiedName }}))};
popupViewModel.Actions = new OverridesPopupTreeViewModelBuilder(member).BuildTreeViewModel(derivedClassesTree); popupViewModel.Actions = new OverridesPopupTreeViewModelBuilder(member).BuildTreeViewModel(derivedClassesTree);
return new ContextActionsPopup { Actions = popupViewModel }; return new ContextActionsPopup { Actions = popupViewModel, IsDropdownAlwaysOpen = true };
} }
class PopupViewModelBuilder class PopupViewModelBuilder

Loading…
Cancel
Save