revised RecentFileManager to provide a stable API and actually limit the number of items tracked

This commit is contained in:
Michael Becker 2021-09-08 21:06:23 -04:00
parent a7e6b55023
commit 6ec7b011c3
No known key found for this signature in database
GPG Key ID: 98C333A81F18C22C
4 changed files with 117 additions and 25 deletions

View File

@ -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);
}

View File

@ -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)

View File

@ -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[]
{

View File

@ -1,42 +1,124 @@
//
// RecentFileManager.cs - provides a simple way of tracking recently-accessed files
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// 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 <http://www.gnu.org/licenses/>.
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
{
/// <summary>
/// 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.
/// </summary>
public class RecentFileManager
{
private System.Collections.Specialized.StringCollection mvarFileNames = new System.Collections.Specialized.StringCollection();
public System.Collections.Specialized.StringCollection FileNames { get { return mvarFileNames; } }
/// <summary>
/// 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
/// <see cref="RecentFileManager" />.
/// </summary>
/// <value>Implementation detail.</value>
private List<string> FileNames { get; } = new List<string>();
private int mvarMaximumDocumentFileNames = 5;
public int MaximumDocumentFileNames { get { return mvarMaximumDocumentFileNames; } set { mvarMaximumDocumentFileNames = value; } }
/// <summary>
/// Appends the given <paramref name="filename" /> 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.
/// </summary>
/// <returns><c>true</c>, if the file name was newly appended to the list;
/// <c>false</c> if the file name already existed in the list.</returns>
/// <param name="filename">The file name to append to the list.</param>
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[]
/// <summary>
/// Retrieves the list of Recent Files in the correct order (i.e., most
/// recently-added file name first).
/// </summary>
/// <returns>The sorted list of recent file names.</returns>
public string[] GetFileNames()
{
List<string> list = new List<string>(FileNames);
list.Reverse(); // stored in reverse order
return list.ToArray();
}
/// <summary>
/// Gets or sets the maximum number of file names that can be stored in
/// this <see cref="RecentFileManager" />. When a unique file name is
/// added to the list with the <see cref="AppendFileName(string)" />
/// method, the oldest file name in the list is discarded.
/// </summary>
/// <value>
/// The maximum number of file names tracked by this
/// <see cref="RecentFileManager" />.
/// </value>
public int MaximumDocumentFileNames { get; set; } = 5;
/// <summary>
/// Gets or sets the full path to the XML file where the
/// <see cref="RecentFileManager"/> data is stored.
/// </summary>
/// <value>
/// The full path to the XML file where the
/// <see cref="RecentFileManager" /> data is stored.
/// </value>
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; } }
/// <summary>
/// Gets the <see cref="Version" /> of the XML serialization format used.
/// </summary>
private Version mvarFormatVersion = new Version(1, 0);
/// <summary>
/// Loads the Recent File data from the XML file specified by
/// <see cref="DataFileName" />.
/// </summary>
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);
}
}
}
/// <summary>
/// Saves the Recent File data to the XML file specified by
/// <see cref="DataFileName" />.
/// </summary>
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);
}
}
}