Handle file writing errors for movies and all tools.

This commit is contained in:
SuuperW 2025-07-21 02:48:17 -05:00
parent 5559b48319
commit 1e57b74fb2
14 changed files with 298 additions and 174 deletions

View File

@ -5,6 +5,13 @@ using System.Diagnostics;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
public enum TryAgainResult
{
Saved,
IgnoredFailure,
Canceled,
}
public static class DialogControllerExtensions public static class DialogControllerExtensions
{ {
public static void AddOnScreenMessage(this IDialogParent dialogParent, string message, int? duration = null) public static void AddOnScreenMessage(this IDialogParent dialogParent, string message, int? duration = null)
@ -80,7 +87,7 @@ namespace BizHawk.Client.Common
/// The user will be repeatedly asked if they want to try again until either success or the user says no. /// The user will be repeatedly asked if they want to try again until either success or the user says no.
/// </summary> /// </summary>
/// <returns>Returns true on success or if the user said no. Returns false if the user said cancel.</returns> /// <returns>Returns true on success or if the user said no. Returns false if the user said cancel.</returns>
public static bool DoWithTryAgainBox( public static TryAgainResult DoWithTryAgainBox(
this IDialogParent dialogParent, this IDialogParent dialogParent,
Func<FileWriteResult> action, Func<FileWriteResult> action,
string message) string message)
@ -94,12 +101,12 @@ namespace BizHawk.Client.Common
$"{fileResult.UserFriendlyErrorMessage()}\n{fileResult.Exception!.Message}", $"{fileResult.UserFriendlyErrorMessage()}\n{fileResult.Exception!.Message}",
caption: "Error", caption: "Error",
icon: EMsgBoxIcon.Error); icon: EMsgBoxIcon.Error);
if (askResult == null) return false; if (askResult == null) return TryAgainResult.Canceled;
if (askResult == false) return true; if (askResult == false) return TryAgainResult.IgnoredFailure;
if (askResult == true) fileResult = action(); if (askResult == true) fileResult = action();
} }
return true; return TryAgainResult.Saved;
} }
/// <summary>Creates and shows a <c>System.Windows.Forms.OpenFileDialog</c> or equivalent with the receiver (<paramref name="dialogParent"/>) as its parent</summary> /// <summary>Creates and shows a <c>System.Windows.Forms.OpenFileDialog</c> or equivalent with the receiver (<paramref name="dialogParent"/>) as its parent</summary>

View File

@ -56,6 +56,22 @@ namespace BizHawk.Client.Common
return createResult.Value.CloseAndDispose(backupPath); return createResult.Value.CloseAndDispose(backupPath);
} }
public static FileWriteResult Write(string path, Action<Stream> writeCallback, string? backupPath = null)
{
FileWriteResult<FileWriter> createResult = Create(path);
if (createResult.IsError) return createResult;
try
{
writeCallback(createResult.Value!.Stream);
}
catch (Exception ex)
{
return new(FileWriteEnum.FailedDuringWrite, createResult.Value!.Paths, ex);
}
return createResult.Value.CloseAndDispose(backupPath);
}
/// <summary> /// <summary>
/// Create a FileWriter instance, or return an error if unable to access the file. /// Create a FileWriter instance, or return an error if unable to access the file.
@ -76,6 +92,7 @@ namespace BizHawk.Client.Common
FileWritePaths paths = new(path, writePath); FileWritePaths paths = new(path, writePath);
try try
{ {
Directory.CreateDirectory(Path.GetDirectoryName(path));
FileStream fs = new(writePath, FileMode.Create, FileAccess.Write); FileStream fs = new(writePath, FileMode.Create, FileAccess.Write);
return new(new FileWriter(paths, fs), paths); return new(new FileWriter(paths, fs), paths);
} }

View File

