From 0b699879a2bde901441f021cdceed05e103b2026 Mon Sep 17 00:00:00 2001 From: Chris Lovett Date: Tue, 24 Sep 2024 23:56:40 -0700 Subject: [PATCH] Fix issue #418: check setttings-file for "read-only" --- src/Application/FormMain.cs | 48 ++++++++++++++++++-- src/Model/Settings.cs | 87 ++++++++++++++++++++----------------- src/Updates/Updates.xml | 3 ++ src/Version/Version.props | 2 +- 4 files changed, 95 insertions(+), 45 deletions(-) diff --git a/src/Application/FormMain.cs b/src/Application/FormMain.cs index e2e11195..fe86c4a9 100644 --- a/src/Application/FormMain.cs +++ b/src/Application/FormMain.cs @@ -12,6 +12,7 @@ using System.Text; using System.Windows.Forms; using System.Xml; +using XmlNotepad.Properties; using SR = XmlNotepad.StringResources; using SystemTask = System.Threading.Tasks.Task; @@ -577,10 +578,41 @@ protected override void OnClosing(CancelEventArgs e) } this.closing = true; this._delayedActions.Close(); - SaveConfig(); + + SaveSettings(e); + base.OnClosing(e); } + private void SaveSettings(CancelEventArgs e) + { + try + { + SaveConfig(); + } + catch (Exception ex) + { + if (this._settings.DiscardChanges) + { + // prompt the user only once per process. + } + else + { + var rc = MessageBox.Show(this, "Error saving " + this._settings.FileName + "\r\n\r\n" + + ex.Message + "\r\n\r\nWould you like to discard your changes to the settings?", + "Error saving settings", MessageBoxButtons.YesNo, MessageBoxIcon.Error); + if (rc == DialogResult.No) + { + e.Cancel = true; + } + else + { + this._settings.DiscardChanges = true; + } + } + } + } + protected override void OnClosed(EventArgs e) { this.xmlTreeView1.Close(); @@ -1539,8 +1571,12 @@ public virtual void SaveConfig() this._settings["TreeViewSize"] = this.xmlTreeView1.ResizerPosition; this._settings["RecentFiles"] = this._recentFiles.ToArray(); this._settings["RecentXsltFiles"] = this._recentXsltFiles.ToArray(); - var path = this._settings.FileName; - this._settings.Save(path); + if (this.Settings.IsDirty) + { + var path = this._settings.FileName; + Debug.WriteLine("Saving settings: " + path); + this._settings.Save(path); + } } #region ISite implementation @@ -1624,7 +1660,7 @@ protected virtual void OnSettingsChanged(object sender, string name) switch (name) { case "File": - // load the new settiongs but don't move the window or anything if another instances of xmlnotepad.exe changed + // load the new settings but don't move the window or anything if another instances of xmlnotepad.exe changed // the settings.xml file. if (!this._loading) { @@ -1718,6 +1754,10 @@ protected virtual void OnSettingsChanged(object sender, string name) } break; } + + this._delayedActions.StartDelayedAction("DelaySaveSettings", + () => SaveSettings(new CancelEventArgs()), + TimeSpan.FromSeconds(1)); } public void SaveErrors(string filename) diff --git a/src/Model/Settings.cs b/src/Model/Settings.cs index 4503a7a3..e27be053 100644 --- a/src/Model/Settings.cs +++ b/src/Model/Settings.cs @@ -256,7 +256,7 @@ public class Settings : IDisposable private readonly Hashtable _map = new Hashtable(); private DelayedActions _delayedActions = null; private PersistentFileNames _pfn; - + private bool _isDirty; public static string DefaultUpdateLocation = "https://lovettsoftwarestorage.blob.core.windows.net/downloads/XmlNotepad/Updates.xml"; /// @@ -278,6 +278,10 @@ public Settings() _instance = this; } + public bool IsDirty => this._isDirty; + + public bool DiscardChanges { get; set; } = false; + public ValueMatchHandler Comparer { get => comparer; @@ -373,6 +377,10 @@ public object this[string name] if (!this.SettingValueMatches(this._map[name], value)) { this._map[name] = value; + if (!(value is SchemaCache) && name != "SettingsLocation") + { + this._isDirty = true; + } OnChanged(name); } } @@ -445,6 +453,7 @@ public void Load(string filename) Debug.WriteLine("Load settings failed: " + ex.Message); } + this._isDirty = false; this.FileName = filename; } @@ -525,53 +534,46 @@ public void Save(string filename) { // make sure directory exists! Directory.CreateDirectory(Path.GetDirectoryName(filename)); - try + using (var w = new XmlTextWriter(filename, System.Text.Encoding.UTF8)) { - using (var w = new XmlTextWriter(filename, System.Text.Encoding.UTF8)) + w.Formatting = Formatting.Indented; + w.WriteStartElement("Settings"); + // create save stability. + List keys = new List(); + foreach (string key in _map.Keys) { - w.Formatting = Formatting.Indented; - w.WriteStartElement("Settings"); - // create save stability. - List keys = new List(); - foreach (string key in _map.Keys) - { - keys.Add(key); - } - keys.Sort(); - foreach (string key in keys) + keys.Add(key); + } + keys.Sort(); + foreach (string key in keys) + { + object value = _map[key]; + if (value != null) { - object value = _map[key]; - if (value != null) + if (value is Hashtable ht) { - if (value is Hashtable ht) - { - w.WriteStartElement(key); // container element - WriteHashTable(w, ht); - w.WriteEndElement(); - } - else if (value is Array va) - { - WriteArray(w, key, va); - } - else if (value is IXmlSerializable xs) - { - w.WriteStartElement(key); // container element - xs.WriteXml(w); - w.WriteEndElement(); - } - else - { - string s = ConvertToString(value); - if (s != null) w.WriteElementString(key, s); - } + w.WriteStartElement(key); // container element + WriteHashTable(w, ht); + w.WriteEndElement(); + } + else if (value is Array va) + { + WriteArray(w, key, va); + } + else if (value is IXmlSerializable xs) + { + w.WriteStartElement(key); // container element + xs.WriteXml(w); + w.WriteEndElement(); + } + else + { + string s = ConvertToString(value); + if (s != null) w.WriteElementString(key, s); } } } } - catch (Exception e) - { - Console.WriteLine(e.Message); - } } private void ReadHashTable(XmlReader r, Hashtable ht) @@ -674,6 +676,9 @@ void OnDelay(int retries) { // make sure file is not still locked by the writer. string text = File.ReadAllText(this._filename); + + // The "File" property is a special signal to the listener that the entire + // settings need to be reloaded. OnChanged("File"); } catch (Exception) @@ -1005,6 +1010,8 @@ public void SetDefaults() this["TextEditor"] = Path.Combine(sysdir, "notepad.exe"); this["MouseCalibration"] = new Point[0]; this["PrimaryScreenSize"] = new Size(); + + this._isDirty = false; } } diff --git a/src/Updates/Updates.xml b/src/Updates/Updates.xml index abb0b899..0a53f477 100644 --- a/src/Updates/Updates.xml +++ b/src/Updates/Updates.xml @@ -9,6 +9,9 @@ https://github.com/microsoft/XmlNotepad/blob/master/src/Updates/Updates.xml 1.00:00:00 + + Fix issue #418: check setttings-file for "read-only". + Issue 409: Not able to validate XML against multiple not referenced Schemas Issue 329: Incomplete schema validation of large XML files ( > ~20 MB). diff --git a/src/Version/Version.props b/src/Version/Version.props index 44022517..15f9f25d 100644 --- a/src/Version/Version.props +++ b/src/Version/Version.props @@ -2,7 +2,7 @@ 0 - 2.9.0.13 + 2.9.0.14 $(ApplicationVersion) Chris Lovett XmlNotepad