diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 9a8e27f395..2142a478f9 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -509,6 +509,8 @@ void Preset::save(DynamicPrintConfig* parent_config) else from_str = std::string("Default"); + boost::filesystem::create_directories(fs::path(this->file).parent_path()); + //BBS: only save difference if it has parent if (parent_config) { DynamicPrintConfig temp_config; @@ -530,6 +532,23 @@ void Preset::save(DynamicPrintConfig* parent_config) this->save_info(idx_file.string()); } +void Preset::reload(Preset const &parent) +{ + DynamicPrintConfig config; + // BBS: change to json format + // ConfigSubstitutions config_substitutions = config.load_from_ini(preset.file, substitution_rule); + std::map key_values; + std::string reason; + ForwardCompatibilitySubstitutionRule substitution_rule = ForwardCompatibilitySubstitutionRule::Disable; + try { + ConfigSubstitutions config_substitutions = config.load_from_json(file, substitution_rule, key_values, reason); + this->config = parent.config; + this->config.apply(std::move(config)); + } catch (const std::exception &err) { + BOOST_LOG_TRIVIAL(error) << boost::format("Failed loading the user-config file: %1%. Reason: %2%") % file % err.what(); + } +} + // Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty. std::string Preset::label(bool no_alias) const { @@ -1042,6 +1061,11 @@ void PresetCollection::load_presets( // see https://github.com/prusa3d/PrusaSlicer/issues/732 boost::filesystem::path dir = boost::filesystem::absolute(boost::filesystem::path(dir_path) / subdir).make_preferred(); + // Load custom roots first + if (fs::exists(dir / "base")) { + load_presets(dir.string(), "base", substitutions, substitution_rule); + } + //BBS: add config related logs BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, load presets from %1%, current type %2%")%dir %Preset::get_type_string(m_type); //BBS do not parse folder if not exists @@ -1110,6 +1134,8 @@ void PresetCollection::load_presets( if (key_values.find(BBL_JSON_KEY_IS_CUSTOM) != key_values.end()) preset.custom_defined = key_values[BBL_JSON_KEY_IS_CUSTOM]; + if (key_values.find("instantiation") != key_values.end()) + preset.is_visible = key_values["instantiation"] != "false"; //BBS: use inherit config as the base Preset* inherit_preset = nullptr; @@ -1129,12 +1155,12 @@ void PresetCollection::load_presets( preset.filament_id = inherit_preset->filament_id; } else { - if (!preset.is_custom_defined()) { + // We support custom root preset now + auto inherits_config2 = dynamic_cast(inherits_config); + if ((inherits_config2 && !inherits_config2->value.empty()) && !preset.is_custom_defined()) { BOOST_LOG_TRIVIAL(error) << boost::format("can not find parent for config %1%!")%preset.file; continue; } - //should not happen - //BOOST_LOG_TRIVIAL(error) << boost::format("can not find parent for config %1%!")%preset.file; // Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field. preset.config = default_preset.config; } @@ -1243,16 +1269,19 @@ int PresetCollection::get_differed_values_to_update(Preset& preset, std::mapserialize(); } - //add other values - key_values[BBL_JSON_KEY_VERSION] = preset.version.to_string(); - key_values[BBL_JSON_KEY_BASE_ID] = preset.base_id; - key_values[BBL_JSON_KEY_UPDATE_TIME] = std::to_string(preset.updated_time); - key_values[BBL_JSON_KEY_TYPE] = Preset::get_iot_type_string(preset.type); } else { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" Error: can not find the parent! Should not happen, name %1%") %preset.name; - return -1; + for (auto iter = preset.config.cbegin(); iter != preset.config.cend(); ++iter) + { + key_values[iter->first] = iter->second->serialize(); + } } + + //add other values + key_values[BBL_JSON_KEY_VERSION] = preset.version.to_string(); + key_values[BBL_JSON_KEY_BASE_ID] = preset.base_id; + key_values[BBL_JSON_KEY_UPDATE_TIME] = std::to_string(preset.updated_time); + key_values[BBL_JSON_KEY_TYPE] = Preset::get_iot_type_string(preset.type); return 0; } @@ -1397,6 +1426,13 @@ void PresetCollection::set_sync_info_and_save(std::string name, std::string sett preset->sync_info.clear(); else preset->sync_info = syncinfo; + if (get_preset_base(*preset) == preset) { + for (auto preset2 : m_presets) + if (preset2.inherits() == preset->name) { + preset2.base_id = setting_id; + preset2.save_info(); + } + } preset->setting_id = setting_id; if (update_time > 0) preset->updated_time = update_time; @@ -1425,6 +1461,8 @@ int PresetCollection::get_user_presets(std::vector& result_presets) lock(); for (Preset &preset : m_presets) { if (!preset.is_user()) continue; + if (get_preset_base(preset) != &preset && preset.base_id.empty()) continue; + if (!preset.setting_id.empty() && preset.sync_info.empty()) continue; result_presets.push_back(preset); count++; @@ -1463,7 +1501,7 @@ void PresetCollection::save_user_presets(const std::string& dir_path, const std: if (!preset->is_user()) continue; if (preset->sync_info != "save") continue; preset->sync_info.clear(); - preset->file = path_from_name(preset->name); + preset->file = path_for_preset(*preset); if (preset->is_custom_defined()) { preset->save(nullptr); @@ -1471,11 +1509,13 @@ void PresetCollection::save_user_presets(const std::string& dir_path, const std: //BBS: only save difference for user preset std::string inherits = Preset::inherits(preset->config); if (inherits.empty()) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" can not find inherits for %1% , should not happen")%preset->name; - // BBS add sync info - preset->sync_info = "delete"; - need_to_delete_list.push_back(preset->setting_id); - delete_name_list.push_back(preset->name); + // We support custom root preset now + //BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" can not find inherits for %1% , should not happen")%preset->name; + //// BBS add sync info + //preset->sync_info = "delete"; + //need_to_delete_list.push_back(preset->setting_id); + //delete_name_list.push_back(preset->name); + preset->save(nullptr); continue; } Preset* parent_preset = this->find_preset(inherits, false, true); @@ -1606,12 +1646,16 @@ bool PresetCollection::load_user_preset(std::string name, std::mapconfig; } else { + // We support custom root preset now + auto inherits_config2 = dynamic_cast(inherits_config); + if (inherits_config2 && !inherits_config2->value.empty()) { + //we should skip this preset here + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip")%name; + unlock(); + return false; + } // Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field. - //new_config = default_preset.config; - //we should skip this preset here - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip")%name; - unlock(); - return false; + new_config = default_preset.config; } new_config.apply(std::move(cloud_config)); Preset::normalize(new_config); @@ -1981,7 +2025,7 @@ std::pair PresetCollection::load_external_preset( } else { //external config - preset.file = path_from_name(preset.name); + preset.file = path_for_preset(preset); //BBS: save full config here for external //we can not reach here preset.save(nullptr); @@ -2058,13 +2102,18 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det //BBS: add lock logic for sync preset in background final_inherits = preset.inherits(); unlock(); + // TODO: apply change from custom root to devided presets. + if (preset.inherits().empty()) { + for (auto &preset2 : m_presets) + if (preset2.inherits() == preset.name) + preset2.reload(preset); + } } else { // Creating a new preset. Preset &preset = *m_presets.insert(it, curr_preset); std::string &inherits = preset.inherits(); std::string old_name = preset.name; preset.name = new_name; - preset.file = this->path_from_name(new_name); preset.vendor = nullptr; preset.alias.clear(); preset.renamed_from.clear(); @@ -2073,16 +2122,13 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det // Clear the link to the parent profile. inherits.clear(); BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": save preset %1% , with detach")%new_name; - } else if (preset.is_system) { - // Inheriting from a system preset. - inherits = /* preset.vendor->name + "/" + */ old_name; - } else if (inherits.empty()) { - // Inheriting from a user preset. Link the new preset to the old preset. - // inherits = old_name; } else { // Inherited from a user preset. Just maintain the "inherited" flag, // meaning it will inherit from either the system preset, or the inherited user preset. + auto base = get_preset_base(curr_preset); + inherits = base ? base->name : ""; } + preset.file = this->path_for_preset(preset); preset.is_default = false; preset.is_system = false; preset.is_external = false; @@ -2128,6 +2174,13 @@ bool PresetCollection::delete_current_preset() Preset &selected = this->get_selected_preset(); if (selected.is_default) return false; + + if (get_preset_base(selected) == &selected) { + for (auto &preset2 : m_presets) + if (preset2.inherits() == selected.name) + return false; + } + //BBS: add project embedded preset logic and refine is_external //if (! selected.is_external && ! selected.is_system) { if (! selected.is_system) { @@ -2177,7 +2230,7 @@ const Preset* PresetCollection::get_selected_preset_parent() const return nullptr; const Preset &selected_preset = this->get_selected_preset(); - if (selected_preset.is_system || selected_preset.is_default) + if (get_preset_base(selected_preset) == &selected_preset) return &selected_preset; const Preset &edited_preset = this->get_edited_preset(); @@ -2225,6 +2278,17 @@ const Preset* PresetCollection::get_preset_parent(const Preset& child) const preset; } +const Preset *PresetCollection::get_preset_base(const Preset &child) const +{ + if (child.is_system) + return &child; + // Handle user preset + if (child.inherits().empty()) + return &child; // this is user root + auto inherits = find_preset(child.inherits()); + return inherits ? get_preset_base(*inherits) : nullptr; +} + // Return vendor of the first parent profile, for which the vendor is defined, or null if such profile does not exist. PresetWithVendorProfile PresetCollection::get_preset_with_vendor_profile(const Preset &preset) const { @@ -2649,12 +2713,20 @@ std::vector PresetCollection::system_preset_names() const } // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. -std::string PresetCollection::path_from_name(const std::string &new_name) const +std::string PresetCollection::path_from_name(const std::string &new_name, bool detach) const { //BBS: change to json format //std::string file_name = boost::iends_with(new_name, ".ini") ? new_name : (new_name + ".ini"); std::string file_name = boost::iends_with(new_name, ".json") ? new_name : (new_name + ".json"); - return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string(); + if (detach) + return (boost::filesystem::path(m_dir_path) / "base" / file_name).make_preferred().string(); + else + return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string(); +} + +std::string PresetCollection::path_for_preset(const Preset &preset) const +{ + return path_from_name(preset.name, get_preset_base(preset) == &preset); } const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConfig &config) const diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index b695d80053..27351b3a74 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -245,6 +245,7 @@ public: //BBS: add logic for only difference save //if parent_config is null, save all keys, otherwise, only save difference void save(DynamicPrintConfig* parent_config); + void reload(Preset const & parent); // Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty. std::string label(bool no_alias) const; @@ -518,6 +519,7 @@ public: // Get parent preset for a child preset, based on the "inherits" field of a child, // where the "inherits" profile name is searched for in both m_presets and m_map_system_profile_renamed. const Preset* get_preset_parent(const Preset& child) const; + const Preset* get_preset_base(const Preset& child) const; // Return the selected preset including the user modifications. Preset& get_edited_preset() { return m_edited_preset; } const Preset& get_edited_preset() const { return m_edited_preset; } @@ -652,7 +654,8 @@ public: bool select_preset_by_name(const std::string &name, bool force); // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. - std::string path_from_name(const std::string &new_name) const; + std::string path_from_name(const std::string &new_name, bool detach = false) const; + std::string path_for_preset(const Preset & preset) const; size_t num_default_presets() { return m_num_default_presets; } diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 57bff3b265..c8ca28fe5e 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -577,9 +577,14 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(AppConfig & remove_users_preset(config, &my_presets); std::map>::iterator it; + for (int pass = 0; pass < 2; ++pass) for (it = my_presets.begin(); it != my_presets.end(); it++) { std::string name = it->first; std::map& value_map = it->second; + // Load user root presets at first pass + std::map::iterator inherits_iter = value_map.find(BBL_JSON_KEY_INHERITS); + if ((pass == 1) == (inherits_iter == value_map.end() || inherits_iter->second.empty())) + continue; //get the type first std::map::iterator type_iter = value_map.find(BBL_JSON_KEY_TYPE); if (type_iter == value_map.end()) { @@ -694,15 +699,20 @@ PresetsConfigSubstitutions PresetBundle::import_presets(std::vector if (inherit_preset) { new_config = inherit_preset->config; } else { + // We support custom root preset now + auto inherits_config2 = dynamic_cast(inherits_config); + if (inherits_config2 && !inherits_config2->value.empty()) { + // we should skip this preset here + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip") % name; + continue; + } // Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field. - // new_config = default_preset.config; - // we should skip this preset here - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip") % name; - continue; + const Preset &default_preset = collection->default_preset_for(config); + new_config = default_preset.config; } new_config.apply(std::move(config)); - Preset &preset = collection->load_preset(collection->path_from_name(name), name, std::move(new_config), false); + Preset &preset = collection->load_preset(collection->path_from_name(name, inherit_preset == nullptr), name, std::move(new_config), false); preset.is_external = true; preset.version = *version; inherit_preset = collection->find_preset(inherits_value, false, true); // pointer maybe wrong after insert, redo find @@ -1988,7 +1998,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool if (is_external) presets.load_external_preset(name_or_path, name, config.opt_string(key, true), config, different_keys, PresetCollection::LoadAndSelect::Always, file_version, filament_id); else - presets.load_preset(presets.path_from_name(name), name, config, selected, file_version, is_custom_defined).save(nullptr); + presets.load_preset(presets.path_from_name(name, inherits.empty()), name, config, selected, file_version, is_custom_defined).save(nullptr); }; switch (Preset::printer_technology(config)) { @@ -2057,7 +2067,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool loaded = this->filaments.load_external_preset(name_or_path, name, old_filament_profile_names->values.front(), config, filament_different_keys_set, PresetCollection::LoadAndSelect::Always, file_version, filament_id).first; else { // called from Config Wizard. - loaded= &this->filaments.load_preset(this->filaments.path_from_name(name), name, config, true, file_version, is_custom_defined); + loaded= &this->filaments.load_preset(this->filaments.path_from_name(name, inherits.empty()), name, config, true, file_version, is_custom_defined); loaded->save(nullptr); } this->filament_presets.clear(); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index b15feb5ae9..ec01080567 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -4481,7 +4481,7 @@ void GUI_App::sync_preset(Preset* preset) if (preset->is_custom_defined()) return; auto setting_id = preset->setting_id; - if (setting_id.empty() && preset->sync_info.empty() && !preset->base_id.empty()) { + if (setting_id.empty() && preset->sync_info.empty()) { std::map values_map; int ret = preset_bundle->get_differed_values_to_update(*preset, values_map); if (!ret) { @@ -4507,7 +4507,7 @@ void GUI_App::sync_preset(Preset* preset) updated_info = "hold"; } } - else if ((preset->sync_info.compare("create") == 0) && !preset->base_id.empty()) { + else if (preset->sync_info.compare("create") == 0) { std::map values_map; int ret = preset_bundle->get_differed_values_to_update(*preset, values_map); if (!ret) { @@ -4531,7 +4531,7 @@ void GUI_App::sync_preset(Preset* preset) BOOST_LOG_TRIVIAL(trace) << "[sync_preset]create: can not generate differed preset"; } } - else if ((preset->sync_info.compare("update") == 0) && !preset->base_id.empty()) { + else if (preset->sync_info.compare("update") == 0) { if (!setting_id.empty()) { std::map values_map; int ret = preset_bundle->get_differed_values_to_update(*preset, values_map); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index e7fde74817..d08689ae64 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4702,12 +4702,31 @@ void Tab::delete_preset() std::string action = _utf8(L("Delete")); //std::string action = current_preset.is_external ? _utf8(L("remove")) : _utf8(L("delete")); // TRN remove/delete + wxString msg; + + if (m_presets->get_preset_base(current_preset) == ¤t_preset) { + int count = 0; + wxString presets; + for (auto &preset2 : *m_presets) + if (preset2.inherits() == current_preset.name) { + ++count; + presets += "\n - " + preset2.name; + } + if (count > 0) { + msg = _L("Presets inherited by other presets cannot be deleted"); + msg += "\n"; + msg += _L_PLURAL("The following presets inherits this preset.", + "The following preset inherits this preset.", count); + wxString title = from_u8((boost::format(_utf8(L("%1% Preset"))) % action).str()); // action + _(L(" Preset")); + MessageDialog(parent(), msg + presets, title, wxOK | wxICON_ERROR).ShowModal(); + return; + } + } BOOST_LOG_TRIVIAL(info) << boost::format("delete preset %1%, setting_id %2%, user_id %3%, base_id %4%, sync_info %5%, type %6%") %current_preset.name%current_preset.setting_id%current_preset.user_id%current_preset.base_id%current_preset.sync_info %Preset::get_type_string(m_type); PhysicalPrinterCollection& physical_printers = m_preset_bundle->physical_printers; - wxString msg; if (m_type == Preset::TYPE_PRINTER && !physical_printers.empty()) {