@ -102,9 +102,8 @@ namespace BizHawk.Client.Common
return true; return true;
} }
public void Save(string path) public FileWriteResult Save(string path)
{ {
using var sw = new StreamWriter(path);
var sb = new StringBuilder(); var sb = new StringBuilder();
var saveDirectory = Path.GetDirectoryName(Path.GetFullPath(path)); var saveDirectory = Path.GetDirectoryName(Path.GetFullPath(path));
foreach (var file in this) foreach (var file in this)
@ -123,10 +122,19 @@ namespace BizHawk.Client.Common
} }
} }
sw.Write(sb.ToString()); FileWriteResult result = FileWriter.Write(path, (fs) =>
{
using var sw = new StreamWriter(fs);
sw.Write(sb.ToString());
});
Filename = path; if (!result.IsError)
Changes = false; {
Filename = path;
Changes = false;
}
return result;
} }
} }
} }

View File

@ -385,6 +385,8 @@ namespace BizHawk.Client.Common
switch (Settings.MovieEndAction) switch (Settings.MovieEndAction)
{ {
case MovieEndAction.Stop: case MovieEndAction.Stop:
// Technically this can save the movie, but it'd be weird to be in that situation.
// Do we want that?
StopMovie(); StopMovie();
break; break;
case MovieEndAction.Record: case MovieEndAction.Record:

View File

@ -88,20 +88,10 @@ namespace BizHawk.Client.Common
return file.Exists && Load(domains, file.FullName, false); return file.Exists && Load(domains, file.FullName, false);
} }
public void NewList(string defaultFileName, bool autosave = false) public void NewList(string defaultFileName)
{ {
_defaultFileName = defaultFileName; _defaultFileName = defaultFileName;
if (autosave && _changes && _cheatList.Count is not 0)
{
if (string.IsNullOrEmpty(CurrentFileName))
{
CurrentFileName = _defaultFileName;
}
Save();
}
_cheatList.Clear(); _cheatList.Clear();
CurrentFileName = ""; CurrentFileName = "";
Changes = false; Changes = false;
@ -220,7 +210,7 @@ namespace BizHawk.Client.Common
public bool IsActive(MemoryDomain domain, long address) public bool IsActive(MemoryDomain domain, long address)
=> _cheatList.Exists(cheat => !cheat.IsSeparator && cheat.Enabled && cheat.Domain == domain && cheat.Contains(address)); => _cheatList.Exists(cheat => !cheat.IsSeparator && cheat.Enabled && cheat.Domain == domain && cheat.Contains(address));
public void SaveOnClose() public FileWriteResult SaveOnClose()
{ {
if (_config.AutoSaveOnClose) if (_config.AutoSaveOnClose)
{ {
@ -231,17 +221,27 @@ namespace BizHawk.Client.Common
CurrentFileName = _defaultFileName; CurrentFileName = _defaultFileName;
} }
SaveFile(CurrentFileName); return SaveFile(CurrentFileName);
} }
else if (_cheatList.Count is 0 && !string.IsNullOrWhiteSpace(CurrentFileName)) else if (_cheatList.Count is 0 && !string.IsNullOrWhiteSpace(CurrentFileName))
{ {
File.Delete(CurrentFileName); try
{
File.Delete(CurrentFileName);
}
catch (Exception ex)
{
return new(FileWriteEnum.FailedToDeleteGeneric, new(CurrentFileName, ""), ex);
}
_config.Recent.Remove(CurrentFileName); _config.Recent.Remove(CurrentFileName);
return new();
} }
} }
return new();
} }
public bool Save() public FileWriteResult Save()
{ {
if (string.IsNullOrWhiteSpace(CurrentFileName)) if (string.IsNullOrWhiteSpace(CurrentFileName))
{ {
@ -251,54 +251,51 @@ namespace BizHawk.Client.Common
return SaveFile(CurrentFileName); return SaveFile(CurrentFileName);
} }
public bool SaveFile(string path) public FileWriteResult SaveFile(string path)
{ {
try var sb = new StringBuilder();
foreach (var cheat in _cheatList)
{ {
new FileInfo(path).Directory?.Create(); if (cheat.IsSeparator)
var sb = new StringBuilder();
foreach (var cheat in _cheatList)
{ {
if (cheat.IsSeparator) sb.AppendLine("----");
{
sb.AppendLine("----");
}
else
{
// Set to hex for saving
var tempCheatType = cheat.Type;
cheat.SetType(WatchDisplayType.Hex);
sb
.Append(cheat.AddressStr).Append('\t')
.Append(cheat.ValueStr).Append('\t')
.Append(cheat.Compare is null ? "N" : cheat.CompareStr).Append('\t')
.Append(cheat.Domain != null ? cheat.Domain.Name : "").Append('\t')
.Append(cheat.Enabled ? '1' : '0').Append('\t')
.Append(cheat.Name).Append('\t')
.Append(cheat.SizeAsChar).Append('\t')
.Append(cheat.TypeAsChar).Append('\t')
.Append(cheat.BigEndian is true ? '1' : '0').Append('\t')
.Append(cheat.ComparisonType).Append('\t')
.AppendLine();
cheat.SetType(tempCheatType);
}
} }
else
{
// Set to hex for saving
var tempCheatType = cheat.Type;
File.WriteAllText(path, sb.ToString()); cheat.SetType(WatchDisplayType.Hex);
sb
.Append(cheat.AddressStr).Append('\t')
.Append(cheat.ValueStr).Append('\t')
.Append(cheat.Compare is null ? "N" : cheat.CompareStr).Append('\t')
.Append(cheat.Domain != null ? cheat.Domain.Name : "").Append('\t')
.Append(cheat.Enabled ? '1' : '0').Append('\t')
.Append(cheat.Name).Append('\t')
.Append(cheat.SizeAsChar).Append('\t')
.Append(cheat.TypeAsChar).Append('\t')
.Append(cheat.BigEndian is true ? '1' : '0').Append('\t')
.Append(cheat.ComparisonType).Append('\t')
.AppendLine();
cheat.SetType(tempCheatType);
}
}
FileWriteResult result = FileWriter.Write(path, (fs) =>
{
StreamWriter sw = new(fs);
sw.Write(sb.ToString());
});
if (!result.IsError)
{
CurrentFileName = path; CurrentFileName = path;
_config.Recent.Add(CurrentFileName); _config.Recent.Add(CurrentFileName);
Changes = false; Changes = false;
return true;
}
catch
{
return false;
} }
return result;
} }
public bool Load(IMemoryDomains domains, string path, bool append) public bool Load(IMemoryDomains domains, string path, bool append)

View File

@ -1,5 +1,6 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -338,39 +339,37 @@ namespace BizHawk.Client.Common
} }
} }
public bool Save() public FileWriteResult Save()
{ {
if (string.IsNullOrWhiteSpace(CurrentFileName)) if (string.IsNullOrWhiteSpace(CurrentFileName))
{ {
return false; return new();
} }
using (var sw = new StreamWriter(CurrentFileName)) var sb = new StringBuilder();
sb.Append("SystemID ").AppendLine(_systemId);
foreach (var watch in _watchList)
{ {
var sb = new StringBuilder(); sb.AppendLine(watch.ToString());
sb.Append("SystemID ").AppendLine(_systemId);
foreach (var watch in _watchList)
{
sb.AppendLine(watch.ToString());
}
sw.WriteLine(sb.ToString());
} }
Changes = false; FileWriteResult result = FileWriter.Write(CurrentFileName, (fs) =>
return true; {
using var sw = new StreamWriter(fs);
sw.WriteLine(sb.ToString());
});
if (!result.IsError) Changes = false;
return result;
} }
public bool SaveAs(FileInfo file) public FileWriteResult SaveAs(FileInfo file)
{ {
if (file != null) Debug.Assert(file != null, "Cannot save as without a file name.");
{
CurrentFileName = file.FullName;
return Save();
}
return false; CurrentFileName = file.FullName;
return Save();
} }
private bool LoadFile(string path, bool append) private bool LoadFile(string path, bool append)

