Merge branch 'main' into zaa

This commit is contained in:
SoftFever
2026-05-01 18:04:05 +08:00
committed by GitHub
116 changed files with 9029 additions and 3590 deletions

View File

@@ -52,6 +52,78 @@ using boost::property_tree::ptree;
namespace Slic3r {
namespace {
struct ParsedName {
PresetOrigin::Kind kind { PresetOrigin::Kind::User };
std::string bundle_id;
std::string bare;
};
// Canonical names are built in-memory with '/' separators, so a straight prefix+split match is enough.
static ParsedName parse_preset_name(const std::string &raw_name)
{
ParsedName out;
auto try_prefix = [&](const char *dir, PresetOrigin::Kind kind) {
const std::string prefix = std::string(dir) + "/";
if (! boost::starts_with(raw_name, prefix))
return false;
const size_t id_start = prefix.size();
const size_t id_end = raw_name.find('/', id_start);
if (id_end == std::string::npos || id_end == id_start)
return false;
out.kind = kind;
out.bundle_id = raw_name.substr(id_start, id_end - id_start);
out.bare = raw_name.substr(id_end + 1);
return true;
};
if (! try_prefix(PRESET_LOCAL_DIR, PresetOrigin::Kind::LocalBundle) &&
! try_prefix(PRESET_SUBSCRIBED_DIR, PresetOrigin::Kind::SubscribedBundle))
out.bare = raw_name;
return out;
}
} // namespace
std::string get_preset_canonical_name(const std::string &preset_bare_name, const PresetOrigin &origin)
{
switch (origin.kind) {
case PresetOrigin::Kind::LocalBundle:
return origin.bundle_id.empty() ? preset_bare_name : std::string(PRESET_LOCAL_DIR) + "/" + origin.bundle_id + "/" + preset_bare_name;
case PresetOrigin::Kind::SubscribedBundle:
return origin.bundle_id.empty() ? preset_bare_name : std::string(PRESET_SUBSCRIBED_DIR) + "/" + origin.bundle_id + "/" + preset_bare_name;
default:
return preset_bare_name;
}
}
std::string get_preset_bare_name(const std::string &canonical_name)
{
const auto pos = canonical_name.find_last_of('/');
return pos == std::string::npos ? canonical_name : canonical_name.substr(pos + 1);
}
PresetOrigin detect_origin_from_path(const boost::filesystem::path &path, const PresetOrigin &explicit_origin)
{
if (explicit_origin.kind != PresetOrigin::Kind::Auto)
return explicit_origin;
for (auto it = path.begin(); it != path.end(); ++ it) {
const auto next = std::next(it);
if (next == path.end())
break;
const std::string segment = it->string();
if (segment == PRESET_LOCAL_DIR)
return PresetOrigin(PresetOrigin::Kind::LocalBundle, next->string());
if (segment == PRESET_SUBSCRIBED_DIR)
return PresetOrigin(PresetOrigin::Kind::SubscribedBundle, next->string());
}
return PresetOrigin(PresetOrigin::Kind::User);
}
//BBS: add a function to load the version from xxx.json
Semver get_version_from_json(std::string file_path)
{
@@ -522,7 +594,7 @@ void Preset::load_info(const std::string& file)
void Preset::save_info(std::string file)
{
//BBS: add project embedded preset logic
if (this->is_project_embedded)
if (this->is_project_embedded || this->is_from_bundle())
return;
if (file.empty()) {
fs::path idx_file(this->file);
@@ -544,17 +616,26 @@ void Preset::save_info(std::string file)
c.close();
}
void Preset::remove_files()
void Preset::remove_files(bool cloud_already_deleted)
{
//BBS: add project embedded preset logic
if (this->is_project_embedded)
if (this->is_project_embedded) {
return;
}
// Erase the preset file.
boost::nowide::remove(this->file.c_str());
fs::path idx_path(this->file);
idx_path.replace_extension(".info");
if (fs::exists(idx_path))
boost::nowide::remove(idx_path.string().c_str());
if (fs::exists(idx_path)) {
if (!this->setting_id.empty() && !cloud_already_deleted) {
// Cloud-synced preset - mark for deletion and keep .info file until sync confirms
this->sync_info = "delete";
this->save_info(idx_path.string());
} else {
// Local-only preset or cloud already confirmed deletion - safe to delete .info immediately
boost::nowide::remove(idx_path.string().c_str());
}
}
}
//BBS: add logic for only difference save
@@ -570,12 +651,15 @@ void Preset::save(DynamicPrintConfig* parent_config)
from_str = std::string("User");
else if (this->is_project_embedded)
from_str = std::string("Project");
else if (this->is_from_bundle())
from_str = std::string("Bundle");
else if (this->is_system)
from_str = std::string("System");
else
from_str = std::string("Default");
boost::filesystem::create_directories(fs::path(this->file).parent_path());
const std::string bare_name = get_preset_bare_name(this->name);
//BBS: only save difference if it has parent
if (parent_config) {
@@ -615,19 +699,22 @@ void Preset::save(DynamicPrintConfig* parent_config)
opt_dst->set(opt_src);
}
}
temp_config.save_to_json(this->file, this->name, from_str, this->version.to_string());
temp_config.save_to_json(this->file, bare_name, from_str, this->version.to_string());
} else if (!filament_id.empty() && inherits().empty()) {
DynamicPrintConfig temp_config = config;
temp_config.set_key_value(BBL_JSON_KEY_FILAMENT_ID, new ConfigOptionString(filament_id));
temp_config.save_to_json(this->file, this->name, from_str, this->version.to_string());
temp_config.save_to_json(this->file, bare_name, from_str, this->version.to_string());
} else {
this->config.save_to_json(this->file, this->name, from_str, this->version.to_string());
this->config.save_to_json(this->file, bare_name, from_str, this->version.to_string());
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " save config for: " << this->name << " and filament_id: " << filament_id << " and base_id: " << this->base_id;
fs::path idx_file(this->file);
idx_file.replace_extension(".info");
this->save_info(idx_file.string());
// Bundle presets are synced via bundle_id and don't need individual .info files.
if (! this->is_from_bundle()) {
fs::path idx_file(this->file);
idx_file.replace_extension(".info");
this->save_info(idx_file.string());
}
}
void Preset::reload(Preset const &parent)
@@ -1429,19 +1516,34 @@ void PresetCollection::add_default_preset(const std::vector<std::string> &keys,
++ m_num_default_presets;
}
std::string PresetCollection::canonical_preset_name(const std::string &name, const PresetOrigin &load_origin) const
{
const ParsedName parsed = parse_preset_name(name);
PresetOrigin origin = load_origin;
if (origin.kind == PresetOrigin::Kind::Auto) {
origin.kind = parsed.kind;
origin.bundle_id = parsed.bundle_id;
} else if (origin.is_bundle() && origin.bundle_id.empty()) {
origin.bundle_id = parsed.bundle_id;
}
return get_preset_canonical_name(parsed.bare, origin);
}
// Load all presets found in dir_path.
// Throws an exception on error.
void PresetCollection::load_presets(
const std::string &dir_path, const std::string &subdir,
PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule substitution_rule)
PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule substitution_rule,
std::function<void(Preset&)> preset_loaded_fn, const PresetOrigin &load_origin)
{
// Don't use boost::filesystem::canonical() on Windows, it is broken in regard to reparse points,
// see https://github.com/prusa3d/PrusaSlicer/issues/732
boost::filesystem::path dir = boost::filesystem::absolute(boost::filesystem::path(dir_path) / subdir).make_preferred();
const PresetOrigin resolved_origin = detect_origin_from_path(dir, load_origin);
// Load custom roots first
if (fs::exists(dir / "base")) {
load_presets(dir.string(), "base", substitutions, substitution_rule);
load_presets(dir.string(), "base", substitutions, substitution_rule, nullptr, resolved_origin);
}
//BBS: add config related logs
@@ -1471,14 +1573,16 @@ void PresetCollection::load_presets(
if (Slic3r::is_json_file(file_name)) {
// Remove the .ini suffix.
std::string name = file_name.erase(file_name.size() - 5);
if (this->find_preset(name, false)) {
std::string canonical_name = this->canonical_preset_name(name, resolved_origin);
if (this->find_preset(canonical_name, false)) {
// This happens when there's is a preset (most likely legacy one) with the same name as a system preset
// that's already been loaded from a bundle.
BOOST_LOG_TRIVIAL(warning) << "Preset already present, not loading: " << name;
BOOST_LOG_TRIVIAL(warning) << "Preset already present, not loading: " << canonical_name;
continue;
}
try {
Preset preset(m_type, name, false);
Preset preset(m_type, canonical_name, false);
preset.bundle_id = resolved_origin.bundle_id;
preset.file = dir_entry.path().string();
// Load the preset file, apply preset values on top of defaults.
try {
@@ -1529,7 +1633,6 @@ void PresetCollection::load_presets(
std::string inherits_value = option_str->value;
// Orca: try to find if the parent preset has been renamed
inherit_preset = this->find_preset2(inherits_value);
} else {
;
}
@@ -1607,6 +1710,9 @@ void PresetCollection::load_presets(
fs::remove(file_path);
}
if (preset_loaded_fn != nullptr)
preset_loaded_fn(preset);
presets_loaded.emplace_back(preset);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " load config successful and preset name is:" << preset.name;
} catch (const std::runtime_error &err) {
@@ -1778,7 +1884,7 @@ void PresetCollection::load_project_embedded_presets(std::vector<Preset*>& proje
inherits_value.replace(pos, 1, 1, '~');
option_str->value = inherits_value;
}*/
inherit_preset = this->find_preset(inherits_value, false, true);
inherit_preset = this->find_preset2(inherits_value, true);
}
const Preset& default_preset = this->default_preset_for(config);
if (inherit_preset) {
@@ -1879,9 +1985,10 @@ bool PresetCollection::reset_project_embedded_presets()
void PresetCollection::set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo, long long update_time)
{
lock();
const std::string canonical_name = this->canonical_preset_name(name);
for (auto it = m_presets.begin(); it != m_presets.end(); it++) {
Preset* preset = &m_presets[it - m_presets.begin()];
if (preset->name == name) {
if (preset->name == canonical_name) {
if (syncinfo.empty())
preset->sync_info.clear();
else
@@ -1946,7 +2053,7 @@ void PresetCollection::update_user_presets_directory(const std::string& dir_path
}
//BBS: save user presets to local
void PresetCollection::save_user_presets(const std::string& dir_path, const std::string& type, std::vector<std::string>& need_to_delete_list)
void PresetCollection::save_user_presets(const std::string& dir_path, const std::string& type, std::map<std::string, std::string>& need_to_delete_list)
{
boost::filesystem::path dir = boost::filesystem::absolute(boost::filesystem::path(dir_path) / type).make_preferred();
@@ -2000,31 +2107,37 @@ void PresetCollection::save_user_presets(const std::string& dir_path, const std:
}
//BBS: load one user preset from key-values
bool PresetCollection::load_user_preset(std::string name, std::map<std::string, std::string> preset_values, PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule rule)
bool PresetCollection::load_user_preset(std::string name, std::map<std::string, std::string> preset_values, PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule rule, const PresetOrigin &load_origin)
{
std::string errors_cummulative;
// Store the loaded presets into a new vector, otherwise the binary search for already existing presets would be broken.
// (see the "Preset already present, not loading" message).
//std::deque<Preset> presets_loaded;
int count = 0;
const std::string canonical_name = this->canonical_preset_name(name, load_origin);
auto update_alias = [this](Preset &preset) {
if (! preset.alias.empty())
return;
set_custom_preset_alias(preset);
};
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, name %1% , total value counts %2%")%name %preset_values.size();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, name %1% , total value counts %2%")%canonical_name %preset_values.size();
//if the version is not matching, skip it
if (preset_values.find(BBL_JSON_KEY_VERSION) == preset_values.end()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find version, not loading for user preset %1%")%name;
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find version, not loading for user preset %1%")%canonical_name;
return false;
}
std::string version_str = preset_values[BBL_JSON_KEY_VERSION];
boost::optional<Semver> cloud_version = Semver::parse(version_str);
if (!cloud_version) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("invalid version %1%, not loading for user preset %2%")%version_str %name;
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("invalid version %1%, not loading for user preset %2%")%version_str %canonical_name;
return false;
}
//setting_id
if (preset_values.find(BBL_JSON_KEY_SETTING_ID) == preset_values.end()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find setting_id, not loading for user preset %1%")%name;
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find setting_id, not loading for user preset %1%")%canonical_name;
return false;
}
std::string cloud_setting_id = preset_values[BBL_JSON_KEY_SETTING_ID];
@@ -2037,17 +2150,17 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
//user_id
if (preset_values.find(BBL_JSON_KEY_USER_ID) == preset_values.end()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find user_id, not loading for user preset %1%")%name;
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find user_id, not loading for user preset %1%")%canonical_name;
return false;
}
std::string cloud_user_id = preset_values[BBL_JSON_KEY_USER_ID];
lock();
//std::string name = preset->name;
auto iter = this->find_preset_internal(name);
auto iter = this->find_preset_internal(canonical_name);
bool need_update = false;
if ((iter != m_presets.end()) && (iter->name == name)) {
BOOST_LOG_TRIVIAL(info) << "Found the Preset locally: " << name;
if ((iter != m_presets.end()) && (iter->name == canonical_name)) {
BOOST_LOG_TRIVIAL(info) << "Found the Preset locally: " << canonical_name;
//BBS: we should compare the time between cloud and local
if ((cloud_update_time == 0) || (cloud_update_time <= iter->updated_time)) {
if (cloud_update_time < iter->updated_time)
@@ -2059,7 +2172,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
fs::path idx_file(iter->file);
idx_file.replace_extension(".info");
iter->save_info(idx_file.string());
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("preset %1%'s update_time is eqaul or newer, cloud update_time %2%, local update_time %3%")%name %cloud_update_time %iter->updated_time;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("preset %1%'s update_time is eqaul or newer, cloud update_time %2%, local update_time %3%")%canonical_name %cloud_update_time %iter->updated_time;
unlock();
return false;
}
@@ -2071,7 +2184,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
// base_id
if (preset_values.find(BBL_JSON_KEY_BASE_ID) == preset_values.end()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find base_id, not loading for user preset %1%") % name;
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find base_id, not loading for user preset %1%") % canonical_name;
unlock();
return false;
}
@@ -2081,14 +2194,14 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
std::string cloud_filament_id;
if ((m_type == Preset::TYPE_FILAMENT) && preset_values.find(BBL_JSON_KEY_FILAMENT_ID) != preset_values.end()) {
cloud_filament_id = preset_values[BBL_JSON_KEY_FILAMENT_ID];
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << name << " filament_id: " << cloud_filament_id << " base_id: " << cloud_base_id;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << canonical_name << " filament_id: " << cloud_filament_id << " base_id: " << cloud_base_id;
}
DynamicPrintConfig new_config, cloud_config;
try {
ConfigSubstitutions config_substitutions = cloud_config.load_string_map(preset_values, rule);
if (! config_substitutions.empty())
substitutions.push_back({ name, m_type, PresetConfigSubstitutions::Source::UserCloud, name, std::move(config_substitutions) });
substitutions.push_back({ canonical_name, m_type, PresetConfigSubstitutions::Source::UserCloud, canonical_name, std::move(config_substitutions) });
//BBS: use inherit config as the base
Preset* inherit_preset = nullptr;
@@ -2096,12 +2209,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
if (inherits_config) {
ConfigOptionString * option_str = dynamic_cast<ConfigOptionString *> (inherits_config);
std::string inherits_value = option_str->value;
/*size_t pos = inherits_value.find_first_of('*');
if (pos != std::string::npos) {
inherits_value.replace(pos, 1, 1, '~');
option_str->value = inherits_value;
}*/
inherit_preset = this->find_preset(inherits_value, false, true);
inherit_preset = this->find_preset2(inherits_value, true);
}
const Preset& default_preset = this->default_preset_for(cloud_config);
if (inherit_preset) {
@@ -2115,7 +2223,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
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;
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip")%canonical_name;
unlock();
return false;
}
@@ -2141,7 +2249,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
std::string incorrect_keys = Preset::remove_invalid_keys(new_config, default_preset.config);
if (!incorrect_keys.empty()) {
++m_errors;
BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" << name
BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" << canonical_name
<< "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
}
if (need_update) {
@@ -2157,15 +2265,17 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
iter->setting_id = cloud_setting_id;
iter->base_id = cloud_base_id;
iter->filament_id = cloud_filament_id;
update_alias(*iter);
//presets_loaded.emplace_back(*it->second);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", update the user preset %1% from cloud, type %2%, setting_id %3%, base_id %4%, sync_info %5% inherits %6%, filament_id %7%")
% iter->name %Preset::get_type_string(m_type) %iter->setting_id %iter->base_id %iter->sync_info %iter->inherits() % iter->filament_id;
}
else {
//create a new one
Preset preset(m_type, name, false);
Preset preset(m_type, canonical_name, false);
preset.is_system = false;
preset.loaded = true;
preset.bundle_id = load_origin.bundle_id;
preset.config = new_config;
preset.updated_time = cloud_update_time;
preset.sync_info = "save";
@@ -2174,6 +2284,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
preset.setting_id = cloud_setting_id;
preset.base_id = cloud_base_id;
preset.filament_id = cloud_filament_id;
update_alias(preset);
size_t cur_index = iter - m_presets.begin();
m_presets.insert(iter, preset);
@@ -2195,7 +2306,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
if (! errors_cummulative.empty())
throw Slic3r::RuntimeError(errors_cummulative);
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, load user preset %1% , type %2%, errors_cummulative %3%")%name %Preset::get_type_string(m_type) %errors_cummulative;
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, load user preset %1% , type %2%, errors_cummulative %3%")%canonical_name %Preset::get_type_string(m_type) %errors_cummulative;
return (need_update)?false:true;
}
@@ -2216,16 +2327,23 @@ void PresetCollection::update_after_user_presets_loaded()
//BBS: validate_preset
bool PresetCollection::validate_preset(const std::string &preset_name, std::string &inherit_name)
{
std::deque<Preset>::iterator it = this->find_preset_internal(preset_name);
bool found = (it != m_presets.end()) && (it->name == preset_name) && (it->is_system || it->is_default);
// Presets that came from system vendors, the built-in defaults, or any loaded bundle (local or
// subscribed) are trusted — their g-code isn't user-authored, so the 3MF importer should not
// warn about them.
auto is_trusted = [](const Preset &p) { return p.is_system || p.is_default || p.is_from_bundle(); };
const std::string canonical_name = this->canonical_preset_name(preset_name);
std::deque<Preset>::iterator it = this->find_preset_internal(canonical_name);
bool found = (it != m_presets.end()) && (it->name == canonical_name) && is_trusted(*it);
if (!found) {
it = this->find_preset_renamed(preset_name);
found = it != m_presets.end() && (it->is_system || it->is_default);
it = this->find_preset_renamed(canonical_name);
found = it != m_presets.end() && is_trusted(*it);
}
if (!found) {
if (!inherit_name.empty()) {
it = this->find_preset_internal(inherit_name);
found = it != m_presets.end() && it->name == inherit_name && (it->is_system || it->is_default);
const std::string canonical_inherit_name = this->canonical_preset_name(inherit_name);
it = this->find_preset_internal(canonical_inherit_name);
found = it != m_presets.end() && it->name == canonical_inherit_name && is_trusted(*it);
if (found)
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": preset_name %1%, inherit_name %2%, found inherit in list")%preset_name %inherit_name;
else
@@ -2302,7 +2420,7 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
cfg.apply_only(combined_config, keys, true);
std::string &inherits = Preset::inherits(cfg);
//BBS: add different settings check logic, replace the old system preset's default value with new system preset's default values
//add different settings check logic, replace the old system preset's default value with new system preset's default values
std::deque<Preset>::iterator it = this->find_preset_internal(original_name);
bool found = it != m_presets.end() && it->name == original_name;
if (! found) {
@@ -2664,7 +2782,7 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
// Preset with the same name found.
Preset &preset = *it;
//BBS: add project embedded preset logic
if (preset.is_default || preset.is_system) {
if (!preset.can_overwrite()) {
//if (preset.is_default || preset.is_external || preset.is_system)
// Cannot overwrite the default preset.
//BBS: add lock logic for sync preset in background
@@ -2723,6 +2841,9 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
preset.is_default = false;
preset.is_system = false;
preset.is_external = false;
preset.bundle_id.clear();
preset.file = this->path_for_preset(preset);
// The newly saved preset will be activated -> make it visible.
preset.is_visible = true;
@@ -2765,7 +2886,7 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
bool PresetCollection::delete_current_preset()
{
Preset &selected = this->get_selected_preset();
if (selected.is_default)
if (!selected.can_overwrite())
return false;
if (get_preset_base(selected) == &selected) {
@@ -2796,18 +2917,24 @@ bool PresetCollection::delete_current_preset()
return true;
}
bool PresetCollection::delete_preset(const std::string& name)
bool PresetCollection::delete_preset(const std::string& name, bool force)
{
auto it = this->find_preset_internal(name);
Preset *preset_ptr = this->find_preset(name, false, true);
if (preset_ptr == nullptr)
return false;
auto it = this->find_preset_internal(preset_ptr->name);
if (it == m_presets.end() || it->name != preset_ptr->name)
return false;
Preset& preset = *it;
if (preset.is_default)
// ORCA: if the preset can't be overridden then don't allow deletion
// force=true bypasses this for bundle preset cleanup from cloud sync
if (!force && !preset.can_overwrite())
return false;
//BBS: add project embedded preset logic and refine is_external
//if (!preset.is_external && !preset.is_system) {
if (! preset.is_system) {
preset.remove_files();
}
preset.remove_files();
//BBS: add lock logic for sync preset in background
lock();
set_printer_hold_alias(it->alias, *it, true);
@@ -2817,6 +2944,30 @@ bool PresetCollection::delete_preset(const std::string& name)
return true;
}
void PresetCollection::check_and_fix_syncinfo(Preset& preset, const std::string& user_id)
{
// user id can't be empty
if (user_id.empty())
return;
// correct the sync info if preset.user_id is empty(the profile json file is copied to the user folder with missing .info file) or preset.user_id
// is not equal to the current user id or preset.setting_id is not in expected format(the .info is copied from the older format)
if (preset.user_id.empty() || preset.user_id != user_id || preset.setting_id.find('-') == std::string::npos) {
preset.user_id = user_id;
preset.setting_id = "";
if (preset.base_id.empty()) {
const std::string inherits = Preset::inherits(preset.config);
Preset* parent_preset = find_preset2(inherits, true);
if (parent_preset)
preset.base_id = parent_preset->setting_id;
}
// tell the sync logic to sync it as a new preset
preset.updated_time = 0;
preset.sync_info = "create";
preset.save_info();
}
}
const Preset* PresetCollection::get_selected_preset_parent() const
{
if (this->get_selected_idx() == size_t(-1))
@@ -2879,7 +3030,7 @@ const Preset *PresetCollection::get_preset_base(const Preset &child) const
// Handle user preset
if (child.inherits().empty())
return &child; // this is user root
auto inherits = find_preset2(child.inherits(),true);
auto inherits = find_preset2(child.inherits(), true);
return inherits ? get_preset_base(*inherits) : nullptr;
}
@@ -2953,20 +3104,21 @@ const std::string& PresetCollection::get_suffix_modified() {
// If a preset was not found by its name, null is returned.
Preset* PresetCollection::find_preset(const std::string &name, bool first_visible_if_not_found, bool real, bool only_from_library)
{
Preset key(m_type, name, false);
auto it = this->find_preset_internal(name, only_from_library);
// Ensure that a temporary copy is returned if the preset found is currently selected.
return (it != m_presets.end() && it->name == key.name) ? &this->preset(it - m_presets.begin(), real) :
first_visible_if_not_found ? &this->first_visible() : nullptr;
const ParsedName parsed = parse_preset_name(name);
const std::string canonical = get_preset_canonical_name(parsed.bare, PresetOrigin(parsed.kind, parsed.bundle_id));
auto it = this->find_preset_internal(canonical, only_from_library);
if (it != m_presets.end() && it->name == canonical)
return &this->preset(it - m_presets.begin(), real);
return first_visible_if_not_found ? &this->first_visible() : nullptr;
}
Preset* PresetCollection::find_preset2(const std::string& name, bool auto_match/* = true */)
{
auto preset = find_preset(name,false,true);
auto preset = find_preset(name, false, true);
if (preset == nullptr) {
auto _name = get_preset_name_renamed(name);
if (_name != nullptr)
preset = find_preset(*_name,false,true);
preset = find_preset(*_name, false, true);
if (auto_match && preset == nullptr) {
//Orca: one more try, find the most likely preset in OrcaFilamentLibrary
if (name.find("Generic") != std::string::npos) {
@@ -2982,7 +3134,6 @@ Preset* PresetCollection::find_preset2(const std::string& name, bool auto_match/
}
}
}
return preset;
}
@@ -3334,10 +3485,11 @@ bool PresetCollection::select_preset_by_name(const std::string &name_w_suffix, b
//BBS: add config related logs
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": %1%, try to select by name %2%, force %3%")%Preset::get_type_string(m_type) %name_w_suffix %force;
std::string name = Preset::remove_suffix_modified(name_w_suffix);
const std::string normalized_name = this->canonical_preset_name(name);
// 1) Try to find the preset by its name.
auto it = this->find_preset_internal(name);
auto it = this->find_preset_internal(normalized_name);
size_t idx = 0;
if (it != m_presets.end() && it->name == name && it->is_visible)
if (it != m_presets.end() && it->name == normalized_name && it->is_visible)
// Preset found by its name and it is visible.
idx = it - m_presets.begin();
else {
@@ -3370,11 +3522,12 @@ bool PresetCollection::select_preset_by_name_strict(const std::string &name)
{
//BBS: add config related logs
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": %1%, try to select by name %2%")%Preset::get_type_string(m_type) %name;
const std::string canonical_name = this->canonical_preset_name(name);
// 1) Try to find the preset by its name.
auto it = this->find_preset_internal(name);
auto it = this->find_preset_internal(canonical_name);
size_t idx = (size_t)-1;
if (it != m_presets.end() && it->name == name && it->is_visible)
if (it != m_presets.end() && it->name == canonical_name && it->is_visible)
// Preset found by its name.
idx = it - m_presets.begin();
// 2) Select the new preset.
@@ -3486,9 +3639,13 @@ void PresetCollection::update_map_system_profile_renamed()
void PresetCollection::set_custom_preset_alias(Preset &preset)
{
// For filaments, remove the postfix
// For printers, there is nothing to remove
// For prints AKA processes, the postfix should be kept
// Alias should be set here, as the preset name may be augmented further later (i.e., prefixing relative path for bundles)
std::string alias_name;
std::string preset_name = get_preset_bare_name(preset.name);
if (m_type == Preset::Type::TYPE_FILAMENT && preset.config.has(BBL_JSON_KEY_INHERITS) && preset.config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS)->value.empty()) {
std::string alias_name;
std::string preset_name = preset.name;
if (alias_name.empty()) {
size_t end_pos = preset_name.find_first_of("@");
if (end_pos != std::string::npos) {
@@ -3496,14 +3653,14 @@ void PresetCollection::set_custom_preset_alias(Preset &preset)
boost::trim_right(alias_name);
}
}
if (alias_name.empty() || is_alias_exist(alias_name, &preset))
preset.alias = "";
else {
preset.alias = std::move(alias_name);
m_map_alias_to_profile_name[preset.alias].push_back(preset.name);
set_printer_hold_alias(preset.alias, preset);
}
}
else {
alias_name = preset_name;
}
preset.alias = std::move(alias_name);
m_map_alias_to_profile_name[preset.alias].push_back(preset.name);
set_printer_hold_alias(preset.alias, preset);
}
void PresetCollection::set_printer_hold_alias(const std::string &alias, Preset &preset, bool remove)
@@ -3604,7 +3761,7 @@ std::string PresetCollection::path_from_name(const std::string &new_name, bool d
std::string PresetCollection::path_for_preset(const Preset &preset) const
{
return path_from_name(preset.name, is_base_preset(preset));
return path_from_name(get_preset_bare_name(preset.name), is_base_preset(preset));
}
const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConfig &config) const