diff --git a/XSDVisualiser.Core/XSDVisualiser.Core.csproj b/XSDVisualiser.Core/XSDVisualiser.Core.csproj index 180cfa3..980dfd8 100644 --- a/XSDVisualiser.Core/XSDVisualiser.Core.csproj +++ b/XSDVisualiser.Core/XSDVisualiser.Core.csproj @@ -1,12 +1,12 @@ - - net9.0 - enable - enable - - - - - - + + net9.0 + enable + enable + + + + + + diff --git a/XSDVisualiser.Desktop/App.axaml b/XSDVisualiser.Desktop/App.axaml index 059c864..8e03f38 100644 --- a/XSDVisualiser.Desktop/App.axaml +++ b/XSDVisualiser.Desktop/App.axaml @@ -4,32 +4,32 @@ xmlns:conv="clr-namespace:XSDVisualiser.Desktop.Converters" x:Class="XSDVisualiser.Desktop.App" RequestedThemeVariant="Light"> - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + - - - + + + - - - - + + + + \ No newline at end of file diff --git a/XSDVisualiser.Desktop/App.axaml.cs b/XSDVisualiser.Desktop/App.axaml.cs index be0ef03..ec7d599 100644 --- a/XSDVisualiser.Desktop/App.axaml.cs +++ b/XSDVisualiser.Desktop/App.axaml.cs @@ -2,22 +2,19 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; -namespace XSDVisualiser.Desktop -{ - public partial class App : Application - { - public override void Initialize() - { - AvaloniaXamlLoader.Load(this); - } +namespace XSDVisualiser.Desktop; - public override void OnFrameworkInitializationCompleted() - { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - desktop.MainWindow = new MainWindow(); - } - base.OnFrameworkInitializationCompleted(); - } +public class App : Application +{ + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); } -} + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + desktop.MainWindow = new MainWindow(); + base.OnFrameworkInitializationCompleted(); + } +} \ No newline at end of file diff --git a/XSDVisualiser.Desktop/Converters/CardinalityToLabelConverter.cs b/XSDVisualiser.Desktop/Converters/CardinalityToLabelConverter.cs index de2ebe9..cab0426 100644 --- a/XSDVisualiser.Desktop/Converters/CardinalityToLabelConverter.cs +++ b/XSDVisualiser.Desktop/Converters/CardinalityToLabelConverter.cs @@ -1,22 +1,22 @@ -using System; using System.Globalization; using Avalonia.Data.Converters; -using XSDVisualiser.Models; +using XSDVisualiser.Core; -namespace XSDVisualiser.Desktop.Converters +namespace XSDVisualiser.Desktop.Converters; + +public class CardinalityToLabelConverter : IValueConverter { - public class CardinalityToLabelConverter : IValueConverter + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) - { - if (value is not Occurs occ) return null; - - var min = occ.Min; - var max = occ.MaxIsUnbounded ? "*" : occ.Max.ToString(culture); - return $"[{min}..{max}]"; - } + if (value is not Occurs occ) return null; - public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) - => throw new NotSupportedException(); + var min = occ.Min; + var max = occ.MaxIsUnbounded ? "*" : occ.Max.ToString(culture); + return $"[{min}..{max}]"; } -} + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } +} \ No newline at end of file diff --git a/XSDVisualiser.Desktop/Converters/CollectionHasItemsConverter.cs b/XSDVisualiser.Desktop/Converters/CollectionHasItemsConverter.cs index 48a53c7..e9ff18f 100644 --- a/XSDVisualiser.Desktop/Converters/CollectionHasItemsConverter.cs +++ b/XSDVisualiser.Desktop/Converters/CollectionHasItemsConverter.cs @@ -1,37 +1,37 @@ -using System; using System.Collections; using System.Globalization; using Avalonia.Data.Converters; -namespace XSDVisualiser.Desktop.Converters -{ - /// - /// Returns true if the bound value is a collection with at least one item. Supports IEnumerable and ICollection. - /// Optional parameter "Invert" to invert the boolean result. - /// - public sealed class CollectionHasItemsConverter : IValueConverter - { - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) - { - var hasItems = false; - switch (value) - { - case ICollection coll: - hasItems = coll.Count > 0; - break; - case IEnumerable enumerable: - { - var enumerator = enumerable.GetEnumerator(); - hasItems = enumerator.MoveNext(); - break; - } - } +namespace XSDVisualiser.Desktop.Converters; - var invert = parameter is string s && s.Equals("Invert", StringComparison.OrdinalIgnoreCase); - return invert ? !hasItems : hasItems; +/// +/// Returns true if the bound value is a collection with at least one item. Supports IEnumerable and ICollection. +/// Optional parameter "Invert" to invert the boolean result. +/// +public sealed class CollectionHasItemsConverter : IValueConverter +{ + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + var hasItems = false; + switch (value) + { + case ICollection coll: + hasItems = coll.Count > 0; + break; + case IEnumerable enumerable: + { + var enumerator = enumerable.GetEnumerator(); + hasItems = enumerator.MoveNext(); + break; + } } - public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) - => throw new NotSupportedException(); + var invert = parameter is string s && s.Equals("Invert", StringComparison.OrdinalIgnoreCase); + return invert ? !hasItems : hasItems; } -} + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } +} \ No newline at end of file diff --git a/XSDVisualiser.Desktop/Converters/OptionalToBorderBrushConverter.cs b/XSDVisualiser.Desktop/Converters/OptionalToBorderBrushConverter.cs index 8fef8b7..d437a32 100644 --- a/XSDVisualiser.Desktop/Converters/OptionalToBorderBrushConverter.cs +++ b/XSDVisualiser.Desktop/Converters/OptionalToBorderBrushConverter.cs @@ -1,27 +1,25 @@ -using System; using System.Globalization; using Avalonia.Data.Converters; using Avalonia.Media; -using XSDVisualiser.Models; +using XSDVisualiser.Core; -namespace XSDVisualiser.Desktop.Converters +namespace XSDVisualiser.Desktop.Converters; + +public class OptionalToBorderBrushConverter : IValueConverter { - public class OptionalToBorderBrushConverter : IValueConverter + private static readonly IBrush RequiredBrush = new SolidColorBrush(Color.FromRgb(0x33, 0x99, 0x33)); + private static readonly IBrush OptionalBrush = new SolidColorBrush(Color.FromRgb(0xCC, 0x66, 0x33)); + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - private static readonly IBrush RequiredBrush = new SolidColorBrush(Color.FromRgb(0x33, 0x99, 0x33)); - private static readonly IBrush OptionalBrush = new SolidColorBrush(Color.FromRgb(0xCC, 0x66, 0x33)); - - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) - { - if (value is Occurs occ) - { - // Optional if minOccurs == 0 - return occ.Min == 0 ? OptionalBrush : RequiredBrush; - } - return RequiredBrush; - } - - public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) - => throw new NotSupportedException(); + if (value is Occurs occ) + // Optional if minOccurs == 0 + return occ.Min == 0 ? OptionalBrush : RequiredBrush; + return RequiredBrush; } -} + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } +} \ No newline at end of file diff --git a/XSDVisualiser.Desktop/Converters/OptionalToThicknessConverter.cs b/XSDVisualiser.Desktop/Converters/OptionalToThicknessConverter.cs index 6145c90..715299e 100644 --- a/XSDVisualiser.Desktop/Converters/OptionalToThicknessConverter.cs +++ b/XSDVisualiser.Desktop/Converters/OptionalToThicknessConverter.cs @@ -1,27 +1,25 @@ -using System; using System.Globalization; using Avalonia; using Avalonia.Data.Converters; -using XSDVisualiser.Models; +using XSDVisualiser.Core; -namespace XSDVisualiser.Desktop.Converters +namespace XSDVisualiser.Desktop.Converters; + +public class OptionalToThicknessConverter : IValueConverter { - public class OptionalToThicknessConverter : IValueConverter + private static readonly Thickness Required = new(2); + private static readonly Thickness Optional = new(2); + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { - private static readonly Thickness Required = new Thickness(2); - private static readonly Thickness Optional = new Thickness(2); - - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) - { - if (value is Occurs occ) - { - // We could vary thickness; for now same thickness regardless, reserved for future styling. - return occ.Min == 0 ? Optional : Required; - } - return Required; - } - - public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) - => throw new NotSupportedException(); + if (value is Occurs occ) + // We could vary thickness; for now same thickness regardless, reserved for future styling. + return occ.Min == 0 ? Optional : Required; + return Required; } -} + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } +} \ No newline at end of file diff --git a/XSDVisualiser.Desktop/MainWindow.axaml b/XSDVisualiser.Desktop/MainWindow.axaml index 0d25244..cc978ca 100644 --- a/XSDVisualiser.Desktop/MainWindow.axaml +++ b/XSDVisualiser.Desktop/MainWindow.axaml @@ -7,11 +7,12 @@ - + - + - + \ No newline at end of file diff --git a/XSDVisualiser.Desktop/MainWindow.axaml.cs b/XSDVisualiser.Desktop/MainWindow.axaml.cs index aad28b6..f0b5a98 100644 --- a/XSDVisualiser.Desktop/MainWindow.axaml.cs +++ b/XSDVisualiser.Desktop/MainWindow.axaml.cs @@ -1,12 +1,11 @@ using Avalonia.Controls; -namespace XSDVisualiser.Desktop +namespace XSDVisualiser.Desktop; + +public partial class MainWindow : Window { - public partial class MainWindow : Window + public MainWindow() { - public MainWindow() - { - InitializeComponent(); - } + InitializeComponent(); } -} +} \ No newline at end of file diff --git a/XSDVisualiser.Desktop/Program.cs b/XSDVisualiser.Desktop/Program.cs index 41f59e6..5b84921 100644 --- a/XSDVisualiser.Desktop/Program.cs +++ b/XSDVisualiser.Desktop/Program.cs @@ -1,21 +1,21 @@ -using System; using Avalonia; using Avalonia.ReactiveUI; -namespace XSDVisualiser.Desktop -{ - internal static class Program - { - [STAThread] - public static void Main(string[] args) - { - BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); - } +namespace XSDVisualiser.Desktop; - private static AppBuilder BuildAvaloniaApp() => - AppBuilder.Configure() - .UsePlatformDetect() - .LogToTrace() - .UseReactiveUI(); +internal static class Program +{ + [STAThread] + public static void Main(string[] args) + { + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); } -} + + private static AppBuilder BuildAvaloniaApp() + { + return AppBuilder.Configure() + .UsePlatformDetect() + .LogToTrace() + .UseReactiveUI(); + } +} \ No newline at end of file diff --git a/XSDVisualiser.Desktop/ViewModels/MainWindowViewModel.cs b/XSDVisualiser.Desktop/ViewModels/MainWindowViewModel.cs index d85b13d..7b24482 100644 --- a/XSDVisualiser.Desktop/ViewModels/MainWindowViewModel.cs +++ b/XSDVisualiser.Desktop/ViewModels/MainWindowViewModel.cs @@ -1,80 +1,80 @@ -using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Linq; using System.Runtime.CompilerServices; -using XSDVisualiser.Models; +using XSDVisualiser.Core; -namespace XSDVisualiser.Desktop.ViewModels +namespace XSDVisualiser.Desktop.ViewModels; + +public class MainWindowViewModel(SchemaModel model) : INotifyPropertyChanged { - public class MainWindowViewModel(SchemaModel model) : INotifyPropertyChanged + private string? _currentFilePath; + private SchemaModel _model = model ?? throw new ArgumentNullException(nameof(model)); + private SchemaNode? _selectedNode; + private SchemaNode? _selectedRootElement; + + public SchemaModel Model { - private SchemaModel _model = model ?? throw new ArgumentNullException(nameof(model)); - private SchemaNode? _selectedRootElement; - private SchemaNode? _selectedNode; - - public event PropertyChangedEventHandler? PropertyChanged; - - private void OnPropertyChanged([CallerMemberName] string? name = null) + get => _model; + set { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); + if (ReferenceEquals(_model, value)) return; + _model = value ?? throw new ArgumentNullException(nameof(value)); + OnPropertyChanged(); + OnPropertyChanged(nameof(RootElements)); + OnPropertyChanged(nameof(VisibleRootElements)); } - - public SchemaModel Model - { - get => _model; - set - { - if (ReferenceEquals(_model, value)) return; - _model = value ?? throw new ArgumentNullException(nameof(value)); - OnPropertyChanged(); - OnPropertyChanged(nameof(RootElements)); - OnPropertyChanged(nameof(VisibleRootElements)); - } - } - - public IEnumerable RootElements => _model?.RootElements ?? Enumerable.Empty(); - - public SchemaNode? SelectedRootElement - { - get => _selectedRootElement; - set - { - if (EqualityComparer.Default.Equals(_selectedRootElement, value)) return; - _selectedRootElement = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(VisibleRootElements)); - } - } - - public SchemaNode? SelectedNode - { - get => _selectedNode; - set - { - if (EqualityComparer.Default.Equals(_selectedNode, value)) return; - _selectedNode = value; - OnPropertyChanged(); - } - } - - public IEnumerable VisibleRootElements => SelectedRootElement != null ? [SelectedRootElement] : RootElements; - - private string? _currentFilePath; - public string? CurrentFilePath - { - get => _currentFilePath; - set - { - if (string.Equals(_currentFilePath, value, StringComparison.Ordinal)) return; - _currentFilePath = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(CurrentFileName)); - OnPropertyChanged(nameof(CurrentDirectory)); - } - } - - public string? CurrentFileName => string.IsNullOrEmpty(_currentFilePath) ? null : System.IO.Path.GetFileName(_currentFilePath); - public string? CurrentDirectory => string.IsNullOrEmpty(_currentFilePath) ? null : System.IO.Path.GetDirectoryName(_currentFilePath); } -} + + public IEnumerable RootElements => _model?.RootElements ?? Enumerable.Empty(); + + public SchemaNode? SelectedRootElement + { + get => _selectedRootElement; + set + { + if (EqualityComparer.Default.Equals(_selectedRootElement, value)) return; + _selectedRootElement = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(VisibleRootElements)); + } + } + + public SchemaNode? SelectedNode + { + get => _selectedNode; + set + { + if (EqualityComparer.Default.Equals(_selectedNode, value)) return; + _selectedNode = value; + OnPropertyChanged(); + } + } + + public IEnumerable VisibleRootElements => + SelectedRootElement != null ? [SelectedRootElement] : RootElements; + + public string? CurrentFilePath + { + get => _currentFilePath; + set + { + if (string.Equals(_currentFilePath, value, StringComparison.Ordinal)) return; + _currentFilePath = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(CurrentFileName)); + OnPropertyChanged(nameof(CurrentDirectory)); + } + } + + public string? CurrentFileName => + string.IsNullOrEmpty(_currentFilePath) ? null : Path.GetFileName(_currentFilePath); + + public string? CurrentDirectory => + string.IsNullOrEmpty(_currentFilePath) ? null : Path.GetDirectoryName(_currentFilePath); + + public event PropertyChangedEventHandler? PropertyChanged; + + private void OnPropertyChanged([CallerMemberName] string? name = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); + } +} \ No newline at end of file diff --git a/XSDVisualiser.Desktop/Views/HeaderView.axaml b/XSDVisualiser.Desktop/Views/HeaderView.axaml index 81842a7..0b9d634 100644 --- a/XSDVisualiser.Desktop/Views/HeaderView.axaml +++ b/XSDVisualiser.Desktop/Views/HeaderView.axaml @@ -8,23 +8,23 @@ FontSize="20" FontWeight="SemiBold" Margin="0,0,12,0" - VerticalAlignment="Center"/> + VerticalAlignment="Center" /> + Margin="0,0,12,0" + Watermark="Search and choose a root element" + ItemsSource="{Binding RootElements}" + FilterMode="Contains" + MinimumPrefixLength="0" + HorizontalAlignment="Stretch" + VerticalAlignment="Center"> - + - + @@ -32,7 +32,7 @@ Content="Open XSD and parse" x:Name="OpenBtn" Width="220" - VerticalAlignment="Center"/> + VerticalAlignment="Center" /> - - + + - + - - + + - + \ No newline at end of file diff --git a/XSDVisualiser.Desktop/Views/HeaderView.axaml.cs b/XSDVisualiser.Desktop/Views/HeaderView.axaml.cs index 67e7b3a..d61d5b9 100644 --- a/XSDVisualiser.Desktop/Views/HeaderView.axaml.cs +++ b/XSDVisualiser.Desktop/Views/HeaderView.axaml.cs @@ -1,12 +1,9 @@ -using System; -using System.Threading.Tasks; -using Avalonia; +using System.Diagnostics; using Avalonia.Controls; using Avalonia.Interactivity; -using Avalonia.Threading; using Avalonia.Platform.Storage; +using Avalonia.Threading; using XSDVisualiser.Core; -using XSDVisualiser.Models; using XSDVisualiser.Desktop.ViewModels; namespace XSDVisualiser.Desktop.Views; @@ -19,10 +16,7 @@ public partial class HeaderView : UserControl { InitializeComponent(); _openBtn = this.FindControl