View File

@ -3934,7 +3934,7 @@ namespace BizHawk.Client.EmuHawk
if (previousRom != CurrentlyOpenRom) if (previousRom != CurrentlyOpenRom)
{ {
CheatList.NewList(Tools.GenerateDefaultCheatFilename(), autosave: true); CheatList.NewList(Tools.GenerateDefaultCheatFilename());
if (Config.Cheats.LoadFileByGame && Emulator.HasMemoryDomains()) if (Config.Cheats.LoadFileByGame && Emulator.HasMemoryDomains())
{ {
if (CheatList.AttemptToLoadCheatFile(Emulator.AsMemoryDomains())) if (CheatList.AttemptToLoadCheatFile(Emulator.AsMemoryDomains()))
@ -3951,7 +3951,7 @@ namespace BizHawk.Client.EmuHawk
} }
else else
{ {
CheatList.NewList(Tools.GenerateDefaultCheatFilename(), autosave: true); CheatList.NewList(Tools.GenerateDefaultCheatFilename());
} }
} }
@ -3988,7 +3988,7 @@ namespace BizHawk.Client.EmuHawk
DisplayManager.UpdateGlobals(Config, Emulator); DisplayManager.UpdateGlobals(Config, Emulator);
DisplayManager.Blank(); DisplayManager.Blank();
ExtToolManager.BuildToolStrip(); ExtToolManager.BuildToolStrip();
CheatList.NewList("", autosave: true); CheatList.NewList("");
OnRomChanged(); OnRomChanged();
return false; return false;
} }
@ -4050,25 +4050,30 @@ namespace BizHawk.Client.EmuHawk
{ {
CommitCoreSettingsToConfig(); // Must happen before stopping the movie, since it checks for active movie. CommitCoreSettingsToConfig(); // Must happen before stopping the movie, since it checks for active movie.
GameIsClosing = true;
if (!Tools.AskSave()) if (!Tools.AskSave())
{ {
GameIsClosing = false;
return false; return false;
} }
// There is a cheats tool, but cheats can be active while the "cheats tool" is not. And have auto-save option. // There is a cheats tool, but cheats can be active while the "cheats tool" is not. And have auto-save option.
CheatList.SaveOnClose(); TryAgainResult cheatSaveResult = this.DoWithTryAgainBox(CheatList.SaveOnClose, "Failed to save cheats.");
if (cheatSaveResult == TryAgainResult.Canceled)
GameIsClosing = true;
FileWriteResult saveResult = MovieSession.StopMovie();
GameIsClosing = false;
if (saveResult.IsError)
{ {
if (!this.ModalMessageBox2( GameIsClosing = false;
caption: "Quit anyway?", return false;
icon: EMsgBoxIcon.Question, }
text: "The currently playing movie could not be saved. Continue and quit anyway? All unsaved changes will be lost."))
{ // If TAStudio is open, we already asked about saving the movie.
return false; if (Tools.IsLoaded<TAStudio>())
} {
GameIsClosing = false;
}
else
{
TryAgainResult saveMovieResult = this.DoWithTryAgainBox(() => MovieSession.StopMovie(), "Failed to save movie.");
GameIsClosing = false;
if (saveMovieResult == TryAgainResult.Canceled) return false;
} }
if (clearSram) if (clearSram)
@ -4076,7 +4081,7 @@ namespace BizHawk.Client.EmuHawk
var path = Config.PathEntries.SaveRamAbsolutePath(Game, MovieSession.Movie); var path = Config.PathEntries.SaveRamAbsolutePath(Game, MovieSession.Movie);
if (File.Exists(path)) if (File.Exists(path))
{ {
bool clearResult = this.DoWithTryAgainBox(() => { TryAgainResult clearResult = this.DoWithTryAgainBox(() => {
try try
{ {
File.Delete(path); File.Delete(path);
@ -4088,7 +4093,7 @@ namespace BizHawk.Client.EmuHawk
return new(FileWriteEnum.FailedToDeleteGeneric, new(path, ""), ex); return new(FileWriteEnum.FailedToDeleteGeneric, new(path, ""), ex);
} }
}, "Failed to clear SRAM."); }, "Failed to clear SRAM.");
if (!clearResult) if (clearResult == TryAgainResult.Canceled)
{ {
return false; return false;
} }
@ -4096,14 +4101,14 @@ namespace BizHawk.Client.EmuHawk
} }
else if (Emulator.HasSaveRam()) else if (Emulator.HasSaveRam())
{ {
bool flushResult = this.DoWithTryAgainBox( TryAgainResult flushResult = this.DoWithTryAgainBox(
() => FlushSaveRAM(), () => FlushSaveRAM(),
"Failed flushing the game's Save RAM to your disk."); "Failed flushing the game's Save RAM to your disk.");
if (!flushResult) return false; if (flushResult == TryAgainResult.Canceled) return false;
} }
bool stateSaveResult = this.DoWithTryAgainBox(AutoSaveStateIfConfigured, "Failed to auto-save state."); TryAgainResult stateSaveResult = this.DoWithTryAgainBox(AutoSaveStateIfConfigured, "Failed to auto-save state.");
if (!stateSaveResult) return false; if (stateSaveResult == TryAgainResult.Canceled) return false;
StopAv(); StopAv();
@ -4146,7 +4151,7 @@ namespace BizHawk.Client.EmuHawk
PauseOnFrame = null; PauseOnFrame = null;
CurrentlyOpenRom = null; CurrentlyOpenRom = null;
CurrentlyOpenRomArgs = null; CurrentlyOpenRomArgs = null;
CheatList.NewList("", autosave: true); CheatList.NewList("");
OnRomChanged(); OnRomChanged();
} }
} }

