Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
9 changes: 6 additions & 3 deletions ICSharpCode.Decompiler/Metadata/MetadataFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,12 @@ public string Name {
if (value == null)
{
var metadata = Metadata;
value = metadata.IsAssembly
? metadata.GetString(metadata.GetAssemblyDefinition().Name)
: metadata.GetString(metadata.GetModuleDefinition().Name);
if (metadata.IsAssembly)
value = metadata.GetString(metadata.GetAssemblyDefinition().Name);
else if (metadata.DebugMetadataHeader == null) // standalone debug metadata does not contain module table
value = metadata.GetString(metadata.GetModuleDefinition().Name);
else
value = "debug metadata";
value = LazyInit.GetOrSet(ref name, value);
}
return value;
Expand Down
4 changes: 4 additions & 0 deletions ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ public virtual object? Text {
get { return null; }
}

public virtual object? NavigationText {
get { return Text; }
}

public virtual object? Icon {
get { return null; }
}
Expand Down
21 changes: 16 additions & 5 deletions ILSpy/AssemblyTree/AssemblyTreeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -853,15 +853,24 @@ public void RefreshDecompiledView()

#endregion

public void NavigateHistory(bool forward)
public void NavigateHistory(bool forward, NavigationState? toState = null)
{
try
{
TabPageModel tabPage = DockWorkspace.ActiveTabPage;
var state = tabPage.GetState();
if (state != null)
history.UpdateCurrent(new NavigationState(tabPage, state));
var newState = forward ? history.GoForward() : history.GoBack();
var currentState = tabPage.GetState();
if (currentState != null)
history.UpdateCurrent(new NavigationState(tabPage, currentState));

NavigationState newState;
do
{
newState = forward ? history.GoForward() : history.GoBack();
} while (newState != null && toState != null && toState != newState);

if (newState == null)
return;

navigatingToState = newState;

TabPageModel activeTabPage = newState.TabPage;
Expand All @@ -884,6 +893,8 @@ public void NavigateHistory(bool forward)
}
}

public NavigationState[] GetNavigateHistory(bool forward) => forward ? history.ForwardList : history.BackList;

public bool CanNavigateBack => history.CanNavigateBack;

public bool CanNavigateForward => history.CanNavigateForward;
Expand Down
13 changes: 11 additions & 2 deletions ILSpy/Commands/BrowseBackCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System.Collections;
using System.Composition;
using System.Linq;
using System.Windows.Input;

using ICSharpCode.ILSpy.AssemblyTree;
Expand All @@ -26,7 +28,7 @@ namespace ICSharpCode.ILSpy
{
[ExportToolbarCommand(ToolTip = nameof(Resources.Back), ToolbarIcon = "Images/Back", ToolbarCategory = nameof(Resources.Navigation), ToolbarOrder = 0)]
[Shared]
sealed class BrowseBackCommand : CommandWrapper
sealed class BrowseBackCommand : CommandWrapper, IProvideParameterList
{
readonly AssemblyTreeModel assemblyTreeModel;

Expand All @@ -49,8 +51,15 @@ protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
if (assemblyTreeModel.CanNavigateBack)
{
e.Handled = true;
assemblyTreeModel.NavigateHistory(false);
assemblyTreeModel.NavigateHistory(false, e.Parameter as NavigationState);
}
}

public IEnumerable ParameterList => assemblyTreeModel.GetNavigateHistory(false).Reverse();

public object GetParamaterText(object parameter)
{
return (parameter as NavigationState)?.NavigationText;
}
}
}
12 changes: 10 additions & 2 deletions ILSpy/Commands/BrowseForwardCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System.Collections;
using System.Composition;
using System.Linq;
using System.Windows.Input;

