Compare commits

..
2 Commits
Author SHA1 Message Date
kozhilya 02d35d72d2 Отчистика кода 2025-04-18 17:32:23 +04:00
kozhilya 9a711c5a9d Программа просмотра базы данных 2025-04-18 17:26:52 +04:00
33 changed files with 1830 additions and 1178 deletions
+6
View File
@@ -17,6 +17,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "output", "output", "{36D591
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pf2eModel", "Pf2eModel\Pf2eModel.csproj", "{D32B7787-D912-4B21-B341-7C1F42F62D36}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pf2eViewer", "Pf2eViewer\Pf2eViewer.csproj", "{9F492EA7-1E1A-439D-A028-506BA445ABE4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -31,6 +33,10 @@ Global
{D32B7787-D912-4B21-B341-7C1F42F62D36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D32B7787-D912-4B21-B341-7C1F42F62D36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D32B7787-D912-4B21-B341-7C1F42F62D36}.Release|Any CPU.Build.0 = Release|Any CPU
{9F492EA7-1E1A-439D-A028-506BA445ABE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9F492EA7-1E1A-439D-A028-506BA445ABE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F492EA7-1E1A-439D-A028-506BA445ABE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F492EA7-1E1A-439D-A028-506BA445ABE4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1,12 +1,4 @@
using Pf2eDataScrapper.Importers.Repositories;
using Pf2eModel.Model.Enum;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static LinqToDB.Reflection.Methods.LinqToDB.Insert;
using Pf2eModel.Model.Enum;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder;
public static class AonprdEnumResolver
@@ -48,7 +40,7 @@ public static class AonprdEnumResolver
Solver<T> tSolver = (Solver<T>) solver;
return tSolver.Data.TryGetValue(value, out var data) ? data : throw new EnumResolverValueUnknownException(type, value);
return tSolver.Data.TryGetValue(value, out T? data) ? data : throw new EnumResolverValueUnknownException(type, value);
}
private abstract class Solver
@@ -3,7 +3,7 @@ using Pf2eModel.Model.Structure;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors;
[AonprdProcessor("trait", new string[] {})]
[AonprdProcessor("trait", new string[] { })]
internal class TraitProcessor(ProcessorInput input) : AbstractProcessor(input)
{
public override EntityType Type => EntityType.Trait;
+37
View File
@@ -0,0 +1,37 @@
using Pf2eModel.Model;
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Enum;
using System.Reflection;
namespace Pf2eModel;
[AttributeUsage(AttributeTargets.Class)]
public class EntityOfTypeAttribute(EntityType type) : Attribute
{
public EntityType Type { get; } = type;
public static Type Resolve(Entity entity)
{
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
if (type.GetCustomAttributes(typeof(EntityOfTypeAttribute), true).Length <= 0)
{
continue;
}
if (!type.IsAssignableTo(typeof(IEntity)))
{
throw new Exception($"'EntityOfTypeAttribute' attribute should only be applied to children of 'IEntity' class. '{type.FullName}' is not.");
}
EntityOfTypeAttribute attribute = type.GetCustomAttribute<EntityOfTypeAttribute>()!;
if (attribute.Type == entity.Type)
{
return type;
}
}
throw new Exception($"Can't resolve class associated with '{entity.Type}' EntityType.");
}
}
@@ -2,11 +2,11 @@
#nullable disable
namespace Pf2eModel.Migrations
namespace Pf2eModel.Migrations;
/// <inheritdoc />
public partial class Function : Migration
{
/// <inheritdoc />
public partial class Function : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
@@ -71,5 +71,4 @@ $func$;
migrationBuilder.Sql("DROP FUNCTION f_drop_tables;");
migrationBuilder.Sql("DROP FUNCTION f_permission_tables;");
}
}
}
+5 -7
View File
@@ -1,15 +1,14 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Pf2eModel.Model.Enum;
#nullable disable
namespace Pf2eModel.Migrations
namespace Pf2eModel.Migrations;
/// <inheritdoc />
public partial class _1 : Migration
{
/// <inheritdoc />
public partial class _1 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
@@ -1195,5 +1194,4 @@ namespace Pf2eModel.Migrations
migrationBuilder.DropTable(
name: "entities");
}
}
}
+2
View File
@@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Pf2eModel.Model.Enum;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -18,5 +19,6 @@ public partial class EntityAlias
[MaxLength(Pf2eDbContext.NameLength)]
public string Alias { get; set; } = null!;
[JsonIgnore]
public virtual Entity Entity { get; set; } = null!;
}
+1
View File
@@ -13,6 +13,7 @@ public partial class Keyword
[Column(Order = 2)]
public string Slug { get; set; } = null!;
[Newtonsoft.Json.JsonIgnore]
public virtual ICollection<Entity> Entities { get; set; } = [];
public virtual ICollection<KeywordAlias> Aliases { get; set; } = [];
@@ -17,5 +17,6 @@ public partial class KeywordAlias
[MaxLength(Pf2eDbContext.NameLength)]
public string Value { get; set; } = null!;
[Newtonsoft.Json.JsonIgnore]
public virtual Keyword Keyword { get; set; } = null!;
}
@@ -22,6 +22,7 @@ public partial class EntitySource
[Comment("Флаг, указывающий, что объект является частью ремастера")]
public bool IsRemaster { get; set; }
[Newtonsoft.Json.JsonIgnore]
public virtual Entity Entity { get; set; } = null!;
public virtual Source Source { get; set; } = null!;
+1
View File
@@ -22,5 +22,6 @@ public partial class Source
public DateOnly? ReleaseDate { get; set; }
[Newtonsoft.Json.JsonIgnore]
public ICollection<EntitySource> EntitySources { get; set; } = [];
}
@@ -23,6 +23,7 @@ public partial class EntityExternal
[Comment("Контроль версии объекта")]
public string Md5 { get; set; } = null!;
[Newtonsoft.Json.JsonIgnore]
public virtual Entity Entity { get; set; } = null!;
public virtual ExternalTarget Target { get; set; } = null!;
@@ -23,5 +23,6 @@ public partial class ExternalTarget
public string Prefix { get; set; } = null!;
[Column(Order = 4)]
[Newtonsoft.Json.JsonIgnore]
public virtual ICollection<EntityExternal> EntityExternals { get; set; } = [];
}
+3 -1
View File
@@ -1,4 +1,5 @@
using Pf2eModel.Model.Base;
using Newtonsoft.Json;
using Pf2eModel.Model.Base;
namespace Pf2eModel.Model;
@@ -6,6 +7,7 @@ public interface IEntity
{
public int Id { get; set; }
[JsonIgnore]
public Entity Entity { get; set; }
}
+1
View File
@@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Structure;
[EntityOfType(EntityType.Action)]
public partial class Action : IEntity
{
[System.ComponentModel.DataAnnotations.Key]
+1
View File
@@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Structure;
[EntityOfType(EntityType.Ancestry)]
public partial class Ancestry : IEntity
{
[System.ComponentModel.DataAnnotations.Key]
+2
View File
@@ -1,10 +1,12 @@
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure.BackgroundRelation;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Structure;
[EntityOfType(EntityType.Background)]
public partial class Background : IEntity
{
[Key]
+2
View File
@@ -1,10 +1,12 @@
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure.ClassRelation;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Structure;
[EntityOfType(EntityType.Class)]
public partial class Class : IEntity
{
[Key]
+1
View File
@@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Structure;
[EntityOfType(EntityType.Condition)]
public partial class Condition : IEntity
{
[Key]
+1
View File
@@ -7,6 +7,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Structure;
[EntityOfType(EntityType.Deity)]
public partial class Deity : IEntity
{
[Key]
+1
View File
@@ -6,6 +6,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Structure;
[EntityOfType(EntityType.Feat)]
public partial class Feat : IEntity
{
[Key]
+2
View File
@@ -1,9 +1,11 @@
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Enum;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Structure;
[EntityOfType(EntityType.Heritage)]
public partial class Heritage : IEntity
{
[Key]
+2
View File
@@ -1,10 +1,12 @@
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure.SpellRelation;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Structure;
[EntityOfType(EntityType.Spell)]
public partial class Spell : IEntity
{
[Key]
+2
View File
@@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace Pf2eModel.Model.Structure;
[EntityOfType(EntityType.Trait)]
public partial class Trait : IEntity
{
[Key]
@@ -17,5 +18,6 @@ public partial class Trait : IEntity
[Column(Order = 2)]
public TraitType Type { get; set; }
[Newtonsoft.Json.JsonIgnore]
public virtual ICollection<Entity> Entities { get; set; } = [];
}
+1 -3
View File
@@ -1,5 +1,4 @@
using LinqToDB.Common;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Base.Keywords;
@@ -14,7 +13,6 @@ using Pf2eModel.Model.Structure.ClassRelation;
using Pf2eModel.Model.Structure.DeityRelation;
using Pf2eModel.Model.Structure.FeatRelation;
using Pf2eModel.Model.Structure.SpellRelation;
using System.Reflection;
namespace Pf2eModel.Model;
+1
View File
@@ -22,6 +22,7 @@
<!--<PrivateAssets>all</PrivateAssets>-->
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Npgsql" Version="9.0.3" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
</ItemGroup>
+81
View File
@@ -0,0 +1,81 @@
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Pf2eModel.Model;
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Structure;
namespace Pf2eViewer;
internal class EntityConventor : JsonConverter
{
private Pf2eDbContext Context = new();
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Entity) || objectType.IsAssignableTo(typeof(IEntity));
}
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
JToken token = JToken.FromObject(value!);
if (token.Type != JTokenType.Object)
{
token.WriteTo(writer);
return;
}
JObject obj = (JObject) token;
switch (value)
{
case Entity e:
obj = ProcessEntity(obj, e);
break;
}
obj.WriteTo(writer);
}
JObject ProcessEntity(JObject obj, Entity e)
{
List<int> traitIds = e.Traits.Select(t => t.Id).ToList();
List<Trait> traits = Context.Traits.Where(t => traitIds.Contains(t.Id)).Include(t => t.Entity).ToList();
foreach (JToken item in (JArray) obj.SelectToken("Traits"))
{
JObject o = (JObject) item;
int id = o.SelectToken("Id").ToObject<int>();
o.Add("Name", traits.FirstOrDefault(t => t.Id == id)!.Entity.Name);
}
obj.Remove("Description");
return obj;
}
public override bool CanRead => false;
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
}
private abstract class Conventer<T>(JsonWriter writer, T value, JsonSerializer serializer, Pf2eDbContext context)
{
public JsonWriter Writer { get; } = writer;
public T Value { get; } = value;
public JsonSerializer Serializer { get; } = serializer;
public Pf2eDbContext Context { get; } = context;
public abstract JObject Process();
}
}
+190
View File
@@ -0,0 +1,190 @@
namespace Pf2eViewer;
partial class MainViewForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
RootSplitContainer = new SplitContainer();
InnerSplitContainer = new SplitContainer();
TypesListBox = new ListBox();
EntityGridView = new DataGridView();
ResultSplitContainer = new SplitContainer();
EntityTreeView = new TreeView();
DescriptionTextBox = new TextBox();
((System.ComponentModel.ISupportInitialize) RootSplitContainer).BeginInit();
RootSplitContainer.Panel1.SuspendLayout();
RootSplitContainer.Panel2.SuspendLayout();
RootSplitContainer.SuspendLayout();
((System.ComponentModel.ISupportInitialize) InnerSplitContainer).BeginInit();
InnerSplitContainer.Panel1.SuspendLayout();
InnerSplitContainer.Panel2.SuspendLayout();
InnerSplitContainer.SuspendLayout();
((System.ComponentModel.ISupportInitialize) EntityGridView).BeginInit();
((System.ComponentModel.ISupportInitialize) ResultSplitContainer).BeginInit();
ResultSplitContainer.Panel1.SuspendLayout();
ResultSplitContainer.Panel2.SuspendLayout();
ResultSplitContainer.SuspendLayout();
SuspendLayout();
//
// RootSplitContainer
//
RootSplitContainer.Dock = DockStyle.Fill;
RootSplitContainer.Location = new Point(0, 0);
RootSplitContainer.Name = "RootSplitContainer";
//
// RootSplitContainer.Panel1
//
RootSplitContainer.Panel1.Controls.Add(InnerSplitContainer);
RootSplitContainer.Panel1MinSize = 200;
//
// RootSplitContainer.Panel2
//
RootSplitContainer.Panel2.Controls.Add(ResultSplitContainer);
RootSplitContainer.Panel2MinSize = 400;
RootSplitContainer.Size = new Size(811, 688);
RootSplitContainer.SplitterDistance = 324;
RootSplitContainer.TabIndex = 0;
//
// InnerSplitContainer
//
InnerSplitContainer.Dock = DockStyle.Fill;
InnerSplitContainer.Location = new Point(0, 0);
InnerSplitContainer.Name = "InnerSplitContainer";
InnerSplitContainer.Orientation = Orientation.Horizontal;
//
// InnerSplitContainer.Panel1
//
InnerSplitContainer.Panel1.Controls.Add(TypesListBox);
//
// InnerSplitContainer.Panel2
//
InnerSplitContainer.Panel2.Controls.Add(EntityGridView);
InnerSplitContainer.Size = new Size(324, 688);
InnerSplitContainer.SplitterDistance = 274;
InnerSplitContainer.TabIndex = 1;
//
// TypesListBox
//
TypesListBox.Dock = DockStyle.Fill;
TypesListBox.FormattingEnabled = true;
TypesListBox.ItemHeight = 15;
TypesListBox.Location = new Point(0, 0);
TypesListBox.Name = "TypesListBox";
TypesListBox.Size = new Size(324, 274);
TypesListBox.TabIndex = 0;
TypesListBox.SelectedIndexChanged += TypesListBox_SelectedIndexChanged;
//
// EntityGridView
//
EntityGridView.AllowUserToAddRows = false;
EntityGridView.AllowUserToDeleteRows = false;
EntityGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
EntityGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
EntityGridView.Dock = DockStyle.Fill;
EntityGridView.Location = new Point(0, 0);
EntityGridView.MultiSelect = false;
EntityGridView.Name = "EntityGridView";
EntityGridView.ReadOnly = true;
EntityGridView.RowHeadersVisible = false;
EntityGridView.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders;
EntityGridView.ShowEditingIcon = false;
EntityGridView.Size = new Size(324, 410);
EntityGridView.TabIndex = 0;
EntityGridView.RowStateChanged += EntityGridView_RowStateChanged;
//
// ResultSplitContainer
//
ResultSplitContainer.Dock = DockStyle.Fill;
ResultSplitContainer.Location = new Point(0, 0);
ResultSplitContainer.Name = "ResultSplitContainer";
ResultSplitContainer.Orientation = Orientation.Horizontal;
//
// ResultSplitContainer.Panel1
//
ResultSplitContainer.Panel1.Controls.Add(EntityTreeView);
//
// ResultSplitContainer.Panel2
//
ResultSplitContainer.Panel2.Controls.Add(DescriptionTextBox);
ResultSplitContainer.Size = new Size(483, 688);
ResultSplitContainer.SplitterDistance = 269;
ResultSplitContainer.TabIndex = 1;
//
// EntityTreeView
//
EntityTreeView.Dock = DockStyle.Fill;
EntityTreeView.Location = new Point(0, 0);
EntityTreeView.Name = "EntityTreeView";
EntityTreeView.Size = new Size(483, 269);
EntityTreeView.TabIndex = 0;
//
// DescriptionTextBox
//
DescriptionTextBox.Dock = DockStyle.Fill;
DescriptionTextBox.Location = new Point(0, 0);
DescriptionTextBox.Multiline = true;
DescriptionTextBox.Name = "DescriptionTextBox";
DescriptionTextBox.ReadOnly = true;
DescriptionTextBox.ScrollBars = ScrollBars.Vertical;
DescriptionTextBox.Size = new Size(483, 415);
DescriptionTextBox.TabIndex = 0;
//
// MainViewForm
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(811, 688);
Controls.Add(RootSplitContainer);
Name = "MainViewForm";
Text = "DataBaseViewer";
RootSplitContainer.Panel1.ResumeLayout(false);
RootSplitContainer.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize) RootSplitContainer).EndInit();
RootSplitContainer.ResumeLayout(false);
InnerSplitContainer.Panel1.ResumeLayout(false);
InnerSplitContainer.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize) InnerSplitContainer).EndInit();
InnerSplitContainer.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize) EntityGridView).EndInit();
ResultSplitContainer.Panel1.ResumeLayout(false);
ResultSplitContainer.Panel2.ResumeLayout(false);
ResultSplitContainer.Panel2.PerformLayout();
((System.ComponentModel.ISupportInitialize) ResultSplitContainer).EndInit();
ResultSplitContainer.ResumeLayout(false);
ResumeLayout(false);
}
#endregion
private SplitContainer RootSplitContainer;
private SplitContainer InnerSplitContainer;
private ListBox TypesListBox;
private DataGridView EntityGridView;
private TreeView EntityTreeView;
private SplitContainer ResultSplitContainer;
private TextBox DescriptionTextBox;
}
+166
View File
@@ -0,0 +1,166 @@
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Pf2eModel;
using Pf2eModel.Model;
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Enum;
namespace Pf2eViewer;
public partial class MainViewForm : Form
{
public Pf2eDbContext Context = new();
public MainViewForm()
{
InitializeComponent();
Reset();
EntityGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
}
public void Reset()
{
Context.Dispose();
Context = new();
TypesListBox.DataSource = Context.Entities.Select(e => e.Type).Distinct().ToList();
TypesListBox.SelectedIndex = 0;
}
private void TypesListBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (TypesListBox.SelectedItem is null)
{
return;
}
EntityGridView.DataSource = Context.Entities
.Where(e => e.Type == (EntityType) TypesListBox.SelectedItem)
.OrderBy(e => e.Id)
.Include(e => e.Sources).Include(e => e.Aliases).Include(e => e.Keywords).Include(e => e.Externals)
.Include(e => e.Traits)
.Select(e => new EntityGridRow(e))
.ToList();
EntityGridView.Rows[0].Selected = true;
}
private void EntityGridView_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
{
int rowsCount = EntityGridView.SelectedRows.Count;
if (rowsCount == 0 || rowsCount > 1)
{
return;
}
DataGridViewRow row = EntityGridView.SelectedRows[0];
EntityGridRow data = (EntityGridRow) row.DataBoundItem;
string json = SerializeEntity(data.GetEntity());
JsonToTreeview(EntityTreeView, json, "Entity");
DescriptionTextBox.Text = data.GetEntity().Description;
}
public string SerializeEntity(Entity entity)
{
JsonSerializerSettings settings = new JsonSerializerSettings()
{
Converters = [new EntityConventor()]
// ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
string result = JsonConvert.SerializeObject(entity, settings);
Type type = EntityOfTypeAttribute.Resolve(entity);
string subReuslt = JsonConvert.SerializeObject(Context.Find(type, entity.Id), settings);
return result[..^1] + $",\"SubEntity\":{subReuslt}}}";
}
public static void JsonToTreeview(TreeView treeView, string jsonString, string rootName)
{
object json = jsonString.StartsWith('[')
? JArray.Parse(jsonString)
: JObject.Parse(jsonString);
treeView.Nodes.Clear();
foreach (TreeNode node in Element2TreeNode(json, rootName).Nodes)
{
treeView.Nodes.Add(node);
}
}
private static TreeNode Element2TreeNode(object element, string text = "")
{
List<TreeNode> subNodes = [];
switch (element.GetType().Name)
{
case "JObject":
JObject jObject = (JObject) element;
foreach (KeyValuePair<string, JToken> token in jObject)
{
subNodes.Add(Element2TreeNode(token.Value, token.Key));
}
break;
case "JArray":
JArray jArray = (JArray) element;
int i = 0;
foreach (JToken oJtok in jArray)
{
subNodes.Add(Element2TreeNode(oJtok, string.Format("[{0}]", i++)));
}
if (i == 0)
{
text += ": []";
}
break;
case "JValue":
JValue jValue = (JValue) element;
text += $": ({jValue.Type}) {jValue}";
break;
default:
throw new Exception("clsJSON2Treeview can't interpret object:" + element.GetType().Name);
}
TreeNode treeNode = new(text);
if (subNodes.Count > 0)
{
treeNode.Nodes.AddRange(subNodes
.OrderBy(node => node.Nodes.Count > 0 ? 1 : 0)
.ToArray()
);
}
return treeNode;
}
private class EntityGridRow(Entity e)
{
public int Id { get; set; } = e.Id;
public string Name { get; set; } = e.Name;
//public string Slug { get; set; } = e.Slug;
//public EntityRarity Rarity { get; set; } = e.Rarity;
private readonly Entity _e = e;
public Entity GetEntity() => _e;
}
}
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+23
View File
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Pf2eModel\Pf2eModel.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
</Project>
+16
View File
@@ -0,0 +1,16 @@
namespace Pf2eViewer;
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new MainViewForm());
}
}