View File

@ -214,19 +214,23 @@ namespace BizHawk.Client.EmuHawk
{ {
if (_currentFilename != null) if (_currentFilename != null)
{ {
RunSave(); bool saveResult2 = RunSave();
ShutdownCDL(); ShutdownCDL();
return true; return saveResult2;
} }
} }
// TODO - I don't like this system. It's hard to figure out how to use it. It should be done in multiple passes. var result = DialogController.ShowMessageBox3("Save changes to CDL session?", "CDL Save", EMsgBoxIcon.Question);
var result = DialogController.ShowMessageBox2("Save changes to CDL session?", "CDL Auto Save", EMsgBoxIcon.Question); if (result == false)
if (!result)
{ {
ShutdownCDL(); ShutdownCDL();
return true; return true;
} }
else if (result == null)
{
ShutdownCDL();
return false;
}
if (string.IsNullOrWhiteSpace(_currentFilename)) if (string.IsNullOrWhiteSpace(_currentFilename))
{ {
@ -240,9 +244,9 @@ namespace BizHawk.Client.EmuHawk
return false; return false;
} }
RunSave(); bool saveResult = RunSave();
ShutdownCDL(); ShutdownCDL();
return true; return saveResult;
} }
private bool _autoloading; private bool _autoloading;
@ -341,11 +345,20 @@ namespace BizHawk.Client.EmuHawk
LoadFile(file.FullName); LoadFile(file.FullName);
} }
private void RunSave() /// <summary>
/// returns false if the operation was canceled
/// </summary>
private bool RunSave()
{ {
_recent.Add(_currentFilename); TryAgainResult result = this.DoWithTryAgainBox(
using var fs = new FileStream(_currentFilename, FileMode.Create, FileAccess.Write); () => FileWriter.Write(_currentFilename, _cdl.Save),
_cdl.Save(fs); "Failed to save CDL session.");
if (result == TryAgainResult.Saved)
{
_recent.Add(_currentFilename);
return true;
}
return result != TryAgainResult.Canceled;
} }
private void SaveMenuItem_Click(object sender, EventArgs e) private void SaveMenuItem_Click(object sender, EventArgs e)
@ -386,8 +399,7 @@ namespace BizHawk.Client.EmuHawk
return false; return false;
SetCurrentFilename(file.FullName); SetCurrentFilename(file.FullName);
RunSave(); return RunSave();
return true;
} }
private void SaveAsMenuItem_Click(object sender, EventArgs e) private void SaveAsMenuItem_Click(object sender, EventArgs e)

