Browse Source

Give the row-details text blob its own Copy/Select All menu

Right-clicking inside the details editor inherited the metadata grid's
cell-oriented context menu, whose Copy entries are enabled only for a
hovered DataGridCell -- inside the details area there is none, so the
menu showed permanently disabled entries and selected text could not be
copied by mouse. The editor now carries the decompiler view's editor
menu shape: Copy (rich HTML copy with plain fallback, enabled while a
selection exists) and Select All. Enablement is decided in
ContextMenu.Opening, which only the context-request gesture raises;
the test therefore raises ContextRequested instead of calling Open().

Assisted-by: Claude:claude-fable-5:Claude Code
pull/3945/head
Siegfried Pammer 2 months ago committed by Siegfried Pammer
parent
commit
46c580a018
  1. 46
      ILSpy.Tests/Metadata/MetadataRowDetailsTests.cs
  2. 31
      ILSpy/Metadata/MetadataRowDetails.cs

46
ILSpy.Tests/Metadata/MetadataRowDetailsTests.cs

@ -23,6 +23,8 @@ using System.Threading.Tasks; @@ -23,6 +23,8 @@ using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Headless.NUnit;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.VisualTree;
@ -247,6 +249,50 @@ public class MetadataRowDetailsTests @@ -247,6 +249,50 @@ public class MetadataRowDetailsTests
}
}
[AvaloniaTest]
public void Text_Blob_Editor_Carries_Its_Own_Copy_And_Select_All_Context_Menu()
{
// Without a menu of its own, a right-click inside the details editor inherits the
// metadata grid's cell-oriented context menu, whose Copy entries are bound to the
// hovered DataGridCell and therefore permanently disabled inside the details area.
// The editor must instead offer the decompiler-view editor menu shape: Copy
// following the selection, plus Select All.
var editor = (DecompilerTextEditor)MetadataRowDetails.BuildTextBlob("class C { }", ".cs");
var window = new Window { Content = editor };
window.Show();
try
{
var menu = editor.ContextMenu;
menu.Should().NotBeNull("the editor must not inherit the metadata grid's cell menu");
// Raise the context-request gesture (what a right-click produces) rather than
// calling menu.Open(): only the gesture path raises ContextMenu.Opening, where
// the enablement of Copy is decided.
editor.RaiseEvent(new ContextRequestedEventArgs());
menu!.IsOpen.Should().BeTrue();
var items = menu.Items.OfType<MenuItem>().ToList();
items.Should().HaveCount(2);
var copy = items[0];
var selectAll = items[1];
copy.Header.Should().Be("Copy");
selectAll.Header.Should().Be("Select All");
copy.IsEnabled.Should().BeFalse("nothing is selected yet");
menu.Close();
editor.Select(0, 5);
editor.RaiseEvent(new ContextRequestedEventArgs());
copy.IsEnabled.Should().BeTrue("a non-empty selection makes Copy actionable");
menu.Close();
selectAll.RaiseEvent(new RoutedEventArgs(MenuItem.ClickEvent));
editor.SelectionLength.Should().Be(editor.Text.Length);
}
finally
{
window.Close();
}
}
[AvaloniaTest]
public async Task Double_Tap_Inside_The_Details_Area_Does_Not_Resolve_To_An_Activatable_Row()
{

31
ILSpy/Metadata/MetadataRowDetails.cs

@ -24,6 +24,7 @@ using Avalonia; @@ -24,6 +24,7 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Input;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels;
@ -138,9 +139,39 @@ namespace ICSharpCode.ILSpy.Metadata @@ -138,9 +139,39 @@ namespace ICSharpCode.ILSpy.Metadata
};
if (highlightExtension != null)
editor.SyntaxHighlighting = HighlightingService.GetByExtension(highlightExtension);
editor.ContextMenu = BuildEditorContextMenu(editor);
return editor;
}
/// <summary>
/// Editor context menu matching the decompiler view's editor entries (Copy / Select
/// All). The metadata grid's own context menu copies the hovered cell, which never
/// exists inside the details area — without a menu of its own the editor would
/// inherit those permanently disabled entries.
/// </summary>
static ContextMenu BuildEditorContextMenu(DecompilerTextEditor editor)
{
var copy = new MenuItem {
Header = Properties.Resources.Copy,
InputGesture = new KeyGesture(Key.C, KeyModifiers.Control),
};
copy.Click += (_, _) => {
// Copy as text + syntax-coloured HTML; fall back to plain copy.
if (!HtmlClipboardCopy.Copy(editor))
editor.Copy();
};
var selectAll = new MenuItem {
Header = Properties.Resources.Select,
InputGesture = new KeyGesture(Key.A, KeyModifiers.Control),
};
selectAll.Click += (_, _) => editor.SelectAll();
var menu = new ContextMenu();
menu.Opening += (_, _) => copy.IsEnabled = editor.SelectionLength > 0;
menu.Items.Add(copy);
menu.Items.Add(selectAll);
return menu;
}
/// <summary>
/// Sub-grid over parsed blob rows; one text column per (header, property) pair.
/// </summary>

Loading…
Cancel
Save