Browse Source

Show only the assembly-tree pane in the default dock config

Search, Analyzer and Debug Steps cluttered the default layout. They now opt out via ExportToolPane.IsVisibleByDefault = false (which BuildToolDock finally honours), so a fresh launch shows just the assembly tree. Each pane keeps its home alignment and is materialised there on demand by ShowToolPane, so opening Search / Analyze surfaces it in the same place as before.
pull/3755/head
Siegfried Pammer 1 month ago
parent
commit
8d2c2e6e05
  1. 31
      ILSpy.Tests/Analyzers/AnalyzeContextMenuTests.cs
  2. 32
      ILSpy.Tests/Analyzers/AnalyzerPaneVisibilityTests.cs
  3. 3
      ILSpy.Tests/Docking/LayoutPersistenceTests.cs
  4. 12
      ILSpy.Tests/MainWindow/ToolPaneRegistryTests.cs
  5. 4
      ILSpy.Tests/Search/SearchInputFocusTests.cs
  6. 9
      ILSpy.Tests/Search/SearchPaneViewTests.cs
  7. 3
      ILSpy.Tests/Search/SearchProgressTests.cs
  8. 2
      ILSpy/Analyzers/AnalyzerTreeViewModel.cs
  9. 6
      ILSpy/Docking/ILSpyDockFactory.cs
  10. 2
      ILSpy/Search/SearchPaneModel.cs

31
ILSpy.Tests/Analyzers/AnalyzeContextMenuTests.cs

@ -154,32 +154,23 @@ public class AnalyzeContextMenuTests @@ -154,32 +154,23 @@ public class AnalyzeContextMenuTests
var methodNode = typeNode.Children.OfType<MethodTreeNode>()
.First(m => m.MethodDefinition.Name == "Count");
// Walk the dock layout to find the analyzer pane's current visibility state.
var analyzerPane = FindAnalyzerPane(dockWorkspace);
Assert.That(analyzerPane, Is.Not.Null, "the analyzer pane must be in the dock layout");
var owningDock = analyzerPane!.Owner as global::Dock.Model.Core.IDock;
Assert.That(owningDock, Is.Not.Null, "the analyzer pane must have a dock parent");
// Pick any sibling dockable and force it to be active first, so the analyzer pane
// starts in the inactive state — that's the regression we're testing.
var sibling = owningDock!.VisibleDockables?
.FirstOrDefault(d => !ReferenceEquals(d, analyzerPane));
if (sibling != null)
{
owningDock.ActiveDockable = sibling;
((object?)owningDock.ActiveDockable).Should().NotBeSameAs(analyzerPane,
"baseline: sibling-active must really make the analyzer pane inactive");
}
// The analyzer pane is hidden by default — not in the layout until something surfaces it.
FindAnalyzerPane(dockWorkspace).Should().BeNull(
"baseline: the analyzer pane is hidden until invoked");
entry.Execute(new TextViewContext {
SelectedTreeNodes = new ICSharpCode.ILSpyX.TreeView.SharpTreeNode[] { methodNode }
});
TestCapture.Step("analyzer-pane-surfaced");
// After Execute, the active dockable in the analyzer pane's owning dock should be
// the analyzer pane itself — that's what ShowToolPane does.
((object?)owningDock.ActiveDockable).Should().BeSameAs(analyzerPane,
"Execute must call ShowToolPane so the analyzer pane surfaces");
// After Execute, the pane is materialised into the layout and active in its dock —
// that's what ShowToolPane does, so the user sees the entity they just analysed.
var analyzerPane = FindAnalyzerPane(dockWorkspace);
analyzerPane.Should().NotBeNull("Execute must surface (materialise) the analyzer pane");
var owningDock = analyzerPane!.Owner as global::Dock.Model.Core.IDock;
owningDock.Should().NotBeNull("the surfaced analyzer pane must have a dock parent");
((object?)owningDock!.ActiveDockable).Should().BeSameAs(analyzerPane,
"Execute must call ShowToolPane so the analyzer pane surfaces and is active");
}
[AvaloniaTest]