View File

@ -142,7 +142,7 @@ namespace BizHawk.Client.EmuHawk
} }
} }
private bool SaveAs() private FileWriteResult SaveAs()
{ {
var fileName = MainForm.CheatList.CurrentFileName; var fileName = MainForm.CheatList.CurrentFileName;
if (string.IsNullOrWhiteSpace(fileName)) if (string.IsNullOrWhiteSpace(fileName))
@ -156,7 +156,8 @@ namespace BizHawk.Client.EmuHawk
CheatsFSFilterSet, CheatsFSFilterSet,
this); this);
return file != null && MainForm.CheatList.SaveFile(file.FullName); if (file == null) return new();
else return MainForm.CheatList.SaveFile(file.FullName);
} }
private void Cheats_Load(object sender, EventArgs e) private void Cheats_Load(object sender, EventArgs e)
@ -361,7 +362,12 @@ namespace BizHawk.Client.EmuHawk
{ {
if (MainForm.CheatList.Changes) if (MainForm.CheatList.Changes)
{ {
if (MainForm.CheatList.Save()) FileWriteResult result = MainForm.CheatList.Save();
if (result.IsError)
{
this.ErrorMessageBox(result);
}
else
{ {
UpdateMessageLabel(saved: true); UpdateMessageLabel(saved: true);
} }
@ -374,7 +380,12 @@ namespace BizHawk.Client.EmuHawk
private void SaveAsMenuItem_Click(object sender, EventArgs e) private void SaveAsMenuItem_Click(object sender, EventArgs e)
{ {
if (SaveAs()) FileWriteResult result = SaveAs();
if (result.IsError)
{
this.ErrorMessageBox(result);
}
else
{ {
UpdateMessageLabel(saved: true); UpdateMessageLabel(saved: true);
} }

View File

@ -681,15 +681,25 @@ namespace BizHawk.Client.EmuHawk
return result is not null ? new FileInfo(result) : null; return result is not null ? new FileInfo(result) : null;
} }
private void SaveSessionAs() private FileWriteResult SaveSessionAs()
{ {
var file = GetSaveFileFromUser(); var file = GetSaveFileFromUser();
if (file != null) if (file != null)
{ {
LuaImp.ScriptList.Save(file.FullName); FileWriteResult saveResult = LuaImp.ScriptList.Save(file.FullName);
Config.RecentLuaSession.Add(file.FullName); if (saveResult.IsError)
OutputMessages.Text = $"{file.Name} saved."; {
this.ErrorMessageBox(saveResult);
OutputMessages.Text = $"Lua session could not be saved to {file.Name}";
}
else
{
Config.RecentLuaSession.Add(file.FullName);
OutputMessages.Text = $"{file.Name} saved.";
}
return saveResult;
} }
return new();
} }
private void LoadSessionFromRecent(string path) private void LoadSessionFromRecent(string path)
@ -717,7 +727,11 @@ namespace BizHawk.Client.EmuHawk
icon: EMsgBoxIcon.Question, icon: EMsgBoxIcon.Question,
text: $"Save {WindowTitleStatic} session?")); text: $"Save {WindowTitleStatic} session?"));
if (result is null) return false; if (result is null) return false;
if (result.Value) SaveOrSaveAs(); if (result.Value)
{
TryAgainResult saveResult = this.DoWithTryAgainBox(SaveOrSaveAs, "Failed to save Lua session.");
return saveResult != TryAgainResult.Canceled;
}
else LuaImp.ScriptList.Changes = false; else LuaImp.ScriptList.Changes = false;
return true; return true;
} }
@ -732,16 +746,20 @@ namespace BizHawk.Client.EmuHawk
} }
} }
private void SaveOrSaveAs() private FileWriteResult SaveOrSaveAs()
{ {
if (!string.IsNullOrWhiteSpace(LuaImp.ScriptList.Filename)) if (!string.IsNullOrWhiteSpace(LuaImp.ScriptList.Filename))
{ {
LuaImp.ScriptList.Save(LuaImp.ScriptList.Filename); FileWriteResult result = LuaImp.ScriptList.Save(LuaImp.ScriptList.Filename);
Config.RecentLuaSession.Add(LuaImp.ScriptList.Filename); if (!result.IsError)
{
Config.RecentLuaSession.Add(LuaImp.ScriptList.Filename);
}
return result;
} }
else else
{ {
SaveSessionAs(); return SaveSessionAs();
} }
} }
@ -784,8 +802,16 @@ namespace BizHawk.Client.EmuHawk
{ {
if (LuaImp.ScriptList.Changes) if (LuaImp.ScriptList.Changes)
{ {
SaveOrSaveAs(); FileWriteResult result = SaveOrSaveAs();
OutputMessages.Text = $"{Path.GetFileName(LuaImp.ScriptList.Filename)} saved."; if (result.IsError)
{
this.ErrorMessageBox(result, "Failed to save Lua session.");
OutputMessages.Text = $"Failed to save {Path.GetFileName(LuaImp.ScriptList.Filename)}";
}
else
{
OutputMessages.Text = $"{Path.GetFileName(LuaImp.ScriptList.Filename)} saved.";
}
} }
} }

