Skip to content
Merged
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
95 changes: 35 additions & 60 deletions ILSpy/Options/DecompilerSettingsPanel.xaml
Original file line number Diff line number Diff line change
@@ -1,63 +1,38 @@
<UserControl x:Class="ICSharpCode.ILSpy.Options.DecompilerSettingsPanel"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:toms="urn:TomsToolbox">
<UserControl.Resources>
<CollectionViewSource x:Key="SettingsCollection" Source="{Binding Settings}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Category" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Margin="3" Grid.ColumnSpan="3" TextWrapping="Wrap" Text="{x:Static properties:Resources.DecompilerSettingsPanelLongText}" />
<ListBox Grid.Row="1" ItemsSource="{Binding Source={StaticResource SettingsCollection}}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Focusable" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}" BasedOn="{StaticResource {x:Type GroupItem}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander Padding="0" BorderThickness="0" IsExpanded="True">
<Expander.Header>
<CheckBox Checked="OnGroupChecked" Unchecked="OnGroupUnchecked" Loaded="OnGroupLoaded" VerticalContentAlignment="Center"
FontSize="16" FontWeight="Bold" Content="{Binding Name}" />
</Expander.Header>
<ItemsPresenter/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Margin="19,0,0,0" IsChecked="{Binding IsEnabled}" Content="{Binding Description}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:options="clr-namespace:ICSharpCode.ILSpy.Options"
d:DataContext="{d:DesignInstance options:DecompilerSettingsViewModel}">
<DockPanel>
<TextBlock Margin="3" DockPanel.Dock="Top" TextWrapping="Wrap" Text="{x:Static properties:Resources.DecompilerSettingsPanelLongText}" />
<ScrollViewer>
<ItemsControl ItemsSource="{Binding Settings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Expander Padding="0" BorderThickness="0" IsExpanded="True">
<Expander.Header>
<CheckBox VerticalContentAlignment="Center"
FontSize="16" FontWeight="Bold"
Content="{Binding Category}"
IsChecked="{Binding AreAllItemsChecked, Mode=TwoWay}"/>
</Expander.Header>
<ItemsControl ItemsSource="{Binding Settings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Margin="28,0,0,0" IsChecked="{Binding IsEnabled}" Content="{Binding Description}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DockPanel>
</UserControl>
59 changes: 2 additions & 57 deletions ILSpy/Options/DecompilerSettingsPanel.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Xml.Linq;

using ICSharpCode.ILSpyX.Settings;
Expand All @@ -32,7 +26,7 @@ namespace ICSharpCode.ILSpy.Options
/// Interaction logic for DecompilerSettingsPanel.xaml
/// </summary>
[ExportOptionPage(Title = nameof(Properties.Resources.Decompiler), Order = 10)]
internal partial class DecompilerSettingsPanel : UserControl, IOptionPage
internal partial class DecompilerSettingsPanel : IOptionPage
{
public DecompilerSettingsPanel()
{
Expand All @@ -59,58 +53,9 @@ public void Save(XElement root)
MainWindow.Instance.AssemblyListManager.UseDebugSymbols = newSettings.UseDebugSymbols;
}

private void OnGroupChecked(object sender, RoutedEventArgs e)
{
CheckGroup((CollectionViewGroup)((CheckBox)sender).DataContext, true);
}
private void OnGroupUnchecked(object sender, RoutedEventArgs e)
{
CheckGroup((CollectionViewGroup)((CheckBox)sender).DataContext, false);
}

void CheckGroup(CollectionViewGroup group, bool value)
{
foreach (var item in group.Items)
{
switch (item)
{
case CollectionViewGroup subGroup:
CheckGroup(subGroup, value);
break;
case CSharpDecompilerSetting setting:
setting.IsEnabled = value;
break;
}
}
}

bool IsGroupChecked(CollectionViewGroup group)
{
bool value = true;
foreach (var item in group.Items)
{
switch (item)
{
case CollectionViewGroup subGroup:
value = value && IsGroupChecked(subGroup);
break;
case CSharpDecompilerSetting setting:
value = value && setting.IsEnabled;
break;
}
}
return value;
}

private void OnGroupLoaded(object sender, RoutedEventArgs e)
{
CheckBox checkBox = (CheckBox)sender;
checkBox.IsChecked = IsGroupChecked((CollectionViewGroup)checkBox.DataContext);
}

public void LoadDefaults()
{
MainWindow.Instance.CurrentDecompilerSettings = new Decompiler.DecompilerSettings();
MainWindow.Instance.CurrentDecompilerSettings = new();
this.DataContext = new DecompilerSettingsViewModel(MainWindow.Instance.CurrentDecompilerSettings);
}
}
Expand Down
101 changes: 69 additions & 32 deletions ILSpy/Options/DecompilerSettingsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,83 +16,120 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;

using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TreeNodes;

using TomsToolbox.Wpf;

namespace ICSharpCode.ILSpy.Options
{
public class DecompilerSettingsViewModel : INotifyPropertyChanged
public sealed class DecompilerSettingsViewModel : ObservableObjectBase
{
public CSharpDecompilerSetting[] Settings { get; set; }
public DecompilerSettingsGroupViewModel[] Settings { get; }

public DecompilerSettingsViewModel(Decompiler.DecompilerSettings settings)
{
Settings = typeof(Decompiler.DecompilerSettings).GetProperties()
.Where(p => p.GetCustomAttribute<BrowsableAttribute>()?.Browsable != false)
.Select(p => new CSharpDecompilerSetting(p) { IsEnabled = (bool)p.GetValue(settings) })
.Select(p => new DecompilerSettingsItemViewModel(p) { IsEnabled = p.GetValue(settings) is true })
.OrderBy(item => item.Category, NaturalStringComparer.Instance)
.ThenBy(item => item.Description)
.GroupBy(p => p.Category)
.Select(g => new DecompilerSettingsGroupViewModel(g.Key, g.OrderBy(i => i.Description).ToArray()))
.ToArray();
}

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

public Decompiler.DecompilerSettings ToDecompilerSettings()
{
var settings = new Decompiler.DecompilerSettings();
foreach (var item in Settings)

foreach (var item in Settings.SelectMany(group => group.Settings))
{
item.Property.SetValue(settings, item.IsEnabled);
}

return settings;
}
}
public class CSharpDecompilerSetting : INotifyPropertyChanged

public sealed class DecompilerSettingsGroupViewModel : ObservableObjectBase
{
bool isEnabled;
private bool? _areAllItemsChecked;

public CSharpDecompilerSetting(PropertyInfo p)
public DecompilerSettingsGroupViewModel(string category, DecompilerSettingsItemViewModel[] settings)
{
this.Property = p;
this.Category = GetResourceString(p.GetCustomAttribute<CategoryAttribute>()?.Category ?? Resources.Other);
this.Description = GetResourceString(p.GetCustomAttribute<DescriptionAttribute>()?.Description ?? p.Name);
}
Settings = settings;
Category = category;

public PropertyInfo Property { get; }
_areAllItemsChecked = GetAreAllItemsChecked(Settings);

public bool IsEnabled {
get => isEnabled;
foreach (DecompilerSettingsItemViewModel viewModel in settings)
{
viewModel.PropertyChanged += Item_PropertyChanged;
}
}

public bool? AreAllItemsChecked {
get => _areAllItemsChecked;
set {
if (value != isEnabled)
SetProperty(ref _areAllItemsChecked, value);

if (!value.HasValue)
return;

foreach (var setting in Settings)
{
isEnabled = value;
OnPropertyChanged();
setting.IsEnabled = value.Value;
}
}
}

public string Description { get; set; }
public string Category { get; }

public string Category { get; set; }
public DecompilerSettingsItemViewModel[] Settings { get; }

public event PropertyChangedEventHandler PropertyChanged;
private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(DecompilerSettingsItemViewModel.IsEnabled))
{
AreAllItemsChecked = GetAreAllItemsChecked(Settings);
}
}

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
private static bool? GetAreAllItemsChecked(ICollection<DecompilerSettingsItemViewModel> settings)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
var numberOfEnabledItems = settings.Count(item => item.IsEnabled);

if (numberOfEnabledItems == settings.Count)
return true;

if (numberOfEnabledItems == 0)
return false;

return null;
}
}

public sealed class DecompilerSettingsItemViewModel(PropertyInfo property) : ObservableObjectBase
{
private bool _isEnabled;

public PropertyInfo Property { get; } = property;

public bool IsEnabled {
get => _isEnabled;
set => SetProperty(ref _isEnabled, value);
}

static string GetResourceString(string key)
public string Description { get; set; } = GetResourceString(property.GetCustomAttribute<DescriptionAttribute>()?.Description ?? property.Name);

public string Category { get; set; } = GetResourceString(property.GetCustomAttribute<CategoryAttribute>()?.Category ?? Resources.Other);

private static string GetResourceString(string key)
{
var str = !string.IsNullOrEmpty(key) ? Resources.ResourceManager.GetString(key) : null;
return string.IsNullOrEmpty(key) || string.IsNullOrEmpty(str) ? key : str;
Expand Down
1 change: 0 additions & 1 deletion ILSpy/Options/DisplaySettingsPanel.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes"
xmlns:toms="urn:TomsToolbox"
d:DataContext="{d:DesignInstance local:DisplaySettingsViewModel}">
<UserControl.Resources>
<local:FontSizeConverter x:Key="fontSizeConv" />
Expand Down