Converted to net6.0

This commit is contained in:
2022-08-13 13:01:47 -07:00
commit 2385affccb
32 changed files with 4847 additions and 0 deletions

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>10.0</LangVersion>
<Nullable>disable</Nullable>
<OutputType>WinExe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net6.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Json2CSharpCodeGenerator.Lib\Json2CSharpCodeGenerator.Lib.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,386 @@

namespace Json2CSharpCodeGenerator.Lib.WinForms
{
partial class MainForm
{
/// <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()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.split = new System.Windows.Forms.SplitContainer();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.jsonInputTextbox = new System.Windows.Forms.TextBox();
this.inputLabel = new System.Windows.Forms.Label();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.csharpOutputTextbox = new System.Windows.Forms.TextBox();
this.outputLabel = new System.Windows.Forms.Label();
this.toolStrip = new System.Windows.Forms.ToolStrip();
this.openButton = new System.Windows.Forms.ToolStripButton();
this.optsPascalCase = new System.Windows.Forms.ToolStripButton();
this.sep1 = new System.Windows.Forms.ToolStripSeparator();
this.optsAttributeMode = new System.Windows.Forms.ToolStripDropDownButton();
this.optAttribJP = new System.Windows.Forms.ToolStripMenuItem();
this.optAttribJpn = new System.Windows.Forms.ToolStripMenuItem();
this.sep2 = new System.Windows.Forms.ToolStripSeparator();
this.optMembersMode = new System.Windows.Forms.ToolStripDropDownButton();
this.optMemberProps = new System.Windows.Forms.ToolStripMenuItem();
this.optMemberFields = new System.Windows.Forms.ToolStripMenuItem();
this.sep3 = new System.Windows.Forms.ToolStripSeparator();
this.copyOutput = new System.Windows.Forms.ToolStripButton();
this.wrapText = new System.Windows.Forms.ToolStripButton();
this.optTypesMode = new System.Windows.Forms.ToolStripDropDownButton();
this.optTypesMutablePoco = new System.Windows.Forms.ToolStripMenuItem();
this.optTypesImmutablePoco = new System.Windows.Forms.ToolStripMenuItem();
this.optTypesRecords = new System.Windows.Forms.ToolStripMenuItem();
this.statusStrip = new System.Windows.Forms.StatusStrip();
this.ofd = new System.Windows.Forms.OpenFileDialog();
((System.ComponentModel.ISupportInitialize)(this.split)).BeginInit();
this.split.Panel1.SuspendLayout();
this.split.Panel2.SuspendLayout();
this.split.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.toolStrip.SuspendLayout();
this.SuspendLayout();
//
// split
//
this.split.Dock = System.Windows.Forms.DockStyle.Fill;
this.split.Location = new System.Drawing.Point(0, 25);
this.split.Name = "split";
//
// split.Panel1
//
this.split.Panel1.Controls.Add(this.tableLayoutPanel1);
//
// split.Panel2
//
this.split.Panel2.Controls.Add(this.tableLayoutPanel2);
this.split.Size = new System.Drawing.Size(1288, 253);
this.split.SplitterDistance = 644;
this.split.TabIndex = 0;
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.AllowDrop = true;
this.tableLayoutPanel1.ColumnCount = 1;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Controls.Add(this.jsonInputTextbox, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.inputLabel, 0, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(644, 253);
this.tableLayoutPanel1.TabIndex = 1;
//
// jsonInputTextbox
//
this.jsonInputTextbox.AcceptsReturn = true;
this.jsonInputTextbox.AcceptsTab = true;
this.jsonInputTextbox.AllowDrop = true;
this.jsonInputTextbox.Dock = System.Windows.Forms.DockStyle.Fill;
this.jsonInputTextbox.Location = new System.Drawing.Point(3, 32);
this.jsonInputTextbox.Multiline = true;
this.jsonInputTextbox.Name = "jsonInputTextbox";
this.jsonInputTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.jsonInputTextbox.Size = new System.Drawing.Size(638, 218);
this.jsonInputTextbox.TabIndex = 0;
this.jsonInputTextbox.WordWrap = false;
//
// inputLabel
//
this.inputLabel.Dock = System.Windows.Forms.DockStyle.Fill;
this.inputLabel.Location = new System.Drawing.Point(1, 4);
this.inputLabel.Margin = new System.Windows.Forms.Padding(1, 4, 4, 2);
this.inputLabel.Name = "inputLabel";
this.inputLabel.Size = new System.Drawing.Size(639, 23);
this.inputLabel.TabIndex = 1;
this.inputLabel.Text = "Paste JSON Input or drag and drop a *.json file:";
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.ColumnCount = 1;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.Controls.Add(this.csharpOutputTextbox, 0, 1);
this.tableLayoutPanel2.Controls.Add(this.outputLabel, 0, 0);
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 2;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.Size = new System.Drawing.Size(640, 253);
this.tableLayoutPanel2.TabIndex = 1;
//
// csharpOutputTextbox
//
this.csharpOutputTextbox.Dock = System.Windows.Forms.DockStyle.Fill;
this.csharpOutputTextbox.Location = new System.Drawing.Point(3, 32);
this.csharpOutputTextbox.Multiline = true;
this.csharpOutputTextbox.Name = "csharpOutputTextbox";
this.csharpOutputTextbox.ReadOnly = true;
this.csharpOutputTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.csharpOutputTextbox.Size = new System.Drawing.Size(634, 218);
this.csharpOutputTextbox.TabIndex = 0;
this.csharpOutputTextbox.WordWrap = false;
//
// outputLabel
//
this.outputLabel.Dock = System.Windows.Forms.DockStyle.Fill;
this.outputLabel.Location = new System.Drawing.Point(1, 4);
this.outputLabel.Margin = new System.Windows.Forms.Padding(1, 4, 4, 2);
this.outputLabel.Name = "outputLabel";
this.outputLabel.Size = new System.Drawing.Size(635, 23);
this.outputLabel.TabIndex = 1;
this.outputLabel.Text = "Generated C# output:";
//
// toolStrip
//
this.toolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.openButton,
this.optsPascalCase,
this.sep1,
this.optsAttributeMode,
this.sep2,
this.optMembersMode,
this.sep3,
this.copyOutput,
this.wrapText,
this.optTypesMode});
this.toolStrip.Location = new System.Drawing.Point(0, 0);
this.toolStrip.Name = "toolStrip";
this.toolStrip.Size = new System.Drawing.Size(1288, 25);
this.toolStrip.TabIndex = 0;
//
// openButton
//
this.openButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.openButton.Name = "openButton";
this.openButton.Size = new System.Drawing.Size(49, 22);
this.openButton.Text = "Open...";
//
// optsPascalCase
//
this.optsPascalCase.Checked = true;
this.optsPascalCase.CheckOnClick = true;
this.optsPascalCase.CheckState = System.Windows.Forms.CheckState.Checked;
this.optsPascalCase.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.optsPascalCase.Name = "optsPascalCase";
this.optsPascalCase.Size = new System.Drawing.Size(94, 22);
this.optsPascalCase.Text = "Use Pascal Case";
//
// sep1
//
this.sep1.Name = "sep1";
this.sep1.Size = new System.Drawing.Size(6, 25);
//
// optsAttributeMode
//
this.optsAttributeMode.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.optsAttributeMode.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.optAttribJP,
this.optAttribJpn});
this.optsAttributeMode.Name = "optsAttributeMode";
this.optsAttributeMode.Size = new System.Drawing.Size(106, 22);
this.optsAttributeMode.Text = "Attributes mode";
//
// optAttribJP
//
this.optAttribJP.CheckOnClick = true;
this.optAttribJP.Name = "optAttribJP";
this.optAttribJP.Size = new System.Drawing.Size(204, 22);
this.optAttribJP.Text = "Use [JsonProperty]";
//
// optAttribJpn
//
this.optAttribJpn.Checked = true;
this.optAttribJpn.CheckOnClick = true;
this.optAttribJpn.Name = "optAttribJpn";
this.optAttribJpn.CheckState = System.Windows.Forms.CheckState.Checked;
this.optAttribJpn.Size = new System.Drawing.Size(204, 22);
this.optAttribJpn.Text = "Use [JsonPropertyName]";
//
// sep2
//
this.sep2.Name = "sep2";
this.sep2.Size = new System.Drawing.Size(6, 25);
//
// optMembersMode
//
this.optMembersMode.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.optMembersMode.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.optMemberProps,
this.optMemberFields});
this.optMembersMode.Name = "optMembersMode";
this.optMembersMode.Size = new System.Drawing.Size(99, 22);
this.optMembersMode.Text = "Member mode";
//
// optMemberProps
//
this.optMemberProps.Checked = true;
this.optMemberProps.CheckOnClick = true;
this.optMemberProps.CheckState = System.Windows.Forms.CheckState.Checked;
this.optMemberProps.Name = "optMemberProps";
this.optMemberProps.Size = new System.Drawing.Size(180, 22);
this.optMemberProps.Text = "Use properties";
//
// optMemberFields
//
this.optMemberFields.CheckOnClick = true;
this.optMemberFields.Name = "optMemberFields";
this.optMemberFields.Size = new System.Drawing.Size(180, 22);
this.optMemberFields.Text = "Use fields";
//
// sep3
//
this.sep3.Name = "sep3";
this.sep3.Size = new System.Drawing.Size(6, 25);
//
// copyOutput
//
this.copyOutput.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.copyOutput.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.copyOutput.Name = "copyOutput";
this.copyOutput.Size = new System.Drawing.Size(167, 22);
this.copyOutput.Text = "Copy C# Output to Clipboard";
//
// wrapText
//
this.wrapText.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.wrapText.CheckOnClick = true;
this.wrapText.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.wrapText.Name = "wrapText";
this.wrapText.Size = new System.Drawing.Size(62, 22);
this.wrapText.Text = "Wrap text";
//
// optTypesMode
//
this.optTypesMode.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.optTypesMode.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.optTypesMutablePoco,
this.optTypesImmutablePoco,
this.optTypesRecords});
this.optTypesMode.Name = "optTypesMode";
this.optTypesMode.Size = new System.Drawing.Size(89, 22);
this.optTypesMode.Text = "Output types";
//
// optTypesMutablePoco
//
this.optTypesMutablePoco.CheckOnClick = true;
this.optTypesMutablePoco.Name = "optTypesMutablePoco";
this.optTypesMutablePoco.Size = new System.Drawing.Size(208, 22);
this.optTypesMutablePoco.Text = "Mutable POCO classes";
//
// optTypesImmutablePoco
//
this.optTypesImmutablePoco.Checked = true;
this.optTypesImmutablePoco.CheckOnClick = true;
this.optTypesImmutablePoco.CheckState = System.Windows.Forms.CheckState.Checked;
this.optTypesImmutablePoco.Name = "optTypesImmutablePoco";
this.optTypesImmutablePoco.Size = new System.Drawing.Size(208, 22);
this.optTypesImmutablePoco.Text = "Immutable POCO classes";
//
// optTypesRecords
//
this.optTypesRecords.CheckOnClick = true;
this.optTypesRecords.Name = "optTypesRecords";
this.optTypesRecords.Size = new System.Drawing.Size(208, 22);
this.optTypesRecords.Text = "Immutable record classes";
//
// statusStrip
//
this.statusStrip.Location = new System.Drawing.Point(0, 278);
this.statusStrip.Name = "statusStrip";
this.statusStrip.Size = new System.Drawing.Size(1288, 22);
this.statusStrip.TabIndex = 1;
//
// ofd
//
this.ofd.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*";
this.ofd.SupportMultiDottedExtensions = true;
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1288, 300);
this.Controls.Add(this.split);
this.Controls.Add(this.statusStrip);
this.Controls.Add(this.toolStrip);
this.DoubleBuffered = true;
this.Name = "MainForm";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
this.Text = "JSON-to-C#";
this.split.Panel1.ResumeLayout(false);
this.split.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.split)).EndInit();
this.split.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.toolStrip.ResumeLayout(false);
this.toolStrip.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.SplitContainer split;
private System.Windows.Forms.ToolStrip toolStrip;
private System.Windows.Forms.ToolStripButton optsPascalCase;
private System.Windows.Forms.ToolStripMenuItem optAttribJpn;
private System.Windows.Forms.ToolStripDropDownButton optMembersMode;
private System.Windows.Forms.ToolStripMenuItem optMemberProps;
private System.Windows.Forms.ToolStripMenuItem optMemberFields;
private System.Windows.Forms.TextBox jsonInputTextbox;
private System.Windows.Forms.TextBox csharpOutputTextbox;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.Label inputLabel;
private System.Windows.Forms.Label outputLabel;
private System.Windows.Forms.ToolStripSeparator sep1;
private System.Windows.Forms.ToolStripSeparator sep2;
private System.Windows.Forms.ToolStripSeparator sep3;
private System.Windows.Forms.ToolStripDropDownButton optsAttributeMode;
private System.Windows.Forms.ToolStripMenuItem optAttribJP;
private System.Windows.Forms.ToolStripButton copyOutput;
private System.Windows.Forms.StatusStrip statusStrip;
private System.Windows.Forms.ToolStripButton openButton;
private System.Windows.Forms.OpenFileDialog ofd;
private System.Windows.Forms.ToolStripButton wrapText;
private System.Windows.Forms.ToolStripDropDownButton optTypesMode;
private System.Windows.Forms.ToolStripMenuItem optTypesMutablePoco;
private System.Windows.Forms.ToolStripMenuItem optTypesImmutablePoco;
private System.Windows.Forms.ToolStripMenuItem optTypesRecords;
}
}