View File

@ -112,6 +112,7 @@ namespace BizHawk.Client.EmuHawk
return true; return true;
} }
// Intentionally not updating this to use FileWriter because this tool is going to be removed later.
foreach (var zone in _unsavedZones) foreach (var zone in _unsavedZones)
{ {
SaveMacroAs(_zones[zone]); SaveMacroAs(_zones[zone]);

View File

@ -161,15 +161,8 @@ namespace BizHawk.Client.EmuHawk
text: $"Save {WindowTitleStatic} project?")); text: $"Save {WindowTitleStatic} project?"));
if (shouldSaveResult == true) if (shouldSaveResult == true)
{ {
FileWriteResult saveResult = SaveTas(); TryAgainResult saveResult = this.DoWithTryAgainBox(() => SaveTas(), "Failed to save movie.");
while (saveResult.IsError && shouldSaveResult != true) return saveResult != TryAgainResult.Canceled;
{
shouldSaveResult = this.ModalMessageBox3(
$"Failed to save movie. {saveResult.UserFriendlyErrorMessage()}\n{saveResult.Exception.Message}\n\nTry again?",
"Error",
EMsgBoxIcon.Error);
if (shouldSaveResult == true) saveResult = SaveTas();
}
} }
if (shouldSaveResult is null) return false; if (shouldSaveResult is null) return false;
else CurrentTasMovie.ClearChanges(); else CurrentTasMovie.ClearChanges();

