diff --git a/Libraries/UniversalEditor.UserInterface/EditorApplication.cs b/Libraries/UniversalEditor.UserInterface/EditorApplication.cs index f2804265..406bf2d3 100644 --- a/Libraries/UniversalEditor.UserInterface/EditorApplication.cs +++ b/Libraries/UniversalEditor.UserInterface/EditorApplication.cs @@ -473,9 +473,11 @@ namespace UniversalEditor.UserInterface if (mnuFileRecentFiles != null) { mnuFileRecentFiles.Items.Clear(); - foreach (string fileName in RecentFileManager.FileNames) + + string[] filenames = RecentFileManager.GetFileNames(); + foreach (string filename in filenames) { - AddRecentMenuItem(fileName); + AddRecentMenuItem(filename); } mnuFileRecentFiles.Visible = (mnuFileRecentFiles.Items.Count > 0); } diff --git a/Libraries/UniversalEditor.UserInterface/MainWindow.cs b/Libraries/UniversalEditor.UserInterface/MainWindow.cs index 9376e1ba..eccb89d4 100644 --- a/Libraries/UniversalEditor.UserInterface/MainWindow.cs +++ b/Libraries/UniversalEditor.UserInterface/MainWindow.cs @@ -1179,10 +1179,7 @@ namespace UniversalEditor.UserInterface { // FIXME: support Accessors other than FileAccessor string fileName = (doc.Accessor as FileAccessor).FileName; - if (!((EditorApplication)Application.Instance).RecentFileManager.FileNames.Contains(fileName)) - { - ((EditorApplication)Application.Instance).RecentFileManager.FileNames.Add(fileName); - } + ((EditorApplication)Application.Instance).RecentFileManager.AppendFileName(fileName); } } catch (System.UnauthorizedAccessException ex) diff --git a/Libraries/UniversalEditor.UserInterface/Pages/StartPage.cs b/Libraries/UniversalEditor.UserInterface/Pages/StartPage.cs index ef14a5fd..616801b2 100644 --- a/Libraries/UniversalEditor.UserInterface/Pages/StartPage.cs +++ b/Libraries/UniversalEditor.UserInterface/Pages/StartPage.cs @@ -72,7 +72,8 @@ namespace UniversalEditor.UserInterface.Panels ctHeaderText.Visible = true; } - foreach (string fileName in ((EditorApplication)Application.Instance).RecentFileManager.FileNames) + string[] filenames = ((EditorApplication)Application.Instance).RecentFileManager.GetFileNames(); + foreach (string fileName in filenames) { TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[] { diff --git a/Libraries/UniversalEditor.UserInterface/RecentFileManager.cs b/Libraries/UniversalEditor.UserInterface/RecentFileManager.cs index 71dce879..805d9592 100644 --- a/Libraries/UniversalEditor.UserInterface/RecentFileManager.cs +++ b/Libraries/UniversalEditor.UserInterface/RecentFileManager.cs @@ -1,42 +1,124 @@ +// +// RecentFileManager.cs - provides a simple way of tracking recently-accessed files +// +// Author: +// Michael Becker +// +// Copyright (c) 2011-2021 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using UniversalEditor.ObjectModels.Markup; using UniversalEditor.DataFormats.Markup.XML; using UniversalEditor.Accessors; -using UniversalEditor; namespace UniversalEditor.UserInterface { + /// + /// Provides a simple way of tracking recently-accessed files, including + /// appending new filenames to the list and retrieving the previously-stored + /// filenames in the appropriate order. + /// public class RecentFileManager { - private System.Collections.Specialized.StringCollection mvarFileNames = new System.Collections.Specialized.StringCollection(); - public System.Collections.Specialized.StringCollection FileNames { get { return mvarFileNames; } } + /// + /// The backing store for the list of file names. This could be a S.C.G. + /// List`1 or a Specialized StringCollection. However, changing this + /// IMPLEMENTATION DETAIL should not change the public-facing API of + /// . + /// + /// Implementation detail. + private List FileNames { get; } = new List(); - private int mvarMaximumDocumentFileNames = 5; - public int MaximumDocumentFileNames { get { return mvarMaximumDocumentFileNames; } set { mvarMaximumDocumentFileNames = value; } } + /// + /// Appends the given to the end of the + /// Recent Files list, if it does not already exist. The position of the + /// existing file name in the list is unmodified. + /// + /// true, if the file name was newly appended to the list; + /// false if the file name already existed in the list. + /// The file name to append to the list. + public bool AppendFileName(string filename) + { + if (!FileNames.Contains(filename)) + { + FileNames.Add(filename); + return true; + } + return false; + } - private string mvarDataFileName = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] + /// + /// Retrieves the list of Recent Files in the correct order (i.e., most + /// recently-added file name first). + /// + /// The sorted list of recent file names. + public string[] GetFileNames() + { + List list = new List(FileNames); + list.Reverse(); // stored in reverse order + return list.ToArray(); + } + + /// + /// Gets or sets the maximum number of file names that can be stored in + /// this . When a unique file name is + /// added to the list with the + /// method, the oldest file name in the list is discarded. + /// + /// + /// The maximum number of file names tracked by this + /// . + /// + public int MaximumDocumentFileNames { get; set; } = 5; + + /// + /// Gets or sets the full path to the XML file where the + /// data is stored. + /// + /// + /// The full path to the XML file where the + /// data is stored. + /// + public string DataFileName { get; set; } = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Mike Becker's Software", "Universal Editor", "RecentItems.xml" }); - public string DataFileName { get { return mvarDataFileName; } set { mvarDataFileName = value; } } + /// + /// Gets the of the XML serialization format used. + /// private Version mvarFormatVersion = new Version(1, 0); + /// + /// Loads the Recent File data from the XML file specified by + /// . + /// public void Load() { MarkupObjectModel mom = new MarkupObjectModel(); XMLDataFormat xml = new XMLDataFormat(); - if (!System.IO.File.Exists(mvarDataFileName)) return; + if (!System.IO.File.Exists(DataFileName)) return; - Document.Load(mom, xml, new FileAccessor(mvarDataFileName, false, false, true)); + Document.Load(mom, xml, new FileAccessor(DataFileName, false, false, true)); MarkupTagElement tagRecentItems = (mom.Elements["RecentItems"] as MarkupTagElement); if (tagRecentItems == null) return; @@ -52,6 +134,11 @@ namespace UniversalEditor.UserInterface MarkupTagElement tagDocuments = (tagRecentItems.Elements["Documents"] as MarkupTagElement); if (tagDocuments != null) { + MarkupAttribute attDocumentsMaximum = tagDocuments.Attributes["Maximum"]; + if (attDocumentsMaximum != null) + { + MaximumDocumentFileNames = Int32.Parse(attDocumentsMaximum.Value); + } foreach (MarkupElement elDocument in tagDocuments.Elements) { MarkupTagElement tagDocument = (elDocument as MarkupTagElement); @@ -61,10 +148,15 @@ namespace UniversalEditor.UserInterface MarkupAttribute attFileName = tagDocument.Attributes["FileName"]; if (attFileName == null) continue; - mvarFileNames.Add(attFileName.Value); + FileNames.Insert(0, attFileName.Value); } } } + + /// + /// Saves the Recent File data to the XML file specified by + /// . + /// public void Save() { MarkupObjectModel mom = new MarkupObjectModel(); @@ -81,28 +173,28 @@ namespace UniversalEditor.UserInterface mom.Elements.Add(tagRecentItems); - if (mvarFileNames.Count > 0) + if (FileNames.Count > 0) { MarkupTagElement tagDocuments = new MarkupTagElement(); tagDocuments.FullName = "Documents"; - tagDocuments.Attributes.Add("Maximum", mvarMaximumDocumentFileNames.ToString()); - foreach (string fileName in mvarFileNames) + tagDocuments.Attributes.Add("Maximum", MaximumDocumentFileNames.ToString()); + for (int i = 0; i < Math.Min(FileNames.Count, MaximumDocumentFileNames); i++) { MarkupTagElement tagDocument = new MarkupTagElement(); tagDocument.FullName = "Document"; - tagDocument.Attributes.Add("FileName", fileName); + tagDocument.Attributes.Add("FileName", FileNames[FileNames.Count - i - 1]); tagDocuments.Elements.Add(tagDocument); } tagRecentItems.Elements.Add(tagDocuments); } - string dir = System.IO.Path.GetDirectoryName (mvarDataFileName); + string dir = System.IO.Path.GetDirectoryName(DataFileName); if (!System.IO.Directory.Exists (dir)) { System.IO.Directory.CreateDirectory (dir); } - Document.Save(mom, xml, new FileAccessor(mvarDataFileName, true, true), true); + Document.Save(mom, xml, new FileAccessor(DataFileName, true, true), true); } } }