diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 046f1c2f42..5cf38043a0 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3828,9 +3828,7 @@ 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) + , std::map>& options) { // find all matching presets when repo prefix is ommited std::vector results; @@ -3854,33 +3852,39 @@ const Preset* find_preset_by_nozzle_and_options( 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 + // options (including nozzle_diameter) bool failed = false; for (const auto& opt : options) { - if (!preset.config.has(opt.first)) { - failed = true; - break; + assert(preset.config.has(opt.first)); + // We compare only first value now, but options contains data for all (some might be empty tho) + std::string opt_val; + if (preset.config.option(opt.first)->is_scalar()) { + opt_val = preset.config.option(opt.first)->serialize(); + } else { + switch (preset.config.option(opt.first)->type()) { + case coInts: opt_val = std::to_string(static_cast(preset.config.option(opt.first))->values[0]); break; + case coFloats: + opt_val = into_u8(double_to_string(static_cast(preset.config.option(opt.first))->values[0])); + if (size_t pos = opt_val.find(",") != std::string::npos) + opt_val.replace(pos, 1, 1, '.'); + break; + case coStrings: opt_val = static_cast(preset.config.option(opt.first))->values[0]; break; + case coBools: opt_val = static_cast(preset.config.option(opt.first))->values[0] ? "1" : "0"; break; + default: + assert(true); + continue; + } } - if (preset.config.option(opt.first)->serialize() != opt.second) { + + if (opt_val != opt.second[0]) + { failed = true; break; } } - if (failed) { - continue; + if (!failed) { + results.push_back(&preset); } - results.push_back(&preset); } // find visible without prefix for (const Preset *preset : results) { @@ -3924,12 +3928,23 @@ 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 = UserAccountUtils::get_nozzle_from_json(ptree); - std::map config_options_to_match; + 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; + // prevent not having nozzle diameter + if (config_options_to_match.find("nozzle_diameter") == config_options_to_match.end()) { + std::string diameter = UserAccountUtils::get_keyword_from_json(ptree, msg, "nozzle_diameter"); + if (!diameter.empty()) + config_options_to_match["nozzle_diameter"] = {diameter}; + } + // log + BOOST_LOG_TRIVIAL(info) << "Select printer from Connect. Model: " << model_name; + for(const auto& pair :config_options_to_match) { + std::string out; + for(const std::string& val :pair.second) { out += val + ",";} + BOOST_LOG_TRIVIAL(info) << pair.first << ": " << out; + } // select printer - const Preset* printer_preset = find_preset_by_nozzle_and_options(preset_bundle->printers, model_name, nozzle, config_options_to_match); + const Preset* printer_preset = find_preset_by_nozzle_and_options(preset_bundle->printers, model_name, config_options_to_match); bool is_installed = printer_preset && select_printer_preset(printer_preset); // notification std::string out = printer_preset ? @@ -4031,6 +4046,9 @@ void GUI_App::select_filament_from_connect(const std::string& msg) size_t extruder_count = preset_bundle->extruders_filaments.size(); if (extruder_count != materials.size()) { BOOST_LOG_TRIVIAL(error) << format("Failed to select filament from Connect. Selected printer has %1% extruders while data from Connect contains %2% materials.", extruder_count, materials.size()); + plater()->get_notification_manager()->close_notification_of_type(NotificationType::SelectFilamentFromConnect); + // TRN: Notification text. + plater()->get_notification_manager()->push_notification(NotificationType::SelectFilamentFromConnect, NotificationManager::NotificationLevel::ImportantNotificationLevel, _u8L("Failed to select filament from Connect.")); return; } std::string notification_text; @@ -4065,7 +4083,6 @@ void GUI_App::handle_connect_request_printer_select_inner(const std::string & ms BOOST_LOG_TRIVIAL(debug) << "Handling web request: " << msg; // return to plater this->mainframe->select_tab(size_t(0)); - if (!select_printer_from_connect(msg)) { // If printer was not selected, do not select filament. return; diff --git a/src/slic3r/GUI/UserAccountUtils.cpp b/src/slic3r/GUI/UserAccountUtils.cpp index 84c6483ed5..a4f1778f3a 100644 --- a/src/slic3r/GUI/UserAccountUtils.cpp +++ b/src/slic3r/GUI/UserAccountUtils.cpp @@ -11,7 +11,7 @@ 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) { +std::string parse_tree_for_param(const pt::ptree& tree, const std::string& param) { for (const auto §ion : tree) { if (section.first == param) { return section.second.data(); @@ -24,8 +24,7 @@ std::string parse_tree_for_param(const pt::ptree &tree, const std::string ¶m } void parse_tree_for_param_vector( - const pt::ptree &tree, const std::string ¶m, std::vector &results -) { +const pt::ptree &tree, const std::string& param, std::vector& results) { for (const auto §ion : tree) { if (section.first == param) { results.emplace_back(section.second.data()); @@ -35,7 +34,7 @@ void parse_tree_for_param_vector( } } -pt::ptree parse_tree_for_subtree(const pt::ptree &tree, const std::string ¶m) { +pt::ptree parse_tree_for_subtree(const pt::ptree& tree, const std::string& param) { for (const auto §ion : tree) { if (section.first == param) { return section.second; @@ -47,7 +46,7 @@ pt::ptree parse_tree_for_subtree(const pt::ptree &tree, const std::string ¶m return pt::ptree(); } -void json_to_ptree(boost::property_tree::ptree &ptree, const std::string &json) { +void json_to_ptree(boost::property_tree::ptree& ptree, const std::string& json) { try { std::stringstream ss(json); pt::read_json(ss, ptree); @@ -59,7 +58,7 @@ void json_to_ptree(boost::property_tree::ptree &ptree, const std::string &json) } // namespace -std::string get_nozzle_from_json(boost::property_tree::ptree &ptree) { +std::string get_nozzle_from_json(boost::property_tree::ptree& ptree) { assert(!ptree.empty()); std::string out = parse_tree_for_param(ptree, "nozzle_diameter"); @@ -74,7 +73,7 @@ std::string get_nozzle_from_json(boost::property_tree::ptree &ptree) { return out; } -std::string get_keyword_from_json(boost::property_tree::ptree &ptree, const std::string &json, const std::string &keyword ) +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); @@ -83,7 +82,7 @@ std::string get_keyword_from_json(boost::property_tree::ptree &ptree, const std: return parse_tree_for_param(ptree, keyword); } -void fill_supported_printer_models_from_json(boost::property_tree::ptree &ptree, std::vector &result) +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"); @@ -102,16 +101,87 @@ void fill_supported_printer_models_from_json(boost::property_tree::ptree &ptree, } } -void fill_config_options_from_json(boost::property_tree::ptree& ptree, std::map& result) +namespace { +std::string json_var_to_opt_string(const std::string& json_var) +{ + if (json_var == "true") + return "1"; + if (json_var == "false") + return "0"; + return json_var; +} +} + +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, "printerConfig"); - for (const auto &item : subtree) { - result[item.first] = item.second.data(); + /* + "slot": { + "active": 3, + "slots": { + "1": { + "material": "PETG", + "temp": 32.0, + "fan_hotend": 0.0, + "fan_print": 0.0, + "nozzle_diameter": 3.2, // float + "high_flow": true, // boolean + "high_temperature": false, // boolean + "hardened": true, // boolean + }, + "3": { + "material": "ASA", + "temp": 35.0, + "fan_hotend": 0.0, + "fan_print": 0.0, + "nozzle_diameter": 3.2, // float + "high_flow": true, // boolean + "high_temperature": false, // boolean + "hardened": true, // boolean + }, + } + } + */ + const std::map parameters = { + // first name from connect, second config option + {"nozzle_diameter","nozzle_diameter"}, + {"high_flow","nozzle_high_flow"}, + //{"",""} + }; + pt::ptree slots = parse_tree_for_subtree(parse_tree_for_subtree(ptree, "slot"), "slots"); + for (const auto &subtree : slots) { + size_t slot_id; + try { + slot_id = boost::lexical_cast(subtree.first); + } catch (const boost::bad_lexical_cast&) { + continue; + } + for (const auto &item : subtree.second) { + if (parameters.find(item.first) == parameters.end()) { + continue; + } + std::string config_name = parameters.at(item.first); + // resolve value + std::string val; + if (item.second.size() > 0) { + for (const auto &subitem : item.second) { + if (!val.empty()) { + val += ","; + } + val += json_var_to_opt_string(subitem.second.data()); + } + } else { + val = json_var_to_opt_string(item.second.data()); + } + // insert value + while (result[config_name].size() < slot_id) + result[config_name].emplace_back(); + result[config_name][slot_id - 1] = val; + } } } -void fill_material_from_json(const std::string &json, std::vector &result) +void fill_material_from_json(const std::string& json, std::vector& result) { pt::ptree ptree; json_to_ptree(ptree, json); @@ -178,10 +248,26 @@ void fill_material_from_json(const std::string &json, std::vector & return; } // search "slot" subtree for all "material"s - parse_tree_for_param_vector(slot_subtree, "material", result); + // this parses "slots" with respect to numbers of slots and adds empty string to missing numbers + // if only filled should be used. Use: parse_tree_for_param_vector(slot_subtree, "material", result); + pt::ptree slots = parse_tree_for_subtree(slot_subtree, "slots"); + assert(!slots.empty()); + for (const auto &subtree : slots) { + size_t slot_id; + try { + slot_id = boost::lexical_cast(subtree.first); + } catch (const boost::bad_lexical_cast&) { + continue; + } + std::string val = parse_tree_for_param(subtree.second, "material"); + // add empty for missing id + while (result.size() < slot_id) + result.emplace_back(); + result[slot_id - 1] = val; + } } -std::string get_print_data_from_json(const std::string &json, const std::string &keyword) { +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, diff --git a/src/slic3r/GUI/UserAccountUtils.hpp b/src/slic3r/GUI/UserAccountUtils.hpp index cfecaaa2f6..e45b385cf5 100644 --- a/src/slic3r/GUI/UserAccountUtils.hpp +++ b/src/slic3r/GUI/UserAccountUtils.hpp @@ -15,7 +15,7 @@ std::string get_keyword_from_json(boost::property_tree::ptree& ptree, const std: // 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); +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); diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp index 30f93c7477..9d5ec17a1f 100644 --- a/src/slic3r/GUI/WebViewDialog.cpp +++ b/src/slic3r/GUI/WebViewDialog.cpp @@ -1288,8 +1288,10 @@ void PrinterPickWebViewDialog::request_compatible_printers_FFF() { 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 = full_config.option("filament_type")->serialize(); - std::string printer_model_serialized = full_config.option("printer_model")->serialize(); + const std::string nozzle_high_flow_serialized = static_cast(full_config.option("nozzle_high_flow"))->values[0] ? "1" : "0"; + const std::string filament_abrasive_serialized = static_cast(full_config.option("filament_abrasive"))->values[0] ? "1" : "0"; + 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; @@ -1311,19 +1313,13 @@ void PrinterPickWebViewDialog::request_compatible_printers_FFF() { "{" "\"printerUuid\": \"%4%\", " "\"printerModel\": \"%3%\", " - "\"nozzleDiameter\": %2%, " + "\"nozzle_diameter\": %2%, " "\"material\": \"%1%\", " "\"filename\": \"%5%\", " - "\"fullConfig\": {" - , filament_type_serialized, nozzle_diameter_serialized, printer_model_serialized, uuid, filename); - - for (auto it = full_config.cbegin(); it != full_config.cend(); ++it) { - std::string value = full_config.option(it->first)->serialize(); - boost::algorithm::replace_all(value, "\"", "\\\""); - request += it == full_config.cbegin() ? "" : ","; - request += GUI::format("\"%1%\": \"%2%\"", it->first, value); - } - request += "}}"; + "\"filament_abrasive\": \"%6%\"," + "\"nozzle_high_flow\": \"%7%\"" + "}" + , filament_type_serialized, nozzle_diameter_serialized, printer_model_serialized, uuid, filename, nozzle_high_flow_serialized, filament_abrasive_serialized); wxString script = GUI::format_wxstr("window._prusaConnect_v1.requestCompatiblePrinter(%1%)", request); run_script(script);