repo_prefix parameter and removing prefix before send to connect.

Change printer_model in full config before applying to print

printer_model prefix handling when showing online printers in sidebar

Select printer from connect by nozzle diameter (instead of pritner_variant) and by additional config options.

+ Moved standalone functions to UserAccountUtils

Set as current without repo prefix

when selecting preset with prefix, mind visible presets.

prefer visible printers for selecting

fix of selecting SLA printer

Added prusalink for prefixed printer_model
This commit is contained in:
David Kocik 2024-07-23 16:21:29 +02:00 committed by Lukas Matena
parent a55c85ecef
commit 756a76a773
12 changed files with 476 additions and 271 deletions

View File

@ -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;
}

View File

@ -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 {

View File

@ -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

View File

@ -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<std::string
, std::string>& options)
{
// find all matching presets when repo prefix is ommited
std::vector<const Preset*> 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<const ConfigOptionFloats*>(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<std::string> 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<std::string, std::string> 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<std::string> 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)

View File

@ -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<VendorProfile::PrinterModel>& 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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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<std::string>& 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<std::string>& 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<std::string> 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.
// { "<keyword>": {"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<std::string>& 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<std::string>& 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

View File

@ -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<std::string>& result) const;
void fill_material_from_json(const std::string& json, std::vector<std::string>& result) const;
const std::map<std::string, ConnectPrinterState>& 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; }

View File

@ -0,0 +1,222 @@
#include "UserAccountUtils.hpp"
#include "format.hpp"
#include <boost/regex.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/log/trivial.hpp>
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 &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<std::string> &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 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<std::string> &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<std::string, std::string>& 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<std::string> &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.
// { "<keyword>": {"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

View File

@ -0,0 +1,27 @@
#ifndef slic3r_UserAccountUtils_hpp_
#define slic3r_UserAccountUtils_hpp_
#include <string>
#include <vector>
#include <boost/property_tree/ptree.hpp>
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<std::string>& result);
void fill_config_options_from_json(boost::property_tree::ptree& ptree, std::map<std::string, std::string>& 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<std::string>& result);
std::string get_print_data_from_json(const std::string &json, const std::string &keyword);
}}} // Slic3r::GUI::UserAccountUtils
#endif // slic3r_UserAccountUtils_hpp_

View File

@ -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<const ConfigOptionFloats*>(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<const ConfigOptionFloats *>(
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);