Check unsaved changes (#6991)

* Check Unsaved changes (partially related to #5903)
 + Allow create new project when Plater is empty, but some of presets are modified (related to #5903)
 + When creating new project allow Keep or Discard modification from previous project
 + Added check of changes:
    * before any load project (including DnD and "Load From Recent Projects")
    * before preset updater
    * when configuration is changing from the ConfigWizard
 + Dialog caption is added for each check

 + Create/Destroy ConfigWizard every time when it's called

* Check Unsaved changes: Next Improvements
 + For dialog "Save project changes" added a reason of saving and name of the current project (or "Untitled")
 + UnsavedChangesDialog: Headers are extended to better explain the reason
 + Preferences: Fixed tooltiops for "Always ask for unsaved changes when..."
 + Suppress "Remember my choice" checkbox for actions which are not frequently used

* Fixed behavior of the application when try to save changed project but "Cancel" button is selected in "Save file as..." dialog

* Check unsaved changes: Improvements for Config Wizard - Check all cases when presets should be updated
 + Fixed info line for Materials pages. Text of the info relates to the printer technology now

* Improved suggested name for a project when Application is closing

* Fixed Linux/OSX build warnings
This commit is contained in:
Oleksandra Yushchenko 2021-09-22 12:44:13 +02:00 committed by GitHub
parent 846b868215
commit 8f064dd155
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 462 additions and 178 deletions

View file

@ -1575,16 +1575,22 @@ struct Plater::priv
bool is_project_dirty() const { return dirty_state.is_dirty(); }
void update_project_dirty_from_presets() { dirty_state.update_from_presets(); }
int save_project_if_dirty() {
int save_project_if_dirty(const wxString& reason) {
int res = wxID_NO;
if (dirty_state.is_dirty()) {
MainFrame* mainframe = wxGetApp().mainframe;
if (mainframe->can_save_as()) {
//wxMessageDialog dlg(mainframe, _L("Do you want to save the changes to the current project ?"), wxString(SLIC3R_APP_NAME), wxYES_NO | wxCANCEL);
MessageDialog dlg(mainframe, _L("Do you want to save the changes to the current project ?"), wxString(SLIC3R_APP_NAME), wxYES_NO | wxCANCEL);
res = dlg.ShowModal();
wxString suggested_project_name;
wxString project_name = suggested_project_name = get_project_filename(".3mf");
if (suggested_project_name.IsEmpty()) {
fs::path output_file = get_export_file_path(FT_3MF);
suggested_project_name = output_file.empty() ? _L("Untitled") : from_u8(output_file.stem().string());
}
res = MessageDialog(mainframe, reason + "\n" + format_wxstr(_L("Do you want to save the changes to \"%1%\"?"), suggested_project_name),
wxString(SLIC3R_APP_NAME), wxYES_NO | wxCANCEL).ShowModal();
if (res == wxID_YES)
mainframe->save_project_as(wxGetApp().plater()->get_project_filename());
if (!mainframe->save_project_as(project_name))
res = wxID_CANCEL;
}
}
return res;
@ -1644,6 +1650,7 @@ struct Plater::priv
std::vector<size_t> load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config, bool used_inches = false);
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false);
fs::path get_export_file_path(GUI::FileType file_type);
wxString get_export_file(GUI::FileType file_type);
const Selection& get_selection() const;
@ -2599,22 +2606,8 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
return obj_idxs;
}
wxString Plater::priv::get_export_file(GUI::FileType file_type)
fs::path Plater::priv::get_export_file_path(GUI::FileType file_type)
{
wxString wildcard;
switch (file_type) {
case FT_STL:
case FT_AMF:
case FT_3MF:
case FT_GCODE:
case FT_OBJ:
wildcard = file_wildcards(file_type);
break;
default:
wildcard = file_wildcards(FT_MODEL);
break;
}
// Update printbility state of each of the ModelInstances.
this->update_print_volume_state();
@ -2639,7 +2632,31 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type)
if (output_file.empty() && !model.objects.empty())
// Find the file name of the first object.
output_file = this->model.objects[0]->get_export_filename();
if (output_file.empty())
// Use _L("Untitled") name
output_file = into_path(_L("Untitled"));
}
return output_file;
}
wxString Plater::priv::get_export_file(GUI::FileType file_type)
{
wxString wildcard;
switch (file_type) {
case FT_STL:
case FT_AMF:
case FT_3MF:
case FT_GCODE:
case FT_OBJ:
wildcard = file_wildcards(file_type);
break;
default:
wildcard = file_wildcards(FT_MODEL);
break;
}
fs::path output_file = get_export_file_path(file_type);
wxString dlg_title;
switch (file_type) {
@ -4714,8 +4731,10 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
if (printer_technology_changed) {
// Switching the printer technology when jumping forwards / backwards in time. Switch to the last active printer profile of the other type.
std::string s_pt = (it_snapshot->snapshot_data.printer_technology == ptFFF) ? "FFF" : "SLA";
if (!wxGetApp().check_and_save_current_preset_changes(format_wxstr(_L(
"%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."), s_pt)))
if (!wxGetApp().check_and_save_current_preset_changes(_L("Undo / Redo is processing"),
// format_wxstr(_L("%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."), s_pt)))
format_wxstr(_L("Switching the printer technology from %1% to %2%.\n"
"Some %1% presets were modified, which will be lost after switching the printer technology."), s_pt =="FFF" ? "SLA" : "FFF", s_pt), false))
// Don't switch the profiles.
return;
}
@ -4893,7 +4912,7 @@ Plater::Plater(wxWindow *parent, MainFrame *main_frame)
bool Plater::is_project_dirty() const { return p->is_project_dirty(); }
void Plater::update_project_dirty_from_presets() { p->update_project_dirty_from_presets(); }
int Plater::save_project_if_dirty() { return p->save_project_if_dirty(); }
int Plater::save_project_if_dirty(const wxString& reason) { return p->save_project_if_dirty(reason); }
void Plater::reset_project_dirty_after_save() { p->reset_project_dirty_after_save(); }
void Plater::reset_project_dirty_initial_presets() { p->reset_project_dirty_initial_presets(); }
#if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW
@ -4910,8 +4929,20 @@ SLAPrint& Plater::sla_print() { return p->sla_print; }
void Plater::new_project()
{
if (p->save_project_if_dirty() == wxID_CANCEL)
if (int saved_project = p->save_project_if_dirty(_L("Creating a new project while the current project is modified.")); saved_project == wxID_CANCEL)
return;
else {
wxString header = _L("Creating a new project while some presets are modified.") + "\n" +
(saved_project == wxID_YES ? _L("You can keep presets modifications to the new project or discard them") :
_L("You can keep presets modifications to the new project, discard them or save changes as new presets.\n"
"Note, if changes will be saved than new project wouldn't keep them"));
using ab = UnsavedChangesDialog::ActionButtons;
int act_buttons = ab::KEEP;
if (saved_project == wxID_NO)
act_buttons |= ab::SAVE;
if (!wxGetApp().check_and_keep_current_preset_changes(_L("New Project is creating"), header, act_buttons))
return;
}
p->select_view_3D("3D");
take_snapshot(_L("New Project"));
@ -4923,7 +4954,7 @@ void Plater::new_project()
void Plater::load_project()
{
if (p->save_project_if_dirty() == wxID_CANCEL)
if (!wxGetApp().can_load_project())
return;
// Ask user for a project file name.
@ -5219,7 +5250,8 @@ bool Plater::load_files(const wxArrayString& filenames)
switch (load_type) {
case LoadType::OpenProject: {
load_project(from_path(*it));
if (wxGetApp().can_load_project())
load_project(from_path(*it));
break;
}
case LoadType::LoadGeometry: {