mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-29 19:53:44 -06:00 
			
		
		
		
	Configuration compatibility - implemented substitution and reporting for vectors
of bools (including the nullable bools).
This commit is contained in:
		
							parent
							
								
									5b843aa291
								
							
						
					
					
						commit
						3a0b71deed
					
				
					 3 changed files with 96 additions and 39 deletions
				
			
		|  | @ -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); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|     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); | ||||
|     assert(opt != nullptr); | ||||
|     bool 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))  | ||||
|     { | ||||
|         // Deserialize failed, try to substitute with a default value.
 | ||||
|         assert(substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSilent); | ||||
|     bool success     = false; | ||||
|     bool substituted = false; | ||||
|     if (optdef->type == coBools && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable) { | ||||
|     	//FIXME Special handling of vectors of bools, quick and not so dirty solution before PrusaSlicer 2.3.2 release.
 | ||||
|     	auto result = opt->nullable() ?  | ||||
|     		static_cast<ConfigOptionBoolsNullable*>(opt)->deserialize_with_substitutions(value, append, true) : | ||||
|     		static_cast<ConfigOptionBools*>(opt)->deserialize_with_substitutions(value, append, true); | ||||
|     	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)) | ||||
|             static_cast<ConfigOptionBool*>(opt)->value = boost::iequals(value, "enabled") || boost::iequals(value, "on"); | ||||
|         else | ||||
|             opt->set(optdef->default_value.get()); | ||||
| 
 | ||||
|         if (substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || | ||||
|             substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent) { | ||||
|             // Log the 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; | ||||
|     if (substituted && (substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || | ||||
|                         substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent)) { | ||||
|         // Log the substitution.
 | ||||
|         ConfigSubstitution config_substitution; | ||||
|         config_substitution.opt_def   = optdef; | ||||
|         config_substitution.old_value = value; | ||||
|         config_substitution.new_value = ConfigOptionUniquePtr(opt->clone()); | ||||
|         substitutions_ctxt.substitutions.emplace_back(std::move(config_substitution)); | ||||
|     } | ||||
|     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); | ||||
| 
 | ||||
| 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.
 | ||||
| class ConfigurationError : public Slic3r::RuntimeError { | ||||
| public: | ||||
|  | @ -1400,24 +1424,39 @@ public: | |||
|         } | ||||
|         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) | ||||
|             this->values.clear(); | ||||
|         std::istringstream is(str); | ||||
|         std::string item_str; | ||||
|         bool substituted = false; | ||||
|         while (std::getline(is, item_str, ',')) { | ||||
|         	boost::trim(item_str); | ||||
|         	unsigned char new_value = 0; | ||||
|         	if (item_str == "nil") { | ||||
|         		if (NULLABLE) | ||||
|         			this->values.push_back(nil_value()); | ||||
|         		else | ||||
|                     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 | ||||
|         		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: | ||||
|  |  | |||
|  | @ -258,7 +258,9 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio | |||
| 		const ConfigOptionDef* def = conf_substitution.opt_def; | ||||
| 		if (!def) | ||||
| 			continue; | ||||
| 		if (def->type == coEnum) { | ||||
| 		switch (def->type) { | ||||
| 		case coEnum: | ||||
| 		{ | ||||
| 			const std::vector<std::string>& labels = def->enum_labels; | ||||
| 			const std::vector<std::string>& values = def->enum_values; | ||||
| 			int val = conf_substitution.new_value->getInt(); | ||||
|  | @ -283,9 +285,24 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio | |||
| 			} | ||||
| 			else | ||||
| 				new_val = from_u8(_utf8(labels[val])); | ||||
| 			break; | ||||
| 		} | ||||
| 		else if (def->type == coBool) | ||||
| 		case coBool: | ||||
| 			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>: " +  | ||||
| 					format_wxstr(_L("new unknown value %1% was changed to default value %2%"), bold(conf_substitution.old_value), bold(new_val)) +  | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv