Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix focus on rename UI opening #60846

Merged
merged 8 commits into from
May 13, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Extensions;
using Microsoft.CodeAnalysis.Telemetry;
using System.Windows;

#if !COCOA
using System.Linq;
Expand Down Expand Up @@ -41,47 +42,49 @@ public RenameCommandHandler(IThreadingContext threadingContext, InlineRenameServ
}

#if !COCOA
protected override bool DashboardShouldReceiveKeyboardNavigation(ITextView textView)
=> GetDashboard(textView) is { } dashboard && dashboard.ShouldReceiveKeyboardNavigation;
protected override bool AdornmentShouldReceiveKeyboardNavigation(ITextView textView)
=> GetAdornment(textView) is RenameDashboard dashboard
? dashboard.ShouldReceiveKeyboardNavigation
: true; // Always receive keyboard navigation for the inline adornment

protected override void SetFocusToTextView(ITextView textView)
{
(textView as IWpfTextView)?.VisualElement.Focus();
}

protected override void SetFocusToDashboard(ITextView textView)
protected override void SetFocusToAdornment(ITextView textView)
{
if (GetDashboard(textView) is { } dashboard)
if (GetAdornment(textView) is { } adornment)
{
dashboard.Focus();
adornment.Focus();
}
}

protected override void SetDashboardFocusToNextElement(ITextView textView)
protected override void SetAdornmentFocusToNextElement(ITextView textView)
{
if (GetDashboard(textView) is { } dashboard)
if (GetAdornment(textView) is RenameDashboard dashboard)
{
dashboard.FocusNextElement();
}
}

protected override void SetDashboardFocusToPreviousElement(ITextView textView)
protected override void SetAdornmentFocusToPreviousElement(ITextView textView)
{
if (GetDashboard(textView) is { } dashboard)
if (GetAdornment(textView) is RenameDashboard dashboard)
{
dashboard.FocusNextElement();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be .FocusPreviousElement()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh it definitely should... idk what that will break though :) I'll file an issue to change it

}
}

private static Dashboard? GetDashboard(ITextView textView)
private static InlineRenameAdornment? GetAdornment(ITextView textView)
{
// If our adornment layer somehow didn't get composed, GetAdornmentLayer will throw.
// Don't crash if that happens.
try
{
var adornment = ((IWpfTextView)textView).GetAdornmentLayer("RoslynRenameDashboard");
return adornment.Elements.Any()
? adornment.Elements[0].Adornment as Dashboard
? adornment.Elements[0].Adornment as InlineRenameAdornment
: null;
}
catch (ArgumentOutOfRangeException)
Expand Down Expand Up @@ -124,25 +127,25 @@ protected override void Commit(InlineRenameSession activeSession, ITextView text
}
}
#else
protected override bool DashboardShouldReceiveKeyboardNavigation(ITextView textView)
protected override bool AdornmentShouldReceiveKeyboardNavigation(ITextView textView)
=> false;

protected override void SetFocusToTextView(ITextView textView)
{
// No action taken for Cocoa
}

protected override void SetFocusToDashboard(ITextView textView)
protected override void SetFocusToAdornment(ITextView textView)
{
// No action taken for Cocoa
}

protected override void SetDashboardFocusToNextElement(ITextView textView)
protected override void SetAdornmentFocusToNextElement(ITextView textView)
{
// No action taken for Cocoa
}

