diff --git a/src/BizHawk.Client.Common/DialogControllerExtensions.cs b/src/BizHawk.Client.Common/DialogControllerExtensions.cs index 9c83be78dc..aa607e9507 100644 --- a/src/BizHawk.Client.Common/DialogControllerExtensions.cs +++ b/src/BizHawk.Client.Common/DialogControllerExtensions.cs @@ -5,6 +5,13 @@ using System.Diagnostics; namespace BizHawk.Client.Common { + public enum TryAgainResult + { + Saved, + IgnoredFailure, + Canceled, + } + public static class DialogControllerExtensions { 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. /// /// Returns true on success or if the user said no. Returns false if the user said cancel. - public static bool DoWithTryAgainBox( + public static TryAgainResult DoWithTryAgainBox( this IDialogParent dialogParent, Func action, string message) @@ -94,12 +101,12 @@ namespace BizHawk.Client.Common $"{fileResult.UserFriendlyErrorMessage()}\n{fileResult.Exception!.Message}", caption: "Error", icon: EMsgBoxIcon.Error); - if (askResult == null) return false; - if (askResult == false) return true; + if (askResult == null) return TryAgainResult.Canceled; + if (askResult == false) return TryAgainResult.IgnoredFailure; if (askResult == true) fileResult = action(); } - return true; + return TryAgainResult.Saved; } /// Creates and shows a System.Windows.Forms.OpenFileDialog or equivalent with the receiver () as its parent diff --git a/src/BizHawk.Client.Common/FileWriter.cs b/src/BizHawk.Client.Common/FileWriter.cs index 8a0a83c22d..227ebb0168 100644 --- a/src/BizHawk.Client.Common/FileWriter.cs +++ b/src/BizHawk.Client.Common/FileWriter.cs @@ -56,6 +56,22 @@ namespace BizHawk.Client.Common return createResult.Value.CloseAndDispose(backupPath); } + public static FileWriteResult Write(string path, Action writeCallback, string? backupPath = null) + { + FileWriteResult 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); + } /// /// 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); try { + Directory.CreateDirectory(Path.GetDirectoryName(path)); FileStream fs = new(writePath, FileMode.Create, FileAccess.Write); return new(new FileWriter(paths, fs), paths); } diff --git a/src/BizHawk.Client.Common/lua/LuaFileList.cs b/src/BizHawk.Client.Common/lua/LuaFileList.cs index 13784bf6f8..15b2493c0a 100644 --- a/src/BizHawk.Client.Common/lua/LuaFileList.cs +++ b/src/BizHawk.Client.Common/lua/LuaFileList.cs @@ -102,9 +102,8 @@ namespace BizHawk.Client.Common return true; } - public void Save(string path) + public FileWriteResult Save(string path) { - using var sw = new StreamWriter(path); var sb = new StringBuilder(); var saveDirectory = Path.GetDirectoryName(Path.GetFullPath(path)); 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; - Changes = false; + if (!result.IsError) + { + Filename = path; + Changes = false; + } + + return result; } } } diff --git a/src/BizHawk.Client.Common/movie/MovieSession.cs b/src/BizHawk.Client.Common/movie/MovieSession.cs index d63501bf4a..52055e4ce9 100644 --- a/src/BizHawk.Client.Common/movie/MovieSession.cs +++ b/src/BizHawk.Client.Common/movie/MovieSession.cs @@ -385,6 +385,8 @@ namespace BizHawk.Client.Common switch (Settings.MovieEndAction) { case MovieEndAction.Stop: + // Technically this can save the movie, but it'd be weird to be in that situation. + // Do we want that? StopMovie(); break; case MovieEndAction.Record: diff --git a/src/BizHawk.Client.Common/tools/CheatList.cs b/src/BizHawk.Client.Common/tools/CheatList.cs index a9cca688a9..5de61df7a3 100644 --- a/src/BizHawk.Client.Common/tools/CheatList.cs +++ b/src/BizHawk.Client.Common/tools/CheatList.cs @@ -88,20 +88,10 @@ namespace BizHawk.Client.Common return file.Exists && Load(domains, file.FullName, false); } - public void NewList(string defaultFileName, bool autosave = false) + public void NewList(string defaultFileName) { _defaultFileName = defaultFileName; - if (autosave && _changes && _cheatList.Count is not 0) - { - if (string.IsNullOrEmpty(CurrentFileName)) - { - CurrentFileName = _defaultFileName; - } - - Save(); - } - _cheatList.Clear(); CurrentFileName = ""; Changes = false; @@ -220,7 +210,7 @@ namespace BizHawk.Client.Common public bool IsActive(MemoryDomain domain, long address) => _cheatList.Exists(cheat => !cheat.IsSeparator && cheat.Enabled && cheat.Domain == domain && cheat.Contains(address)); - public void SaveOnClose() + public FileWriteResult SaveOnClose() { if (_config.AutoSaveOnClose) { @@ -231,17 +221,27 @@ namespace BizHawk.Client.Common CurrentFileName = _defaultFileName; } - SaveFile(CurrentFileName); + return SaveFile(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); + return new(); } } + + return new(); } - public bool Save() + public FileWriteResult Save() { if (string.IsNullOrWhiteSpace(CurrentFileName)) { @@ -251,54 +251,51 @@ namespace BizHawk.Client.Common 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(); - var sb = new StringBuilder(); - - foreach (var cheat in _cheatList) + if (cheat.IsSeparator) { - if (cheat.IsSeparator) - { - 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); - } + sb.AppendLine("----"); } + 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; _config.Recent.Add(CurrentFileName); Changes = false; - return true; - } - catch - { - return false; } + return result; } public bool Load(IMemoryDomains domains, string path, bool append) diff --git a/src/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs b/src/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs index 0a3e12d913..eb5afeb1de 100644 --- a/src/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs +++ b/src/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; @@ -338,39 +339,37 @@ namespace BizHawk.Client.Common } } - public bool Save() + public FileWriteResult Save() { 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.Append("SystemID ").AppendLine(_systemId); - - foreach (var watch in _watchList) - { - sb.AppendLine(watch.ToString()); - } - - sw.WriteLine(sb.ToString()); + sb.AppendLine(watch.ToString()); } - Changes = false; - return true; + FileWriteResult result = FileWriter.Write(CurrentFileName, (fs) => + { + 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) - { - CurrentFileName = file.FullName; - return Save(); - } + Debug.Assert(file != null, "Cannot save as without a file name."); - return false; + CurrentFileName = file.FullName; + return Save(); } private bool LoadFile(string path, bool append) diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index 4bfebc1358..0479ab9f8b 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -3934,7 +3934,7 @@ namespace BizHawk.Client.EmuHawk if (previousRom != CurrentlyOpenRom) { - CheatList.NewList(Tools.GenerateDefaultCheatFilename(), autosave: true); + CheatList.NewList(Tools.GenerateDefaultCheatFilename()); if (Config.Cheats.LoadFileByGame && Emulator.HasMemoryDomains()) { if (CheatList.AttemptToLoadCheatFile(Emulator.AsMemoryDomains())) @@ -3951,7 +3951,7 @@ namespace BizHawk.Client.EmuHawk } else { - CheatList.NewList(Tools.GenerateDefaultCheatFilename(), autosave: true); + CheatList.NewList(Tools.GenerateDefaultCheatFilename()); } } @@ -3988,7 +3988,7 @@ namespace BizHawk.Client.EmuHawk DisplayManager.UpdateGlobals(Config, Emulator); DisplayManager.Blank(); ExtToolManager.BuildToolStrip(); - CheatList.NewList("", autosave: true); + CheatList.NewList(""); OnRomChanged(); return false; } @@ -4050,25 +4050,30 @@ namespace BizHawk.Client.EmuHawk { CommitCoreSettingsToConfig(); // Must happen before stopping the movie, since it checks for active movie. + GameIsClosing = true; if (!Tools.AskSave()) { + GameIsClosing = false; return false; } // There is a cheats tool, but cheats can be active while the "cheats tool" is not. And have auto-save option. - CheatList.SaveOnClose(); - - GameIsClosing = true; - FileWriteResult saveResult = MovieSession.StopMovie(); - GameIsClosing = false; - if (saveResult.IsError) + TryAgainResult cheatSaveResult = this.DoWithTryAgainBox(CheatList.SaveOnClose, "Failed to save cheats."); + if (cheatSaveResult == TryAgainResult.Canceled) { - if (!this.ModalMessageBox2( - caption: "Quit anyway?", - icon: EMsgBoxIcon.Question, - text: "The currently playing movie could not be saved. Continue and quit anyway? All unsaved changes will be lost.")) - { - return false; - } + GameIsClosing = false; + return false; + } + + // If TAStudio is open, we already asked about saving the movie. + if (Tools.IsLoaded()) + { + GameIsClosing = false; + } + else + { + TryAgainResult saveMovieResult = this.DoWithTryAgainBox(() => MovieSession.StopMovie(), "Failed to save movie."); + GameIsClosing = false; + if (saveMovieResult == TryAgainResult.Canceled) return false; } if (clearSram) @@ -4076,7 +4081,7 @@ namespace BizHawk.Client.EmuHawk var path = Config.PathEntries.SaveRamAbsolutePath(Game, MovieSession.Movie); if (File.Exists(path)) { - bool clearResult = this.DoWithTryAgainBox(() => { + TryAgainResult clearResult = this.DoWithTryAgainBox(() => { try { File.Delete(path); @@ -4088,7 +4093,7 @@ namespace BizHawk.Client.EmuHawk return new(FileWriteEnum.FailedToDeleteGeneric, new(path, ""), ex); } }, "Failed to clear SRAM."); - if (!clearResult) + if (clearResult == TryAgainResult.Canceled) { return false; } @@ -4096,14 +4101,14 @@ namespace BizHawk.Client.EmuHawk } else if (Emulator.HasSaveRam()) { - bool flushResult = this.DoWithTryAgainBox( + TryAgainResult flushResult = this.DoWithTryAgainBox( () => FlushSaveRAM(), "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."); - if (!stateSaveResult) return false; + TryAgainResult stateSaveResult = this.DoWithTryAgainBox(AutoSaveStateIfConfigured, "Failed to auto-save state."); + if (stateSaveResult == TryAgainResult.Canceled) return false; StopAv(); @@ -4146,7 +4151,7 @@ namespace BizHawk.Client.EmuHawk PauseOnFrame = null; CurrentlyOpenRom = null; CurrentlyOpenRomArgs = null; - CheatList.NewList("", autosave: true); + CheatList.NewList(""); OnRomChanged(); } } diff --git a/src/BizHawk.Client.EmuHawk/tools/CDL.cs b/src/BizHawk.Client.EmuHawk/tools/CDL.cs index 5c12ce5572..317a104128 100644 --- a/src/BizHawk.Client.EmuHawk/tools/CDL.cs +++ b/src/BizHawk.Client.EmuHawk/tools/CDL.cs @@ -214,19 +214,23 @@ namespace BizHawk.Client.EmuHawk { if (_currentFilename != null) { - RunSave(); + bool saveResult2 = RunSave(); 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.ShowMessageBox2("Save changes to CDL session?", "CDL Auto Save", EMsgBoxIcon.Question); - if (!result) + var result = DialogController.ShowMessageBox3("Save changes to CDL session?", "CDL Save", EMsgBoxIcon.Question); + if (result == false) { ShutdownCDL(); return true; } + else if (result == null) + { + ShutdownCDL(); + return false; + } if (string.IsNullOrWhiteSpace(_currentFilename)) { @@ -240,9 +244,9 @@ namespace BizHawk.Client.EmuHawk return false; } - RunSave(); + bool saveResult = RunSave(); ShutdownCDL(); - return true; + return saveResult; } private bool _autoloading; @@ -341,11 +345,20 @@ namespace BizHawk.Client.EmuHawk LoadFile(file.FullName); } - private void RunSave() + /// + /// returns false if the operation was canceled + /// + private bool RunSave() { - _recent.Add(_currentFilename); - using var fs = new FileStream(_currentFilename, FileMode.Create, FileAccess.Write); - _cdl.Save(fs); + TryAgainResult result = this.DoWithTryAgainBox( + () => FileWriter.Write(_currentFilename, _cdl.Save), + "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) @@ -386,8 +399,7 @@ namespace BizHawk.Client.EmuHawk return false; SetCurrentFilename(file.FullName); - RunSave(); - return true; + return RunSave(); } private void SaveAsMenuItem_Click(object sender, EventArgs e) diff --git a/src/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs b/src/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs index 3c8447ea79..0addc928b8 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs @@ -142,7 +142,7 @@ namespace BizHawk.Client.EmuHawk } } - private bool SaveAs() + private FileWriteResult SaveAs() { var fileName = MainForm.CheatList.CurrentFileName; if (string.IsNullOrWhiteSpace(fileName)) @@ -156,7 +156,8 @@ namespace BizHawk.Client.EmuHawk CheatsFSFilterSet, 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) @@ -361,7 +362,12 @@ namespace BizHawk.Client.EmuHawk { if (MainForm.CheatList.Changes) { - if (MainForm.CheatList.Save()) + FileWriteResult result = MainForm.CheatList.Save(); + if (result.IsError) + { + this.ErrorMessageBox(result); + } + else { UpdateMessageLabel(saved: true); } @@ -374,7 +380,12 @@ namespace BizHawk.Client.EmuHawk private void SaveAsMenuItem_Click(object sender, EventArgs e) { - if (SaveAs()) + FileWriteResult result = SaveAs(); + if (result.IsError) + { + this.ErrorMessageBox(result); + } + else { UpdateMessageLabel(saved: true); } diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index 7fdd0e5cd0..c74284f79f 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -681,15 +681,25 @@ namespace BizHawk.Client.EmuHawk return result is not null ? new FileInfo(result) : null; } - private void SaveSessionAs() + private FileWriteResult SaveSessionAs() { var file = GetSaveFileFromUser(); if (file != null) { - LuaImp.ScriptList.Save(file.FullName); - Config.RecentLuaSession.Add(file.FullName); - OutputMessages.Text = $"{file.Name} saved."; + FileWriteResult saveResult = LuaImp.ScriptList.Save(file.FullName); + if (saveResult.IsError) + { + 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) @@ -717,7 +727,11 @@ namespace BizHawk.Client.EmuHawk icon: EMsgBoxIcon.Question, text: $"Save {WindowTitleStatic} session?")); 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; return true; } @@ -732,16 +746,20 @@ namespace BizHawk.Client.EmuHawk } } - private void SaveOrSaveAs() + private FileWriteResult SaveOrSaveAs() { if (!string.IsNullOrWhiteSpace(LuaImp.ScriptList.Filename)) { - LuaImp.ScriptList.Save(LuaImp.ScriptList.Filename); - Config.RecentLuaSession.Add(LuaImp.ScriptList.Filename); + FileWriteResult result = LuaImp.ScriptList.Save(LuaImp.ScriptList.Filename); + if (!result.IsError) + { + Config.RecentLuaSession.Add(LuaImp.ScriptList.Filename); + } + return result; } else { - SaveSessionAs(); + return SaveSessionAs(); } } @@ -784,8 +802,16 @@ namespace BizHawk.Client.EmuHawk { if (LuaImp.ScriptList.Changes) { - SaveOrSaveAs(); - OutputMessages.Text = $"{Path.GetFileName(LuaImp.ScriptList.Filename)} saved."; + FileWriteResult result = SaveOrSaveAs(); + 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."; + } } } diff --git a/src/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.cs b/src/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.cs index dc865572e0..a3758c05ce 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.cs @@ -112,6 +112,7 @@ namespace BizHawk.Client.EmuHawk return true; } + // Intentionally not updating this to use FileWriter because this tool is going to be removed later. foreach (var zone in _unsavedZones) { SaveMacroAs(_zones[zone]); diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.IToolForm.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.IToolForm.cs index 3b8a33b1e5..16e9ea4302 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.IToolForm.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.IToolForm.cs @@ -161,15 +161,8 @@ namespace BizHawk.Client.EmuHawk text: $"Save {WindowTitleStatic} project?")); if (shouldSaveResult == true) { - FileWriteResult saveResult = SaveTas(); - while (saveResult.IsError && shouldSaveResult != true) - { - shouldSaveResult = this.ModalMessageBox3( - $"Failed to save movie. {saveResult.UserFriendlyErrorMessage()}\n{saveResult.Exception.Message}\n\nTry again?", - "Error", - EMsgBoxIcon.Error); - if (shouldSaveResult == true) saveResult = SaveTas(); - } + TryAgainResult saveResult = this.DoWithTryAgainBox(() => SaveTas(), "Failed to save movie."); + return saveResult != TryAgainResult.Canceled; } if (shouldSaveResult is null) return false; else CurrentTasMovie.ClearChanges(); diff --git a/src/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs b/src/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs index 6a303c2a95..07921b0b22 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs @@ -1008,7 +1008,13 @@ namespace BizHawk.Client.EmuHawk 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; MessageLabel.Text = $"{Path.GetFileName(_currentFileName)} saved"; @@ -1017,11 +1023,20 @@ namespace BizHawk.Client.EmuHawk } else { - var result = watches.SaveAs(GetWatchSaveFileFromUser(CurrentFileName())); - if (result) + FileInfo/*?*/ file = GetWatchSaveFileFromUser(CurrentFileName()); + if (file != null) { - MessageLabel.Text = $"{Path.GetFileName(_currentFileName)} saved"; - Settings.RecentSearches.Add(watches.CurrentFileName); + var result = watches.SaveAs(file); + 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]); } - 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; MessageLabel.Text = $"{Path.GetFileName(_currentFileName)} saved"; diff --git a/src/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/src/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index e54bf3a62f..9555251765 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -213,15 +213,8 @@ namespace BizHawk.Client.EmuHawk if (result is null) return false; if (result.Value) { - if (string.IsNullOrWhiteSpace(_watches.CurrentFileName)) - { - SaveAs(); - } - else - { - _watches.Save(); - Config.RecentWatches.Add(_watches.CurrentFileName); - } + TryAgainResult saveResult = this.DoWithTryAgainBox(Save, "Failed to save watch list."); + return saveResult != TryAgainResult.Canceled; } else { @@ -591,14 +584,47 @@ namespace BizHawk.Client.EmuHawk : Game.FilesystemSafeName(); } - private void SaveAs() + private FileWriteResult SaveAs() { - var result = _watches.SaveAs(GetWatchSaveFileFromUser(CurrentFileName())); - if (result) + FileInfo/*?*/ file = GetWatchSaveFileFromUser(CurrentFileName()); + if (file == null) return new(); + + FileWriteResult result = _watches.SaveAs(file); + if (result.IsError) { - UpdateStatusBar(saved: true); - Config.RecentWatches.Add(_watches.CurrentFileName); + 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 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() @@ -727,23 +753,20 @@ namespace BizHawk.Client.EmuHawk private void SaveMenuItem_Click(object sender, EventArgs e) { - if (!string.IsNullOrWhiteSpace(_watches.CurrentFileName)) + FileWriteResult saveResult = Save(); + if (saveResult.IsError) { - if (_watches.Save()) - { - Config.RecentWatches.Add(_watches.CurrentFileName); - UpdateStatusBar(saved: true); - } - } - else - { - SaveAs(); + this.ErrorMessageBox(saveResult, "Failed to save watch list."); } } 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)