32
ILSpy.Tests/Analyzers/AnalyzerPaneVisibilityTests.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Headless.NUnit;
@ -59,8 +60,10 @@ public class AnalyzerPaneVisibilityTests @@ -59,8 +60,10 @@ public class AnalyzerPaneVisibilityTests
var analyzer = AppComposition.Current.GetExport<AnalyzerTreeViewModel>();
var factory = (ILSpyDockFactory)dockWorkspace.Factory;
// The analyzer pane is hidden by default; show it so the user has it open.
dockWorkspace.ShowToolPane(AnalyzerTreeViewModel.PaneContentId);
AllDockables(dockWorkspace.Layout).Should().Contain(analyzer,
"baseline: the analyzer pane is in the default layout");
"showing the analyzer pane adds it to the layout");
// The user closes the bottom Analyzer panel (its close button calls CloseDockable).
factory.CloseDockable(analyzer);
@ -75,4 +78,31 @@ public class AnalyzerPaneVisibilityTests @@ -75,4 +78,31 @@ public class AnalyzerPaneVisibilityTests
(analyzer.Owner as IDock)?.ActiveDockable.Should().BeSameAs(analyzer,
"the restored pane must be the active dockable in its dock");
}
[AvaloniaTest]
public async Task Default_Layout_Shows_Only_The_Assembly_Tree_Pane()
{
// The default dock config shows just the assembly-tree pane: Search, Analyzer and Debug
// Steps are hidden until invoked (IsVisibleByDefault = false), while keeping their home
// locations for when they are first opened.
var (_, vm) = await TestHarness.BootAsync(3);
var dockWorkspace = AppComposition.Current.GetExport<DockWorkspace>();
var analyzer = AppComposition.Current.GetExport<AnalyzerTreeViewModel>();
var search = AppComposition.Current.GetExport<global::ILSpy.Search.SearchPaneModel>();
var paneIds = AllDockables(dockWorkspace.Layout)
.OfType<global::ILSpy.ViewModels.ToolPaneModel>()
.Select(p => p.Id)
.ToList();
paneIds.Should().Contain("AssemblyTree", "the assembly-tree pane is visible by default");
paneIds.Should().NotContain("Search", "Search is hidden until invoked");
paneIds.Should().NotContain("Analyzer", "Analyzer is hidden until invoked");
// ...but showing one materialises it into its home location.
dockWorkspace.ShowToolPane(global::ILSpy.Search.SearchPaneModel.PaneContentId);
AllDockables(dockWorkspace.Layout).Should().Contain(search,
"Show Search must materialise the hidden Search pane");
(search.Owner as IDock)!.Id.Should().Be("TopTools",
"Search keeps its top-edge home dock");
}
}

3
ILSpy.Tests/Docking/LayoutPersistenceTests.cs

@ -61,6 +61,9 @@ public class LayoutPersistenceTests @@ -61,6 +61,9 @@ public class LayoutPersistenceTests
_ = await TestHarness.BootAsync();
var dockWorkspace = AppComposition.Current.GetExport<DockWorkspace>();
// Search is hidden by default; surface it so the round-trip covers a tool pane that
// lives in a materialised-on-demand dock, not just the assembly tree.
dockWorkspace.ShowToolPane(global::ILSpy.Search.SearchPaneModel.PaneContentId);
var path = Path.Combine(Path.GetTempPath(), $"ILSpy.Layout.test.{System.Guid.NewGuid():N}.json");
try

12
ILSpy.Tests/MainWindow/ToolPaneRegistryTests.cs

@ -74,19 +74,19 @@ public class ToolPaneRegistryTests @@ -74,19 +74,19 @@ public class ToolPaneRegistryTests
[AvaloniaTest]
public void DockFactory_Builds_Layout_Zones_Driven_By_The_Registry()
{
// ILSpyDockFactory iterates the registry instead of taking each pane in its ctor
// verifies via the live DockWorkspace that the same three docks (Left/Top/Bottom)
// still get created and contain the right panes.
// ILSpyDockFactory iterates the registry instead of taking each pane in its ctor.
// The default config places only the visible-by-default assembly-tree pane; Search and
// Analyzer are hidden (IsVisibleByDefault = false) and materialised on demand.
// Arrange + Act — DockWorkspace is constructed by the composition host; its layout is
// built eagerly in the constructor.
var workspace = AppComposition.Current.GetExport<DockWorkspace>();
var allDockables = FlattenDockables(workspace.Layout).ToArray();
// Assert — each pane is registered as a dockable inside the layout.
// Assert — only the assembly-tree pane is placed up front.
allDockables.OfType<AssemblyTreeModel>().Should().ContainSingle();
allDockables.OfType<SearchPaneModel>().Should().ContainSingle();
allDockables.OfType<AnalyzerTreeViewModel>().Should().ContainSingle();
allDockables.OfType<SearchPaneModel>().Should().BeEmpty("Search is hidden until invoked");
allDockables.OfType<AnalyzerTreeViewModel>().Should().BeEmpty("Analyzer is hidden until invoked");
}
static System.Collections.Generic.IEnumerable<Dock.Model.Core.IDockable> FlattenDockables(Dock.Model.Core.IDockable root)

4
ILSpy.Tests/Search/SearchInputFocusTests.cs