protected override void SetDashboardFocusToPreviousElement(ITextView textView)
protected override void SetAdornmentFocusToPreviousElement(ITextView textView)
{
// No action taken for Cocoa
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<UserControl x:Class="Microsoft.CodeAnalysis.Editor.InlineRename.Adornment.InlineRenameAdornment"
<UserControl x:Class="Microsoft.CodeAnalysis.Editor.Implementation.InlineRename.RenameFlyout"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Microsoft.CodeAnalysis.Editor.InlineRename.Adornment"
xmlns:rename="clr-namespace:Microsoft.CodeAnalysis.Editor.Implementation.InlineRename"
xmlns:imaging="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.Imaging"
xmlns:imagecatalog="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.ImageCatalog"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@
using System.Windows.Input;
using Microsoft.VisualStudio.Text.Editor;

namespace Microsoft.CodeAnalysis.Editor.InlineRename.Adornment
namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename
{
/// <summary>
/// Interaction logic for InlineRenameAdornment.xaml
/// </summary>
internal partial class InlineRenameAdornment : UserControl, IDisposable
internal partial class RenameFlyout : UserControl, IDisposable
{
private readonly InlineRenameAdornmentViewModel _viewModel;
private readonly RenameFlyoutViewModel _viewModel;
private readonly ITextView _textView;

public InlineRenameAdornment(InlineRenameAdornmentViewModel viewModel, ITextView textView)
public RenameFlyout(RenameFlyoutViewModel viewModel, ITextView textView)
{
DataContext = _viewModel = viewModel;
_textView = textView;
Expand All @@ -29,8 +29,12 @@ public InlineRenameAdornment(InlineRenameAdornmentViewModel viewModel, ITextView
_textView.LostAggregateFocus += TextView_LostFocus;
_textView.Caret.PositionChanged += TextView_CursorChanged;

// On initialization focus the first tab target
Initialized += (s, e) => MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
// On load focus the first tab target
Loaded += (s, e) =>
{
Focus();
MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
};

InitializeComponent();
PositionAdornment();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
using Microsoft.CodeAnalysis.Rename;
using Microsoft.VisualStudio.PlatformUI.OleComponentSupport;

namespace Microsoft.CodeAnalysis.Editor.InlineRename.Adornment
namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename
{
internal class InlineRenameAdornmentViewModel : INotifyPropertyChanged, IDisposable
internal class RenameFlyoutViewModel : INotifyPropertyChanged, IDisposable
{
private readonly InlineRenameSession _session;
private OleComponent? _oleComponent;
private bool _disposedValue;
public event PropertyChangedEventHandler? PropertyChanged;

public InlineRenameAdornmentViewModel(InlineRenameSession session)
public RenameFlyoutViewModel(InlineRenameSession session)
{
_session = session;
_session.ReplacementTextChanged += OnReplacementTextChanged;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<UserControl x:Class="Microsoft.CodeAnalysis.Editor.Implementation.InlineRename.Dashboard"
x:Name="dashboard"
<rename:InlineRenameAdornment x:Class="Microsoft.CodeAnalysis.Editor.Implementation.InlineRename.RenameDashboard"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Expand All @@ -21,7 +20,7 @@
Do not change this automation id.
-->

<UserControl.Resources>
<rename:InlineRenameAdornment.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../InlineRenameColors.xaml"/>
Expand All @@ -47,7 +46,7 @@
Stretch="Uniform"
Data="F1 M 0,0L 2,0L 5,3L 8,0L 10,0L 6,4L 10,8L 8,8L 5,5L 2,8L 0,8L 4,4L 0,0 Z" />
</ResourceDictionary>
</UserControl.Resources>
</rename:InlineRenameAdornment.Resources>

<Grid>
<Grid.RowDefinitions>
Expand Down Expand Up @@ -252,4 +251,4 @@

<Rectangle Name="DashboardAccentBar" Grid.Row="1" Height="4" Fill="{DynamicResource {x:Static rename:InlineRenameColors.AccentBarColorKey}}" />
</Grid>
</UserControl>
</rename:InlineRenameAdornment>
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@

namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename
{
internal partial class Dashboard : UserControl, IDisposable
internal partial class RenameDashboard : InlineRenameAdornment
{
private readonly DashboardViewModel _model;
private readonly RenameDashboardViewModel _model;
private readonly IWpfTextView _textView;
private readonly IAdornmentLayer _findAdornmentLayer;
private PresentationSource _presentationSource;
Expand All @@ -45,8 +45,8 @@ internal partial class Dashboard : UserControl, IDisposable
RenameShortcutKey.PreviewChanges
};

public Dashboard(
DashboardViewModel model,
public RenameDashboard(
RenameDashboardViewModel model,
IEditorFormatMapService editorFormatMapService,
IWpfTextView textView)
{
Expand Down Expand Up @@ -253,7 +253,7 @@ protected override void OnAccessKey(AccessKeyEventArgs e)
}

protected override AutomationPeer OnCreateAutomationPeer()
=> new DashboardAutomationPeer(this, _model.OriginalName);
=> new RenameDashboardAutomationPeer(this, _model.OriginalName);

private void DisconnectFromPresentationSource()
{
Expand Down Expand Up @@ -363,7 +363,7 @@ private void Commit()
}
}

public void Dispose()
public override void Dispose()
{
_textView.GotAggregateFocus -= OnTextViewGotAggregateFocus;
_textView.LostAggregateFocus -= OnTextViewLostAggregateFocus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename
/// <summary>
/// Custom AutomationPeer to announce that an Inline Rename session has begun.
/// </summary>
internal class DashboardAutomationPeer : UserControlAutomationPeer
internal class RenameDashboardAutomationPeer : UserControlAutomationPeer
{
private readonly string _identifier;

public DashboardAutomationPeer(UserControl owner, string identifier) : base(owner)
public RenameDashboardAutomationPeer(UserControl owner, string identifier) : base(owner)
=> _identifier = identifier;

protected override bool HasKeyboardFocusCore()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename
{
internal enum DashboardSeverity
internal enum RenameDashboardSeverity
{
None,
Info,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@

namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename
{
internal class DashboardViewModel : INotifyPropertyChanged, IDisposable
internal class RenameDashboardViewModel : INotifyPropertyChanged, IDisposable
{
private readonly InlineRenameSession _session;

private DashboardSeverity _severity = DashboardSeverity.None;
private RenameDashboardSeverity _severity = RenameDashboardSeverity.None;
private string _searchText;
private int _resolvableConflictCount;
private int _unresolvableConflictCount;
private string _errorText;
private bool _isReplacementTextValid;

public DashboardViewModel(InlineRenameSession session)
public RenameDashboardViewModel(InlineRenameSession session)
{
_session = session;
_searchText = EditorFeaturesResources.Searching;
Expand Down Expand Up @@ -141,21 +141,21 @@ private void UpdateSeverity()
if (_errorText != null ||
_unresolvableConflictCount > 0)
{
_severity = DashboardSeverity.Error;
_severity = RenameDashboardSeverity.Error;
}
else if (_resolvableConflictCount > 0)
{
_severity = DashboardSeverity.Info;
_severity = RenameDashboardSeverity.Info;
}
else
{
_severity = DashboardSeverity.None;
_severity = RenameDashboardSeverity.None;
}
}

public InlineRenameSession Session => _session;

public DashboardSeverity Severity => _severity;
public RenameDashboardSeverity Severity => _severity;

public bool AllowFileRename => _session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid;
public bool ShowFileRename => _session.FileRenameInfo != InlineRenameFileRenameInfo.NotAllowed;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename
{
internal abstract class InlineRenameAdornment : UserControl, IDisposable
{
public abstract void Dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.InlineRename;
using Microsoft.CodeAnalysis.Editor.InlineRename.Adornment;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Text.Classification;
Expand Down Expand Up @@ -72,8 +71,8 @@ private void UpdateAdornments()
var useInlineAdornment = _globalOptionService.GetOption(InlineRenameExperimentationOptions.UseInlineAdornment);
if (useInlineAdornment)
{
var adornment = new InlineRenameAdornment(
(InlineRenameAdornmentViewModel)s_createdViewModels.GetValue(_renameService.ActiveSession, session => new InlineRenameAdornmentViewModel(session)),
var adornment = new RenameFlyout(
(RenameFlyoutViewModel)s_createdViewModels.GetValue(_renameService.ActiveSession, session => new RenameFlyoutViewModel(session)),
_textView);

_adornmentLayer.AddAdornment(
Expand All @@ -85,13 +84,13 @@ private void UpdateAdornments()
}
else
{
var newAdornment = new Dashboard(
(DashboardViewModel)s_createdViewModels.GetValue(_renameService.ActiveSession, session => new DashboardViewModel(session)),
var newAdornment = new RenameDashboard(
(RenameDashboardViewModel)s_createdViewModels.GetValue(_renameService.ActiveSession, session => new RenameDashboardViewModel(session)),
_editorFormatMapService,
_textView);

_adornmentLayer.AddAdornment(AdornmentPositioningBehavior.ViewportRelative, null, null, newAdornment,
(tag, adornment) => ((Dashboard)adornment).Dispose());
(tag, adornment) => ((RenameDashboard)adornment).Dispose());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ protected AbstractRenameCommandHandler(

public string DisplayName => EditorFeaturesResources.Rename;

protected abstract bool DashboardShouldReceiveKeyboardNavigation(ITextView textView);
protected abstract bool AdornmentShouldReceiveKeyboardNavigation(ITextView textView);

protected abstract void SetFocusToTextView(ITextView textView);

protected abstract void SetFocusToDashboard(ITextView textView);
protected abstract void SetFocusToAdornment(ITextView textView);

protected abstract void SetDashboardFocusToPreviousElement(ITextView textView);
protected abstract void SetAdornmentFocusToPreviousElement(ITextView textView);

protected abstract void SetDashboardFocusToNextElement(ITextView textView);
protected abstract void SetAdornmentFocusToNextElement(ITextView textView);

private CommandState GetCommandState(Func<CommandState> nextHandler)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private void ExecuteRenameWorker(RenameCommandArgs args, CommandExecutionContext
// If so, focus the dashboard
if (_renameService.ActiveSession.TryGetContainingEditableSpan(caretPoint.Value, out _))
{
SetFocusToDashboard(args.TextView);
SetFocusToAdornment(args.TextView);
return;
}
else
Expand Down
Loading