diff --git a/src/cocoa/cocoamain.mm b/src/cocoa/cocoamain.mm index b160a57f..ea2debee 100644 --- a/src/cocoa/cocoamain.mm +++ b/src/cocoa/cocoamain.mm @@ -791,7 +791,7 @@ bool SolveSpace::GetSaveFile(std::string &file, const std::string &defExtension, } } -int SolveSpace::SaveFileYesNoCancel(void) { +SolveSpace::DialogChoice SolveSpace::SaveFileYesNoCancel(void) { NSAlert *alert = [[NSAlert alloc] init]; if(!std::string(SolveSpace::SS.saveFile).empty()) { [alert setMessageText: @@ -809,16 +809,16 @@ int SolveSpace::SaveFileYesNoCancel(void) { [alert addButtonWithTitle:@"Don't Save"]; switch([alert runModal]) { case NSAlertFirstButtonReturn: - return SAVE_YES; + return DIALOG_YES; case NSAlertSecondButtonReturn: - return SAVE_CANCEL; + default: + return DIALOG_CANCEL; case NSAlertThirdButtonReturn: - return SAVE_NO; + return DIALOG_NO; } - abort(); /* unreachable */ } -int SolveSpace::LoadAutosaveYesNo(void) { +SolveSpace::DialogChoice SolveSpace::LoadAutosaveYesNo(void) { NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText: @"An autosave file is availible for this project."]; @@ -828,11 +828,37 @@ int SolveSpace::LoadAutosaveYesNo(void) { [alert addButtonWithTitle:@"Don't Load"]; switch([alert runModal]) { case NSAlertFirstButtonReturn: - return SAVE_YES; + return DIALOG_YES; case NSAlertSecondButtonReturn: - return SAVE_NO; + default: + return DIALOG_NO; + } +} + +SolveSpace::DialogChoice SolveSpace::LocateImportedFileYesNoCancel( + const std::string &filename, bool canCancel) { + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:[NSString stringWithUTF8String: + ("The imported file " + filename + " is not present.").c_str()]]; + [alert setInformativeText: + @"Do you want to locate it manually?\n" + "If you select \"No\", any geometry that depends on " + "the missing file will be removed."]; + [alert addButtonWithTitle:@"Yes"]; + if(canCancel) + [alert addButtonWithTitle:@"Cancel"]; + [alert addButtonWithTitle:@"No"]; + switch([alert runModal]) { + case NSAlertFirstButtonReturn: + return DIALOG_YES; + case NSAlertSecondButtonReturn: + default: + if(canCancel) + return DIALOG_CANCEL; + /* fallthrough */ + case NSAlertThirdButtonReturn: + return DIALOG_NO; } - abort(); /* unreachable */ } /* Text window */ diff --git a/src/file.cpp b/src/file.cpp index cf72bcf4..95eefe59 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -765,8 +765,9 @@ static std::string PathSepUNIXToPlatform(const std::string &filename) #endif } -void SolveSpaceUI::ReloadAllImported(void) +bool SolveSpaceUI::ReloadAllImported(bool canCancel) { + std::map importMap; allConsistent = false; int i; @@ -785,6 +786,12 @@ void SolveSpaceUI::ReloadAllImported(void) g->impMesh.Clear(); g->impShell.Clear(); + if(importMap.count(g->impFile)) { + std::string newPath = importMap[g->impFile]; + if(!newPath.empty()) + g->impFile = newPath; + } + FILE *test = ssfopen(g->impFile, "rb"); if(test) { fclose(test); // okay, exists @@ -803,6 +810,7 @@ void SolveSpaceUI::ReloadAllImported(void) } } +try_load_file: if(LoadEntitiesFromFile(g->impFile, &(g->impEntity), &(g->impMesh), &(g->impShell))) { if(!SS.saveFile.empty()) { @@ -816,9 +824,34 @@ void SolveSpaceUI::ReloadAllImported(void) // is always nonempty when we are actually writing anything. g->impFileRel = g->impFile; } + } else if(!importMap.count(g->impFile)) { + switch(LocateImportedFileYesNoCancel(g->impFileRel, canCancel)) { + case DIALOG_YES: { + std::string oldImpFile = g->impFile; + if(!GetOpenFile(g->impFile, "", SLVS_PATTERN)) { + if(canCancel) + return false; + break; + } else { + importMap[oldImpFile] = g->impFile; + goto try_load_file; + } + } + + case DIALOG_NO: + importMap[g->impFile] = ""; + /* Geometry will be pruned by GenerateAll(). */ + break; + + case DIALOG_CANCEL: + return false; + } } else { - Error("Failed to load imported file '%s'", g->impFile.c_str()); + // User was already asked to and refused to locate a missing + // imported file. } } + + return true; } diff --git a/src/gtk/gtkmain.cpp b/src/gtk/gtkmain.cpp index d0f085e9..738353d0 100644 --- a/src/gtk/gtkmain.cpp +++ b/src/gtk/gtkmain.cpp @@ -1165,7 +1165,7 @@ bool GetSaveFile(std::string &file, const std::string &activeOrEmpty, } } -int SaveFileYesNoCancel(void) { +DialogChoice SaveFileYesNoCancel(void) { Glib::ustring message = "The file has changed since it was last saved.\n" "Do you want to save the changes?"; @@ -1178,18 +1178,18 @@ int SaveFileYesNoCancel(void) { switch(dialog.run()) { case Gtk::RESPONSE_YES: - return SAVE_YES; + return DIALOG_YES; case Gtk::RESPONSE_NO: - return SAVE_NO; + return DIALOG_NO; case Gtk::RESPONSE_CANCEL: default: - return SAVE_CANCEL; + return DIALOG_CANCEL; } } -int LoadAutosaveYesNo(void) { +DialogChoice LoadAutosaveYesNo(void) { Glib::ustring message = "An autosave file is availible for this project.\n" "Do you want to load the autosave file instead?"; @@ -1201,11 +1201,39 @@ int LoadAutosaveYesNo(void) { switch(dialog.run()) { case Gtk::RESPONSE_YES: - return SAVE_YES; + return DIALOG_YES; case Gtk::RESPONSE_NO: default: - return SAVE_NO; + return DIALOG_NO; + } +} + +DialogChoice LocateImportedFileYesNoCancel(const std::string &filename, + bool canCancel) { + Glib::ustring message = + "The imported file " + filename + " is not present.\n" + "Do you want to locate it manually?\n" + "If you select \"No\", any geometry that depends on " + "the missing file will be removed."; + Gtk::MessageDialog dialog(*GW, message, /*use_markup*/ true, Gtk::MESSAGE_QUESTION, + Gtk::BUTTONS_NONE, /*is_modal*/ true); + dialog.set_title("SolveSpace - Missing File"); + dialog.add_button("_Yes", Gtk::RESPONSE_YES); + dialog.add_button("_No", Gtk::RESPONSE_NO); + if(canCancel) + dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); + + switch(dialog.run()) { + case Gtk::RESPONSE_YES: + return DIALOG_YES; + + case Gtk::RESPONSE_NO: + return DIALOG_NO; + + case Gtk::RESPONSE_CANCEL: + default: + return DIALOG_CANCEL; } } diff --git a/src/solvespace.cpp b/src/solvespace.cpp index 106c817d..ec818ab3 100644 --- a/src/solvespace.cpp +++ b/src/solvespace.cpp @@ -110,7 +110,7 @@ bool SolveSpaceUI::LoadAutosaveFor(const std::string &filename) { return false; fclose(f); - if(LoadAutosaveYesNo() == SAVE_YES) { + if(LoadAutosaveYesNo() == DIALOG_YES) { unsaved = true; return LoadFromFile(autosaveFile); } @@ -120,12 +120,15 @@ bool SolveSpaceUI::LoadAutosaveFor(const std::string &filename) { bool SolveSpaceUI::OpenFile(const std::string &filename) { bool autosaveLoaded = LoadAutosaveFor(filename); - bool success = autosaveLoaded || LoadFromFile(filename); + bool fileLoaded = autosaveLoaded || LoadFromFile(filename); + if(fileLoaded) + saveFile = filename; + bool success = fileLoaded && ReloadAllImported(/*canCancel=*/true); if(success) { RemoveAutosave(); AddToRecentList(filename); - saveFile = filename; } else { + saveFile = ""; NewFile(); } AfterNewFile(); @@ -291,7 +294,6 @@ void SolveSpaceUI::AfterNewFile(void) { SS.GW.projRight = Vector::From(1, 0, 0); SS.GW.projUp = Vector::From(0, 1, 0); - ReloadAllImported(); GenerateAll(-1, -1); TW.Init(); @@ -386,13 +388,13 @@ bool SolveSpaceUI::OkayToStartNewFile(void) { if(!unsaved) return true; switch(SaveFileYesNoCancel()) { - case SAVE_YES: + case DIALOG_YES: return GetFilenameAndSave(false); - case SAVE_NO: + case DIALOG_NO: return true; - case SAVE_CANCEL: + case DIALOG_CANCEL: return false; default: oops(); break; @@ -415,7 +417,6 @@ void SolveSpaceUI::MenuFile(int id) { if(!SS.OkayToStartNewFile()) return; std::string newFile = RecentFile[id - RECENT_OPEN]; - RemoveFromRecentList(newFile); SS.OpenFile(newFile); return; } diff --git a/src/solvespace.h b/src/solvespace.h index 866cb9b7..7bede6c6 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -19,6 +19,7 @@ #include #include #include +#include #ifdef HAVE_STDINT_H # include #endif @@ -146,11 +147,11 @@ void ssremove(const std::string &filename); extern std::string RecentFile[MAX_RECENT]; void RefreshRecentMenus(void); -#define SAVE_YES (1) -#define SAVE_NO (-1) -#define SAVE_CANCEL (0) -int SaveFileYesNoCancel(void); -int LoadAutosaveYesNo(void); +enum DialogChoice { DIALOG_YES = 1, DIALOG_NO = -1, DIALOG_CANCEL = 0 }; +DialogChoice SaveFileYesNoCancel(void); +DialogChoice LoadAutosaveYesNo(void); +DialogChoice LocateImportedFileYesNoCancel(const std::string &filename, + bool canCancel); #define AUTOSAVE_SUFFIX "~" @@ -851,7 +852,7 @@ public: bool LoadFromFile(const std::string &filename); bool LoadEntitiesFromFile(const std::string &filename, EntityList *le, SMesh *m, SShell *sh); - void ReloadAllImported(void); + bool ReloadAllImported(bool canCancel=false); // And the various export options void ExportAsPngTo(const std::string &filename); void ExportMeshTo(const std::string &filename); diff --git a/src/win32/w32main.cpp b/src/win32/w32main.cpp index 10376297..d9d9799e 100644 --- a/src/win32/w32main.cpp +++ b/src/win32/w32main.cpp @@ -1024,13 +1024,13 @@ bool SolveSpace::GetSaveFile(std::string &filename, return OpenSaveFile(false, filename, defExtension, selPattern); } -int SolveSpace::SaveFileYesNoCancel(void) +DialogChoice SolveSpace::SaveFileYesNoCancel(void) { EnableWindow(GraphicsWnd, false); EnableWindow(TextWnd, false); int r = MessageBoxW(GraphicsWnd, - L"The program has changed since it was last saved.\r\n\r\n" + L"The file has changed since it was last saved.\n\n" L"Do you want to save the changes?", L"SolveSpace", MB_YESNOCANCEL | MB_ICONWARNING); @@ -1039,22 +1039,23 @@ int SolveSpace::SaveFileYesNoCancel(void) SetForegroundWindow(GraphicsWnd); switch(r) { - case IDYES: return SAVE_YES; - case IDNO: return SAVE_NO; - case IDCANCEL: return SAVE_CANCEL; + case IDYES: + return DIALOG_YES; + case IDNO: + return DIALOG_NO; + case IDCANCEL: + default: + return DIALOG_CANCEL; } - - oops(); - return SAVE_CANCEL; } -int SolveSpace::LoadAutosaveYesNo(void) +DialogChoice SolveSpace::LoadAutosaveYesNo(void) { EnableWindow(GraphicsWnd, false); EnableWindow(TextWnd, false); int r = MessageBoxW(GraphicsWnd, - L"An autosave file is availible for this project.\r\n\r\n" + L"An autosave file is availible for this project.\n\n" L"Do you want to load the autosave file instead?", L"SolveSpace", MB_YESNO | MB_ICONWARNING); @@ -1063,11 +1064,41 @@ int SolveSpace::LoadAutosaveYesNo(void) SetForegroundWindow(GraphicsWnd); switch (r) { - case IDYES: return SAVE_YES; - case IDNO: return SAVE_NO; + case IDYES: + return DIALOG_YES; + case IDNO: + default: + return DIALOG_NO; } +} - oops(); +DialogChoice SolveSpace::LocateImportedFileYesNoCancel(const std::string &filename, + bool canCancel) { + EnableWindow(GraphicsWnd, false); + EnableWindow(TextWnd, false); + + std::string message = + "The imported file " + filename + " is not present.\n\n" + "Do you want to locate it manually?\n\n" + "If you select \"No\", any geometry that depends on " + "the missing file will be removed."; + + int r = MessageBoxW(GraphicsWnd, Widen(message).c_str(), L"SolveSpace", + (canCancel ? MB_YESNOCANCEL : MB_YESNO) | MB_ICONWARNING); + + EnableWindow(TextWnd, true); + EnableWindow(GraphicsWnd, true); + SetForegroundWindow(GraphicsWnd); + + switch(r) { + case IDYES: + return DIALOG_YES; + case IDNO: + return DIALOG_NO; + case IDCANCEL: + default: + return DIALOG_CANCEL; + } } void SolveSpace::LoadAllFontFiles(void)