|
16 | 16 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
17 | 17 | // DEALINGS IN THE SOFTWARE. |
18 | 18 |
|
| 19 | +using System.Collections.Generic; |
19 | 20 | using System.ComponentModel; |
20 | 21 | using System.Linq; |
21 | 22 | using System.Reflection; |
22 | | -using System.Runtime.CompilerServices; |
23 | 23 |
|
24 | 24 | using ICSharpCode.ILSpy.Properties; |
25 | 25 | using ICSharpCode.ILSpy.TreeNodes; |
26 | 26 |
|
| 27 | +using TomsToolbox.Wpf; |
| 28 | + |
27 | 29 | namespace ICSharpCode.ILSpy.Options |
28 | 30 | { |
29 | | - public class DecompilerSettingsViewModel : INotifyPropertyChanged |
| 31 | + public sealed class DecompilerSettingsViewModel : ObservableObjectBase |
30 | 32 | { |
31 | | - public CSharpDecompilerSetting[] Settings { get; set; } |
| 33 | + public DecompilerSettingsGroupViewModel[] Settings { get; } |
32 | 34 |
|
33 | 35 | public DecompilerSettingsViewModel(Decompiler.DecompilerSettings settings) |
34 | 36 | { |
35 | 37 | Settings = typeof(Decompiler.DecompilerSettings).GetProperties() |
36 | 38 | .Where(p => p.GetCustomAttribute<BrowsableAttribute>()?.Browsable != false) |
37 | | - .Select(p => new CSharpDecompilerSetting(p) { IsEnabled = (bool)p.GetValue(settings) }) |
| 39 | + .Select(p => new DecompilerSettingsItemViewModel(p) { IsEnabled = p.GetValue(settings) is true }) |
38 | 40 | .OrderBy(item => item.Category, NaturalStringComparer.Instance) |
39 | | - .ThenBy(item => item.Description) |
| 41 | + .GroupBy(p => p.Category) |
| 42 | + .Select(g => new DecompilerSettingsGroupViewModel(g.Key, g.OrderBy(i => i.Description).ToArray())) |
40 | 43 | .ToArray(); |
41 | 44 | } |
42 | 45 |
|
43 | | - public event PropertyChangedEventHandler PropertyChanged; |
44 | | - |
45 | | - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) |
46 | | - { |
47 | | - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); |
48 | | - } |
49 | | - |
50 | 46 | public Decompiler.DecompilerSettings ToDecompilerSettings() |
51 | 47 | { |
52 | 48 | var settings = new Decompiler.DecompilerSettings(); |
53 | | - foreach (var item in Settings) |
| 49 | + |
| 50 | + foreach (var item in Settings.SelectMany(group => group.Settings)) |
54 | 51 | { |
55 | 52 | item.Property.SetValue(settings, item.IsEnabled); |
56 | 53 | } |
| 54 | + |
57 | 55 | return settings; |
58 | 56 | } |
59 | 57 | } |
60 | | - public class CSharpDecompilerSetting : INotifyPropertyChanged |
| 58 | + |
| 59 | + public sealed class DecompilerSettingsGroupViewModel : ObservableObjectBase |
61 | 60 | { |
62 | | - bool isEnabled; |
| 61 | + private bool? _areAllItemsChecked; |
63 | 62 |
|
64 | | - public CSharpDecompilerSetting(PropertyInfo p) |
| 63 | + public DecompilerSettingsGroupViewModel(string category, DecompilerSettingsItemViewModel[] settings) |
65 | 64 | { |
66 | | - this.Property = p; |
67 | | - this.Category = GetResourceString(p.GetCustomAttribute<CategoryAttribute>()?.Category ?? Resources.Other); |
68 | | - this.Description = GetResourceString(p.GetCustomAttribute<DescriptionAttribute>()?.Description ?? p.Name); |
69 | | - } |
| 65 | + Settings = settings; |
| 66 | + Category = category; |
70 | 67 |
|
71 | | - public PropertyInfo Property { get; } |
| 68 | + _areAllItemsChecked = GetAreAllItemsChecked(Settings); |
72 | 69 |
|
73 | | - public bool IsEnabled { |
74 | | - get => isEnabled; |
| 70 | + foreach (DecompilerSettingsItemViewModel viewModel in settings) |
| 71 | + { |
| 72 | + viewModel.PropertyChanged += Item_PropertyChanged; |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + public bool? AreAllItemsChecked { |
| 77 | + get => _areAllItemsChecked; |
75 | 78 | set { |
76 | | - if (value != isEnabled) |
| 79 | + SetProperty(ref _areAllItemsChecked, value); |
| 80 | + |
| 81 | + if (!value.HasValue) |
| 82 | + return; |
| 83 | + |
| 84 | + foreach (var setting in Settings) |
77 | 85 | { |
78 | | - isEnabled = value; |
79 | | - OnPropertyChanged(); |
| 86 | + setting.IsEnabled = value.Value; |
80 | 87 | } |
81 | 88 | } |
82 | 89 | } |
83 | 90 |
|
84 | | - public string Description { get; set; } |
| 91 | + public string Category { get; } |
85 | 92 |
|
86 | | - public string Category { get; set; } |
| 93 | + public DecompilerSettingsItemViewModel[] Settings { get; } |
87 | 94 |
|
88 | | - public event PropertyChangedEventHandler PropertyChanged; |
| 95 | + private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e) |
| 96 | + { |
| 97 | + if (e.PropertyName == nameof(DecompilerSettingsItemViewModel.IsEnabled)) |
| 98 | + { |
| 99 | + AreAllItemsChecked = GetAreAllItemsChecked(Settings); |
| 100 | + } |
| 101 | + } |
89 | 102 |
|
90 | | - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) |
| 103 | + private static bool? GetAreAllItemsChecked(ICollection<DecompilerSettingsItemViewModel> settings) |
91 | 104 | { |
92 | | - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); |
| 105 | + var numberOfEnabledItems = settings.Count(item => item.IsEnabled); |
| 106 | + |
| 107 | + if (numberOfEnabledItems == settings.Count) |
| 108 | + return true; |
| 109 | + |
| 110 | + if (numberOfEnabledItems == 0) |
| 111 | + return false; |
| 112 | + |
| 113 | + return null; |
| 114 | + } |
| 115 | + } |
| 116 | + |
| 117 | + public sealed class DecompilerSettingsItemViewModel(PropertyInfo property) : ObservableObjectBase |
| 118 | + { |
| 119 | + private bool _isEnabled; |
| 120 | + |
| 121 | + public PropertyInfo Property { get; } = property; |
| 122 | + |
| 123 | + public bool IsEnabled { |
| 124 | + get => _isEnabled; |
| 125 | + set => SetProperty(ref _isEnabled, value); |
93 | 126 | } |
94 | 127 |
|
95 | | - static string GetResourceString(string key) |
| 128 | + public string Description { get; set; } = GetResourceString(property.GetCustomAttribute<DescriptionAttribute>()?.Description ?? property.Name); |
| 129 | + |
| 130 | + public string Category { get; set; } = GetResourceString(property.GetCustomAttribute<CategoryAttribute>()?.Category ?? Resources.Other); |
| 131 | + |
| 132 | + private static string GetResourceString(string key) |
96 | 133 | { |
97 | 134 | var str = !string.IsNullOrEmpty(key) ? Resources.ResourceManager.GetString(key) : null; |
98 | 135 | return string.IsNullOrEmpty(key) || string.IsNullOrEmpty(str) ? key : str; |
|
0 commit comments