using ICSharpCode.ILSpy.AssemblyTree;
Expand All @@ -26,7 +28,7 @@ namespace ICSharpCode.ILSpy
{
[ExportToolbarCommand(ToolTip = nameof(Resources.Forward), ToolbarIcon = "Images/Forward", ToolbarCategory = nameof(Resources.Navigation), ToolbarOrder = 1)]
[Shared]
sealed class BrowseForwardCommand : CommandWrapper
sealed class BrowseForwardCommand : CommandWrapper, IProvideParameterList
{
private readonly AssemblyTreeModel assemblyTreeModel;

Expand All @@ -49,9 +51,15 @@ protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
if (assemblyTreeModel.CanNavigateForward)
{
e.Handled = true;
assemblyTreeModel.NavigateHistory(true);
assemblyTreeModel.NavigateHistory(true, e.Parameter as NavigationState);
}
}

public IEnumerable ParameterList => assemblyTreeModel.GetNavigateHistory(true).Reverse();

public object GetParamaterText(object parameter)
{
return (parameter as NavigationState)?.NavigationText;
}
}
}
7 changes: 7 additions & 0 deletions ILSpy/Commands/SimpleCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections;
using System.Windows.Data;
using System.Windows.Input;

Expand All @@ -41,4 +42,10 @@ public interface IProvideParameterBinding
{
Binding ParameterBinding { get; }
}

public interface IProvideParameterList
{
IEnumerable ParameterList { get; }
object GetParamaterText(object parameter);
}
}
104 changes: 103 additions & 1 deletion ILSpy/Controls/MainToolBar.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,20 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.ComponentModel;
using System.Composition;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

using ICSharpCode.ILSpy.Themes;
using ICSharpCode.ILSpyX.TreeView;

using TomsToolbox.Composition;

Expand Down Expand Up @@ -85,7 +89,8 @@ static void InitToolbar(ToolBar toolBar, IExportProvider exportProvider)
}
}

static Button CreateToolbarItem(IExport<ICommand, IToolbarCommandMetadata> commandExport)

static UIElement CreateToolbarItem(IExport<ICommand, IToolbarCommandMetadata> commandExport)
{
var command = commandExport.Value;

Expand All @@ -108,9 +113,106 @@ static Button CreateToolbarItem(IExport<ICommand, IToolbarCommandMetadata> comma
parameterBinding.ParameterBinding);
}

if (command is IProvideParameterList parameterList)
{
toolbarItem.Margin = new Thickness(2, 0, 0, 0);

var dropDownPanel = new StackPanel { Orientation = Orientation.Horizontal };

var dropDownToggle = new ToggleButton {
Style = ThemeManager.Current.CreateToolBarToggleButtonStyle(),
Content = "▾",
Padding = new Thickness(0),
MinWidth = 0,
Margin = new Thickness(0, 0, 2, 0)
};

var contextMenu = new ContextMenu {
PlacementTarget = dropDownPanel,
Tag = command
};

ContextMenuService.SetPlacement(toolbarItem, PlacementMode.Bottom);
toolbarItem.ContextMenu = contextMenu;
toolbarItem.ContextMenuOpening += (_, _) =>
PrepareParameterList(contextMenu);
dropDownToggle.Checked += (_, _) => {
PrepareParameterList(contextMenu);
contextMenu.Placement = PlacementMode.Bottom;
contextMenu.SetCurrentValue(ContextMenu.IsOpenProperty, true);
};

BindingOperations.SetBinding(dropDownToggle, ToggleButton.IsCheckedProperty,
new Binding(nameof(contextMenu.IsOpen)) { Source = contextMenu });

BindingOperations.SetBinding(dropDownToggle, IsEnabledProperty,
new Binding(nameof(IsEnabled)) { Source = toolbarItem });

// When the toggle button is checked, clicking it to uncheck will dimiss the menu first
// which unchecks the toggle button via binding above and the click is used to open it again.
// This is a workaround to ignore the click to uncheck the already unchecked toggle button.
// We have to ensure the dismissing click is on the toggle button, otherwise the flag
// will not get cleared and menu will not open next time.
Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(contextMenu, (_, e) => {
var point = e.GetPosition(dropDownToggle);
dropDownToggle.Tag = dropDownToggle.InputHitTest(point);
});
dropDownToggle.PreviewMouseLeftButtonDown += (_, e) => {
e.Handled = dropDownToggle.Tag != null;
dropDownToggle.Tag = null;
};

dropDownPanel.Children.Add(toolbarItem);
dropDownPanel.Children.Add(dropDownToggle);
return dropDownPanel;
}

return toolbarItem;
}