View File

@ -0,0 +1,496 @@
using Microsoft.Win32;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
namespace Json2CSharpCodeGenerator.Lib.WinForms;
public partial class MainForm : Form
{
private bool _PreventReentrancy = false;
public MainForm()
{
// `IconTitleFont` is what WinForms *should* be using by default.
// Need to set `Font` first, before `InitializeComponent();` to ensure font inheritance by controls in the form.
Font = SystemFonts.IconTitleFont;
InitializeComponent();
ResetFonts();
// Also: https://docs.microsoft.com/en-us/dotnet/desktop/winforms/how-to-respond-to-font-scheme-changes-in-a-windows-forms-application?view=netframeworkdesktop-4.8
SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
//
openButton.Click += OpenButton_Click;
optAttribJP.CheckedChanged += OnAttributesModeCheckedChanged;
optAttribJpn.CheckedChanged += OnAttributesModeCheckedChanged;
//optAttribNone .CheckedChanged += OnAttributesModeCheckedChanged;
optMemberFields.CheckedChanged += OnMemberModeCheckedChanged;
optMemberProps.CheckedChanged += OnMemberModeCheckedChanged;
optTypesMutablePoco.CheckedChanged += OnOutputTypeModeCheckedChanged;
optTypesImmutablePoco.CheckedChanged += OnOutputTypeModeCheckedChanged;
optTypesRecords.CheckedChanged += OnOutputTypeModeCheckedChanged;
optsPascalCase.CheckedChanged += OnOptionsChanged;
wrapText.CheckedChanged += WrapText_CheckedChanged;
copyOutput.Click += CopyOutput_Click;
copyOutput.Enabled = false;
jsonInputTextbox.TextChanged += JsonInputTextbox_TextChanged;
jsonInputTextbox.DragDrop += JsonInputTextbox_DragDrop;
jsonInputTextbox.DragOver += JsonInputTextbox_DragOver;
//jsonInputTextbox.paste // annoyingly, it isn't (easily) feasible to hook/detect TextBox paste events, even globally... grrr.
// Invoke event-handlers to set initial toolstrip text:
optsAttributeMode.Tag = optsAttributeMode.Text + ": {0}";
optMembersMode.Tag = optMembersMode.Text + ": {0}";
optTypesMode.Tag = optTypesMode.Text + ": {0}";
OnAttributesModeCheckedChanged(optAttribJP, EventArgs.Empty);
OnMemberModeCheckedChanged(optMemberProps, EventArgs.Empty);
OnOutputTypeModeCheckedChanged(optTypesMutablePoco, EventArgs.Empty);
}
private void WrapText_CheckedChanged(object sender, EventArgs e)
{
ToolStripButton tsb = (ToolStripButton)sender;
// For some reason, toggling WordWrap causes a text selection in `jsonInputTextbox`. So, doing this:
try
{
jsonInputTextbox.HideSelection = true;
// ayayayay: https://stackoverflow.com/questions/1140250/how-to-remove-the-focus-from-a-textbox-in-winforms
ActiveControl = toolStrip;
#if WINFORMS_TEXTBOX_GET_SCROLL_POSITION_WORKS_ARGH // It's non-trivial: https://stackoverflow.com/questions/4494162/change-scrollbar-position-in-textbox
//int idx1 = jsonInputTextbox.GetFirstCharIndexOfCurrentLine(); // but what is the "current line"?
int firstLineCharIndex = -1;
if( jsonInputTextbox.Height > 10 )
{
// https://stackoverflow.com/questions/10175400/maintain-textbox-scroll-position-while-adding-line
jsonInputTextbox.GetCharIndexFromPosition( new Point( 3, 3 ) );
}
#endif
jsonInputTextbox.WordWrap = tsb.Checked;
csharpOutputTextbox.WordWrap = tsb.Checked;
#if WINFORMS_TEXTBOX_GET_SCROLL_POSITION_WORKS_ARGH
if( firstLineCharIndex > 0 ) // Greater than zero, not -1, because `GetCharIndexFromPosition` returns a meaningless zero sometimes.
{
jsonInputTextbox.SelectionStart = firstLineCharIndex;
jsonInputTextbox.ScrollToCaret();
}
#endif
}
finally
{
jsonInputTextbox.HideSelection = false;
}
}
#region WinForms Taxes
private static Font GetMonospaceFont(float emFontSizePoints)
{
// See if Consolas or Lucida Sans Typewriter is available before falling-back:
string[] preferredFonts = new[] { "Consolas", "Lucida Sans Typewriter" };
foreach (string fontName in preferredFonts)
{
if (TestFont(fontName, emFontSizePoints))
{
return new Font(fontName, emFontSizePoints, FontStyle.Regular);
}
}
// Fallback:
return new Font(FontFamily.GenericMonospace, emSize: emFontSizePoints);
}
private static bool TestFont(string fontName, float emFontSizePoints)
{
try
{
using Font test = new(fontName, emFontSizePoints, FontStyle.Regular);
return test.Name == fontName;
}
catch
{
return false;
}
}
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
switch (e.Category)
{
case UserPreferenceCategory.Accessibility:
case UserPreferenceCategory.Window:
case UserPreferenceCategory.VisualStyle:
case UserPreferenceCategory.Menu:
ResetFonts();
break;
}
}
private void ResetFonts()
{
Font = SystemFonts.IconTitleFont;
Font monospaceFont = GetMonospaceFont(emFontSizePoints: SystemFonts.IconTitleFont.SizeInPoints);
jsonInputTextbox.Font = monospaceFont;
csharpOutputTextbox.Font = monospaceFont;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (!e.Cancel)
{
SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(SystemEvents_UserPreferenceChanged);
}
}
#endregion
#region Methods to ensure only a single checkbox-style menu item is checked at-a-time, and that the ToolStripDropDownButton's text indicates the currently selected option:
private void OnAttributesModeCheckedChanged(object sender, EventArgs e)
{
EnsureSingleCheckedDropDownItemAndUpdateToolStripItemText((ToolStripMenuItem)sender, defaultItem: optAttribJP, parent: optsAttributeMode);
GenerateCSharp();
}
private void OnMemberModeCheckedChanged(object sender, EventArgs e)
{
EnsureSingleCheckedDropDownItemAndUpdateToolStripItemText((ToolStripMenuItem)sender, defaultItem: optMemberProps, parent: optMembersMode);
GenerateCSharp();
}
private void OnOutputTypeModeCheckedChanged(object sender, EventArgs e)
{
EnsureSingleCheckedDropDownItemAndUpdateToolStripItemText((ToolStripMenuItem)sender, defaultItem: optTypesMutablePoco, parent: optTypesMode);
GenerateCSharp();
}
private void EnsureSingleCheckedDropDownItemAndUpdateToolStripItemText(ToolStripMenuItem subject, ToolStripMenuItem defaultItem, ToolStripDropDownButton parent)
{
if (_PreventReentrancy)
return;
try
{
_PreventReentrancy = true;
ToolStripMenuItem singleCheckedItem;
if (subject.Checked)
{
singleCheckedItem = subject;
UncheckOthers(subject, parent);
}
else
{
EnsureAtLeast1IsCheckedAfterItemWasUnchecked(subject, defaultItem, parent);
singleCheckedItem = parent.DropDownItems.Cast<ToolStripMenuItem>().Single(item => item.Checked);
}
string parentTextFormat = (string)parent.Tag;
parent.Text = string.Format(format: parentTextFormat, arg0: singleCheckedItem.Text);
}
finally
{
_PreventReentrancy = false;
}
}
private static void UncheckOthers(ToolStripMenuItem sender, ToolStripDropDownButton parent)
{
foreach (ToolStripMenuItem menuItem in parent.DropDownItems.Cast<ToolStripMenuItem>()) // I really hate old-style IEnumerable, *grumble*
{
if (!ReferenceEquals(menuItem, sender))
{
menuItem.Checked = false;
}
}
}
private static void EnsureAtLeast1IsCheckedAfterItemWasUnchecked(ToolStripMenuItem subject, ToolStripMenuItem defaultItem, ToolStripDropDownButton parent)
{
int countChecked = parent.DropDownItems.Cast<ToolStripMenuItem>().Count(item => item.Checked);
if (countChecked == 1)
{
// Is exactly 1 checked already? If so, then NOOP.
}
else if (countChecked > 1)
{
// If more than 1 are checked, then check only the default:
defaultItem.Checked = true;
UncheckOthers(sender: defaultItem, parent);
}
else
{
// If none are checked, then *if* the unchecked item is NOT the default item, then check the default item:
if (!ReferenceEquals(subject, defaultItem))
{
defaultItem.Checked = true;
}
else
{
// Otherwise, check the first non-default item:
ToolStripMenuItem nextBestItem = parent.DropDownItems.Cast<ToolStripMenuItem>().First(item => item != defaultItem);
nextBestItem.Checked = true;
}
}
}
#endregion
private void OnOptionsChanged(object sender, EventArgs e) => GenerateCSharp();
#region Drag and Drop
private void JsonInputTextbox_DragOver(object sender, DragEventArgs e)
{
bool acceptable =
e.Data.GetDataPresent(DataFormats.FileDrop) ||
// e.Data.GetDataPresent( DataFormats.Text ) ||
// e.Data.GetDataPresent( DataFormats.OemText ) ||
e.Data.GetDataPresent(DataFormats.UnicodeText, autoConvert: true)// ||
// e.Data.GetDataPresent( DataFormats.Html ) ||
// e.Data.GetDataPresent( DataFormats.StringFormat ) ||
// e.Data.GetDataPresent( DataFormats.Rtf )
;
if (acceptable)
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.None;
}
}
private void JsonInputTextbox_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] fileNames = (string[])e.Data.GetData(DataFormats.FileDrop);
if (fileNames.Length >= 1)
{
// hmm, maybe allow multiple files by concatenating them all into a horrible JSON array? :D
TryLoadJsonFile(fileNames[0]);
}
}
else if (e.Data.GetDataPresent(DataFormats.UnicodeText, autoConvert: true))
{
statusStrip.Text = "";
string text = (string)e.Data.GetData(DataFormats.UnicodeText, autoConvert: true);
if (text != null)
{
jsonInputTextbox.Text = text; // This will invoke `GenerateCSharp()`.
statusStrip.Text = "Loaded JSON from drag and drop data.";
}
}
}
/// <summary>This regex won't match <c>\r\n</c>, only <c>\n</c>.</summary>
private static readonly Regex _OnlyUnixLineBreaks = new("(?<!\r)\n", RegexOptions.Compiled); // Don't use `[^\r]?\n` because it *will* match `\r\n`, and don't use `[^\r]\n` because it won't match a leading `$\n` in a file.
private static string RepairLineBreaks(string text)
{
if (_OnlyUnixLineBreaks.IsMatch(text))
{
return _OnlyUnixLineBreaks.Replace(text, replacement: "\r\n");
}
return text;
}
#endregion
#region Open JSON file
private void OpenButton_Click(object sender, EventArgs e)
{
if (ofd.ShowDialog(owner: this) == DialogResult.OK)
{
TryLoadJsonFile(ofd.FileName);
}
}
private void TryLoadJsonFile(string filePath)
{
if (string.IsNullOrWhiteSpace(filePath))
{
csharpOutputTextbox.Text = "Error: an empty file path was specified.";
}
// else if ( filePath.IndexOfAny( Path.GetInvalidFileNameChars() ) > -1 )
// {
// const String fmt = "Invalid file path: \"{0}\"";
// csharpOutputTextbox.Text = String.Format( CultureInfo.CurrentCulture, fmt, filePath );
// }
else
{
FileInfo jsonFileInfo;
try
{
jsonFileInfo = new FileInfo(filePath);
}
catch (Exception ex)
{
const string fmt = "Invalid file path: \"{0}\"\r\n{1}";
csharpOutputTextbox.Text = string.Format(CultureInfo.CurrentCulture, fmt, filePath, ex.ToString());
return;
}
TryLoadJsonFile(jsonFileInfo);
}
}
private void TryLoadJsonFile(FileInfo jsonFile)
{
if (jsonFile is null)
return;
statusStrip.Text = "";
try
{
jsonFile.Refresh();
if (jsonFile.Exists)
{
string jsonText = File.ReadAllText(jsonFile.FullName);
jsonInputTextbox.Text = jsonText; // This will invoke `GenerateCSharp()`.
statusStrip.Text = "Loaded \"" + jsonFile.FullName + "\" successfully.";
}
else
{
csharpOutputTextbox.Text = string.Format(CultureInfo.CurrentCulture, "Error: File \"{0}\" does not exist.", jsonFile.FullName);
}
}
catch (Exception ex)
{
const string fmt = "Error loading file: \"{0}\"\r\n{1}";
csharpOutputTextbox.Text = string.Format(CultureInfo.CurrentCulture, fmt, jsonFile.FullName, ex.ToString());
}
}
#endregion
private void ConfigureGenerator(IJsonClassGeneratorConfig config)
{
config.UsePascalCase = optsPascalCase.Checked;
//
if (optAttribJP.Checked)
{
config.AttributeLibrary = JsonLibrary.NewtonsoftJson;
}
else// implicit: ( optAttribJpn.Checked )
{
config.AttributeLibrary = JsonLibrary.SystemTextJson;
}
//
if (optMemberProps.Checked)
{
config.MutableClasses.Members = OutputMembers.AsProperties;
}
else// implicit: ( optMemberFields.Checked )
{
config.MutableClasses.Members = OutputMembers.AsPublicFields;
}
//
if (optTypesImmutablePoco.Checked)
{
config.OutputType = OutputTypes.ImmutableClass;
}
else if (optTypesMutablePoco.Checked)
{
config.OutputType = OutputTypes.MutableClass;
}
else// implicit: ( optTypesRecords.Checked )
{
config.OutputType = OutputTypes.ImmutableRecord;
}
}
private void JsonInputTextbox_TextChanged(object sender, EventArgs e)
{
if (_PreventReentrancy)
return;
_PreventReentrancy = true;
try
{
jsonInputTextbox.Text = RepairLineBreaks(jsonInputTextbox.Text);
GenerateCSharp();
}
finally
{
_PreventReentrancy = false;
}
}
private void GenerateCSharp()
{
copyOutput.Enabled = false;
string jsonText = jsonInputTextbox.Text;
if (string.IsNullOrWhiteSpace(jsonText))
{
csharpOutputTextbox.Text = string.Empty;
return;
}
JsonClassGenerator generator = new();
ConfigureGenerator(generator);
try
{
StringBuilder sb = generator.GenerateClasses(jsonText, errorMessage: out string errorMessage);
if (!string.IsNullOrWhiteSpace(errorMessage))
{
csharpOutputTextbox.Text = "Error:\r\n" + errorMessage;
}
else
{
csharpOutputTextbox.Text = sb.ToString();
copyOutput.Enabled = true;
}
}
catch (Exception ex)
{
csharpOutputTextbox.Text = "Error:\r\n" + ex.ToString();
}
}
private void CopyOutput_Click(object sender, EventArgs e)
{
if (csharpOutputTextbox.Text?.Length > 0)
{
Clipboard.SetText(csharpOutputTextbox.Text, TextDataFormat.UnicodeText);
}
}
}

View File

@ -0,0 +1,16 @@
namespace Json2CSharpCodeGenerator.Lib.WinForms;
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 MainForm());
}
}