mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-08 00:01:09 +00:00
fix: Create Printer finds no system vendors in release builds (#16175)
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
This commit is contained in:
co-authored by
Rodrigo Faselli
parent
e027f8b225
commit
c33515914d
@@ -39,7 +39,7 @@ presets are never serialized — they have their own storage and their own lifec
|
||||
|
||||
| Location | Contents on a shipped build | Role |
|
||||
|---|---|---|
|
||||
| `resources/profiles/` | `<vendor>.opc` alone — the profile and its preset JSONs both pruned | What the app ships with; what installing copies from, and the only thing it is read for |
|
||||
| `resources/profiles/` | `<vendor>.opc` alone — the profile and its preset JSONs both pruned | What the app ships with and what installing copies from; read directly for vendors not installed |
|
||||
| `<data_dir>/system/` | `<vendor>.opc` alone, or `<vendor>.json` + `<vendor>/` after an update | What the user has installed |
|
||||
| `<data_dir>/system/` (dev build) | `<vendor>.json` + `<vendor>/` + `<vendor>.opc` written at runtime | A developer tree caches as it parses |
|
||||
| `<data_dir>/cache/wizard_profile_data.json` | The wizard's derived vendor catalog plus the stamps it was built from | Written and read by the setup wizard only; never shipped (see "The wizard's profile-data cache") |
|
||||
@@ -182,10 +182,11 @@ one startup.
|
||||
|
||||
**A vendor is loaded from where it is installed and nowhere else.** For startup that
|
||||
is `<data_dir>/system/`; resources reaches the app by being *installed* into that
|
||||
directory first, never by being loaded from. (The setup wizard is the one caller with
|
||||
a different notion of "where": it also shows vendors the user has not installed, and
|
||||
loads those from `resources/profiles` — see "The wizard's profile-data cache".) There
|
||||
is one lookup tier and one parse source:
|
||||
directory first, never by being loaded from. (The setup wizard and the Create Printer
|
||||
dialog also offer vendors the user has not installed, and load those from
|
||||
`resources/profiles`; see "The wizard's profile-data cache". The dialog's vendor-only and
|
||||
filament-only scans read a cache only where it is the whole installation, and never write
|
||||
one.) There is one lookup tier and one parse source:
|
||||
|
||||
```
|
||||
load vendor V from <data_dir>/system:
|
||||
|
||||
@@ -2806,19 +2806,13 @@ std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_mod
|
||||
boost::filesystem::path dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred();
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
std::string errors_cummulative;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir)) {
|
||||
std::string vendor_file = dir_entry.path().string();
|
||||
if (Slic3r::is_json_file(vendor_file)) {
|
||||
std::string vendor_name = dir_entry.path().filename().string();
|
||||
// Remove the .json suffix.
|
||||
vendor_name.erase(vendor_name.size() - 5);
|
||||
try {
|
||||
// Load the config bundle, flatten it.
|
||||
append(substitutions, load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadVendorOnly, compatibility_rule).first);
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
}
|
||||
for (const std::string &vendor_name : vendor_names_in(dir)) {
|
||||
try {
|
||||
// Load the config bundle, flatten it.
|
||||
append(substitutions, load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadVendorOnly, compatibility_rule).first);
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2841,35 +2835,33 @@ std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_fil
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
std::string errors_cummulative;
|
||||
bool first = true;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir)) {
|
||||
std::string vendor_file = dir_entry.path().string();
|
||||
if (Slic3r::is_json_file(vendor_file)) {
|
||||
std::string vendor_name = dir_entry.path().filename().string();
|
||||
// Remove the .json suffix.
|
||||
vendor_name.erase(vendor_name.size() - 5);
|
||||
try {
|
||||
if (first) {
|
||||
// Reset this PresetBundle and load the first vendor config.
|
||||
append(substitutions, this->load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadSystem | PresetBundle::LoadFilamentOnly, compatibility_rule).first);
|
||||
first = false;
|
||||
} else {
|
||||
// Load the other vendor configs, merge them with this PresetBundle.
|
||||
// Report duplicate profiles.
|
||||
PresetBundle other;
|
||||
append(substitutions, other.load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadSystem | PresetBundle::LoadFilamentOnly, compatibility_rule).first);
|
||||
std::vector<std::string> duplicates = std::move(this->merge_presets({ &other }).front());
|
||||
if (!duplicates.empty()) {
|
||||
errors_cummulative += "Found duplicated settings in vendor " + vendor_name + "'s json file lists: ";
|
||||
for (size_t i = 0; i < duplicates.size(); ++i) {
|
||||
if (i > 0) errors_cummulative += ", ";
|
||||
errors_cummulative += duplicates[i];
|
||||
}
|
||||
// The filament library loads first, so the filaments that inherit its bases resolve.
|
||||
std::vector<std::string> vendor_names;
|
||||
for (const std::string &vendor_name : vendor_names_in(dir))
|
||||
vendor_names.insert(vendor_name == ORCA_FILAMENT_LIBRARY ? vendor_names.begin() : vendor_names.end(), vendor_name);
|
||||
for (const std::string &vendor_name : vendor_names) {
|
||||
try {
|
||||
if (first) {
|
||||
// Reset this PresetBundle and load the first vendor config.
|
||||
append(substitutions, this->load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadSystem | PresetBundle::LoadFilamentOnly, compatibility_rule).first);
|
||||
first = false;
|
||||
} else {
|
||||
// Load the other vendor configs, merge them with this PresetBundle.
|
||||
// Report duplicate profiles.
|
||||
PresetBundle other;
|
||||
append(substitutions, other.load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadSystem | PresetBundle::LoadFilamentOnly, compatibility_rule, this).first);
|
||||
std::vector<std::string> duplicates = std::move(this->merge_presets({ &other }).front());
|
||||
if (!duplicates.empty()) {
|
||||
errors_cummulative += "Found duplicated settings in vendor " + vendor_name + "'s json file lists: ";
|
||||
for (size_t i = 0; i < duplicates.size(); ++i) {
|
||||
if (i > 0) errors_cummulative += ", ";
|
||||
errors_cummulative += duplicates[i];
|
||||
}
|
||||
}
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
}
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7149,22 +7141,38 @@ PresetBundle::VendorRead PresetBundle::read_vendor(const std::string& dir, const
|
||||
// Reset this bundle, delete user profile files if SaveImported.
|
||||
this->reset(flags.has(LoadConfigBundleAttribute::SaveImported));
|
||||
|
||||
// Orca: only a whole-vendor load has a cache — the vendor-only and filament-only
|
||||
// scans want a slice of one. Validation reads the JSONs whatever is cached.
|
||||
read.cacheable = allow_cache && flags.has(LoadConfigBundleAttribute::LoadSystem) && ! flags.has(LoadConfigBundleAttribute::LoadFilamentOnly);
|
||||
if (read.cacheable && ! validation_mode) {
|
||||
// A vendor is loaded from where it is installed and nowhere else; resources
|
||||
// reaches the app by being installed into `dir` first. The cache there is
|
||||
// judged against the profile beside it — or, where the cache is the whole
|
||||
// of the installation, against nothing, since nothing on disk can then be
|
||||
// Orca: only a whole-vendor load writes a cache, and a vendor-only or filament-only
|
||||
// scan reads one only where it is the whole installation, as in a shipped build.
|
||||
// Validation reads the JSONs whatever is cached.
|
||||
const bool vendor_only = flags.has(LoadConfigBundleAttribute::LoadVendorOnly);
|
||||
const bool filament_only = flags.has(LoadConfigBundleAttribute::LoadFilamentOnly);
|
||||
read.cacheable = allow_cache && flags.has(LoadConfigBundleAttribute::LoadSystem) && ! filament_only;
|
||||
const boost::filesystem::path dir_path(dir);
|
||||
const boost::filesystem::path profile = dir_path / (vendor_name + ".json");
|
||||
const bool has_profile = boost::filesystem::exists(profile);
|
||||
if (allow_cache && ! validation_mode && (read.cacheable || ((vendor_only || filament_only) && ! has_profile))) {
|
||||
// The cache is judged against the profile beside it, or, where the cache is the
|
||||
// whole of the installation, against nothing, since nothing on disk can then be
|
||||
// newer than it. That state is Semver::inf(), which no real profile carries.
|
||||
const boost::filesystem::path dir_path(dir);
|
||||
const boost::filesystem::path profile = dir_path / (vendor_name + ".json");
|
||||
const Semver version = boost::filesystem::exists(profile) ? get_version_from_json(profile.string()) : Semver::inf();
|
||||
const Semver version = has_profile ? get_version_from_json(profile.string()) : Semver::inf();
|
||||
read.cache_path = (dir_path / (vendor_name + ".opc")).string();
|
||||
read.from_cache = VendorCacheFile::load(read.cache_path, vendor_name, version, read.data);
|
||||
if (read.from_cache)
|
||||
if (vendor_only) {
|
||||
VendorProfile vendor_profile;
|
||||
if (VendorCacheFile::load_vendor_profile(read.cache_path, vendor_name, version, vendor_profile)) {
|
||||
this->vendors.emplace(vendor_name, std::move(vendor_profile));
|
||||
read.vendor_only = true;
|
||||
return read;
|
||||
}
|
||||
} else if (VendorCacheFile::load(read.cache_path, vendor_name, version, read.data)) {
|
||||
read.from_cache = true;
|
||||
if (filament_only) {
|
||||
read.data.process_entries.clear();
|
||||
read.data.machine_entries.clear();
|
||||
// The stamp counts errors across the whole vendor.
|
||||
read.data.parse_errors = 0;
|
||||
}
|
||||
return read;
|
||||
}
|
||||
}
|
||||
this->parse_vendor_json(read);
|
||||
return read;
|
||||
|
||||
@@ -471,9 +471,11 @@ bool VendorCacheFile::save(const std::string& path, const std::string& vendor_na
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool VendorCacheFile::load(const std::string& path, const std::string& expected_vendor_name,
|
||||
const Semver& expected_vendor_version, VendorCacheData& data)
|
||||
// Reads a cache through its vendor profiles under the checks load() documents, then
|
||||
// calls read_rest on the archive.
|
||||
template<class ReadRest>
|
||||
static bool read_cache_up_to_presets(const std::string& path, const std::string& expected_vendor_name,
|
||||
const Semver& expected_vendor_version, VendorMap& vendors, ReadRest&& read_rest)
|
||||
{
|
||||
std::string blob;
|
||||
if (! read_cache_blob(path, blob))
|
||||
@@ -488,12 +490,9 @@ bool VendorCacheFile::load(const std::string& path, const std::string& expected_
|
||||
return false;
|
||||
CacheDictionary dict;
|
||||
dict.load(ar);
|
||||
ar(data.vendors);
|
||||
load_entries(ar, data.process_entries, dict);
|
||||
load_entries(ar, data.filament_entries, dict);
|
||||
load_entries(ar, data.machine_entries, dict);
|
||||
ar(data.parse_errors);
|
||||
if (data.vendors.find(expected_vendor_name) == data.vendors.end())
|
||||
ar(vendors);
|
||||
read_rest(ar, dict);
|
||||
if (vendors.find(expected_vendor_name) == vendors.end())
|
||||
throw std::runtime_error("vendor cache does not carry its own vendor profile");
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
@@ -502,6 +501,31 @@ bool VendorCacheFile::load(const std::string& path, const std::string& expected_
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool VendorCacheFile::load(const std::string& path, const std::string& expected_vendor_name,
|
||||
const Semver& expected_vendor_version, VendorCacheData& data)
|
||||
{
|
||||
return read_cache_up_to_presets(path, expected_vendor_name, expected_vendor_version, data.vendors,
|
||||
[&data](cereal::BinaryInputArchive& ar, const CacheDictionary& dict) {
|
||||
load_entries(ar, data.process_entries, dict);
|
||||
load_entries(ar, data.filament_entries, dict);
|
||||
load_entries(ar, data.machine_entries, dict);
|
||||
ar(data.parse_errors);
|
||||
});
|
||||
}
|
||||
|
||||
// static
|
||||
bool VendorCacheFile::load_vendor_profile(const std::string& path, const std::string& expected_vendor_name,
|
||||
const Semver& expected_vendor_version, VendorProfile& vendor)
|
||||
{
|
||||
VendorMap vendors;
|
||||
if (! read_cache_up_to_presets(path, expected_vendor_name, expected_vendor_version, vendors,
|
||||
[](cereal::BinaryInputArchive&, const CacheDictionary&) {}))
|
||||
return false;
|
||||
vendor = std::move(vendors.find(expected_vendor_name)->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
std::string VendorCacheFile::peek_version(const std::string& path, const std::string& expected_vendor_name)
|
||||
{
|
||||
|
||||
@@ -169,6 +169,11 @@ public:
|
||||
static bool load(const std::string& path, const std::string& expected_vendor_name,
|
||||
const Semver& expected_vendor_version, VendorCacheData& data);
|
||||
|
||||
// Read only the vendor's own profile, under the same checks as load(),
|
||||
// without deserializing its presets.
|
||||
static bool load_vendor_profile(const std::string& path, const std::string& expected_vendor_name,
|
||||
const Semver& expected_vendor_version, VendorProfile& vendor);
|
||||
|
||||
// Read the profile version a cache was stamped with, without deserializing
|
||||
// its presets. Empty if the file is unreadable, not a cache this build
|
||||
// understands, or not this vendor's. This is how an installed vendor's
|
||||
|
||||
@@ -540,12 +540,9 @@ static std::string calculate_md5(const std::string &input)
|
||||
return md5;
|
||||
}
|
||||
|
||||
static std::string get_filament_id(std::string vendor_typr_serial)
|
||||
// Loads every system filament and the user's own, which a new filament id must not collide with.
|
||||
static void load_filament_id_sources(PresetBundle &temp_preset_bundle)
|
||||
{
|
||||
std::unordered_map<std::string, std::set<std::string>> filament_id_to_filament_name;
|
||||
|
||||
// temp filament presets
|
||||
PresetBundle temp_preset_bundle;
|
||||
temp_preset_bundle.load_system_filaments_json(Slic3r::ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||
std::string dir_user_presets = wxGetApp().app_config->get("preset_folder");
|
||||
if (dir_user_presets.empty()) {
|
||||
@@ -553,6 +550,13 @@ static std::string get_filament_id(std::string vendor_typr_serial)
|
||||
} else {
|
||||
temp_preset_bundle.load_user_presets(dir_user_presets, ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string get_filament_id(std::string vendor_typr_serial, const PresetBundle &temp_preset_bundle)
|
||||
{
|
||||
std::unordered_map<std::string, std::set<std::string>> filament_id_to_filament_name;
|
||||
|
||||
// temp filament presets
|
||||
const std::deque<Preset> &filament_presets = temp_preset_bundle.filaments.get_presets();
|
||||
|
||||
for (const Preset &preset : filament_presets) {
|
||||
@@ -1193,7 +1197,9 @@ wxWindow *CreateFilamentPresetDialog::create_dialog_buttons()
|
||||
if (wxID_YES != dlg.ShowModal()) { return; }
|
||||
}
|
||||
|
||||
std::string user_filament_id = get_filament_id(filament_preset_name);
|
||||
PresetBundle filament_id_sources;
|
||||
load_filament_id_sources(filament_id_sources);
|
||||
std::string user_filament_id = get_filament_id(filament_preset_name, filament_id_sources);
|
||||
|
||||
const wxString &curr_create_type = curr_create_filament_type();
|
||||
|
||||
@@ -2259,13 +2265,19 @@ bool CreatePrinterPresetDialog::load_system_and_user_presets_with_curr_model(Pre
|
||||
} else {
|
||||
selected_vendor_id = m_printer_preset_vendor_selected.id;
|
||||
|
||||
// The vendor list is built from the bundled profiles, so a vendor the user never
|
||||
// installed loads from them.
|
||||
const boost::filesystem::path vendor_dir = is_vendor_installed(selected_vendor_id) ?
|
||||
boost::filesystem::path(Slic3r::data_dir()) / PRESET_SYSTEM_DIR :
|
||||
boost::filesystem::path(Slic3r::resources_dir()) / PRESET_PROFILES_DIR;
|
||||
|
||||
try {
|
||||
// Pass the app's preset bundle (which already holds OrcaFilamentLibrary) as the base
|
||||
// bundle so vendor filaments that inherit OFL bases resolve via the existing
|
||||
// cross-vendor inheritance path.
|
||||
// Orca: served from the vendor's preset cache where one covers it — a shipped
|
||||
// build carries that instead of the raw preset JSONs — and parsed otherwise.
|
||||
temp_preset_bundle.load_vendor_configs_from_json((boost::filesystem::path(Slic3r::data_dir()) / PRESET_SYSTEM_DIR).string(),
|
||||
temp_preset_bundle.load_vendor_configs_from_json(vendor_dir.string(),
|
||||
selected_vendor_id,
|
||||
PresetBundle::LoadConfigBundleAttribute::LoadSystem,
|
||||
ForwardCompatibilitySubstitutionRule::EnableSilent,
|
||||
@@ -2873,13 +2885,21 @@ wxWindow *CreatePrinterPresetDialog::create_page2_dialog_buttons(wxWindow *paren
|
||||
return;
|
||||
}
|
||||
|
||||
// One load serves every clone below, since cloning assigns all filament ids before it saves a preset.
|
||||
PresetBundle filament_id_sources;
|
||||
if (!selected_filament_presets.empty())
|
||||
load_filament_id_sources(filament_id_sources);
|
||||
auto create_filament_id = [&filament_id_sources](std::string vendor_typr_serial) {
|
||||
return get_filament_id(vendor_typr_serial, filament_id_sources);
|
||||
};
|
||||
|
||||
std::vector<std::string> successful_preset_names;
|
||||
if (curr_selected_preset_type == m_create_type.base_template) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " base template";
|
||||
/****************************** clone filament preset ********************************/
|
||||
std::vector<std::string> failures;
|
||||
if (!selected_filament_presets.empty()) {
|
||||
bool create_preset_result = preset_bundle->filaments.clone_presets_for_printer(selected_filament_presets, failures, printer_preset_name, get_filament_id, rewritten);
|
||||
bool create_preset_result = preset_bundle->filaments.clone_presets_for_printer(selected_filament_presets, failures, printer_preset_name, create_filament_id, rewritten);
|
||||
if (!create_preset_result) {
|
||||
std::string message;
|
||||
for (const std::string &failure : failures) { message += "\t" + failure + "\n"; }
|
||||
@@ -2889,7 +2909,7 @@ wxWindow *CreatePrinterPresetDialog::create_page2_dialog_buttons(wxWindow *paren
|
||||
int res = dlg.ShowModal();
|
||||
if (wxID_YES == res) {
|
||||
create_preset_result = preset_bundle->filaments.clone_presets_for_printer(selected_filament_presets, failures, printer_preset_name,
|
||||
get_filament_id, true);
|
||||
create_filament_id, true);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " printer preset no same preset but filament has same preset, user cancel create the printer preset";
|
||||
return;
|
||||
@@ -2905,7 +2925,7 @@ wxWindow *CreatePrinterPresetDialog::create_page2_dialog_buttons(wxWindow *paren
|
||||
if (!selected_process_presets.empty()) {
|
||||
generate_process_presets_data(selected_process_presets, printer_nozzle_name);
|
||||
bool create_preset_result = preset_bundle->prints.clone_presets_for_printer(selected_process_presets, failures, printer_preset_name,
|
||||
get_filament_id, rewritten);
|
||||
create_filament_id, rewritten);
|
||||
if (!create_preset_result) {
|
||||
std::string message;
|
||||
for (const std::string &failure : failures) { message += "\t" + failure + "\n"; }
|
||||
@@ -2914,7 +2934,7 @@ wxWindow *CreatePrinterPresetDialog::create_page2_dialog_buttons(wxWindow *paren
|
||||
wxYES | wxYES_DEFAULT | wxCENTRE);
|
||||
int res = dlg.ShowModal();
|
||||
if (wxID_YES == res) {
|
||||
create_preset_result = preset_bundle->prints.clone_presets_for_printer(selected_process_presets, failures, printer_preset_name, get_filament_id, true);
|
||||
create_preset_result = preset_bundle->prints.clone_presets_for_printer(selected_process_presets, failures, printer_preset_name, create_filament_id, true);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " printer preset no same preset but process has same preset, user cancel create the printer preset";
|
||||
return;
|
||||
@@ -2926,7 +2946,7 @@ wxWindow *CreatePrinterPresetDialog::create_page2_dialog_buttons(wxWindow *paren
|
||||
/****************************** clone filament preset ********************************/
|
||||
std::vector<std::string> failures;
|
||||
if (!selected_filament_presets.empty()) {
|
||||
bool create_preset_result = preset_bundle->filaments.clone_presets_for_printer(selected_filament_presets, failures, printer_preset_name, get_filament_id, rewritten);
|
||||
bool create_preset_result = preset_bundle->filaments.clone_presets_for_printer(selected_filament_presets, failures, printer_preset_name, create_filament_id, rewritten);
|
||||
if (!create_preset_result) {
|
||||
std::string message;
|
||||
for (const std::string& failure : failures) {
|
||||
@@ -2937,7 +2957,7 @@ wxWindow *CreatePrinterPresetDialog::create_page2_dialog_buttons(wxWindow *paren
|
||||
wxYES | wxYES_DEFAULT | wxCENTRE);
|
||||
int res = dlg.ShowModal();
|
||||
if (wxID_YES == res) {
|
||||
create_preset_result = preset_bundle->filaments.clone_presets_for_printer(selected_filament_presets, failures, printer_preset_name, get_filament_id, true);
|
||||
create_preset_result = preset_bundle->filaments.clone_presets_for_printer(selected_filament_presets, failures, printer_preset_name, create_filament_id, true);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " printer preset no same preset but filament has same preset, user cancel create the printer preset";
|
||||
return;
|
||||
@@ -2948,7 +2968,7 @@ wxWindow *CreatePrinterPresetDialog::create_page2_dialog_buttons(wxWindow *paren
|
||||
/****************************** clone process preset ********************************/
|
||||
failures.clear();
|
||||
if (!selected_process_presets.empty()) {
|
||||
bool create_preset_result = preset_bundle->prints.clone_presets_for_printer(selected_process_presets, failures, printer_preset_name, get_filament_id, rewritten);
|
||||
bool create_preset_result = preset_bundle->prints.clone_presets_for_printer(selected_process_presets, failures, printer_preset_name, create_filament_id, rewritten);
|
||||
if (!create_preset_result) {
|
||||
std::string message;
|
||||
for (const std::string& failure : failures) {
|
||||
@@ -2957,7 +2977,7 @@ wxWindow *CreatePrinterPresetDialog::create_page2_dialog_buttons(wxWindow *paren
|
||||
MessageDialog dlg(this, _L("Create process presets failed. As follows:\n") + from_u8(message) + _L("\nDo you want to rewrite it?"), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE);
|
||||
int res = dlg.ShowModal();
|
||||
if (wxID_YES == res) {
|
||||
create_preset_result = preset_bundle->prints.clone_presets_for_printer(selected_process_presets, failures, printer_preset_name, get_filament_id, true);
|
||||
create_preset_result = preset_bundle->prints.clone_presets_for_printer(selected_process_presets, failures, printer_preset_name, create_filament_id, true);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " printer preset no same preset but filament has same preset, user cancel create the printer preset";
|
||||
return;
|
||||
|
||||
@@ -6086,6 +6086,57 @@ TEST_CASE("A vendor updated over the air resolves against the library installed
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("The vendor and filament scans read the bundled vendors that ship as their cache alone", "[Preset][Bundle][Regression]")
|
||||
{
|
||||
ScopedTemporaryDir temp_dir;
|
||||
const fs::path profiles = temp_dir.path() / "resources" / PRESET_PROFILES_DIR;
|
||||
ScopedResourcesDir scoped_resources(temp_dir.path() / "resources");
|
||||
const std::string lib(PresetBundle::ORCA_FILAMENT_LIBRARY);
|
||||
fs::create_directories(profiles / lib / "filament");
|
||||
std::ofstream((profiles / (lib + ".json")).string())
|
||||
<< R"({"version":"1.0.0","name":")" << lib << R"(",)"
|
||||
<< R"("filament_list":[{"name":"Generic PLA","sub_path":"filament/generic_pla.json"}]})";
|
||||
std::ofstream((profiles / lib / "filament" / "generic_pla.json").string())
|
||||
<< R"({"type":"filament","name":"Generic PLA","from":"system","instantiation":"false","filament_id":"GFL99"})";
|
||||
fs::create_directories(profiles / "Acme" / "machine");
|
||||
fs::create_directories(profiles / "Acme" / "filament");
|
||||
std::ofstream((profiles / "Acme.json").string())
|
||||
<< R"({"version":"1.0.0","name":"Acme",)"
|
||||
<< R"("machine_model_list":[{"name":"Acme One","sub_path":"machine/model.json"}],)"
|
||||
<< R"("machine_list":[{"name":"Acme Printer","sub_path":"machine/printer.json"}],)"
|
||||
<< R"("filament_list":[{"name":"Acme PLA","sub_path":"filament/pla.json"}]})";
|
||||
std::ofstream((profiles / "Acme" / "machine" / "model.json").string())
|
||||
<< R"({"type":"machine_model","name":"Acme One","nozzle_diameter":"0.4"})";
|
||||
std::ofstream((profiles / "Acme" / "machine" / "printer.json").string())
|
||||
<< R"({"type":"machine","name":"Acme Printer","from":"system","instantiation":"true","printer_model":"Acme One","printer_variant":"0.4"})";
|
||||
std::ofstream((profiles / "Acme" / "filament" / "pla.json").string())
|
||||
<< R"({"type":"filament","name":"Acme PLA","from":"system","instantiation":"true","inherits":"Generic PLA","filament_id":"P0000001"})";
|
||||
|
||||
auto installed = [](const PresetCollection &presets) {
|
||||
return std::count_if(presets.get_presets().begin(), presets.get_presets().end(), [](const Preset &preset) { return !preset.is_default; });
|
||||
};
|
||||
auto scan = [&installed] {
|
||||
std::vector<std::string> found;
|
||||
PresetBundle models;
|
||||
models.load_system_models_from_json(ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||
CHECK(installed(models.printers) + installed(models.prints) + installed(models.filaments) == 0);
|
||||
for (const auto &[vendor_id, vendor] : models.vendors)
|
||||
for (const VendorProfile::PrinterModel &model : vendor.models)
|
||||
found.push_back(vendor_id + " model " + model.id);
|
||||
PresetBundle filaments;
|
||||
filaments.load_system_filaments_json(ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||
CHECK(installed(filaments.printers) + installed(filaments.prints) == 0);
|
||||
for (const Preset &preset : filaments.filaments.get_presets())
|
||||
if (!preset.is_default)
|
||||
found.push_back(preset.name + " " + preset.filament_id);
|
||||
return found;
|
||||
};
|
||||
const std::vector<std::string> expected{"Acme model Acme One", "Acme PLA P0000001"};
|
||||
REQUIRE(scan() == expected);
|
||||
reduce_vendors_to_caches(profiles, {lib, "Acme"});
|
||||
CHECK(scan() == expected);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// A default preset config for type, built the way PresetBundle builds its default presets.
|
||||
|
||||
Reference in New Issue
Block a user