static void PrepareParameterList(ContextMenu menu)
{
const int maximumParameterListCount = 20;

var command = (ICommand)menu.Tag;
var parameterList = (IProvideParameterList)command;

menu.Items.Clear();
foreach (var parameter in parameterList.ParameterList)
{
MenuItem parameterItem = new MenuItem();
parameterItem.Command = CommandWrapper.Unwrap(command);
parameterItem.CommandParameter = parameter;
parameterItem.CommandTarget = menu.PlacementTarget;
parameterItem.InputGestureText = " ";

var headerPresenter = new ContentPresenter { RecognizesAccessKey = false };
parameterItem.Header = headerPresenter;

var header = parameterList.GetParamaterText(parameter);
switch (header)
{
case SharpTreeNode node:
headerPresenter.Content = node.NavigationText;
if (node.Icon is ImageSource icon)
parameterItem.Icon = new Image {
Width = 16,
Height = 16,
Source = icon
};
break;

default:
headerPresenter.Content = header;
break;
}

menu.Items.Add(parameterItem);
if (menu.Items.Count >= maximumParameterListCount)
break;
}
}

void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
if (e.Handled || e.KeyboardDevice.Modifiers != ModifierKeys.Alt || e.Key != Key.System)
Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/CoffHeaderTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public CoffHeaderTreeNode(PEFile module)

public override object Text => "COFF Header";

public override object NavigationText => $"{Text} ({module.Name})";

public override object Icon => Images.Header;

public override bool View(TabPageModel tabPage)
Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/DataDirectoriesTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public DataDirectoriesTreeNode(PEFile module)

public override object Text => "Data Directories";

public override object NavigationText => $"{Text} ({module.Name})";

public override object Icon => Images.ListFolder;
public override object ExpandedIcon => Images.ListFolderOpen;

Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/DebugDirectory/DebugDirectoryEntryTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public DebugDirectoryEntryTreeNode(PEFile module, DebugDirectoryEntry entry)

override public object Text => entry.Type.ToString();

public override object NavigationText => $"{Text} ({module.Name})";

public override object Icon => Images.MetadataTable;

public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/DebugDirectoryTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public DebugDirectoryTreeNode(PEFile module)

public override object Text => "Debug Directory";

public override object NavigationText => $"{Text} ({module.Name})";

public override object Icon => Images.ListFolder;
public override object ExpandedIcon => Images.ListFolderOpen;

Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/DebugMetadataTablesTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public DebugMetadataTablesTreeNode(MetadataFile metadataFile)

public override object Text => "Tables";

public override object NavigationText => $"{Text} ({metadataFile.Name})";

public override object Icon => Images.MetadataTableGroup;

protected override void LoadChildren()
Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/DosHeaderTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public DosHeaderTreeNode(PEFile module)

public override object Text => "DOS Header";

public override object NavigationText => $"{Text} ({module.Name})";

public override object Icon => Images.Header;

public override bool View(TabPageModel tabPage)
Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/MetadataHeapTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ internal abstract class MetadataHeapTreeNode : ILSpyTreeNode

public HandleKind Kind { get; }

public override object NavigationText => $"{Text} ({metadataFile.Name})";

public override object Icon => Images.Heap;

public MetadataHeapTreeNode(HandleKind kind, MetadataFile metadataFile)
Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/MetadataTableTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ internal abstract class MetadataTableTreeNode : ILSpyTreeNode

public override object Text => $"{(int)Kind:X2} {Kind} ({metadataFile.Metadata.GetTableRowCount(Kind)})";

public override object NavigationText => $"{(int)Kind:X2} {Kind} ({metadataFile.Name})";

public override object Icon => Images.MetadataTable;

public MetadataTableTreeNode(TableIndex table, MetadataFile metadataFile)
Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/MetadataTablesTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public MetadataTablesTreeNode(MetadataFile metadataFile)

public override object Text => "Tables";

public override object NavigationText => $"{Text} ({metadataFile.Name})";

public override object Icon => Images.MetadataTableGroup;

protected override void LoadChildren()
Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/MetadataTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public MetadataTreeNode(MetadataFile module, string title)

public override object Text => title;

public override object NavigationText => $"{Text} ({metadataFile.Name})";

public override object Icon => Images.Metadata;

public override bool View(TabPageModel tabPage)
Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Metadata/OptionalHeaderTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public OptionalHeaderTreeNode(PEFile module)

public override object Text => "Optional Header";

public override object NavigationText => $"{Text} ({module.Name})";

public override object Icon => Images.Header;

public override bool View(ViewModels.TabPageModel tabPage)
Expand Down
Loading
Loading