Files
Pf2eDataScrapper/Pf2eViewer/MainViewForm.cs
T
2025-04-26 10:53:50 +04:00

348 lines
9.6 KiB
C#

using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Pf2eModel;
using Pf2eModel.Model;
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
using Pf2eViewer.Converters;
namespace Pf2eViewer;
public partial class MainViewForm : Form
{
public Pf2eDbContext Context = new();
public string JsonViewerHtml = string.Empty;
private DarkModeCS dm = null;
public MainViewForm()
{
InitializeComponent();
dm = new DarkModeCS(this) { ColorMode = DarkModeCS.DisplayMode.SystemDefault };
Reset();
EntityGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
using StreamReader reader = new("Resources/json-viewer.html");
JsonViewerHtml = reader.ReadToEnd();
}
public void Reset()
{
Context.Dispose();
Context = new();
TypesListBox.DataSource = Context.Entities.Select(e => e.Type).Distinct().ToList();
TypesListBox.SelectedIndex = 0;
}
public const int PerPage = 30;
public int Count;
public int Page
{
get => Convert.ToInt32(PageTextBox.Text);
set
{
PageTextBox.Text = value.ToString();
UpdateTreeView();
}
}
public int MaxPage => Convert.ToInt32(Math.Ceiling(1.0 * Count / PerPage));
private void UpdateTreeView()
{
// EntityTreeView.Nodes.Clear();
EntityType type = (EntityType)TypesListBox.SelectedItem!;
Count = Context.Entities.Count(e => e.Type == type);
if (Page < 1 || Page > MaxPage)
{
Page = Math.Min(MaxPage, Math.Max(1, Page));
return;
}
EntityGridView.DataSource = Context
.Entities.Where(e => e.Type == (EntityType)TypesListBox.SelectedItem)
.OrderBy(e => e.Id)
.Select(e => new EntityGridRow(e))
.Skip((Page - 1) * PerPage)
.Take(PerPage)
.ToList();
EntityGridView.Rows[0].Selected = true;
PaginationLabel.Text = $"Всего: {Count} объектов, {MaxPage} страниц";
FirstPageButton.Enabled = Page > 1;
PrevPageButton.Enabled = Page > 1;
NextPageButton.Enabled = Page < MaxPage;
LastPageButton.Enabled = Page < MaxPage;
}
private void TypesListBox_SelectedIndexChanged(object sender, EventArgs _)
{
if (TypesListBox.SelectedItem is null)
{
return;
}
Page = 1;
}
private void FirstPageButton_Click(object sender, EventArgs e)
{
Page = 1;
}
private void PrevPageButton_Click(object sender, EventArgs e)
{
Page--;
}
private void NextPageButton_Click(object sender, EventArgs e)
{
Page++;
}
private void LastPageButton_Click(object sender, EventArgs e)
{
Page = MaxPage;
}
private void PageTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
if (e.KeyChar == (char)Keys.Return)
{
UpdateTreeView();
}
}
private void EntityGridView_RowStateChanged(
object sender,
DataGridViewRowStateChangedEventArgs e
)
{
int rowsCount = EntityGridView.SelectedRows.Count;
if (rowsCount is 0 or > 1)
{
return;
}
DataGridViewRow row = EntityGridView.SelectedRows[0];
EntityGridRow data = (EntityGridRow)row.DataBoundItem;
ViewEntity(data.Id);
}
public void ViewEntity(int id)
{
// EntityTreeView.Nodes.Clear();
Entity? entity = Context
.Entities.Where(e => e.Id == id && e.Type == (EntityType)TypesListBox.SelectedItem!)
.Include(e => e.Sources)
.ThenInclude(s => s.Source)
.Include(e => e.Keywords)
.Include(e => e.Externals)
.ThenInclude(x => x.Target)
.Include(e => e.Traits)
.ThenInclude(t => t.Entity)
.FirstOrDefault();
if (entity == null)
{
DescriptionTextBox.Text = "Not found";
return;
}
string json = SerializeEntity(entity);
// JsonToTreeview(EntityTreeView, json, "Entity");
RenderJson(json);
DescriptionTextBox.Text = entity.Description.Replace("\\r", "").Replace("\\n", "\\r\\n");
}
public void RenderJson(string json)
{
if (JsonWebView.CoreWebView2 == null)
{
JsonWebView.EnsureCoreWebView2Async();
return;
}
string html = JsonViewerHtml.Replace("{JSON}", json);
JsonWebView.CoreWebView2.NavigateToString(html);
}
private void JsonWebView_CoreWebView2InitializationCompleted(
object sender,
Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs e
)
{
JsonWebView.Visible = true;
DataGridViewRow row = EntityGridView.SelectedRows[0];
EntityGridRow data = (EntityGridRow)row.DataBoundItem;
ViewEntity(data.Id);
}
public string SerializeEntity(Entity entity)
{
JsonSerializerSettings settings = new()
{
Converters =
[
new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy() },
new EntityConverter(),
new LocaleStringConverter(),
],
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
};
string result = JsonConvert.SerializeObject(entity, settings);
Type type = EntityOfTypeAttribute.Resolve(entity);
string subResult = JsonConvert.SerializeObject(ResolveSubEntity(entity), settings);
return result[..^1] + $",\"SubEntity\":{subResult}}}";
}
public IEntity? ResolveSubEntity(Entity entity)
{
switch (entity.Type)
{
case EntityType.Ancestry:
return Context
.Ancestries.Include(a => a.AncestryBoosts)
.FirstOrDefault(e => e.Id == entity.Id);
case EntityType.Archetype:
return Context
.Archetypes.Include(a => a.DedicationFeat)
.ThenInclude(f => f.Entity)
.Include(a => a.Feats)
.ThenInclude(f => f.Entity)
.FirstOrDefault(a => a.Id == entity.Id);
case EntityType.Background:
return Context
.Backgrounds.Include(b => b.BackgroundBoosts)
.Include(b => b.BackgroundSkills)
.ThenInclude(t => t.Training)
.Include(b => b.BackgroundItems)
.FirstOrDefault(e => e.Id == entity.Id);
case EntityType.Class:
return Context
.Classes.Include(c => c.ClassKeyAbilities)
.Include(c => c.ClassTrainings)
.ThenInclude(t => t.Training)
.Include(c => c.ClassProgressions)
.FirstOrDefault(c => c.Id == entity.Id);
case EntityType.Feat:
return Context
.Feats.Include(f => f.Archetypes)
.ThenInclude(a => a.Entity)
.FirstOrDefault(f => f.Id == entity.Id);
default:
Type type = EntityOfTypeAttribute.Resolve(entity);
return (IEntity?)Context.Find(type, entity.Id);
}
}
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);
}
treeView.ExpandAll();
}
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;
subNodes.AddRange(jArray.Select(token => Element2TreeNode(token, $"[{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[LocaleType.English];
public EntityRarity Rarity { get; set; } = e.Rarity;
private readonly Entity _e = e;
public Entity GetEntity() => _e;
}
}