ENH: [STUDIO-4005] support custom root preset

Change-Id: I0cf2142a2d3cee7269b53b73ad44e05934c2e9e6
Jira: STUDIO-4005
This commit is contained in:
chunmao.guo 2023-08-16 10:19:14 +08:00 committed by Lane.Wei
parent 375932aea0
commit f4ffe8621b
5 changed files with 148 additions and 44 deletions

View file

@ -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<std::string, std::string> 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<ConfigOptionString *>(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::map<std
if (opt_src)
key_values[option] = opt_src->serialize();
}
}
else {
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);
}
else {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" Error: can not find the parent! Should not happen, name %1%") %preset.name;
return -1;
}
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<Preset>& 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,13 +1646,17 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
new_config = inherit_preset->config;
}
else {
// 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 support custom root preset now
auto inherits_config2 = dynamic_cast<ConfigOptionString *>(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;
}
new_config.apply(std::move(cloud_config));
Preset::normalize(new_config);
// Report configuration fields, which are misplaced into a wrong group.
@ -1981,7 +2025,7 @@ std::pair<Preset*, bool> 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,14 +2713,22 @@ std::vector<std::string> 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");
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
{
const ConfigOptionEnumGeneric *opt_printer_technology = config.opt<ConfigOptionEnumGeneric>("printer_technology");

View file

@ -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; }

View file

@ -577,9 +577,14 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(AppConfig &
remove_users_preset(config, &my_presets);
std::map<std::string, std::map<std::string, std::string>>::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<std::string, std::string>& value_map = it->second;
// Load user root presets at first pass
std::map<std::string, std::string>::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<std::string, std::string>::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<std::string>
if (inherit_preset) {
new_config = inherit_preset->config;
} else {
// 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 support custom root preset now
auto inherits_config2 = dynamic_cast<ConfigOptionString *>(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.
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();

View file

@ -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<std::string, std::string> 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<std::string, std::string> 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<std::string, std::string> values_map;
int ret = preset_bundle->get_differed_values_to_update(*preset, values_map);

View file

@ -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) == &current_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())
{