View File

@ -1008,7 +1008,13 @@ namespace BizHawk.Client.EmuHawk
if (!string.IsNullOrWhiteSpace(watches.CurrentFileName)) if (!string.IsNullOrWhiteSpace(watches.CurrentFileName))
{ {
if (watches.Save()) FileWriteResult saveResult = watches.Save();
if (saveResult.IsError)
{
this.ErrorMessageBox(saveResult);
MessageLabel.Text = $"Failed to save {Path.GetFileName(_currentFileName)}";
}
else
{ {
_currentFileName = watches.CurrentFileName; _currentFileName = watches.CurrentFileName;
MessageLabel.Text = $"{Path.GetFileName(_currentFileName)} saved"; MessageLabel.Text = $"{Path.GetFileName(_currentFileName)} saved";
@ -1017,11 +1023,20 @@ namespace BizHawk.Client.EmuHawk
} }
else else
{ {
var result = watches.SaveAs(GetWatchSaveFileFromUser(CurrentFileName())); FileInfo/*?*/ file = GetWatchSaveFileFromUser(CurrentFileName());
if (result) if (file != null)
{ {
MessageLabel.Text = $"{Path.GetFileName(_currentFileName)} saved"; var result = watches.SaveAs(file);
Settings.RecentSearches.Add(watches.CurrentFileName); if (result.IsError)
{
this.ErrorMessageBox(result);
MessageLabel.Text = $"Failed to save {Path.GetFileName(_currentFileName)}";
}
else
{
MessageLabel.Text = $"{Path.GetFileName(_currentFileName)} saved";
Settings.RecentSearches.Add(watches.CurrentFileName);
}
} }
} }
} }
@ -1035,7 +1050,15 @@ namespace BizHawk.Client.EmuHawk
watches.Add(_searches[i]); watches.Add(_searches[i]);
} }
if (watches.SaveAs(GetWatchSaveFileFromUser(CurrentFileName()))) FileInfo/*?*/ file = GetWatchSaveFileFromUser(CurrentFileName());
if (file == null) return;
FileWriteResult result = watches.SaveAs(file);
if (result.IsError)
{
this.ErrorMessageBox(result);
MessageLabel.Text = $"Failed to save {Path.GetFileName(_currentFileName)}";
}
else
{ {
_currentFileName = watches.CurrentFileName; _currentFileName = watches.CurrentFileName;
MessageLabel.Text = $"{Path.GetFileName(_currentFileName)} saved"; MessageLabel.Text = $"{Path.GetFileName(_currentFileName)} saved";

View File

@ -213,15 +213,8 @@ namespace BizHawk.Client.EmuHawk
if (result is null) return false; if (result is null) return false;
if (result.Value) if (result.Value)
{ {
if (string.IsNullOrWhiteSpace(_watches.CurrentFileName)) TryAgainResult saveResult = this.DoWithTryAgainBox(Save, "Failed to save watch list.");
{ return saveResult != TryAgainResult.Canceled;
SaveAs();
}
else
{
_watches.Save();
Config.RecentWatches.Add(_watches.CurrentFileName);
}
} }
else else
{ {
@ -591,14 +584,47 @@ namespace BizHawk.Client.EmuHawk
: Game.FilesystemSafeName(); : Game.FilesystemSafeName();
} }
private void SaveAs() private FileWriteResult SaveAs()
{ {
var result = _watches.SaveAs(GetWatchSaveFileFromUser(CurrentFileName())); FileInfo/*?*/ file = GetWatchSaveFileFromUser(CurrentFileName());
if (result) if (file == null) return new();
FileWriteResult result = _watches.SaveAs(file);
if (result.IsError)
{ {
UpdateStatusBar(saved: true); MessageLabel.Text = $"Failed to save {Path.GetFileName(_watches.CurrentFileName)}";
Config.RecentWatches.Add(_watches.CurrentFileName);
} }
else
{
MessageLabel.Text = $"{Path.GetFileName(_watches.CurrentFileName)} saved";
Config.RecentWatches.Add(_watches.CurrentFileName);
UpdateStatusBar(saved: true);
}
return result;
}
private FileWriteResult Save()
{
if (string.IsNullOrWhiteSpace(_watches.CurrentFileName))
{
return SaveAs();
}
else
{
FileWriteResult saveResult = _watches.Save();
if (saveResult.IsError)
{
MessageLabel.Text = $"Failed to save {Path.GetFileName(_watches.CurrentFileName)}";
}
else
{
MessageLabel.Text = $"{Path.GetFileName(_watches.CurrentFileName)} saved";
Config.RecentWatches.Add(_watches.CurrentFileName);
UpdateStatusBar(saved: true);
}
return saveResult;
}
} }
private void SaveConfigSettings() private void SaveConfigSettings()
@ -727,23 +753,20 @@ namespace BizHawk.Client.EmuHawk
private void SaveMenuItem_Click(object sender, EventArgs e) private void SaveMenuItem_Click(object sender, EventArgs e)
{ {
if (!string.IsNullOrWhiteSpace(_watches.CurrentFileName)) FileWriteResult saveResult = Save();
if (saveResult.IsError)
{ {
if (_watches.Save()) this.ErrorMessageBox(saveResult, "Failed to save watch list.");
{
Config.RecentWatches.Add(_watches.CurrentFileName);
UpdateStatusBar(saved: true);
}
}
else
{
SaveAs();
} }
} }
private void SaveAsMenuItem_Click(object sender, EventArgs e) private void SaveAsMenuItem_Click(object sender, EventArgs e)
{ {
SaveAs(); FileWriteResult saveResult = SaveAs();
if (saveResult.IsError)
{
this.ErrorMessageBox(saveResult, "Failed to save watch list.");
}
} }
private void RecentSubMenu_DropDownOpened(object sender, EventArgs e) private void RecentSubMenu_DropDownOpened(object sender, EventArgs e)