From a3ded8fa95f758f03688bd36c3d455f3b1eef547 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sat, 14 Mar 2020 18:35:42 +0100 Subject: [PATCH] Reworked filaments / SLA materials in installation wizard: 1) When the wizard is initialized, filament and SLA profile names are verified and current names of renamed profiles are resolved. Fixes "Add/Remove Filaments is not hiding all of the un-checked filaments #3835" 2) When adding a printer model, default materials are installed in case the printer model has no default material installed. 3) When leaving the Filaments or SLA materials page, and some printer models have no material installed, those Printer Models are listed in a message box and only for those printer models the default materials are installed. --- src/slic3r/GUI/ConfigWizard.cpp | 202 ++++++++++++++++-------- src/slic3r/GUI/ConfigWizard_private.hpp | 19 +-- src/slic3r/GUI/Preset.cpp | 10 +- src/slic3r/GUI/Preset.hpp | 3 +- src/slic3r/GUI/PresetBundle.hpp | 2 + 5 files changed, 149 insertions(+), 87 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index bbdf5f2a1..d35cfa2b6 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1473,12 +1473,34 @@ void ConfigWizard::priv::load_vendors() pair.second.preset_bundle->load_installed_printers(appconfig_new); } - if (app_config->has_section(AppConfig::SECTION_FILAMENTS)) { - appconfig_new.set_section(AppConfig::SECTION_FILAMENTS, app_config->get_section(AppConfig::SECTION_FILAMENTS)); - } - if (app_config->has_section(AppConfig::SECTION_MATERIALS)) { - appconfig_new.set_section(AppConfig::SECTION_MATERIALS, app_config->get_section(AppConfig::SECTION_MATERIALS)); - } + // Copy installed filaments and SLA material names from app_config to appconfig_new + // while resolving current names of profiles, which were renamed in the meantime. + for (PrinterTechnology technology : { ptFFF, ptSLA }) { + const std::string §ion_name = (technology == ptFFF) ? AppConfig::SECTION_FILAMENTS : AppConfig::SECTION_MATERIALS; + std::map section_new; + if (app_config->has_section(section_name)) { + const std::map §ion_old = app_config->get_section(section_name); + for (const std::pair &material_name_and_installed : section_old) + if (material_name_and_installed.second == "1") { + // Material is installed. Resolve it in bundles. + const std::string &material_name = material_name_and_installed.first; + for (auto &bundle : bundles) { + const PresetCollection &materials = bundle.second.preset_bundle->materials(technology); + const Preset *preset = materials.find_preset(material_name); + if (preset == nullptr) { + // Not found. Maybe the material preset is there, bu it was was renamed? + const std::string *new_name = materials.get_preset_name_renamed(material_name); + if (new_name != nullptr) + preset = materials.find_preset(material_name); + } + if (preset != nullptr) + // Materal preset was found, mark it as installed. + section_new[preset->name] = "1"; + } + } + } + appconfig_new.set_section(section_name, section_new); + }; } void ConfigWizard::priv::add_page(ConfigWizardPage *page) @@ -1642,9 +1664,9 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPicker } } - // if at list one printer is selected but there in no one selected material, - // select materials which is default for selected printer(s) - select_default_materials_if_needed(pair.second.vendor_profile, page->technology, evt.model_id); + // When a printer model is picked, but there is no material installed compatible with this printer model, + // install default materials for selected printer model silently. + check_and_install_missing_materials(page->technology, evt.model_id); } if (page->technology & T_FFF) { @@ -1654,41 +1676,26 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPicker } } -void ConfigWizard::priv::select_default_materials_for_printer_model(const std::vector& models, Technology technology, const std::string& model_id) +void ConfigWizard::priv::select_default_materials_for_printer_model(const VendorProfile::PrinterModel &printer_model, Technology technology) { PageMaterials* page_materials = technology & T_FFF ? page_filaments : page_sla_materials; - - auto it = std::find_if(models.begin(), models.end(), [model_id](VendorProfile::PrinterModel model) {return model_id == model.id; }); - if (it != models.end()) - for (const std::string& material : it->default_materials) - appconfig_new.set(page_materials->materials->appconfig_section(), material, "1"); + for (const std::string& material : printer_model.default_materials) + appconfig_new.set(page_materials->materials->appconfig_section(), material, "1"); } -void ConfigWizard::priv::select_default_materials_if_needed(VendorProfile* vendor_profile, Technology technology, const std::string& model_id) +void ConfigWizard::priv::select_default_materials_for_printer_models(Technology technology, const std::set &printer_models) { - if ((technology & T_FFF && !any_fff_selected) || - (technology & T_SLA && !any_sla_selected) || - check_materials_in_config(technology, false)) - return; + PageMaterials *page_materials = technology & T_FFF ? page_filaments : page_sla_materials; + const std::string &appconfig_section = page_materials->materials->appconfig_section(); - select_default_materials_for_printer_model(vendor_profile->models, technology, model_id); -} - -void ConfigWizard::priv::selected_default_materials(Technology technology) -{ - auto select_default_materials_for_printer_page = [this](PagePrinters * page_printers, Technology technology) + auto select_default_materials_for_printer_page = [this, appconfig_section, printer_models](PagePrinters *page_printers, Technology technology) { - std::set selected_models = page_printers->get_selected_models(); - const std::string vendor_id = page_printers->get_vendor_id(); - + const std::string vendor_id = page_printers->get_vendor_id(); for (auto& pair : bundles) - { - if (pair.first != vendor_id) - continue; - - for (const std::string& model_id : selected_models) - select_default_materials_for_printer_model(pair.second.vendor_profile->models, technology, model_id); - } + if (pair.first == vendor_id) + for (const VendorProfile::PrinterModel *printer_model : printer_models) + for (const std::string &material : printer_model->default_materials) + appconfig_new.set(appconfig_section, material, "1"); }; PagePrinters* page_printers = technology & T_FFF ? page_fff : page_msla; @@ -1702,7 +1709,7 @@ void ConfigWizard::priv::selected_default_materials(Technology technology) } update_materials(technology); - (technology& T_FFF ? page_filaments : page_sla_materials)->reload_presets(); + ((technology & T_FFF) ? page_filaments : page_sla_materials)->reload_presets(); } void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool install) @@ -1743,51 +1750,105 @@ bool ConfigWizard::priv::on_bnt_finish() // theres no need to check that filament is selected if we have only custom printer if (custom_printer_selected && !any_fff_selected && !any_sla_selected) return true; // check, that there is selected at least one filament/material - return check_materials_in_config(T_ANY); + return check_and_install_missing_materials(T_ANY); } -bool ConfigWizard::priv::check_materials_in_config(Technology technology, bool show_info_msg) +// This allmighty method verifies, whether there is at least a single compatible filament or SLA material installed +// for each Printer preset of each Printer Model installed. +// +// In case only_for_model_id is set, then the test is done for that particular printer model only, and the default materials are installed silently. +// Otherwise the user is quieried whether to install the missing default materials or not. +// +// Return true if the tested Printer Models already had materials installed. +// Return false if there were some Printer Models with missing materials, independent from whether the defaults were installed for these +// respective Printer Models or not. +bool ConfigWizard::priv::check_and_install_missing_materials(Technology technology, const std::string &only_for_model_id) { - const auto exist_preset = [this](const std::string& section, const Materials& materials) + // Walk over all installed Printer presets and verify whether there is a filament or SLA material profile installed at the same PresetBundle, + // which is compatible with it. + const auto printer_models_missing_materials = [this, only_for_model_id](PrinterTechnology technology, const std::string §ion) { - if (appconfig_new.has_section(section) && - !appconfig_new.get_section(section).empty()) - { - const std::map& appconfig_presets = appconfig_new.get_section(section); - for (const auto& preset : appconfig_presets) - if (materials.exist_preset(preset.first)) - return true; + const std::map &appconfig_presets = appconfig_new.has_section(section) ? appconfig_new.get_section(section) : std::map(); + std::set printer_models_without_material; + for (const auto &pair : bundles) { + const PresetCollection &materials = pair.second.preset_bundle->materials(technology); + for (const auto &printer : pair.second.preset_bundle->printers) { + if (printer.is_visible && printer.printer_technology() == technology) { + const VendorProfile::PrinterModel *printer_model = PresetUtils::system_printer_model(printer); + assert(printer_model != nullptr); + if ((only_for_model_id.empty() || only_for_model_id == printer_model->id) && + printer_models_without_material.find(printer_model) == printer_models_without_material.end()) { + bool has_material = false; + for (const std::pair &preset : appconfig_presets) { + if (preset.second == "1") { + const Preset *material = materials.find_preset(preset.first, false); + if (material != nullptr && is_compatible_with_printer(PresetWithVendorProfile(*material, nullptr), PresetWithVendorProfile(printer, nullptr))) { + has_material = true; + break; + } + } + } + if (! has_material) + printer_models_without_material.insert(printer_model); + } + } + } } - return false; + assert(printer_models_without_material.empty() || only_for_model_id.empty() || only_for_model_id == (*printer_models_without_material.begin())->id); + return printer_models_without_material; }; - const auto ask_and_selected_default_materials = [this](wxString message, Technology technology) + const auto ask_and_select_default_materials = [this](const wxString &message, const std::set &printer_models, Technology technology) { wxMessageDialog msg(q, message, _(L("Notice")), wxYES_NO); if (msg.ShowModal() == wxID_YES) - selected_default_materials(technology); + select_default_materials_for_printer_models(technology, printer_models); }; - if (any_fff_selected && technology & T_FFF && !exist_preset(AppConfig::SECTION_FILAMENTS, filaments)) - { - if (show_info_msg) - { - wxString message = _(L("You have to select at least one filament for selected printers")) + "\n\n\t" + - _(L("Do you want to automatic select default filaments?")); - ask_and_selected_default_materials(message, T_FFF); + const auto printer_model_list = [](const std::set &printer_models) -> wxString { + wxString out; + for (const VendorProfile::PrinterModel *printer_model : printer_models) { + out += "\t\t"; + out += from_u8(printer_model->name); + out += "\n"; + } + return out; + }; + + if (any_fff_selected && (technology & T_FFF)) { + std::set printer_models_without_material = printer_models_missing_materials(ptFFF, AppConfig::SECTION_FILAMENTS); + if (! printer_models_without_material.empty()) { + if (only_for_model_id.empty()) + ask_and_select_default_materials( + _L("The following FFF printer models have no filament selected:") + + "\n\n\t" + + printer_model_list(printer_models_without_material) + + "\n\n\t" + + _L("Do you want to select default filaments for these FFF printer models?"), + printer_models_without_material, + T_FFF); + else + select_default_materials_for_printer_model(**printer_models_without_material.begin(), T_FFF); + return false; } - return false; } - if (any_sla_selected && technology & T_SLA && !exist_preset(AppConfig::SECTION_MATERIALS, sla_materials)) - { - if (show_info_msg) - { - wxString message = _(L("You have to select at least one material for selected printers")) + "\n\n\t" + - _(L("Do you want to automatic select default materials?")); - ask_and_selected_default_materials(message, T_SLA); - } - return false; + if (any_sla_selected && (technology & T_SLA)) { + std::set printer_models_without_material = printer_models_missing_materials(ptSLA, AppConfig::SECTION_MATERIALS); + if (! printer_models_without_material.empty()) { + if (only_for_model_id.empty()) + ask_and_select_default_materials( + _L("The following SLA printer models have no materials selected:") + + "\n\n\t" + + printer_model_list(printer_models_without_material) + + "\n\n\t" + + _L("Do you want to select default SLA materials for these printer models?"), + printer_models_without_material, + T_SLA); + else + select_default_materials_for_printer_model(**printer_models_without_material.begin(), T_SLA); + return false; + } } return true; @@ -2062,8 +2123,11 @@ ConfigWizard::ConfigWizard(wxWindow *parent) { // check, that there is selected at least one filament/material ConfigWizardPage* active_page = this->p->index->active_page(); - if ( (active_page == p->page_filaments || active_page == p->page_sla_materials) - && !p->check_materials_in_config(dynamic_cast(active_page)->materials->technology)) + if (// Leaving the filaments or SLA materials page and + (active_page == p->page_filaments || active_page == p->page_sla_materials) && + // some Printer models had no filament or SLA material selected. + ! p->check_and_install_missing_materials(dynamic_cast(active_page)->materials->technology)) + // In that case don't leave the page and the function above queried the user whether to install default materials. return; this->p->index->go_next(); }); diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 64081153d..49993bfb1 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -82,14 +82,6 @@ struct Materials } } - bool exist_preset(const std::string& preset_name) const - { - for (const Preset* preset : presets) - if (preset->name == preset_name) - return true; - return false; - } - static const std::string UNKNOWN; static const std::string& get_filament_type(const Preset *preset); static const std::string& get_filament_vendor(const Preset *preset); @@ -503,17 +495,12 @@ struct ConfigWizard::priv void on_custom_setup(const bool custom_wanted); void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt); - void select_default_materials_for_printer_model(const std::vector &models, - Technology technology, - const std::string & model_id); - void select_default_materials_if_needed(VendorProfile* vendor_profile, - Technology technology, - const std::string &model_id); - void selected_default_materials(Technology technology); + void select_default_materials_for_printer_model(const VendorProfile::PrinterModel &printer_model, Technology technology); + void select_default_materials_for_printer_models(Technology technology, const std::set &printer_models); void on_3rdparty_install(const VendorProfile *vendor, bool install); bool on_bnt_finish(); - bool check_materials_in_config(Technology technology, bool show_info_msg = true); + bool check_and_install_missing_materials(Technology technology, const std::string &only_for_model_id = std::string()); void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater); // #ys_FIXME_alise void update_presets_in_config(const std::string& section, const std::string& alias_key, bool add); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 84bd9bd74..1b03a558d 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -381,7 +381,7 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config) return; is_visible = app_config.get_variant(vendor->id, model, variant); } else if (type == TYPE_FILAMENT || type == TYPE_SLA_MATERIAL) { - const char *section_name = (type == TYPE_FILAMENT) ? "filaments" : "sla_materials"; + const std::string §ion_name = (type == TYPE_FILAMENT) ? AppConfig::SECTION_FILAMENTS : AppConfig::SECTION_MATERIALS; if (app_config.has_section(section_name)) { // Check whether this profile is marked as "installed" in PrusaSlicer.ini, // or whether a profile is marked as "installed", which this profile may have been renamed from. @@ -1032,6 +1032,14 @@ const std::string& PresetCollection::get_preset_name_by_alias(const std::string& return alias; } +const std::string* PresetCollection::get_preset_name_renamed(const std::string &old_name) const +{ + auto it_renamed = m_map_system_profile_renamed.find(old_name); + if (it_renamed != m_map_system_profile_renamed.end()) + return &it_renamed->second; + return nullptr; +} + const std::string& PresetCollection::get_suffix_modified() { return g_suffix_modified; } diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 1116070b2..efcbd9a28 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -361,7 +361,8 @@ public: PresetWithVendorProfile get_preset_with_vendor_profile(const Preset &preset) const; PresetWithVendorProfile get_edited_preset_with_vendor_profile() const { return this->get_preset_with_vendor_profile(this->get_edited_preset()); } - const std::string& get_preset_name_by_alias(const std::string& alias) const; + const std::string& get_preset_name_by_alias(const std::string& alias) const; + const std::string* get_preset_name_renamed(const std::string &old_name) const; // used to update preset_choice from Tab const std::deque& get_presets() const { return m_presets; } diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index 33c9d5ff4..e4300c15e 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -42,6 +42,8 @@ public: PresetCollection sla_prints; PresetCollection filaments; PresetCollection sla_materials; + PresetCollection& materials(PrinterTechnology pt) { return pt == ptFFF ? this->filaments : this->sla_materials; } + const PresetCollection& materials(PrinterTechnology pt) const { return pt == ptFFF ? this->filaments : this->sla_materials; } PrinterPresetCollection printers; // Filament preset names for a multi-extruder or multi-material print. // extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()