Configuration compatibility - implemented substitution and reporting for vectors
of bools (including the nullable bools).
This commit is contained in:
parent
5b843aa291
commit
3a0b71deed
@ -506,16 +506,6 @@ void ConfigBase::set_deserialize(std::initializer_list<SetDeserializeItem> items
|
|||||||
this->set_deserialize(item.opt_key, item.opt_value, substitutions_ctxt, item.append);
|
this->set_deserialize(item.opt_key, item.opt_value, substitutions_ctxt, item.append);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool looks_like_enum_value(const std::string &value)
|
|
||||||
{
|
|
||||||
if (value.empty() || value.size() > 64 || ! isalpha(value.front()))
|
|
||||||
return false;
|
|
||||||
for (const char c : value)
|
|
||||||
if (! (isalnum(c) || c == '_' || c == '-'))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, const std::string &value, ConfigSubstitutionContext& substitutions_ctxt, bool append)
|
bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, const std::string &value, ConfigSubstitutionContext& substitutions_ctxt, bool append)
|
||||||
{
|
{
|
||||||
t_config_option_key opt_key = opt_key_src;
|
t_config_option_key opt_key = opt_key_src;
|
||||||
@ -552,30 +542,41 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con
|
|||||||
|
|
||||||
ConfigOption *opt = this->option(opt_key, true);
|
ConfigOption *opt = this->option(opt_key, true);
|
||||||
assert(opt != nullptr);
|
assert(opt != nullptr);
|
||||||
bool success = opt->deserialize(value, append);
|
bool success = false;
|
||||||
if (! success && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable &&
|
bool substituted = false;
|
||||||
// Only allow substitutions of an enum value by another enum value or a boolean value with an enum value.
|
if (optdef->type == coBools && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable) {
|
||||||
// That means, we expect enum values being added in the future and possibly booleans being converted to enums.
|
//FIXME Special handling of vectors of bools, quick and not so dirty solution before PrusaSlicer 2.3.2 release.
|
||||||
(optdef->type == coEnum || optdef->type == coBool))
|
auto result = opt->nullable() ?
|
||||||
{
|
static_cast<ConfigOptionBoolsNullable*>(opt)->deserialize_with_substitutions(value, append, true) :
|
||||||
// Deserialize failed, try to substitute with a default value.
|
static_cast<ConfigOptionBools*>(opt)->deserialize_with_substitutions(value, append, true);
|
||||||
assert(substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSilent);
|
success = result != ConfigHelpers::DeserializationResult::Failed;
|
||||||
|
substituted = result == ConfigHelpers::DeserializationResult::Substituted;
|
||||||
|
} else {
|
||||||
|
success = opt->deserialize(value, append);
|
||||||
|
if (! success && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable &&
|
||||||
|
// Only allow substitutions of an enum value by another enum value or a boolean value with an enum value.
|
||||||
|
// That means, we expect enum values being added in the future and possibly booleans being converted to enums.
|
||||||
|
(optdef->type == coEnum || optdef->type == coBool) && ConfigHelpers::looks_like_enum_value(value)) {
|
||||||
|
// Deserialize failed, try to substitute with a default value.
|
||||||
|
assert(substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||||
|
if (optdef->type == coBool)
|
||||||
|
static_cast<ConfigOptionBool*>(opt)->value = ConfigHelpers::enum_looks_like_true_value(value);
|
||||||
|
else
|
||||||
|
// Just use the default of the option.
|
||||||
|
opt->set(optdef->default_value.get());
|
||||||
|
success = true;
|
||||||
|
substituted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (optdef->type == coBool && looks_like_enum_value(value))
|
if (substituted && (substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable ||
|
||||||
static_cast<ConfigOptionBool*>(opt)->value = boost::iequals(value, "enabled") || boost::iequals(value, "on");
|
substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent)) {
|
||||||
else
|
// Log the substitution.
|
||||||
opt->set(optdef->default_value.get());
|
ConfigSubstitution config_substitution;
|
||||||
|
config_substitution.opt_def = optdef;
|
||||||
if (substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable ||
|
config_substitution.old_value = value;
|
||||||
substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent) {
|
config_substitution.new_value = ConfigOptionUniquePtr(opt->clone());
|
||||||
// Log the substitution.
|
substitutions_ctxt.substitutions.emplace_back(std::move(config_substitution));
|
||||||
ConfigSubstitution config_substitution;
|
|
||||||
config_substitution.opt_def = optdef;
|
|
||||||
config_substitution.old_value = value;//std::unique_ptr<ConfigOption>(opt);
|
|
||||||
config_substitution.new_value = ConfigOptionUniquePtr(this->option(opt_key, true)->clone());
|
|
||||||
substitutions_ctxt.substitutions.emplace_back(std::move(config_substitution));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,30 @@ extern bool unescape_strings_cstyle(const std::string &str, std::vector<
|
|||||||
|
|
||||||
extern std::string escape_ampersand(const std::string& str);
|
extern std::string escape_ampersand(const std::string& str);
|
||||||
|
|
||||||
|
namespace ConfigHelpers {
|
||||||
|
inline bool looks_like_enum_value(std::string value)
|
||||||
|
{
|
||||||
|
boost::trim(value);
|
||||||
|
if (value.empty() || value.size() > 64 || ! isalpha(value.front()))
|
||||||
|
return false;
|
||||||
|
for (const char c : value)
|
||||||
|
if (! (isalnum(c) || c == '_' || c == '-'))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool enum_looks_like_true_value(std::string value) {
|
||||||
|
boost::trim(value);
|
||||||
|
return boost::iequals(value, "enabled") || boost::iequals(value, "on");
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DeserializationResult {
|
||||||
|
Loaded,
|
||||||
|
Substituted,
|
||||||
|
Failed,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// Base for all exceptions thrown by the configuration layer.
|
// Base for all exceptions thrown by the configuration layer.
|
||||||
class ConfigurationError : public Slic3r::RuntimeError {
|
class ConfigurationError : public Slic3r::RuntimeError {
|
||||||
public:
|
public:
|
||||||
@ -1400,24 +1424,39 @@ public:
|
|||||||
}
|
}
|
||||||
return vv;
|
return vv;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deserialize(const std::string &str, bool append = false) override
|
ConfigHelpers::DeserializationResult deserialize_with_substitutions(const std::string &str, bool append, bool substitute)
|
||||||
{
|
{
|
||||||
if (! append)
|
if (! append)
|
||||||
this->values.clear();
|
this->values.clear();
|
||||||
std::istringstream is(str);
|
std::istringstream is(str);
|
||||||
std::string item_str;
|
std::string item_str;
|
||||||
|
bool substituted = false;
|
||||||
while (std::getline(is, item_str, ',')) {
|
while (std::getline(is, item_str, ',')) {
|
||||||
boost::trim(item_str);
|
boost::trim(item_str);
|
||||||
|
unsigned char new_value = 0;
|
||||||
if (item_str == "nil") {
|
if (item_str == "nil") {
|
||||||
if (NULLABLE)
|
if (NULLABLE)
|
||||||
this->values.push_back(nil_value());
|
this->values.push_back(nil_value());
|
||||||
else
|
else
|
||||||
throw ConfigurationError("Deserializing nil into a non-nullable object");
|
throw ConfigurationError("Deserializing nil into a non-nullable object");
|
||||||
|
} else if (item_str == "1") {
|
||||||
|
new_value = true;
|
||||||
|
} else if (item_str == "0") {
|
||||||
|
new_value = false;
|
||||||
|
} else if (substitute && ConfigHelpers::looks_like_enum_value(item_str)) {
|
||||||
|
new_value = ConfigHelpers::enum_looks_like_true_value(item_str);
|
||||||
|
substituted = true;
|
||||||
} else
|
} else
|
||||||
this->values.push_back(item_str.compare("1") == 0);
|
return ConfigHelpers::DeserializationResult::Failed;
|
||||||
|
this->values.push_back(new_value);
|
||||||
}
|
}
|
||||||
return true;
|
return substituted ? ConfigHelpers::DeserializationResult::Substituted : ConfigHelpers::DeserializationResult::Loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool deserialize(const std::string &str, bool append = false) override
|
||||||
|
{
|
||||||
|
return this->deserialize_with_substitutions(str, append, false) == ConfigHelpers::DeserializationResult::Loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -258,7 +258,9 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio
|
|||||||
const ConfigOptionDef* def = conf_substitution.opt_def;
|
const ConfigOptionDef* def = conf_substitution.opt_def;
|
||||||
if (!def)
|
if (!def)
|
||||||
continue;
|
continue;
|
||||||
if (def->type == coEnum) {
|
switch (def->type) {
|
||||||
|
case coEnum:
|
||||||
|
{
|
||||||
const std::vector<std::string>& labels = def->enum_labels;
|
const std::vector<std::string>& labels = def->enum_labels;
|
||||||
const std::vector<std::string>& values = def->enum_values;
|
const std::vector<std::string>& values = def->enum_values;
|
||||||
int val = conf_substitution.new_value->getInt();
|
int val = conf_substitution.new_value->getInt();
|
||||||
@ -283,9 +285,24 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
new_val = from_u8(_utf8(labels[val]));
|
new_val = from_u8(_utf8(labels[val]));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (def->type == coBool)
|
case coBool:
|
||||||
new_val = conf_substitution.new_value->getBool() ? "true" : "false";
|
new_val = conf_substitution.new_value->getBool() ? "true" : "false";
|
||||||
|
break;
|
||||||
|
case coBools:
|
||||||
|
if (conf_substitution.new_value->nullable())
|
||||||
|
for (const char v : static_cast<const ConfigOptionBoolsNullable*>(conf_substitution.new_value.get())->values)
|
||||||
|
new_val += std::string(v == ConfigOptionBoolsNullable::nil_value() ? "nil" : v ? "true" : "false") + ", ";
|
||||||
|
else
|
||||||
|
for (const char v : static_cast<const ConfigOptionBools*>(conf_substitution.new_value.get())->values)
|
||||||
|
new_val += std::string(v ? "true" : "false") + ", ";
|
||||||
|
if (! new_val.empty())
|
||||||
|
new_val.erase(new_val.begin() + new_val.size() - 2, new_val.end());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
changes += "<tr><td>" + bold(_(def->label)) + "</td><td>: " +
|
changes += "<tr><td>" + bold(_(def->label)) + "</td><td>: " +
|
||||||
format_wxstr(_L("new unknown value %1% was changed to default value %2%"), bold(conf_substitution.old_value), bold(new_val)) +
|
format_wxstr(_L("new unknown value %1% was changed to default value %2%"), bold(conf_substitution.old_value), bold(new_val)) +
|
||||||
|
Loading…
Reference in New Issue
Block a user