From b69869725661dbb2f76b45701aa809089b2a9d11 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Tue, 21 Jun 2022 23:39:24 -0600 Subject: [PATCH] Improve display and function of character replacement --- Source/FileManager/FileUtility.cs | 29 +- Source/FileManager/ReplacementCharacters.cs | 281 +++++++++++------- .../Dialogs/EditReplacementChars.Designer.cs | 81 +++-- .../Dialogs/EditReplacementChars.cs | 127 +++----- .../Dialogs/SettingsDialog.DownloadDecrypt.cs | 3 +- 5 files changed, 272 insertions(+), 249 deletions(-) diff --git a/Source/FileManager/FileUtility.cs b/Source/FileManager/FileUtility.cs index 550f46e0..80905aaa 100644 --- a/Source/FileManager/FileUtility.cs +++ b/Source/FileManager/FileUtility.cs @@ -84,39 +84,12 @@ namespace FileManager var pathNoPrefix = path.PathWithoutPrefix; - pathNoPrefix = replaceInvalidChars(pathNoPrefix, replacements); + pathNoPrefix = replacements.ReplaceInvalidChars(pathNoPrefix); pathNoPrefix = removeDoubleSlashes(pathNoPrefix); return pathNoPrefix; } - public static char[] invalidChars { get; } = Path.GetInvalidPathChars().Union(new[] { - '*', '?', ':', - // these are weird. If you run Path.GetInvalidPathChars() in Visual Studio's "C# Interactive", then these characters are included. - // In live code, Path.GetInvalidPathChars() does not include them - '"', '<', '>' - }).ToArray(); - private static string replaceInvalidChars(string path, ReplacementCharacters replacements) - { - // replace all colons except within the first 2 chars - var builder = new System.Text.StringBuilder(); - for (var i = 0; i < path.Length; i++) - { - var c = path[i]; - - if (!invalidChars.Contains(c) || (i <= 2 && Path.IsPathRooted(path))) - builder.Append(c); - else - { - char preceding = i > 0 ? path[i - 1] : default; - char succeeding = i < path.Length - 1 ? path[i + 1] : default; - builder.Append(replacements.GetReplacement(c, preceding, succeeding)); - } - - } - return builder.ToString(); - } - private static string removeDoubleSlashes(string path) { if (path.Length < 2) diff --git a/Source/FileManager/ReplacementCharacters.cs b/Source/FileManager/ReplacementCharacters.cs index 0fb91189..a689e6f2 100644 --- a/Source/FileManager/ReplacementCharacters.cs +++ b/Source/FileManager/ReplacementCharacters.cs @@ -2,43 +2,177 @@ using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; +using System.IO; using System.Linq; namespace FileManager { public class Replacement { - [JsonIgnore] - public bool Mandatory { get; set; } - [JsonProperty] - public char CharacterToReplace { get; init; } - [JsonProperty] - public string ReplacementString { get; set; } - [JsonProperty] - public string Description { get; set; } - - public Replacement Clone() => new() - { - Mandatory = Mandatory, - CharacterToReplace = CharacterToReplace, - ReplacementString = ReplacementString, - Description = Description - }; + public const int FIXED_COUNT = 4; + internal const char QUOTE_MARK = '"'; + internal const string DEFAULT_DESCRIPTION = "Any other invalid characters"; + internal const string OPEN_QUOTE_DESCRIPTION = "Open Quote"; + internal const string CLOSE_QUOTE_DESCRIPTION = "Close Quote"; + internal const string OTHER_QUOTE_DESCRIPTION = "Other Quote"; + [JsonIgnore] public bool Mandatory { get; internal set; } + [JsonProperty] public char CharacterToReplace { get; private set; } + [JsonProperty] public string ReplacementString { get; private set; } + [JsonProperty] public string Description { get; private set; } public override string ToString() => $"{CharacterToReplace} → {ReplacementString} ({Description})"; - public static Replacement Colon(string replacement) => new Replacement { CharacterToReplace = ':', Description = "Colon", ReplacementString = replacement}; - public static Replacement Asterisk(string replacement) => new Replacement { CharacterToReplace = '*', Description = "Asterisk", ReplacementString = replacement }; - public static Replacement QuestionMark(string replacement) => new Replacement { CharacterToReplace = '?', Description = "Question Mark", ReplacementString = replacement }; - public static Replacement OpenAngleBracket(string replacement) => new Replacement { CharacterToReplace = '<', Description = "Open Angle Bracket", ReplacementString = replacement }; - public static Replacement CloseAngleBracket(string replacement) => new Replacement { CharacterToReplace = '>', Description = "Close Angle Bracket", ReplacementString = replacement }; - public static Replacement OpenQuote(string replacement) => new Replacement { CharacterToReplace = '"', Description = "Open Quote", ReplacementString = replacement }; - public static Replacement CloseQuote(string replacement) => new Replacement { CharacterToReplace = '"', Description = "Close Quote", ReplacementString = replacement }; - public static Replacement OtherQuote(string replacement) => new Replacement { CharacterToReplace = '"', Description = "Other Quote", ReplacementString = replacement }; - public static Replacement Pipe(string replacement) => new Replacement { CharacterToReplace = '|', Description = "Vertical Line", ReplacementString = replacement }; - public static Replacement OtherInvalid(string replacement) => new Replacement { CharacterToReplace = default, Description = "Any other invalid characters", ReplacementString = replacement }; + public Replacement(char charToReplace, string replacementString, string description) + { + CharacterToReplace = charToReplace; + ReplacementString = replacementString; + Description = description; + } + private Replacement(char charToReplace, string replacementString, string description, bool mandatory) + : this(charToReplace, replacementString, description) + { + Mandatory = mandatory; + } + + public void Update(char charToReplace, string replacementString, string description) + { + ReplacementString = replacementString; + + if (!Mandatory) + { + CharacterToReplace = charToReplace; + Description = description; + } + } + + public static Replacement OtherInvalid(string replacement) => new(default, replacement, DEFAULT_DESCRIPTION, true); + public static Replacement OpenQuote(string replacement) => new('"', replacement, OPEN_QUOTE_DESCRIPTION, true); + public static Replacement CloseQuote(string replacement) => new('"', replacement, CLOSE_QUOTE_DESCRIPTION, true); + public static Replacement OtherQuote(string replacement) => new('"', replacement, OTHER_QUOTE_DESCRIPTION, true); + public static Replacement Colon(string replacement) => new(':', replacement, "Colon"); + public static Replacement Asterisk(string replacement) => new('*', replacement, "Asterisk"); + public static Replacement QuestionMark(string replacement) => new('?', replacement, "Question Mark"); + public static Replacement OpenAngleBracket(string replacement) => new('<', replacement, "Open Angle Bracket"); + public static Replacement CloseAngleBracket(string replacement) => new('>', replacement, "Close Angle Bracket"); + public static Replacement Pipe(string replacement) => new('|', replacement, "Vertical Line"); } + [JsonConverter(typeof(ReplacementCharactersConverter))] + public class ReplacementCharacters + { + public static readonly ReplacementCharacters Default = new() + { + Replacements = new List() + { + Replacement.OtherInvalid("_"), + Replacement.OpenQuote("“"), + Replacement.CloseQuote("”"), + Replacement.OtherQuote("""), + Replacement.OpenAngleBracket("<"), + Replacement.CloseAngleBracket(">"), + Replacement.Colon("꞉"), + Replacement.Asterisk("✱"), + Replacement.QuestionMark("?"), + Replacement.Pipe("⏐"), + } + }; + + public static readonly ReplacementCharacters LoFiDefault = new() + { + Replacements = new List() + { + Replacement.OtherInvalid("_"), + Replacement.OpenQuote("'"), + Replacement.CloseQuote("'"), + Replacement.OtherQuote("'"), + Replacement.OpenAngleBracket("{"), + Replacement.CloseAngleBracket("}"), + Replacement.Colon("-"), + Replacement.Asterisk(""), + Replacement.QuestionMark(""), + } + }; + + public static readonly ReplacementCharacters Minimum = new() + { + Replacements = new List() + { + Replacement.OtherInvalid("_"), + Replacement.OpenQuote("_"), + Replacement.CloseQuote("_"), + Replacement.OtherQuote("_"), + } + }; + + private static readonly char[] invalidChars = Path.GetInvalidPathChars().Union(new[] { + '*', '?', ':', + // these are weird. If you run Path.GetInvalidPathChars() in Visual Studio's "C# Interactive", then these characters are included. + // In live code, Path.GetInvalidPathChars() does not include them + '"', '<', '>' + }).ToArray(); + + public IReadOnlyList Replacements { get; init; } + private string DefaultReplacement => Replacements[0].ReplacementString; + private string OpenQuote => Replacements[1].ReplacementString; + private string CloseQuote => Replacements[2].ReplacementString; + private string OtherQuote => Replacements[3].ReplacementString; + + private string GetReplacement(char toReplace, char preceding, char succeding) + { + if (toReplace == Replacement.QUOTE_MARK) + { + if ( + preceding != default + && !char.IsLetter(preceding) + && !char.IsNumber(preceding) + && (char.IsLetter(succeding) || char.IsNumber(succeding)) + ) + return OpenQuote; + else if ( + succeding != default + && !char.IsLetter(succeding) + && !char.IsNumber(succeding) + && (char.IsLetter(preceding) || char.IsNumber(preceding)) + ) + return CloseQuote; + else + return OtherQuote; + } + + for (int i = Replacement.FIXED_COUNT; i < Replacements.Count; i++) + { + var r = Replacements[i]; + if (r.CharacterToReplace == toReplace) + return r.ReplacementString; + } + return DefaultReplacement; + } + + public static bool ContainsInvalid(string path) + => path.Any(c => invalidChars.Contains(c)); + + public string ReplaceInvalidChars(string pathStr) + { + // replace all colons except within the first 2 chars + var builder = new System.Text.StringBuilder(); + for (var i = 0; i < pathStr.Length; i++) + { + var c = pathStr[i]; + + if (!invalidChars.Contains(c) || (i <= 2 && Path.IsPathRooted(pathStr))) + builder.Append(c); + else + { + char preceding = i > 0 ? pathStr[i - 1] : default; + char succeeding = i < pathStr.Length - 1 ? pathStr[i + 1] : default; + builder.Append(GetReplacement(c, preceding, succeeding)); + } + + } + return builder.ToString(); + } + } + #region JSON Converter internal class ReplacementCharactersConverter : JsonConverter { public override bool CanConvert(Type objectType) @@ -51,22 +185,21 @@ namespace FileManager var dict = replaceArr .ToObject().ToList(); - //Add any missing defaults and ensure they are in the expected order. - for (int i = 0; i < ReplacementCharacters.Default.Replacements.Count; i++) + //Ensure that the first 4 replacements are for the expected chars and that all replacement strings are valid. + //If not, reset to default. + if (dict.Count < Replacement.FIXED_COUNT || + dict[0].CharacterToReplace != default || dict[0].Description != Replacement.DEFAULT_DESCRIPTION || + dict[1].CharacterToReplace != Replacement.QUOTE_MARK || dict[1].Description != Replacement.OPEN_QUOTE_DESCRIPTION || + dict[2].CharacterToReplace != Replacement.QUOTE_MARK || dict[2].Description != Replacement.CLOSE_QUOTE_DESCRIPTION || + dict[3].CharacterToReplace != Replacement.QUOTE_MARK || dict[3].Description != Replacement.OTHER_QUOTE_DESCRIPTION || + dict.Any(r => ReplacementCharacters.ContainsInvalid(r.ReplacementString)) + ) { - var rep = ReplacementCharacters.Default.Replacements[i].Clone(); - - if (i < dict.Count) - { - var replacementStr = dict[i].ReplacementString; - dict[i] = rep; - dict[i].ReplacementString = replacementStr; - } - else - { - dict.Insert(i, rep); - } + dict = ReplacementCharacters.Default.Replacements; } + //First 4 are mandatory + for (int i = 0; i < Replacement.FIXED_COUNT; i++) + dict[i].Mandatory = true; return new ReplacementCharacters { Replacements = dict }; } @@ -85,71 +218,5 @@ namespace FileManager obj.WriteTo(writer); } } - - [JsonConverter(typeof(ReplacementCharactersConverter))] - public class ReplacementCharacters - { - public static readonly ReplacementCharacters Default = new() - { - Replacements = new() - { - Replacement.OtherInvalid("_"), - Replacement.OpenQuote("“"), - Replacement.CloseQuote("”"), - Replacement.OtherQuote("""), - Replacement.Colon("꞉"), - Replacement.Asterisk("✱"), - Replacement.QuestionMark("?"), - Replacement.OpenAngleBracket("<"), - Replacement.CloseAngleBracket(">"), - Replacement.Pipe("⏐"), - } - }; - - public static readonly ReplacementCharacters LoFiDefault = new() - { - Replacements = new() - { - Replacement.OtherInvalid("_"), - Replacement.OpenQuote("'"), - Replacement.CloseQuote("'"), - Replacement.OtherQuote("'"), - Replacement.Colon("-"), - Replacement.Asterisk(""), - Replacement.QuestionMark(""), - Replacement.OpenAngleBracket("["), - Replacement.CloseAngleBracket("]"), - Replacement.Pipe("_"), - } - }; - - public List Replacements { get; init; } - public string DefaultReplacement => Replacements[0].ReplacementString; - public string OpenQuote => Replacements[1].ReplacementString; - public string CloseQuote => Replacements[2].ReplacementString; - public string OtherQuote => Replacements[3].ReplacementString; - - private const char QuoteMark = '"'; - - public string GetReplacement(char toReplace, char preceding, char succeding) - { - if (toReplace == QuoteMark) - { - if (preceding != default && !char.IsLetter(preceding) && !char.IsNumber(preceding)) - return OpenQuote; - else if (succeding != default && !char.IsLetter(succeding) && !char.IsNumber(succeding)) - return CloseQuote; - else - return OtherQuote; - } - - for (int i = 4; i < Replacements.Count; i++) - { - var r = Replacements[i]; - if (r.CharacterToReplace == toReplace) - return r.ReplacementString; - } - return DefaultReplacement; - } - } + #endregion } diff --git a/Source/LibationWinForms/Dialogs/EditReplacementChars.Designer.cs b/Source/LibationWinForms/Dialogs/EditReplacementChars.Designer.cs index 4bfe2c91..07bced72 100644 --- a/Source/LibationWinForms/Dialogs/EditReplacementChars.Designer.cs +++ b/Source/LibationWinForms/Dialogs/EditReplacementChars.Designer.cs @@ -29,18 +29,21 @@ private void InitializeComponent() { this.dataGridView1 = new System.Windows.Forms.DataGridView(); - this.charToReplaceCol = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.replacementStringCol = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.descriptionCol = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.defaultsBtn = new System.Windows.Forms.Button(); this.loFiDefaultsBtn = new System.Windows.Forms.Button(); this.saveBtn = new System.Windows.Forms.Button(); this.cancelBtn = new System.Windows.Forms.Button(); + this.minDefaultBtn = new System.Windows.Forms.Button(); + this.charToReplaceCol = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.replacementStringCol = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.descriptionCol = new System.Windows.Forms.DataGridViewTextBoxColumn(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); this.SuspendLayout(); // // dataGridView1 // + this.dataGridView1.AllowUserToResizeColumns = false; + this.dataGridView1.AllowUserToResizeRows = false; this.dataGridView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); @@ -52,35 +55,12 @@ this.dataGridView1.Location = new System.Drawing.Point(12, 12); this.dataGridView1.Name = "dataGridView1"; this.dataGridView1.RowTemplate.Height = 25; - this.dataGridView1.Size = new System.Drawing.Size(416, 393); + this.dataGridView1.Size = new System.Drawing.Size(498, 393); this.dataGridView1.TabIndex = 0; this.dataGridView1.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellEndEdit); - this.dataGridView1.CellValidating += new System.Windows.Forms.DataGridViewCellValidatingEventHandler(this.dataGridView1_CellValidating); this.dataGridView1.UserDeletingRow += new System.Windows.Forms.DataGridViewRowCancelEventHandler(this.dataGridView1_UserDeletingRow); this.dataGridView1.Resize += new System.EventHandler(this.dataGridView1_Resize); // - // charToReplaceCol - // - this.charToReplaceCol.HeaderText = "Char to Replace"; - this.charToReplaceCol.MinimumWidth = 70; - this.charToReplaceCol.Name = "charToReplaceCol"; - this.charToReplaceCol.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this.charToReplaceCol.Width = 70; - // - // replacementStringCol - // - this.replacementStringCol.HeaderText = "Replacement String"; - this.replacementStringCol.MinimumWidth = 85; - this.replacementStringCol.Name = "replacementStringCol"; - this.replacementStringCol.Width = 85; - // - // descriptionCol - // - this.descriptionCol.HeaderText = "Description"; - this.descriptionCol.MinimumWidth = 100; - this.descriptionCol.Name = "descriptionCol"; - this.descriptionCol.Width = 200; - // // defaultsBtn // this.defaultsBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); @@ -106,7 +86,7 @@ // saveBtn // this.saveBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.saveBtn.Location = new System.Drawing.Point(346, 430); + this.saveBtn.Location = new System.Drawing.Point(428, 430); this.saveBtn.Name = "saveBtn"; this.saveBtn.Size = new System.Drawing.Size(82, 25); this.saveBtn.TabIndex = 1; @@ -117,7 +97,7 @@ // cancelBtn // this.cancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.cancelBtn.Location = new System.Drawing.Point(258, 430); + this.cancelBtn.Location = new System.Drawing.Point(340, 430); this.cancelBtn.Name = "cancelBtn"; this.cancelBtn.Size = new System.Drawing.Size(82, 25); this.cancelBtn.TabIndex = 1; @@ -125,11 +105,45 @@ this.cancelBtn.UseVisualStyleBackColor = true; this.cancelBtn.Click += new System.EventHandler(this.cancelBtn_Click); // + // minDefaultBtn + // + this.minDefaultBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.minDefaultBtn.Location = new System.Drawing.Point(172, 430); + this.minDefaultBtn.Name = "minDefaultBtn"; + this.minDefaultBtn.Size = new System.Drawing.Size(80, 25); + this.minDefaultBtn.TabIndex = 1; + this.minDefaultBtn.Text = "Barebones"; + this.minDefaultBtn.UseVisualStyleBackColor = true; + this.minDefaultBtn.Click += new System.EventHandler(this.minDefaultBtn_Click); + // + // charToReplaceCol + // + this.charToReplaceCol.HeaderText = "Char to Replace"; + this.charToReplaceCol.MinimumWidth = 70; + this.charToReplaceCol.Name = "charToReplaceCol"; + this.charToReplaceCol.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.charToReplaceCol.Width = 70; + // + // replacementStringCol + // + this.replacementStringCol.HeaderText = "Replacement Text"; + this.replacementStringCol.MinimumWidth = 85; + this.replacementStringCol.Name = "replacementStringCol"; + this.replacementStringCol.Width = 85; + // + // descriptionCol + // + this.descriptionCol.HeaderText = "Description"; + this.descriptionCol.MinimumWidth = 100; + this.descriptionCol.Name = "descriptionCol"; + this.descriptionCol.Width = 200; + // // EditReplacementChars // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(440, 467); + this.ClientSize = new System.Drawing.Size(522, 467); + this.Controls.Add(this.minDefaultBtn); this.Controls.Add(this.loFiDefaultsBtn); this.Controls.Add(this.cancelBtn); this.Controls.Add(this.saveBtn); @@ -145,12 +159,13 @@ #endregion private System.Windows.Forms.DataGridView dataGridView1; - private System.Windows.Forms.DataGridViewTextBoxColumn charToReplaceCol; - private System.Windows.Forms.DataGridViewTextBoxColumn replacementStringCol; - private System.Windows.Forms.DataGridViewTextBoxColumn descriptionCol; private System.Windows.Forms.Button defaultsBtn; private System.Windows.Forms.Button loFiDefaultsBtn; private System.Windows.Forms.Button saveBtn; private System.Windows.Forms.Button cancelBtn; + private System.Windows.Forms.Button minDefaultBtn; + private System.Windows.Forms.DataGridViewTextBoxColumn charToReplaceCol; + private System.Windows.Forms.DataGridViewTextBoxColumn replacementStringCol; + private System.Windows.Forms.DataGridViewTextBoxColumn descriptionCol; } } \ No newline at end of file diff --git a/Source/LibationWinForms/Dialogs/EditReplacementChars.cs b/Source/LibationWinForms/Dialogs/EditReplacementChars.cs index 0322ce64..11a0bf6c 100644 --- a/Source/LibationWinForms/Dialogs/EditReplacementChars.cs +++ b/Source/LibationWinForms/Dialogs/EditReplacementChars.cs @@ -15,25 +15,30 @@ namespace LibationWinForms.Dialogs InitializeComponent(); dataGridView1_Resize(this, EventArgs.Empty); } + public EditReplacementChars(Configuration config) : this() { this.config = config; LoadTable(config.ReplacementCharacters.Replacements); } - private void LoadTable(List replacements) + private void LoadTable(IReadOnlyList replacements) { dataGridView1.Rows.Clear(); - foreach (var r in replacements) + for (int i = 0; i < replacements.Count; i++) { + var r = replacements[i]; + int row = dataGridView1.Rows.Add(r.CharacterToReplace, r.ReplacementString, r.Description); dataGridView1.Rows[row].Tag = r; - if (ReplacementCharacters.Default.Replacements.Any(rep => rep.CharacterToReplace == r.CharacterToReplace)) + + if (r.Mandatory) { - r.Mandatory = true; dataGridView1.Rows[row].Cells[charToReplaceCol.Index].ReadOnly = true; dataGridView1.Rows[row].Cells[descriptionCol.Index].ReadOnly = true; + dataGridView1.Rows[row].Cells[charToReplaceCol.Index].Style.BackColor = System.Drawing.Color.LightGray; + dataGridView1.Rows[row].Cells[descriptionCol.Index].Style.BackColor = System.Drawing.Color.LightGray; } } } @@ -45,67 +50,14 @@ namespace LibationWinForms.Dialogs } private void loFiDefaultsBtn_Click(object sender, EventArgs e) - { - LoadTable(ReplacementCharacters.LoFiDefault.Replacements); - } + => LoadTable(ReplacementCharacters.LoFiDefault.Replacements); private void defaultsBtn_Click(object sender, EventArgs e) - { - LoadTable(ReplacementCharacters.Default.Replacements); - } + => LoadTable(ReplacementCharacters.Default.Replacements); - private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) - { - if (e.RowIndex < 0) return; + private void minDefaultBtn_Click(object sender, EventArgs e) + => LoadTable(ReplacementCharacters.Minimum.Replacements); - var cellValue = e.FormattedValue?.ToString(); - - if (dataGridView1.Rows[e.RowIndex].Tag is Replacement row && row.Mandatory) - { - if (e.ColumnIndex == replacementStringCol.Index) - { - //Ensure replacement string doesn't contain an illegal character. - var replaceString = cellValue ?? string.Empty; - if (replaceString != string.Empty && replaceString.Any(c => FileUtility.invalidChars.Contains(c))) - { - dataGridView1.Rows[e.RowIndex].ErrorText = $"{replaceString} contains an illegal path character"; - e.Cancel = true; - } - } - return; - } - - - - if (e.ColumnIndex == charToReplaceCol.Index) - { - if (cellValue.Length != 1) - { - dataGridView1.Rows[e.RowIndex].ErrorText = "Only 1 character to replace per entry"; - e.Cancel = true; - } - else if ( - dataGridView1.Rows - .Cast() - .Where(r => r.Index != e.RowIndex) - .OfType() - .Any(r => r.CharacterToReplace == cellValue[0]) - ) - { - dataGridView1.Rows[e.RowIndex].ErrorText = $"The {cellValue[0]} character is already being replaced"; - e.Cancel = true; - } - } - else if (e.ColumnIndex == descriptionCol.Index || e.ColumnIndex == replacementStringCol.Index) - { - var value = dataGridView1.Rows[e.RowIndex].Cells[charToReplaceCol.Index].Value; - if (value is null || value is string str && string.IsNullOrEmpty(str)) - { - dataGridView1.Rows[e.RowIndex].ErrorText = $"You must choose a character to replace"; - e.Cancel = true; - } - } - } private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) { @@ -113,10 +65,14 @@ namespace LibationWinForms.Dialogs dataGridView1.Rows[e.RowIndex].ErrorText = string.Empty; - var cellValue = dataGridView1.Rows[e.RowIndex].Cells[charToReplaceCol.Index].Value?.ToString(); + var charToReplaceStr = dataGridView1.Rows[e.RowIndex].Cells[charToReplaceCol.Index].Value?.ToString(); + var replacement = dataGridView1.Rows[e.RowIndex].Cells[replacementStringCol.Index].Value?.ToString() ?? string.Empty; + var description = dataGridView1.Rows[e.RowIndex].Cells[descriptionCol.Index].Value?.ToString() ?? string.Empty; - if (string.IsNullOrEmpty(cellValue) || cellValue.Length > 1) + //Validate the whole row. If it passes all validation, add or update the row's tag. + if (string.IsNullOrEmpty(charToReplaceStr) && replacement == string.Empty && description == string.Empty) { + //Invalid entry, so delete row var row = dataGridView1.Rows[e.RowIndex]; if (!row.IsNewRow) { @@ -126,26 +82,38 @@ namespace LibationWinForms.Dialogs })); } } + else if (string.IsNullOrEmpty(charToReplaceStr)) + { + dataGridView1.Rows[e.RowIndex].ErrorText = $"You must choose a character to replace"; + } + else if (charToReplaceStr.Length > 1) + { + dataGridView1.Rows[e.RowIndex].ErrorText = $"Only 1 {charToReplaceCol.HeaderText} per entry"; + } + else if (e.RowIndex >= Replacement.FIXED_COUNT && + dataGridView1.Rows + .Cast() + .Where(r => r.Index != e.RowIndex) + .Select(r => r.Tag) + .OfType() + .Any(r => r.CharacterToReplace == charToReplaceStr[0]) + ) + { + dataGridView1.Rows[e.RowIndex].ErrorText = $"The {charToReplaceStr[0]} character is already being replaced"; + } + else if (ReplacementCharacters.ContainsInvalid(replacement)) + { + dataGridView1.Rows[e.RowIndex].ErrorText = $"Your {replacementStringCol.HeaderText} contains illegal characters"; + } else { - char charToReplace = cellValue[0]; - string description = dataGridView1.Rows[e.RowIndex].Cells[descriptionCol.Index].Value?.ToString() ?? string.Empty; - string replacement = dataGridView1.Rows[e.RowIndex].Cells[replacementStringCol.Index].Value?.ToString() ?? string.Empty; + //valid entry. Add or update Replacement in row's Tag + var charToReplace = charToReplaceStr[0]; - var mandatory = false; if (dataGridView1.Rows[e.RowIndex].Tag is Replacement existing) - { - mandatory = existing.Mandatory; - } - - dataGridView1.Rows[e.RowIndex].Tag = - new Replacement() - { - CharacterToReplace = charToReplace, - ReplacementString = replacement, - Description = description, - Mandatory = mandatory - }; + existing.Update(charToReplace, replacement, description); + else + dataGridView1.Rows[e.RowIndex].Tag = new Replacement(charToReplace, replacement, description); } } @@ -155,7 +123,6 @@ namespace LibationWinForms.Dialogs .Cast() .Select(r => r.Tag) .OfType() - .Where(r => r.ReplacementString != null && (r.ReplacementString == string.Empty || !r.ReplacementString.Any(c => FileUtility.invalidChars.Contains(c)))) .ToList(); config.ReplacementCharacters = new ReplacementCharacters { Replacements = replacements }; diff --git a/Source/LibationWinForms/Dialogs/SettingsDialog.DownloadDecrypt.cs b/Source/LibationWinForms/Dialogs/SettingsDialog.DownloadDecrypt.cs index 8a5266e9..035fdf98 100644 --- a/Source/LibationWinForms/Dialogs/SettingsDialog.DownloadDecrypt.cs +++ b/Source/LibationWinForms/Dialogs/SettingsDialog.DownloadDecrypt.cs @@ -15,7 +15,8 @@ namespace LibationWinForms.Dialogs private void editCharreplacementBtn_Click(object sender, EventArgs e) { var form = new EditReplacementChars(config); - form.ShowDialog(); + form.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + form.ShowDialog(this); } private void Load_DownloadDecrypt(Configuration config)