mirror of
https://github.com/haven1433/HexManiacAdvance.git
synced 2026-10-03 05:36:34 -05:00
adding ability for IFileSystem to tell me when something changes on disk.
first pass at implementing the windows version of the new interface methods IViewPort now has a public method to call whenever you want to notify it that its underlying file has been changed. Added 3 tests showing how the Editor and ViewPort should behave with this new functionality. - Editor should hook up ViewPorts whenever a new tab is opened - Editor should clear out ViewPorts whenever a tab is closed - ViewPort should reload when the file is changed and it is not. Note that the model isn't implemented yet. This is just some failing tests.
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
namespace HavenSoft.Gen3Hex.Model {
|
||||
using System;
|
||||
|
||||
namespace HavenSoft.Gen3Hex.Model {
|
||||
public interface IFileSystem {
|
||||
string CopyText { get; set; }
|
||||
|
||||
@@ -34,6 +36,22 @@
|
||||
/// </returns>
|
||||
LoadedFile OpenFile(params string[] extensionOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Have the filesystem open a specific file.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// If the file exists, it is loaded and returned.
|
||||
/// If it doesn't exist, returns null.
|
||||
/// </returns>
|
||||
LoadedFile LoadFile(string fileName);
|
||||
|
||||
/// <summary>
|
||||
/// When a file changes, the filesystem will call all listeners for that file.
|
||||
/// </summary>
|
||||
void AddListenerToFile(string fileName, Action<IFileSystem> listener);
|
||||
|
||||
void RemoveAllListenersForFile(string fileName);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the file without prompting the user for permission.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
using HavenSoft.Gen3Hex.Model;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
namespace HavenSoft.Gen3Hex.View {
|
||||
public class WindowsFileSystem : IFileSystem {
|
||||
private readonly Dictionary<string, List<FileSystemWatcher>> watchers = new Dictionary<string, List<FileSystemWatcher>>();
|
||||
|
||||
public string CopyText {
|
||||
get => Clipboard.ContainsText() ? Clipboard.GetText() : string.Empty;
|
||||
set => Clipboard.SetText(value);
|
||||
@@ -15,9 +19,31 @@ namespace HavenSoft.Gen3Hex.View {
|
||||
var dialog = new OpenFileDialog { Filter = CreateFilterFromOptions(extensionOptions) };
|
||||
var result = dialog.ShowDialog();
|
||||
if (result != true) return null;
|
||||
if (!File.Exists(dialog.FileName)) return null;
|
||||
var data = File.ReadAllBytes(dialog.FileName);
|
||||
return new LoadedFile(dialog.FileName, data);
|
||||
return LoadFile(dialog.FileName);
|
||||
}
|
||||
|
||||
public LoadedFile LoadFile(string fileName) {
|
||||
if (!File.Exists(fileName)) return null;
|
||||
var data = File.ReadAllBytes(fileName);
|
||||
return new LoadedFile(fileName, data);
|
||||
}
|
||||
|
||||
public void AddListenerToFile(string fileName, Action<IFileSystem> listener) {
|
||||
var watcher = new FileSystemWatcher(Path.GetDirectoryName(fileName)) {
|
||||
NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName,
|
||||
};
|
||||
watcher.Changed += (sender, e) => {
|
||||
if (e.FullPath.EndsWith(fileName)) listener(this);
|
||||
};
|
||||
watcher.EnableRaisingEvents = true;
|
||||
|
||||
if (!watchers.ContainsKey(fileName)) watchers[fileName] = new List<FileSystemWatcher>();
|
||||
watchers[fileName].Add(watcher);
|
||||
}
|
||||
|
||||
public void RemoveAllListenersForFile(string fileName) {
|
||||
if (!watchers.ContainsKey(fileName)) return;
|
||||
watchers[fileName].Clear();
|
||||
}
|
||||
|
||||
public string RequestNewName(string currentName, params string[] extensionOptions) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using HavenSoft.Gen3Hex.Model;
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace HavenSoft.Gen3Hex.ViewModel {
|
||||
|
||||
@@ -22,5 +22,6 @@ namespace HavenSoft.Gen3Hex.ViewModel {
|
||||
IReadOnlyList<int> Find(string search);
|
||||
IChildViewPort CreateChildView(int offset);
|
||||
void FollowLink(int x, int y);
|
||||
void ConsiderReload(IFileSystem fileSystem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,8 @@ namespace HavenSoft.Gen3Hex.ViewModel {
|
||||
RequestTabChange?.Invoke(this, parent);
|
||||
}
|
||||
|
||||
public void ConsiderReload(IFileSystem fileSystem) { }
|
||||
|
||||
private void NotifyCollectionChanged() {
|
||||
if (children.Count == 0) return;
|
||||
UpdateHeaders();
|
||||
|
||||
@@ -301,6 +301,10 @@ namespace HavenSoft.Gen3Hex.ViewModel {
|
||||
|
||||
public void FollowLink(int x, int y) { }
|
||||
|
||||
public void ConsiderReload(IFileSystem fileSystem) {
|
||||
|
||||
}
|
||||
|
||||
private void Edit(char input) {
|
||||
var point = GetEditPoint();
|
||||
var element = currentView[point.X, point.Y];
|
||||
|
||||
@@ -204,7 +204,6 @@ namespace HavenSoft.HexTests {
|
||||
Assert.Equal(7, count);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData(nameof(EditorViewModel.Copy))]
|
||||
[InlineData(nameof(EditorViewModel.Delete))]
|
||||
@@ -323,6 +322,58 @@ namespace HavenSoft.HexTests {
|
||||
Assert.Equal(1, editor.SelectedIndex);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EditorAddsOpenedFilesToFileSystemWatch() {
|
||||
var fileSystem = new StubFileSystem();
|
||||
string name = null;
|
||||
fileSystem.AddListenerToFile = (fileName, action) => name = fileName;
|
||||
var editor = new EditorViewModel(fileSystem);
|
||||
|
||||
editor.Open.Execute(new LoadedFile("InputFile.txt", new byte[20]));
|
||||
|
||||
Assert.Equal("InputFile.txt", name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EditorRemovesFileSystemWatchWhenTabsClose() {
|
||||
var fileSystem = new StubFileSystem();
|
||||
string name = null;
|
||||
fileSystem.RemoveAllListenersForFile = fileName => name = fileName;
|
||||
var editor = new EditorViewModel(fileSystem);
|
||||
editor.Open.Execute(new LoadedFile("InputFile.txt", new byte[20]));
|
||||
|
||||
editor.Close.Execute();
|
||||
|
||||
Assert.Equal("InputFile.txt", name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ViewPortReloadsIfNoLocalChangesWhenFileChanges() {
|
||||
var fileSystem = new StubFileSystem();
|
||||
string file = null;
|
||||
fileSystem.LoadFile = input => { file = input; return new LoadedFile(input, new byte[] { 0x10, 0x20 }); };
|
||||
var viewPort = new ViewPort(new LoadedFile("file.txt", new byte[] { 0x00, 0x00 }));
|
||||
|
||||
viewPort.ConsiderReload(fileSystem);
|
||||
|
||||
Assert.Equal("file.txt", file);
|
||||
Assert.Equal(0x10, viewPort[0, 0].Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ViewPortDoesNotReloadIfLocalChangesWhenFileChanges() {
|
||||
var fileSystem = new StubFileSystem();
|
||||
string file = null;
|
||||
fileSystem.LoadFile = input => { file = input; return new LoadedFile(input, new byte[] { 0x10, 0x20 }); };
|
||||
var viewPort = new ViewPort(new LoadedFile("file.txt", new byte[] { 0x00, 0x00 }));
|
||||
|
||||
viewPort.Edit("05");
|
||||
viewPort.ConsiderReload(fileSystem);
|
||||
|
||||
Assert.Null(file);
|
||||
Assert.Equal(0x05, viewPort[0, 0].Value);
|
||||
}
|
||||
|
||||
private StubTabContent CreateClosableTab() {
|
||||
var tab = new StubTabContent();
|
||||
var close = new StubCommand { CanExecute = arg => true };
|
||||
|
||||
Reference in New Issue
Block a user