diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 96a5572435..0f1b6cef61 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -165,6 +165,13 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem res.repo_id = ""; } + const auto repo_prefix = vendor_section.find("repo_prefix"); + if (repo_prefix != vendor_section.not_found()) { + res.repo_prefix = repo_prefix->second.data(); + } else { + res.repo_prefix = ""; + } + if (! load_all) { return res; } diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index a2985ac4ec..5b430442f4 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -40,6 +40,7 @@ public: std::string config_update_url; std::string changelog_url; std::string repo_id; + std::string repo_prefix; bool templates_profile { false }; struct PrinterVariant { diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index d2b2459a5a..e09515f08c 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -23,6 +23,8 @@ set(SLIC3R_GUI_SOURCES GUI/UserAccountCommunication.hpp GUI/UserAccountSession.cpp GUI/UserAccountSession.hpp + GUI/UserAccountUtils.cpp + GUI/UserAccountUtils.hpp GUI/UserAccount.cpp GUI/UserAccount.hpp GUI/WebViewDialog.cpp diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 805d012a43..eca27a09b6 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -101,6 +101,7 @@ #include "PhysicalPrinterDialog.hpp" #include "WifiConfigDialog.hpp" #include "UserAccount.hpp" +#include "UserAccountUtils.hpp" #include "WebViewDialog.hpp" #include "LoginDialog.hpp" // IWYU pragma: keep #include "PresetArchiveDatabase.hpp" @@ -3823,14 +3824,98 @@ bool GUI_App::select_printer_preset(const Preset* preset) return is_installed; } +namespace { +const Preset* find_preset_by_nozzle_and_options( + const PrinterPresetCollection& collection + , const std::string& model_id + , const std::string& nozzle + , const std::map& options) +{ + // find all matching presets when repo prefix is ommited + std::vector results; + for (const Preset &preset : collection) { + // trim repo prefix + std::string printer_model = preset.config.opt_string("printer_model"); + std::string vendor_repo_prefix; + if (preset.vendor) { + vendor_repo_prefix = preset.vendor->repo_prefix; + } else if (std::string inherits = preset.inherits(); !inherits.empty()) { + const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits); + if (parent && parent->vendor) { + vendor_repo_prefix = parent->vendor->repo_prefix; + } + } + if (printer_model.find(vendor_repo_prefix) == 0) { + printer_model = printer_model.substr(vendor_repo_prefix.size() + ); + boost::trim_left(printer_model); + } + + if (!preset.is_system || printer_model != model_id) + continue; + // nozzle diameter + if (!nozzle.empty() && preset.config.has("nozzle_diameter")) { + double nozzle_diameter = static_cast(preset.config.option("nozzle_diameter"))->values[0]; + std::string nozzle_diameter_serialized = into_u8(double_to_string(nozzle_diameter)); + if (size_t pos = nozzle_diameter_serialized.find(",") != std::string::npos) { + nozzle_diameter_serialized.replace(pos, 1, 1, '.'); + } + if (nozzle != nozzle_diameter_serialized) { + continue; + } + } + // other options + bool failed = false; + for (const auto& opt : options) { + if (!preset.config.has(opt.first)) { + failed = true; + break; + } + if (preset.config.option(opt.first)->serialize() != opt.second) { + failed = true; + break; + } + } + if (failed) { + continue; + } + results.push_back(&preset); + } + // find visible without prefix + for (const Preset *preset : results) { + if (preset->is_visible && preset->config.opt_string("printer_model") == model_id) { + return preset; + } + } + // find one visible + for (const Preset *preset : results) { + if (preset->is_visible) { + return preset; + } + } + // find one without prefix + for (const Preset* preset : results) { + if (preset->config.opt_string("printer_model") == model_id) { + return preset; + } + } + if (results.size() != 0) { + return results.front(); + } + return nullptr; +} +} + bool GUI_App::select_printer_from_connect(const std::string& msg) { - // parse message - std::string model_name = plater()->get_user_account()->get_keyword_from_json(msg, "printer_model"); - std::string uuid = plater()->get_user_account()->get_keyword_from_json(msg, "uuid"); + // parse message "binary_gcode" + boost::property_tree::ptree ptree; + std::string model_name = UserAccountUtils::get_keyword_from_json(ptree, msg, "printer_model"); + std::string uuid = UserAccountUtils::get_keyword_from_json(ptree, msg, "uuid"); if (model_name.empty()) { std::vector compatible_printers; - plater()->get_user_account()->fill_supported_printer_models_from_json(msg, compatible_printers); + UserAccountUtils::fill_supported_printer_models_from_json(ptree, compatible_printers); if (!compatible_printers.empty()) { model_name = compatible_printers.front(); } @@ -3839,10 +3924,12 @@ bool GUI_App::select_printer_from_connect(const std::string& msg) BOOST_LOG_TRIVIAL(error) << "Failed to select printer from Connect. Printer_model is empty."; return false; } - std::string nozzle = plater()->get_user_account()->get_nozzle_from_json(msg); + std::string nozzle = UserAccountUtils::get_nozzle_from_json(ptree); + std::map config_options_to_match; + //UserAccountUtils::fill_config_options_from_json(ptree, config_options_to_match); BOOST_LOG_TRIVIAL(info) << "Select printer from Connect. Model: " << model_name << "nozzle: " << nozzle; // select printer - const Preset* printer_preset = preset_bundle->printers.find_system_preset_by_model_and_variant(model_name, nozzle); + const Preset* printer_preset = find_preset_by_nozzle_and_options(preset_bundle->printers, model_name, nozzle, config_options_to_match); bool is_installed = printer_preset && select_printer_preset(printer_preset); // notification std::string out = printer_preset ? @@ -3935,7 +4022,7 @@ void GUI_App::select_filament_from_connect(const std::string& msg) { // parse message std::vector materials; - plater()->get_user_account()->fill_material_from_json(msg, materials); + UserAccountUtils::fill_material_from_json(msg, materials); if (materials.empty()) { BOOST_LOG_TRIVIAL(error) << "Failed to select filament from Connect. No material data."; return; @@ -3969,7 +4056,8 @@ void GUI_App::handle_connect_request_printer_select(const std::string& msg) // Here comes code from ConnectWebViewPanel // It only contains uuid of a printer to be selected // Lets queue it and wait on result. The result is send via event to plater, where it is send to handle_connect_request_printer_select_inner - std::string uuid = plater()->get_user_account()->get_keyword_from_json(msg, "uuid"); + boost::property_tree::ptree ptree; + std::string uuid = UserAccountUtils::get_keyword_from_json(ptree, msg, "uuid"); plater()->get_user_account()->enqueue_printer_data_action(uuid); } void GUI_App::handle_connect_request_printer_select_inner(const std::string & msg) diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 4cae18c133..10b05d62c2 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -728,9 +728,10 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change) for (PresetForPrinter* prstft : m_presets) { std::string preset_name = prstft->get_preset_name(); if (Preset* preset = wxGetApp().preset_bundle->printers.find_preset(preset_name)) { - std::string model_id = preset->config.opt_string("printer_model"); + std::string model_id = preset->config.opt_string("printer_model"); if (preset->vendor) { - if (preset->vendor->name == "Prusa Research") { + // No need to remove prefix from printer_model, family is not prefixed + if (preset->vendor->name.find("Prusa Research") != std::string::npos) { const std::vector& models = preset->vendor->models; auto it = std::find_if(models.begin(), models.end(), [model_id](const VendorProfile::PrinterModel& model) { return model.id == model_id; }); @@ -754,11 +755,16 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change) break; } std::string model_id = preset->config.opt_string("printer_model"); - if (preset->vendor && preset->vendor->name != "Prusa Research") { - connect.supported = false; - break; + // remove prefix from printer_model + if (preset->vendor) { + std::string vendor_repo_prefix; + vendor_repo_prefix = preset->vendor->repo_prefix; + if (model_id.find(vendor_repo_prefix) == 0) { + model_id = model_id.substr(vendor_repo_prefix.size()); + boost::trim_left(model_id); + } } - if (preset->vendor && preset->vendor->name != "Prusa Research") { + if (preset->vendor && preset->vendor->name.find("Prusa Research") == std::string::npos) { connect.supported = false; break; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 162c8b09bf..9c70d60074 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -123,6 +123,7 @@ #include "Gizmos/GLGizmoCut.hpp" #include "FileArchiveDialog.hpp" #include "UserAccount.hpp" +#include "UserAccountUtils.hpp" #include "DesktopIntegrationDialog.hpp" #include "WebViewDialog.hpp" #include "PresetArchiveDatabase.hpp" @@ -2059,6 +2060,22 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool if (full_config.has("binary_gcode")) // needed for SLA full_config.set("binary_gcode", bool(full_config.opt_bool("binary_gcode") & wxGetApp().app_config->get_bool("use_binary_gcode_when_supported"))); + const Preset &selected_printer = wxGetApp().preset_bundle->printers.get_selected_preset(); + std::string printer_model_serialized = full_config.option("printer_model")->serialize(); + std::string vendor_repo_prefix; + if (selected_printer.vendor) { + vendor_repo_prefix = selected_printer.vendor->repo_prefix; + } else if (std::string inherits = selected_printer.inherits(); !inherits.empty()) { + const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits); + if (parent && parent->vendor) { + vendor_repo_prefix = parent->vendor->repo_prefix; + } + } + if (printer_model_serialized.find(vendor_repo_prefix) == 0) { + printer_model_serialized = printer_model_serialized.substr(vendor_repo_prefix.size()); + boost::trim_left(printer_model_serialized); + full_config.set("printer_model", printer_model_serialized); + } // If the update_background_process() was not called by the timer, kill the timer, // so the update_restart_background_process() will not be called again in vain. background_process_timer.Stop(); @@ -3648,7 +3665,9 @@ bool Plater::priv::can_show_upload_to_connect() const vendor_id = parent->vendor->id; } } - return vendor_id.compare(0, 5, "Prusa") == 0; + // Upload to Connect should show only for prusa printers + // Some vendors might have prefixed name due to repository id. + return vendor_id.find("Prusa") != std::string::npos; } void Plater::priv::show_action_buttons(const bool ready_to_slice_) const @@ -6022,10 +6041,11 @@ void Plater::connect_gcode() */ const Preset* selected_printer_preset = &wxGetApp().preset_bundle->printers.get_selected_preset(); - const std::string filename = p->user_account->get_keyword_from_json(dialog_msg, "filename"); - const std::string team_id = p->user_account->get_keyword_from_json(dialog_msg, "team_id"); + boost::property_tree::ptree ptree; + const std::string filename = UserAccountUtils::get_keyword_from_json(ptree, dialog_msg, "filename"); + const std::string team_id = UserAccountUtils::get_keyword_from_json(ptree, dialog_msg, "team_id"); - std::string data_subtree = p->user_account->get_print_data_from_json(dialog_msg, "data"); + std::string data_subtree = UserAccountUtils::get_print_data_from_json(dialog_msg, "data"); if (filename.empty() || team_id.empty() || data_subtree.empty()) { std::string msg = _u8L("Failed to read response from Prusa Connect server. Upload is cancelled."); BOOST_LOG_TRIVIAL(error) << msg; diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 6b3aea7f6d..ff7815a18e 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -970,7 +970,22 @@ static std::string get_connect_state_suffix_for_printer(const Preset& printer_pr !printer_state_map.empty()) { for (const auto& [printer_model_nozzle_pair, states] : printer_state_map) { - if (printer_model_nozzle_pair.first == printer_preset.config.opt_string("printer_model") + std::string printer_model = printer_preset.config.opt_string("printer_model"); + std::string vendor_repo_prefix; + if (printer_preset.vendor) { + vendor_repo_prefix = printer_preset.vendor->repo_prefix; + } else if (std::string inherits = printer_preset.inherits(); !inherits.empty()) { + const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits); + if (parent && parent->vendor) { + vendor_repo_prefix = parent->vendor->repo_prefix; + } + } + if (printer_model.find(vendor_repo_prefix) == 0) { + printer_model = printer_model.substr(vendor_repo_prefix.size()); + boost::trim_left(printer_model); + } + + if (printer_model_nozzle_pair.first == printer_model && printer_model_nozzle_pair.second == printer_preset.config.opt_string("printer_variant")) { PrinterStatesCount states_cnt = get_printe_states_count(states); @@ -1002,7 +1017,23 @@ static bool fill_data_to_connect_info_line( const Preset& printer_preset, !printer_state_map.empty()) { for (const auto& [printer_model_nozzle_pair, states] : printer_state_map) { - if (printer_model_nozzle_pair.first == printer_preset.config.opt_string("printer_model") + // get printer_model without repo prefix + std::string printer_model = printer_preset.config.opt_string("printer_model"); + std::string vendor_repo_prefix; + if (printer_preset.vendor) { + vendor_repo_prefix = printer_preset.vendor->repo_prefix; + } else if (std::string inherits = printer_preset.inherits(); !inherits.empty()) { + const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits); + if (parent && parent->vendor) { + vendor_repo_prefix = parent->vendor->repo_prefix; + } + } + if (printer_model.find(vendor_repo_prefix) == 0) { + printer_model = printer_model.substr(vendor_repo_prefix.size()); + boost::trim_left(printer_model); + } + + if (printer_model_nozzle_pair.first == printer_model && printer_model_nozzle_pair.second == printer_preset.config.opt_string("printer_variant")) { PrinterStatesCount states_cnt = get_printe_states_count(states); diff --git a/src/slic3r/GUI/UserAccount.cpp b/src/slic3r/GUI/UserAccount.cpp index 265c89cc3c..b7bc79a59f 100644 --- a/src/slic3r/GUI/UserAccount.cpp +++ b/src/slic3r/GUI/UserAccount.cpp @@ -1,5 +1,6 @@ #include "UserAccount.hpp" +#include "UserAccountUtils.hpp" #include "format.hpp" #include "GUI.hpp" @@ -160,64 +161,7 @@ void UserAccount::on_communication_fail() } } -namespace { - std::string parse_tree_for_param(const pt::ptree& tree, const std::string& param) - { - for (const auto& section : tree) { - if (section.first == param) { - return section.second.data(); - } - if (std::string res = parse_tree_for_param(section.second, param); !res.empty()) { - return res; - } - } - return {}; - } - void parse_tree_for_param_vector(const pt::ptree& tree, const std::string& param, std::vector& results) - { - for (const auto& section : tree) { - if (section.first == param) { - results.emplace_back(section.second.data()); - } else { - parse_tree_for_param_vector(section.second, param, results); - } - } - } - - pt::ptree parse_tree_for_subtree(const pt::ptree& tree, const std::string& param) - { - for (const auto& section : tree) { - if (section.first == param) { - return section.second; - } - else { - if (pt::ptree res = parse_tree_for_subtree(section.second, param); !res.empty()) - return res; - } - - } - return pt::ptree(); - } - - void fill_supported_printer_models_from_json_inner(const pt::ptree& ptree, std::vector& result) { - std::string printer_model = parse_tree_for_param(ptree, "printer_model"); - if (!printer_model.empty()) { - result.emplace_back(printer_model); - } - pt::ptree out = parse_tree_for_subtree(ptree, "supported_printer_models"); - if (out.empty()) { - BOOST_LOG_TRIVIAL(error) << "Failed to find supported_printer_models in printer detail."; - return; - } - for (const auto& sub : out) { - if (printer_model != sub.second.data()) { - result.emplace_back(sub.second.data()); - } - - } - } -} bool UserAccount::on_connect_printers_success(const std::string& data, AppConfig* app_config, bool& out_printers_changed) { @@ -327,8 +271,8 @@ bool UserAccount::on_connect_uiid_map_success(const std::string& data, AppConfig return on_connect_printers_success(data, app_config, out_printers_changed); } -std::string UserAccount::get_current_printer_uuid_from_connect(const std::string& selected_printer_id) const -{ +std::string UserAccount::get_current_printer_uuid_from_connect(const std::string &selected_printer_id +) const { if (m_current_printer_data_json_from_connect.empty() || m_current_printer_uuid_from_connect.empty()) { return {}; } @@ -343,12 +287,12 @@ std::string UserAccount::get_current_printer_uuid_from_connect(const std::string return {}; } - std::string data_uuid = parse_tree_for_param(ptree, "uuid"); + std::string data_uuid = UserAccountUtils::get_keyword_from_json(ptree, "", "uuid"); assert(data_uuid == m_current_printer_uuid_from_connect); //std::string model_name = parse_tree_for_param(ptree, "printer_model"); std::vector compatible_printers; - fill_supported_printer_models_from_json_inner(ptree, compatible_printers); + UserAccountUtils::fill_supported_printer_models_from_json(ptree, compatible_printers); if (compatible_printers.empty()) { return {}; } @@ -356,173 +300,4 @@ std::string UserAccount::get_current_printer_uuid_from_connect(const std::string return std::find(compatible_printers.begin(), compatible_printers.end(), selected_printer_id) == compatible_printers.end() ? "" : m_current_printer_uuid_from_connect; } - -std::string UserAccount::get_nozzle_from_json(const std::string& message) const -{ - std::string out; - try { - std::stringstream ss(message); - pt::ptree ptree; - pt::read_json(ss, ptree); - - out = parse_tree_for_param(ptree, "nozzle_diameter"); - //assert(!out.empty()); - } - catch (const std::exception& e) { - BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what(); - } - - // Get rid of trailing zeros. - // This is because somtimes we get "nozzle_diameter":0.40000000000000002 - // This will return wrong result for f.e. 0.05. But we dont have such profiles right now. - if (size_t fist_dot = out.find('.'); fist_dot != std::string::npos) { - if (size_t first_zero = out.find('0', fist_dot); first_zero != std::string::npos) { - return out.substr(0, first_zero); - } - } - return out; -} - -std::string UserAccount::get_keyword_from_json(const std::string& json, const std::string& keyword) const -{ - std::string out; - try { - std::stringstream ss(json); - pt::ptree ptree; - pt::read_json(ss, ptree); - - out = parse_tree_for_param(ptree, keyword); - //assert(!out.empty()); - } - catch (const std::exception& e) { - BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what(); - } - return out; -} - -std::string UserAccount::get_print_data_from_json(const std::string &json, const std::string &keyword) const -{ - // copy subtree string f.e. - // { "": {"param1": "something", "filename":"abcd.gcode", "param3":true}, "something_else" : 0 } - // into: {"param1": "something", "filename":"%1%", "param3":true, "size":%2%} - // yes there will be 2 placeholders for later format - - // this will fail if not flat subtree - size_t start_of_keyword = json.find("\""+keyword+"\""); - if (start_of_keyword == std::string::npos) - return {}; - size_t start_of_sub = json.find('{', start_of_keyword); - if (start_of_sub == std::string::npos) - return {}; - size_t end_of_sub = json.find('}', start_of_sub); - if (end_of_sub == std::string::npos) - return {}; - size_t start_of_filename = json.find("\"filename\"", start_of_sub); - if (start_of_filename == std::string::npos) - return {}; - size_t filename_doubledot = json.find(':', start_of_filename); - if (filename_doubledot == std::string::npos) - return {}; - size_t start_of_filename_data = json.find('\"', filename_doubledot); - if (start_of_filename_data == std::string::npos) - return {}; - size_t end_of_filename_data = json.find('\"', start_of_filename_data + 1); - if (end_of_filename_data == std::string::npos) - return {}; - size_t size = json.size(); - std::string result = json.substr(start_of_sub, start_of_filename_data - start_of_sub + 1); - result += "%1%"; - result += json.substr(end_of_filename_data, end_of_sub - end_of_filename_data); - result += ",\"size\":%2%}"; - return result; -} - -void UserAccount::fill_supported_printer_models_from_json(const std::string& json, std::vector& result) const -{ - try { - std::stringstream ss(json); - pt::ptree ptree; - pt::read_json(ss, ptree); - - fill_supported_printer_models_from_json_inner(ptree, result); - } - catch (const std::exception& e) { - BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what(); - } -} - -void UserAccount::fill_material_from_json(const std::string& json, std::vector& result) const -{ - - /* option 1: - "slot": { - "active": 2, - "slots": { - "1": { - "material": "PLA", - "temp": 170, - "fan_hotend": 7689, - "fan_print": 0 - }, - "2": { - "material": "PLA", - "temp": 225, - "fan_hotend": 7798, - "fan_print": 6503 - }, - "3": { - "material": "PLA", - "temp": 36, - "fan_hotend": 6636, - "fan_print": 0 - }, - "4": { - "material": "PLA", - "temp": 35, - "fan_hotend": 0, - "fan_print": 0 - }, - "5": { - "material": "PETG", - "temp": 136, - "fan_hotend": 8132, - "fan_print": 0 - } - } - } - */ - /* option 2 - "filament": { - "material": "PLA", - "bed_temperature": 60, - "nozzle_temperature": 210 - } - */ - // try finding "slot" subtree a use it to - // if not found, find "filament" subtree - try { - std::stringstream ss(json); - pt::ptree ptree; - pt::read_json(ss, ptree); - // find "slot" subtree - pt::ptree slot_subtree = parse_tree_for_subtree(ptree, "slot"); - if (slot_subtree.empty()) { - // if not found, find "filament" subtree - pt::ptree filament_subtree = parse_tree_for_subtree(ptree, "filament"); - if (!filament_subtree.empty()) { - std::string material = parse_tree_for_param(filament_subtree, "material"); - if (!material.empty()) { - result.emplace_back(std::move(material)); - } - } - return; - } - // search "slot" subtree for all "material"s - parse_tree_for_param_vector(slot_subtree, "material", result); - } - catch (const std::exception& e) { - BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what(); - } -} - }} // namespace slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/UserAccount.hpp b/src/slic3r/GUI/UserAccount.hpp index d241f778be..e38efdd02c 100644 --- a/src/slic3r/GUI/UserAccount.hpp +++ b/src/slic3r/GUI/UserAccount.hpp @@ -67,13 +67,6 @@ public: const ConnectPrinterStateMap& get_printer_state_map() const { return m_printer_map; } boost::filesystem::path get_avatar_path(bool logged) const; - // standalone utility methods - std::string get_nozzle_from_json(const std::string& message) const; - std::string get_keyword_from_json(const std::string& json, const std::string& keyword) const; - std::string get_print_data_from_json(const std::string &json, const std::string &keyword) const; - void fill_supported_printer_models_from_json(const std::string& json, std::vector& result) const; - void fill_material_from_json(const std::string& json, std::vector& result) const; - const std::map& get_printer_state_table() const { return printer_state_table; } void set_current_printer_uuid_from_connect(const std::string& uuid) { m_current_printer_uuid_from_connect = uuid; } diff --git a/src/slic3r/GUI/UserAccountUtils.cpp b/src/slic3r/GUI/UserAccountUtils.cpp new file mode 100644 index 0000000000..07c56065e8 --- /dev/null +++ b/src/slic3r/GUI/UserAccountUtils.cpp @@ -0,0 +1,222 @@ +#include "UserAccountUtils.hpp" + +#include "format.hpp" + +#include +#include +#include + +namespace pt = boost::property_tree; + +namespace Slic3r { namespace GUI { namespace UserAccountUtils { + +namespace { +std::string parse_tree_for_param(const pt::ptree &tree, const std::string ¶m) { + for (const auto §ion : tree) { + if (section.first == param) { + return section.second.data(); + } + if (std::string res = parse_tree_for_param(section.second, param); !res.empty()) { + return res; + } + } + return {}; +} + +void parse_tree_for_param_vector( + const pt::ptree &tree, const std::string ¶m, std::vector &results +) { + for (const auto §ion : tree) { + if (section.first == param) { + results.emplace_back(section.second.data()); + } else { + parse_tree_for_param_vector(section.second, param, results); + } + } +} + +pt::ptree parse_tree_for_subtree(const pt::ptree &tree, const std::string ¶m) { + for (const auto §ion : tree) { + if (section.first == param) { + return section.second; + } else { + if (pt::ptree res = parse_tree_for_subtree(section.second, param); !res.empty()) + return res; + } + } + return pt::ptree(); +} + +void json_to_ptree(boost::property_tree::ptree &ptree, const std::string &json) { + try { + std::stringstream ss(json); + pt::read_json(ss, ptree); + } catch (const std::exception &e) { + BOOST_LOG_TRIVIAL(error) << "Failed to parse json to ptree. " << e.what(); + BOOST_LOG_TRIVIAL(error) << "json: " << json; + } +} + +} // namespace + +std::string get_nozzle_from_json(boost::property_tree::ptree &ptree) { + assert(!ptree.empty()); + + std::string out = parse_tree_for_param(ptree, "nozzle_diameter"); + // Get rid of trailing zeros. + // This is because somtimes we get "nozzle_diameter":0.40000000000000002 + // This will return wrong result for f.e. 0.05. But we dont have such profiles right now. + if (size_t fist_dot = out.find('.'); fist_dot != std::string::npos) { + if (size_t first_zero = out.find('0', fist_dot); first_zero != std::string::npos) { + return out.substr(0, first_zero); + } + } + return out; +} + +std::string get_keyword_from_json(boost::property_tree::ptree &ptree, const std::string &json, const std::string &keyword ) +{ + if (ptree.empty()) { + json_to_ptree(ptree, json); + } + assert(!ptree.empty()); + return parse_tree_for_param(ptree, keyword); +} + +void fill_supported_printer_models_from_json(boost::property_tree::ptree &ptree, std::vector &result) +{ + assert(!ptree.empty()); + std::string printer_model = parse_tree_for_param(ptree, "printer_model"); + if (!printer_model.empty()) { + result.emplace_back(printer_model); + } + pt::ptree out = parse_tree_for_subtree(ptree, "supported_printer_models"); + if (out.empty()) { + BOOST_LOG_TRIVIAL(error) << "Failed to find supported_printer_models in printer detail."; + return; + } + for (const auto &sub : out) { + if (printer_model != sub.second.data()) { + result.emplace_back(sub.second.data()); + } + } +} + +void fill_config_options_from_json(boost::property_tree::ptree& ptree, std::map& result) +{ + assert(!ptree.empty()); + pt::ptree subtree = parse_tree_for_subtree(ptree, "config_options"); + for (const auto &item : subtree) { + result[item.first] = item.second.data(); + } +} + +void fill_material_from_json(const std::string &json, std::vector &result) +{ + pt::ptree ptree; + json_to_ptree(ptree, json); + assert(!ptree.empty()); + + /* option 1: + "slot": { + "active": 2, + "slots": { + "1": { + "material": "PLA", + "temp": 170, + "fan_hotend": 7689, + "fan_print": 0 + }, + "2": { + "material": "PLA", + "temp": 225, + "fan_hotend": 7798, + "fan_print": 6503 + }, + "3": { + "material": "PLA", + "temp": 36, + "fan_hotend": 6636, + "fan_print": 0 + }, + "4": { + "material": "PLA", + "temp": 35, + "fan_hotend": 0, + "fan_print": 0 + }, + "5": { + "material": "PETG", + "temp": 136, + "fan_hotend": 8132, + "fan_print": 0 + } + } + } + */ + /* option 2 + "filament": { + "material": "PLA", + "bed_temperature": 60, + "nozzle_temperature": 210 + } + */ + // try finding "slot" subtree a use it to + // if not found, find "filament" subtree + + // find "slot" subtree + pt::ptree slot_subtree = parse_tree_for_subtree(ptree, "slot"); + if (slot_subtree.empty()) { + // if not found, find "filament" subtree + pt::ptree filament_subtree = parse_tree_for_subtree(ptree, "filament"); + if (!filament_subtree.empty()) { + std::string material = parse_tree_for_param(filament_subtree, "material"); + if (!material.empty()) { + result.emplace_back(std::move(material)); + } + } + return; + } + // search "slot" subtree for all "material"s + parse_tree_for_param_vector(slot_subtree, "material", result); +} + +std::string get_print_data_from_json(const std::string &json, const std::string &keyword) { + // copy subtree string f.e. + // { "": {"param1": "something", "filename":"abcd.gcode", "param3":true}, + // "something_else" : 0 } into: {"param1": "something", "filename":"%1%", "param3":true, + // "size":%2%} yes there will be 2 placeholders for later format + + // this will fail if not flat subtree + size_t start_of_keyword = json.find("\"" + keyword + "\""); + if (start_of_keyword == std::string::npos) + return {}; + size_t start_of_sub = json.find('{', start_of_keyword); + if (start_of_sub == std::string::npos) + return {}; + size_t end_of_sub = json.find('}', start_of_sub); + if (end_of_sub == std::string::npos) + return {}; + size_t start_of_filename = json.find("\"filename\"", start_of_sub); + if (start_of_filename == std::string::npos) + return {}; + size_t filename_doubledot = json.find(':', start_of_filename); + if (filename_doubledot == std::string::npos) + return {}; + size_t start_of_filename_data = json.find('\"', filename_doubledot); + if (start_of_filename_data == std::string::npos) + return {}; + size_t end_of_filename_data = json.find('\"', start_of_filename_data + 1); + if (end_of_filename_data == std::string::npos) + return {}; + size_t size = json.size(); + std::string result = json.substr(start_of_sub, start_of_filename_data - start_of_sub + 1); + result += "%1%"; + result += json.substr(end_of_filename_data, end_of_sub - end_of_filename_data); + result += ",\"size\":%2%}"; + return result; +} + +}}} // Slic3r::GUI::UserAccountUtils + + diff --git a/src/slic3r/GUI/UserAccountUtils.hpp b/src/slic3r/GUI/UserAccountUtils.hpp new file mode 100644 index 0000000000..cfecaaa2f6 --- /dev/null +++ b/src/slic3r/GUI/UserAccountUtils.hpp @@ -0,0 +1,27 @@ +#ifndef slic3r_UserAccountUtils_hpp_ +#define slic3r_UserAccountUtils_hpp_ + +#include +#include + +#include + +namespace Slic3r { namespace GUI { +namespace UserAccountUtils { + +// If ptree parameter is empty, json parameter needs to contain data and ptree is filled. +// If ptree is non-epty, json parameter is not used. +std::string get_keyword_from_json(boost::property_tree::ptree& ptree, const std::string& json, const std::string& keyword); +// Only ptree is passed since these functions are called on places that already has the ptree from get_keyword_from_json call +std::string get_nozzle_from_json(boost::property_tree::ptree &ptree); +void fill_supported_printer_models_from_json(boost::property_tree::ptree& ptree, std::vector& result); +void fill_config_options_from_json(boost::property_tree::ptree& ptree, std::map& result); + +// Since fill_material_from_json is called only from one place where ptree doesnt need to be shared, it is not always read from json. +void fill_material_from_json(const std::string& json, std::vector& result); + +std::string get_print_data_from_json(const std::string &json, const std::string &keyword); + +}}} // Slic3r::GUI::UserAccountUtils + +#endif // slic3r_UserAccountUtils_hpp_ \ No newline at end of file diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp index cc2fe608b2..a0114a2474 100644 --- a/src/slic3r/GUI/WebViewDialog.cpp +++ b/src/slic3r/GUI/WebViewDialog.cpp @@ -1274,22 +1274,41 @@ void PrinterPickWebViewDialog::on_connect_action_webapp_ready(const std::string& } } -void PrinterPickWebViewDialog::request_compatible_printers_FFF() -{ - //PrinterParams: { - //material: Material; - //nozzleDiameter: number; - //printerType: string; - //filename: string; - //} - const Preset& selected_printer = wxGetApp().preset_bundle->printers.get_selected_preset(); - const Preset& selected_filament = wxGetApp().preset_bundle->filaments.get_selected_preset(); - double nozzle_diameter = static_cast(selected_printer.config.option("nozzle_diameter"))->values[0]; +void PrinterPickWebViewDialog::request_compatible_printers_FFF() { + // PrinterParams: { + // material: Material; + // nozzleDiameter: number; + // printerType: string; + // filename: string; + // } + const Preset &selected_printer = wxGetApp().preset_bundle->printers.get_selected_preset(); + const Preset &selected_filament = wxGetApp().preset_bundle->filaments.get_selected_preset(); + double nozzle_diameter = static_cast( + selected_printer.config.option("nozzle_diameter") + ) + ->values[0]; wxString nozzle_diameter_serialized = double_to_string(nozzle_diameter); nozzle_diameter_serialized.Replace(L",", L"."); // Sending only first filament type for now. This should change to array of values - const std::string filament_type_serialized = selected_filament.config.option("filament_type")->serialize(); - const std::string printer_model_serialized = selected_printer.config.option("printer_model")->serialize(); + const std::string filament_type_serialized = selected_filament.config.option("filament_type") + ->serialize(); + std::string printer_model_serialized = selected_printer.config.option("printer_model") + ->serialize(); + + std::string vendor_repo_prefix; + if (selected_printer.vendor) { + vendor_repo_prefix = selected_printer.vendor->repo_prefix; + } else if (std::string inherits = selected_printer.inherits(); !inherits.empty()) { + const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits); + if (parent && parent->vendor) { + vendor_repo_prefix = parent->vendor->repo_prefix; + } + } + if (printer_model_serialized.find(vendor_repo_prefix) == 0) { + printer_model_serialized = printer_model_serialized.substr(vendor_repo_prefix.size()); + boost::trim_left(printer_model_serialized); + } + const std::string uuid = wxGetApp().plater()->get_user_account()->get_current_printer_uuid_from_connect(printer_model_serialized); const std::string filename = wxGetApp().plater()->get_upload_filename(); const std::string request = GUI::format( @@ -1307,7 +1326,21 @@ void PrinterPickWebViewDialog::request_compatible_printers_FFF() void PrinterPickWebViewDialog::request_compatible_printers_SLA() { const Preset& selected_printer = wxGetApp().preset_bundle->printers.get_selected_preset(); - const std::string printer_model_serialized = selected_printer.config.option("printer_model")->serialize(); + std::string printer_model_serialized = selected_printer.config.option("printer_model")->serialize(); + + std::string vendor_repo_prefix; + if (selected_printer.vendor) { + vendor_repo_prefix = selected_printer.vendor->repo_prefix; + } else if (std::string inherits = selected_printer.inherits(); !inherits.empty()) { + const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits); + if (parent && parent->vendor) { + vendor_repo_prefix = parent->vendor->repo_prefix; + } + } + if (printer_model_serialized.find(vendor_repo_prefix) == 0) { + printer_model_serialized = printer_model_serialized.substr(vendor_repo_prefix.size()); + boost::trim_left(printer_model_serialized); + } const Preset& selected_material = wxGetApp().preset_bundle->sla_materials.get_selected_preset(); const std::string material_type_serialized = selected_material.config.option("material_type")->serialize(); const std::string uuid = wxGetApp().plater()->get_user_account()->get_current_printer_uuid_from_connect(printer_model_serialized);