diff --git a/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/EntityTreeViewerControl.cs b/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/EntityTreeViewerControl.cs index ce1d0bc..e05d7b3 100644 --- a/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/EntityTreeViewerControl.cs +++ b/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/EntityTreeViewerControl.cs @@ -1,5 +1,6 @@ using System.ComponentModel; using Pf2eDataScrapper.Helpers; +using Pf2eDataScrapper.WPF.ViewModels.EntityViewStructure; namespace Pf2eDataScrapper.Forms.Controls.EntityTreeViewer; diff --git a/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/EntityTreeViewerControlRow.cs b/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/EntityTreeViewerControlRow.cs index 672bd51..f8c204f 100644 --- a/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/EntityTreeViewerControlRow.cs +++ b/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/EntityTreeViewerControlRow.cs @@ -1,4 +1,5 @@ using FontAwesome.Sharp; +using Pf2eDataScrapper.WPF.ViewModels.EntityViewStructure; using Font = System.Drawing.Font; using FontStyle = System.Drawing.FontStyle; using Image = System.Drawing.Image; diff --git a/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/StructureBuilder.cs b/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/StructureBuilder.cs deleted file mode 100644 index 731b64e..0000000 --- a/Pf2eDataScrapper/Forms/Controls/EntityTreeViewer/StructureBuilder.cs +++ /dev/null @@ -1,627 +0,0 @@ -using System.Collections; -using System.Reflection; -using LinqToDB.Extensions; -using Pf2eModel.Model.Common.I18n; - -namespace Pf2eDataScrapper.Forms.Controls.EntityTreeViewer; - -/// -/// Класс для построения структуры данных класса. -/// -internal class StructureBuilder -{ - /// - /// Список обработанных объектов. - /// - private readonly List _processedObjects = []; - - /// - /// Создание поля структуры. - /// - /// Название поля. - /// Значение поля. - /// Глубина, на котором поле отображается. - /// Поле структуры. - public StructureFieldComplex Create(string name, object value, int depth = 0) - { - _ = RegisterProcessed(value); - - StructureFieldComplex field = new(this, value, name, depth); - - CompleteProcessed(value, field); - - return field; - } - - /// - /// Регистрация обработанного объекта. - /// - /// Регистрируемый объект. - /// `true`, если объект был добавлен; `false`, если объект был добавлен ранее. - public bool RegisterProcessed(object value) - { - if (_processedObjects.Any(p => p.Value == value)) - { - return false; - } - - StructureProcessedObject processed = new(value); - - _processedObjects.Add(processed); - - return true; - } - - /// - /// Дополнить обработанный объект. - /// - /// Значение. - /// Поле объекта. - public void CompleteProcessed(object value, StructureFieldComplex field) - { - StructureProcessedObject? q = _processedObjects.FirstOrDefault(p => p.Value == value); - - if (q == null) - { - return; - } - - q.Field = field; - } - - /// - /// Выбор поля структуры по значению. - /// - /// Название поля. - /// Значение поля. - /// Глубина, на котором поле отображается. - /// - public StructureField Resolve(string name, object? value, int depth) - { - switch (GetFieldType(value)) - { - case StructureFieldType.Null: - return new StructureFieldNull(this, name, depth); - - case StructureFieldType.Primitive: - return new StructureFieldPrimitive(this, value!, name, depth); - - case StructureFieldType.Enum: - return new StructureFieldEnum(this, value!, name, depth); - - case StructureFieldType.Reference: - break; - - case StructureFieldType.Complex: - default: - - StructureProcessedObject? processed = _processedObjects.FirstOrDefault(p => - p.Value == value - ); - - if (processed is null) - { - return Create(name, value!, depth); - } - - StructureFieldReference reference = new StructureFieldReference( - this, - name, - null, - depth - ); - processed.AddReference(reference); - return reference; - } - - throw new("Impossible"); - } - - /// - /// Получить тип поля структуры по значению. - /// - /// Значение поля. - /// Тип поля структуры. - public static StructureFieldType GetFieldType(object? value) - { - if (value is null) - { - return StructureFieldType.Null; - } - - Type type = value.GetType(); - - if (type.IsEnum) - { - return StructureFieldType.Enum; - } - - if (type.IsPrimitive || type == typeof(string)) - { - return StructureFieldType.Primitive; - } - - return StructureFieldType.Complex; - } -} - -/// -/// Класс для хранения обработанного объекта. -/// -/// Объект. -internal class StructureProcessedObject(object value) -{ - public readonly object Value = value; - - private StructureFieldComplex? _field; - - public StructureFieldComplex? Field - { - get => _field; - set - { - _field = value; - foreach (StructureFieldReference reference in _references) - { - reference.Reference = Field; - } - } - } - - private readonly List _references = []; - - public void AddReference(StructureFieldReference reference) - { - _references.Add(reference); - - if (_field is not null) - { - reference.Reference = Field; - } - } -} - -/// -/// Тип поля структуры. -/// -internal enum StructureFieldType -{ - /// - /// Пустое поле. - /// - Null, - - /// - /// Простое поле. - /// - Primitive, - - /// - /// Поле с перечислением. - /// - Enum, - - /// - /// Поле с объектом. - /// - Complex, - - /// - /// Поле с ссылкой на объект. - /// - Reference, -} - -/// -/// Тип лестницы глубины. -/// -internal enum LadderType -{ - /// - /// Пустой элемент: [ ]. - /// - Empty, - - /// - /// Последний элемент: [└]. - /// - Last, - - /// - /// Проходной элемент: [├] или [│]. - /// - Through, -} - -/// -/// Базовый класс для полей структуры. -/// -/// Класс построения структуры данных. -/// Название поля. -/// Глубина поля. -internal abstract class StructureField(StructureBuilder builder, string name, int depth) -{ - /// - /// Название поля. - /// - public readonly string Name = name; - - /// - /// Тип поля структуры. - /// - public abstract StructureFieldType FieldType { get; } - - /// - /// Класс построения структуры данных. - /// - public readonly StructureBuilder Builder = builder; - - /// - /// Флаг, указывающий, отображается ли поле. - /// - public virtual bool Visible { get; set; } = true; - - /// - /// Глубина поля структуры. - /// - public readonly int Depth = depth; - - /// - /// Получить строку, представляющую тип поля. - /// - /// Строка, представляющая тип поля. - public abstract string GetTypeString(); - - /// - /// Получить строку, представляющую значение поля. - /// - /// Строка, представляющая значение поля. - public abstract string GetValueString(); - - /// - /// Получить набор строк, используя результат функция. - /// - /// Тип результирующей строки. - /// Функция, оборажения поля в результирующую строку. - /// Коллекция, содержащая набор строк. - public virtual ICollection GetRows(Func func) - { - StructureField[] q = [this]; - return q.Select(func).ToList(); - } -} - -/// -/// Пустое поле структуры. -/// -/// Класс построения структуры данных. -/// Название поля. -/// Глубина поля. -internal class StructureFieldNull(StructureBuilder builder, string name, int depth) - : StructureField(builder, name, depth) -{ - /// - public override StructureFieldType FieldType => StructureFieldType.Null; - - /// - public override string GetTypeString() => "null"; - - /// - public override string GetValueString() => ""; -} - -/// -/// Простое поле структуры. -/// -/// Класс построения структуры данных. -/// Значение поля. -/// Название поля. -/// Глубина поля. -internal class StructureFieldPrimitive( - StructureBuilder builder, - object value, - string name, - int depth -) : StructureField(builder, name, depth) -{ - /// - public override StructureFieldType FieldType => StructureFieldType.Primitive; - - /// - /// Значение поля. - /// - public readonly object Value = value; - - /// - /// Тип значения поля. - /// - public readonly Type Type = value.GetType(); - - /// - public override string GetTypeString() - { - return Type.GetTypeCode(Type) switch - { - TypeCode.Boolean => "bool", - TypeCode.Int32 => "int", - TypeCode.String => "string", - TypeCode.Double => "double", - _ => Type.Name, - }; - } - - /// - public override string GetValueString() - { - if (Type == typeof(string)) - { - return "\"" + ((string)Value).Replace("\"", "\\\"") + "\""; - } - - return Value.ToString() ?? string.Empty; - } -} - -/// -/// Поле структуры с перечислением. -/// -/// Класс построения структуры данных. -/// Значение поля. -/// Название поля. -/// Глубина поля. -internal class StructureFieldEnum(StructureBuilder builder, object value, string name, int depth) - : StructureField(builder, name, depth) -{ - /// - public override StructureFieldType FieldType => StructureFieldType.Enum; - - /// - /// Значение поля. - /// - public readonly object Value = value; - - /// - /// Тип значения поля. - /// - public readonly Type Type = value.GetType(); - - /// - public override string GetTypeString() => "enum"; - - /// - public override string GetValueString() => $"{Type.Name}.{Value}"; -} - -/// -/// Поле стркутуры с объектом. -/// -internal class StructureFieldComplex : StructureField -{ - /// - public override StructureFieldType FieldType => StructureFieldType.Complex; - - /// - /// Набор полей объекта. - /// - public readonly List Fields = []; - - /// - /// Тип значения поля. - /// - public readonly Type Type; - - /// - /// Флаг, указывающий, отображается ли поля объекта. - /// - public bool Collapsed - { - get => _collapsed; - set - { - _collapsed = value; - UpdateFieldVisibility(); - } - } - private bool _collapsed; - - /// - public override bool Visible - { - get => _visible; - set - { - _visible = value; - UpdateFieldVisibility(); - } - } - private bool _visible = true; - - /// - /// Конструктор класса поля структуры с объектом. - /// - /// Класс построения структуры данных. - /// Значение поля. - /// Название поля. - /// Глубина поля. - public StructureFieldComplex(StructureBuilder builder, object value, string name, int depth) - : base(builder, name, depth) - { - Type = value.GetType(); - - SetFields((dynamic)value); - } - - /// - /// Обновить видимость полей структуры. - /// - private void UpdateFieldVisibility() - { - foreach (StructureField field in Fields) - { - field.Visible = Visible && !Collapsed; - } - } - - /// - /// Установить поля структуры `LocaleString`. - /// - /// Объект строки локализации. - private void SetFields(LocaleString localeString) - { - SetFieldsFromRecords( - localeString - .Select(field => new FieldRecord(field.Locale.ToString(), field.Value)) - .ToList() - ); - } - - /// - /// Установить поля структуры `IEnumerable`. - /// - /// Объект-перечисление. - private void SetFields(IEnumerable enumerable) - { - int i = 0; - - List records = []; - - foreach (object? item in enumerable) - { - records.Add(new($"[{i++}]", item)); - } - - SetFieldsFromRecords(records); - } - - /// - /// Установить поля структуры общего объекта. - /// - /// Объект. - private void SetFields(object value) - { - Type type = value.GetType(); - PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); - - SetFieldsFromRecords( - properties - .Where(property => - property.GetAttribute() is null - ) - .Select(property => new FieldRecord(property.Name, property.GetValue(value, null))) - .ToList() - ); - } - - /// - /// Установить поля структуры из списка записей. - /// - /// - private void SetFieldsFromRecords(List records) - { - foreach ( - FieldRecord record in records.Where(record => - record.FieldType == StructureFieldType.Complex - ) - ) - { - record.Allowed = Builder.RegisterProcessed(record.Value!); - } - - foreach (FieldRecord record in records) - { - Fields.Add( - record is { FieldType: StructureFieldType.Complex, Allowed: true } - ? Builder.Create(record.Name, record.Value!, Depth + 1) - : Builder.Resolve(record.Name, record.Value!, Depth + 1) - ); - } - } - - /// - /// Запись поля структуры. - /// - /// Название поля. - /// Значение поля. - private class FieldRecord(string name, object? value) - { - /// - /// Название поля. - /// - public readonly string Name = name; - - /// - /// Значение поля. - /// - public readonly object? Value = value; - - /// - /// Тип поля структуры. - /// - public StructureFieldType FieldType => StructureBuilder.GetFieldType(Value); - - /// - /// Флаг, указывающий, использовать ли поле. - /// - public bool Allowed = true; - } - - /// - public override string GetTypeString() - { - if (Type.IsGenericEnumerableType()) - { - Type elementType = Type.GetGenericArguments().Single(); - - return $"{elementType.Name}[]"; - } - else - { - return Type.Name; - } - } - - /// - public override string GetValueString() - { - if (Type.IsGenericEnumerableType()) - { - return Fields.Count.ToString() + (Fields.Count == 1 ? " item" : " items"); - } - return ""; - } - - /// - public override ICollection GetRows(Func func) - { - return [.. base.GetRows(func), .. Fields.SelectMany(f => f.GetRows(func)).ToList()]; - } -} - -/// -/// Поле структуры с ссылкой на объект. -/// -/// Класс построения структуры данных. -/// Название поля. -/// Ссылка на объект. -/// Глубина поля. -internal class StructureFieldReference( - StructureBuilder builder, - string name, - StructureFieldComplex? reference, - int depth -) : StructureField(builder, name, depth) -{ - /// - /// Ссылка на объект. - /// - public StructureFieldComplex? Reference = reference; - - /// - public override StructureFieldType FieldType => StructureFieldType.Reference; - - /// - public override string GetTypeString() => Reference?.GetTypeString() ?? "???"; - - /// - public override string GetValueString() => ""; -} diff --git a/Pf2eDataScrapper/ImportApplication.cs b/Pf2eDataScrapper/ImportApplication.cs index 3111401..cb6de5d 100644 --- a/Pf2eDataScrapper/ImportApplication.cs +++ b/Pf2eDataScrapper/ImportApplication.cs @@ -1,5 +1,6 @@ using System.ComponentModel; using System.Windows; +using System.Windows.Forms.Integration; using Microsoft.Extensions.DependencyInjection; using Pf2eDataScrapper.App; using Pf2eDataScrapper.Helpers; @@ -76,11 +77,12 @@ internal sealed class ImportApplication : ApplicationContext case ApplicationStage.InitialSettings: _startFormWpf = ActivatorUtilities.CreateInstance(ServiceProvider); - _startFormWpf.WindowStartupLocation = WindowStartupLocation.CenterOwner; + _startFormWpf.WindowStartupLocation = WindowStartupLocation.CenterScreen; _startFormWpf.Closing += Wpf_HandleFormClosing; _startFormWpf.ApplicationStateChange += ApplicationStateChange; _startFormWpf.Show(); + ElementHost.EnableModelessKeyboardInterop(_startFormWpf); CurrentWpfForm = _startFormWpf; break; @@ -92,22 +94,25 @@ internal sealed class ImportApplication : ApplicationContext _progressFormWpf = ActivatorUtilities.CreateInstance( ServiceProvider ); - _progressFormWpf.WindowStartupLocation = WindowStartupLocation.CenterOwner; + _progressFormWpf.WindowStartupLocation = WindowStartupLocation.CenterScreen; _progressFormWpf.Closing += Wpf_HandleFormClosing; _progressFormWpf.ApplicationStateChange += ApplicationStateChange; - - CurrentWpfForm = _progressFormWpf; _progressFormWpf.Show(); + + ElementHost.EnableModelessKeyboardInterop(_progressFormWpf); + CurrentWpfForm = _progressFormWpf; + executor.Start(); break; case ApplicationStage.Viewer: _entityForm = ActivatorUtilities.CreateInstance(ServiceProvider); - _entityForm.WindowStartupLocation = WindowStartupLocation.CenterOwner; + _entityForm.WindowStartupLocation = WindowStartupLocation.CenterScreen; _entityForm.Closing += Wpf_HandleFormClosing; //_entityForm.ApplicationStateChange += ApplicationStateChange; _entityForm.Show(); + ElementHost.EnableModelessKeyboardInterop(_entityForm); CurrentWpfForm = _entityForm; break; diff --git a/Pf2eDataScrapper/Program.cs b/Pf2eDataScrapper/Program.cs index 71d8b6c..6fc7b65 100644 --- a/Pf2eDataScrapper/Program.cs +++ b/Pf2eDataScrapper/Program.cs @@ -30,8 +30,6 @@ internal static class Program ImportApplication app = ActivatorUtilities.CreateInstance( serviceProvider ); - - Application.Run(app); } private static IServiceCollection RegisterServices() diff --git a/Pf2eDataScrapper/WPF/Components/DbEntityListControl.xaml b/Pf2eDataScrapper/WPF/Components/DbEntityListControl.xaml index e595937..cb9c466 100644 --- a/Pf2eDataScrapper/WPF/Components/DbEntityListControl.xaml +++ b/Pf2eDataScrapper/WPF/Components/DbEntityListControl.xaml @@ -6,6 +6,7 @@ xmlns:local="clr-namespace:Pf2eDataScrapper.WPF.Components" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewModels="clr-namespace:Pf2eDataScrapper.WPF.ViewModels" + Padding="3,3,3,3" d:DataContext="{d:DesignInstance Type=viewModels:DbEntityListViewModel}" d:DesignHeight="450" d:DesignWidth="400" @@ -14,10 +15,11 @@ + - + @@ -26,33 +28,48 @@