@ -64,8 +64,10 @@ public class SearchInputFocusTests @@ -64,8 +64,10 @@ public class SearchInputFocusTests
{
var (window, _) = await TestHarness.BootAsync();
var pane = await window.WaitForComponent<SearchPane>();
var dockWorkspace = AppComposition.Current.GetExport<DockWorkspace>();
// Search is hidden by default; surface it so its view realises.
dockWorkspace.ShowToolPane(global::ILSpy.Search.SearchPaneModel.PaneContentId);
var pane = await window.WaitForComponent<SearchPane>();
dockWorkspace.ShowSearchCommand.Execute(null);

9
ILSpy.Tests/Search/SearchPaneViewTests.cs

@ -45,6 +45,9 @@ public class SearchPaneViewTests @@ -45,6 +45,9 @@ public class SearchPaneViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
// Search is hidden by default; surface it so its view realises.
AppComposition.Current.GetExport<global::ILSpy.Docking.DockWorkspace>()
.ShowToolPane(SearchPaneModel.PaneContentId);
var pane = await window.WaitForComponent<SearchPane>();
TestCapture.Step("booted");
@ -65,6 +68,9 @@ public class SearchPaneViewTests @@ -65,6 +68,9 @@ public class SearchPaneViewTests
{
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
// Search is hidden by default; surface it so its view realises.
AppComposition.Current.GetExport<global::ILSpy.Docking.DockWorkspace>()
.ShowToolPane(SearchPaneModel.PaneContentId);
var pane = await window.WaitForComponent<SearchPane>();
TestCapture.Step("booted");
var vm = (SearchPaneModel)pane.DataContext!;
@ -87,6 +93,9 @@ public class SearchPaneViewTests @@ -87,6 +93,9 @@ public class SearchPaneViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
// Search is hidden by default; surface it so its view realises.
AppComposition.Current.GetExport<global::ILSpy.Docking.DockWorkspace>()
.ShowToolPane(SearchPaneModel.PaneContentId);
var pane = await window.WaitForComponent<SearchPane>();
TestCapture.Step("booted");
var vm = (SearchPaneModel)pane.DataContext!;

3
ILSpy.Tests/Search/SearchProgressTests.cs

@ -106,6 +106,9 @@ public class SearchProgressTests @@ -106,6 +106,9 @@ public class SearchProgressTests
{
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
// Search is hidden by default; surface it so its view realises.
AppComposition.Current.GetExport<global::ILSpy.Docking.DockWorkspace>()
.ShowToolPane(global::ILSpy.Search.SearchPaneModel.PaneContentId);
var pane = await window.WaitForComponent<SearchPane>();
TestCapture.Step("booted");

2
ILSpy/Analyzers/AnalyzerTreeViewModel.cs

@ -31,7 +31,7 @@ using ILSpy.ViewModels; @@ -31,7 +31,7 @@ using ILSpy.ViewModels;
namespace ILSpy.Analyzers
{
[Export]
[ExportToolPane(ContentId = PaneContentId, Alignment = ToolPaneAlignment.Bottom, Order = 0)]
[ExportToolPane(ContentId = PaneContentId, Alignment = ToolPaneAlignment.Bottom, Order = 0, IsVisibleByDefault = false)]
[Shared]
public class AnalyzerTreeViewModel : ToolPaneModel
{

6
ILSpy/Docking/ILSpyDockFactory.cs

@ -416,8 +416,12 @@ namespace ILSpy.Docking @@ -416,8 +416,12 @@ namespace ILSpy.Docking
ToolDock? BuildToolDock(string id, ToolPaneAlignment alignment, double proportion)
{
// Only panes that opt into the default layout are placed up front; the rest
// (Search, Analyzer, Debug Steps) are materialised on demand by ShowToolPane, so the
// default config shows just the assembly-tree pane while keeping every pane's home
// location intact for when it is first opened.
var dockables = panes
.Where(p => p.Metadata.Alignment == alignment)
.Where(p => p.Metadata.Alignment == alignment && p.Metadata.IsVisibleByDefault)
.OrderBy(p => p.Metadata.Order)
.Select(p => (IDockable)p.Pane)
.ToArray();

2
ILSpy/Search/SearchPaneModel.cs

@ -51,7 +51,7 @@ namespace ILSpy.Search @@ -51,7 +51,7 @@ namespace ILSpy.Search
}
[Export]
[ExportToolPane(ContentId = PaneContentId, Alignment = ToolPaneAlignment.Top, Order = 0)]
[ExportToolPane(ContentId = PaneContentId, Alignment = ToolPaneAlignment.Top, Order = 0, IsVisibleByDefault = false)]
[Shared]
public partial class SearchPaneModel : ToolPaneModel
{

Loading…
Cancel
Save