diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 18a6e387c..ddcadf928 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1361,7 +1361,7 @@ const std::vector& PhysicalPrinter::printer_options() s_opts = { "preset_name", "printer_technology", - "printer_model", +// "printer_model", "host_type", "print_host", "printhost_apikey", @@ -1576,6 +1576,24 @@ void PhysicalPrinterCollection::load_printers(const std::string& dir_path, const throw Slic3r::RuntimeError(errors_cummulative); } +void PhysicalPrinterCollection::load_printer(const std::string& path, const std::string& name, DynamicPrintConfig&& config, bool select, bool save/* = false*/) +{ + auto it = this->find_printer_internal(name); + if (it == m_printers.end() || it->name != name) { + // The preset was not found. Create a new preset. + it = m_printers.emplace(it, PhysicalPrinter(name, config)); + } + + it->file = path; + it->config = std::move(config); + it->loaded = true; + if (select) + this->select_printer(*it); + + if (save) + it->save(); +} + // if there is saved user presets, contains information about "Print Host upload", // Create default printers with this presets // Note! "Print Host upload" options will be cleared after physical printer creations @@ -1623,12 +1641,39 @@ void PhysicalPrinterCollection::load_printers_from_presets(PrinterPresetCollecti } } -PhysicalPrinter* PhysicalPrinterCollection::find_printer( const std::string& name, bool first_visible_if_not_found) +PhysicalPrinter* PhysicalPrinterCollection::find_printer( const std::string& name, bool case_sensitive_search) { - auto it = this->find_printer_internal(name); + auto it = this->find_printer_internal(name, case_sensitive_search); + // Ensure that a temporary copy is returned if the preset found is currently selected. - return (it != m_printers.end() && it->name == name) ? &this->printer(it - m_printers.begin()) : - first_visible_if_not_found ? &this->printer(0) : nullptr; + auto is_equal_name = [name, case_sensitive_search](const std::string& in_name) { + if (case_sensitive_search) + return in_name == name; + return boost::to_lower_copy(in_name) == boost::to_lower_copy(name); + }; + + if (it == m_printers.end() || !is_equal_name(it->name)) + return nullptr; + return &this->printer(it - m_printers.begin()); +} + +std::deque::iterator PhysicalPrinterCollection::find_printer_internal(const std::string& name, bool case_sensitive_search/* = true*/) +{ + if (case_sensitive_search) + return Slic3r::lower_bound_by_predicate(m_printers.begin(), m_printers.end(), [&name](const auto& l) { return l.name < name; }); + + std::string low_name = boost::to_lower_copy(name); + + int i = 0; + for (const PhysicalPrinter& printer : m_printers) { + if (boost::to_lower_copy(printer.name) == low_name) + break; + i++; + } + if (i == m_printers.size()) + return m_printers.end(); + + return m_printers.begin() + i; } PhysicalPrinter* PhysicalPrinterCollection::find_printer_with_same_config(const DynamicPrintConfig& config) @@ -1667,10 +1712,13 @@ void PhysicalPrinterCollection::save_printer(PhysicalPrinter& edited_printer, co it->config = std::move(edited_printer.config); it->name = edited_printer.name; it->preset_names = edited_printer.preset_names; + // sort printers and get new it + std::sort(m_printers.begin(), m_printers.end()); + it = this->find_printer_internal(edited_printer.name); } else { // Creating a new printer. - it = m_printers.insert(it, edited_printer); + it = m_printers.emplace(it, edited_printer); } assert(it != m_printers.end()); diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index ec11d59fa..e3e16b65d 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -632,6 +632,8 @@ public: // Load ini files of the particular type from the provided directory path. void load_printers(const std::string& dir_path, const std::string& subdir); void load_printers_from_presets(PrinterPresetCollection &printer_presets); + // Load printer from the loaded configuration + void load_printer(const std::string& path, const std::string& name, DynamicPrintConfig&& config, bool select, bool save=false); // Save the printer under a new name. If the name is different from the old one, // a new printer is stored into the list of printers. @@ -687,10 +689,11 @@ public: // Return a preset by its name. If the preset is active, a temporary copy is returned. // If a preset is not found by its name, null is returned. - PhysicalPrinter* find_printer(const std::string& name, bool first_visible_if_not_found = false); - const PhysicalPrinter* find_printer(const std::string& name, bool first_visible_if_not_found = false) const + // It is possible case (in)sensitive search + PhysicalPrinter* find_printer(const std::string& name, bool case_sensitive_search = true); + const PhysicalPrinter* find_printer(const std::string& name, bool case_sensitive_search = true) const { - return const_cast(this)->find_printer(name, first_visible_if_not_found); + return const_cast(this)->find_printer(name, case_sensitive_search); } // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. @@ -701,15 +704,11 @@ public: private: PhysicalPrinterCollection& operator=(const PhysicalPrinterCollection& other); - // Find a preset position in the sorted list of presets. - // The "-- default -- " preset is always the first, so it needs - // to be handled differently. - // If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name. - std::deque::iterator find_printer_internal(const std::string& name) - { - return Slic3r::lower_bound_by_predicate(m_printers.begin(), m_printers.end(), [&name](const auto& l) { return l.name < name; }); - } - std::deque::const_iterator find_printer_internal(const std::string& name) const + // Find a physical printer position in the sorted list of printers. + // The name of a printer should be unique and case insensitive + // Use this functions with case_sensitive_search = false, when you need case insensitive search + std::deque::iterator find_printer_internal(const std::string& name, bool case_sensitive_search = true); + std::deque::const_iterator find_printer_internal(const std::string& name, bool case_sensitive_search = true) const { return const_cast(this)->find_printer_internal(name); } diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index c100e6971..4309f0732 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -1113,16 +1113,22 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla std::vector loaded_sla_prints; std::vector loaded_sla_materials; std::vector loaded_printers; + std::vector loaded_physical_printers; std::string active_print; std::vector active_filaments; std::string active_sla_print; std::string active_sla_material; std::string active_printer; + std::string active_physical_printer; size_t presets_loaded = 0; + size_t ph_printers_loaded = 0; + for (const auto §ion : tree) { PresetCollection *presets = nullptr; std::vector *loaded = nullptr; std::string preset_name; + PhysicalPrinterCollection *ph_printers = nullptr; + std::string ph_printer_name; if (boost::starts_with(section.first, "print:")) { presets = &this->prints; loaded = &loaded_prints; @@ -1143,6 +1149,10 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla presets = &this->printers; loaded = &loaded_printers; preset_name = section.first.substr(8); + } else if (boost::starts_with(section.first, "physical_printer:")) { + ph_printers = &this->physical_printers; + loaded = &loaded_physical_printers; + ph_printer_name = section.first.substr(17); } else if (section.first == "presets") { // Load the names of the active presets. for (auto &kvp : section.second) { @@ -1161,6 +1171,8 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla active_sla_material = kvp.second.data(); } else if (kvp.first == "printer") { active_printer = kvp.second.data(); + }else if (kvp.first == "physical_printer") { + active_physical_printer = kvp.second.data(); } } } else if (section.first == "obsolete_presets") { @@ -1317,9 +1329,46 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla ++ presets_loaded; } + + if (ph_printers != nullptr) { + // Load the physical printer + const DynamicPrintConfig& default_config = ph_printers->default_config(); + DynamicPrintConfig config = default_config; + + for (auto& kvp : section.second) + config.set_deserialize(kvp.first, kvp.second.data()); + + // Report configuration fields, which are misplaced into a wrong group. + std::string incorrect_keys = Preset::remove_invalid_keys(config, default_config); + if (!incorrect_keys.empty()) + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The physical printer \"" << + section.first << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed"; + + const PhysicalPrinter* ph_printer_existing = ph_printers->find_printer(ph_printer_name, false); + if (ph_printer_existing != nullptr) { + BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The physical printer \"" << + section.first << "\" has already been loaded from another Confing Bundle."; + continue; + } + + // Decide a full path to this .ini file. + auto file_name = boost::algorithm::iends_with(ph_printer_name, ".ini") ? ph_printer_name : ph_printer_name + ".ini"; + auto file_path = (boost::filesystem::path(data_dir()) +#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR + // Store the physical printers into a "presets" directory. + / "presets" +#else + // Store the physical printers at the same location as the upstream Slic3r. +#endif + / "physical_printer" / file_name).make_preferred(); + // Load the preset into the list of presets, save it to disk. + ph_printers->load_printer(file_path.string(), ph_printer_name, std::move(config), false, flags & LOAD_CFGBNDLE_SAVE); + + ++ph_printers_loaded; + } } - // 3) Activate the presets. + // 3) Activate the presets and physical printer if any exists. if ((flags & LOAD_CFGBNDLE_SYSTEM) == 0) { if (! active_print.empty()) prints.select_preset_by_name(active_print, true); @@ -1329,6 +1378,8 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla sla_materials.select_preset_by_name(active_sla_material, true); if (! active_printer.empty()) printers.select_preset_by_name(active_printer, true); + if (! active_physical_printer.empty()) + physical_printers.select_printer(active_physical_printer +" * " + active_printer); // Activate the first filament preset. if (! active_filaments.empty() && ! active_filaments.front().empty()) filaments.select_preset_by_name(active_filaments.front(), true); @@ -1338,7 +1389,7 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla this->update_compatible(PresetSelectCompatibleType::Never); } - return presets_loaded; + return presets_loaded + ph_printers_loaded; } void PresetBundle::update_multi_material_filament_presets() @@ -1458,7 +1509,7 @@ void PresetBundle::update_compatible(PresetSelectCompatibleType select_other_pri } } -void PresetBundle::export_configbundle(const std::string &path, bool export_system_settings) +void PresetBundle::export_configbundle(const std::string &path, bool export_system_settings, bool export_physical_printers/* = false*/) { boost::nowide::ofstream c; c.open(path, std::ios::out | std::ios::trunc); @@ -1482,6 +1533,14 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst } } + if (export_physical_printers) { + for (const PhysicalPrinter& ph_printer : this->physical_printers) { + c << std::endl << "[physical_printer:" << ph_printer.name << "]" << std::endl; + for (const std::string& opt_key : ph_printer.config.keys()) + c << opt_key << " = " << ph_printer.config.opt_serialize(opt_key) << std::endl; + } + } + // Export the names of the active presets. c << std::endl << "[presets]" << std::endl; c << "print = " << this->prints.get_selected_preset_name() << std::endl; @@ -1497,6 +1556,8 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst c << "filament" << suffix << " = " << this->filament_presets[i] << std::endl; } + if (export_physical_printers && this->physical_printers.get_selected_idx() >= 0) + c << "physical_printer = " << this->physical_printers.get_selected_printer_name() << std::endl; #if 0 // Export the following setting values from the provided setting repository. static const char *settings_keys[] = { "autocenter" }; diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index ff02bbeae..609e25e2c 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -102,7 +102,7 @@ public: size_t load_configbundle(const std::string &path, unsigned int flags = LOAD_CFGBNDLE_SAVE); // Export a config bundle file containing all the presets and the names of the active presets. - void export_configbundle(const std::string &path, bool export_system_settings = false); + void export_configbundle(const std::string &path, bool export_system_settings = false, bool export_physical_printers = false); // Enable / disable the "- default -" preset. void set_default_suppressed(bool default_suppressed); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 3165b625b..ca9ddf512 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1071,6 +1071,9 @@ void MainFrame::init_menubar() append_menu_item(export_menu, wxID_ANY, _L("Export Config &Bundle") + dots, _L("Export all presets to file"), [this](wxCommandEvent&) { export_configbundle(); }, "export_config_bundle", nullptr, [this]() {return true; }, this); + append_menu_item(export_menu, wxID_ANY, _L("Export Config Bundle With Physical Printers") + dots, _L("Export all presets including physical printers to file"), + [this](wxCommandEvent&) { export_configbundle(true); }, "export_config_bundle", nullptr, + [this]() {return true; }, this); append_submenu(fileMenu, export_menu, wxID_ANY, _L("&Export"), ""); append_menu_item(fileMenu, wxID_ANY, _L("Ejec&t SD card / Flash drive") + dots + "\tCtrl+T", _L("Eject SD card / Flash drive after the G-code was exported to it."), @@ -1641,7 +1644,7 @@ bool MainFrame::load_config_file(const std::string &path) return true; } -void MainFrame::export_configbundle() +void MainFrame::export_configbundle(bool export_physical_printers /*= false*/) { if (!wxGetApp().check_unsaved_changes()) return; @@ -1663,7 +1666,7 @@ void MainFrame::export_configbundle() // Export the config bundle. wxGetApp().app_config->update_config_dir(get_dir_name(file)); try { - wxGetApp().preset_bundle->export_configbundle(file.ToUTF8().data()); + wxGetApp().preset_bundle->export_configbundle(file.ToUTF8().data(), false, export_physical_printers); } catch (const std::exception &ex) { show_error(this, ex.what()); } diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 18d2a73bd..0a6cefd9a 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -180,7 +180,7 @@ public: void load_config_file(); // Open a config file. Return true if loaded. bool load_config_file(const std::string &path); - void export_configbundle(); + void export_configbundle(bool export_physical_printers = false); void load_configbundle(wxString file = wxEmptyString); void load_config(const DynamicPrintConfig& config); // Select tab in m_tabpanel diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index aa8a3811a..827bff28c 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -468,15 +468,17 @@ void PhysicalPrinterDialog::OnOK(wxEvent& event) } PhysicalPrinterCollection& printers = wxGetApp().preset_bundle->physical_printers; - const PhysicalPrinter* existing = printers.find_printer(into_u8(printer_name)); + const PhysicalPrinter* existing = printers.find_printer(into_u8(printer_name), false); if (existing && into_u8(printer_name) != printers.get_selected_printer_name()) { - wxString msg_text = from_u8((boost::format(_u8L("Printer with name \"%1%\" already exists.")) % printer_name).str()); + wxString msg_text = from_u8((boost::format(_u8L("Printer with name \"%1%\" already exists.")) % existing->name/*printer_name*/).str()); msg_text += "\n" + _L("Replace?"); wxMessageDialog dialog(nullptr, msg_text, _L("Warning"), wxICON_WARNING | wxYES | wxNO); if (dialog.ShowModal() == wxID_NO) return; + + m_printer.name = existing->name; } std::set repeat_presets;