diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a72bfc5a8f..ddc66e93dc 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3681,6 +3681,7 @@ 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"); if (model_name.empty()) { std::vector compatible_printers; plater()->get_user_account()->fill_supported_printer_models_from_json(msg, compatible_printers); @@ -3707,6 +3708,7 @@ bool GUI_App::select_printer_from_connect(const std::string& msg) NotificationType::SelectPrinterFromConnect , printer_preset ? NotificationManager::NotificationLevel::ImportantNotificationLevel : NotificationManager::NotificationLevel::WarningNotificationLevel , out); + plater()->get_user_account()->set_current_printer_uuid_from_connect(uuid); return printer_preset; } @@ -3725,11 +3727,29 @@ bool GUI_App::select_filament_preset(const Preset* preset, size_t extruder_index } void GUI_App::search_and_select_filaments(const std::string& material, size_t extruder_index, std::string& out_message) { - const DynamicPrintConfig& config = preset_bundle->extruders_filaments[extruder_index].get_selected_preset()->config; + const Preset* preset = preset_bundle->extruders_filaments[extruder_index].get_selected_preset(); // selected is ok - if (config.has("filament_type") && config.option("filament_type")->serialize() == material) { + if (!preset->is_default && preset->config.has("filament_type") && preset->config.option("filament_type")->serialize() == material) { return; } + // find installed compatible filament that is Prusa with suitable type and select it + for (const auto& filament : preset_bundle->extruders_filaments[extruder_index]) { + if (filament.is_compatible + && !filament.preset->is_default + && filament.preset->is_visible + && (!filament.preset->vendor || !filament.preset->vendor->templates_profile) + && filament.preset->config.has("filament_type") + && filament.preset->config.option("filament_type")->serialize() == material + && filament.preset->name.compare(0, 9, "Prusament") == 0 + && select_filament_preset(filament.preset, extruder_index) + ) + { + out_message += /*(extruder_count == 1) + ? GUI::format(_L("Selected Filament:\n%1%"), filament_preset.preset->name) + : */GUI::format(_L("Extruder %1%: Selected Filament %2%\n"), extruder_index + 1, filament.preset->name); + return; + } + } // find first installed compatible filament with suitable type and select it for (const auto& filament : preset_bundle->extruders_filaments[extruder_index]) { if (filament.is_compatible @@ -3798,7 +3818,15 @@ void GUI_App::select_filament_from_connect(const std::string& msg) } } -void GUI_App::handle_connect_request_printer_pick(const std::string& msg) +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"); + plater()->get_user_account()->enqueue_printer_data_action(uuid); +} +void GUI_App::handle_connect_request_printer_select_inner(const std::string & msg) { BOOST_LOG_TRIVIAL(debug) << "Handling web request: " << msg; // return to plater diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 0f2b84a434..d37c659c51 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -413,7 +413,8 @@ public: int request_user_unbind(std::string dev_id) { return 0; } bool select_printer_from_connect(const std::string& cmd); void select_filament_from_connect(const std::string& cmd); - void handle_connect_request_printer_pick(const std::string& cmd); + void handle_connect_request_printer_select(const std::string& cmd); + void handle_connect_request_printer_select_inner(const std::string& cmd); void show_printer_webview_tab(); // return true if preset vas invisible and we have to installed it to make it selectable bool select_printer_preset(const Preset* printer_preset); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index ad6603fcf0..03ed13f2d6 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -272,8 +272,8 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S //FIXME it seems this method is not called on application start-up, at least not on Windows. Why? // The same applies to wxEVT_CREATE, it is not being called on startup on Windows. Bind(wxEVT_ACTIVATE, [this](wxActivateEvent& event) { - if (m_plater != nullptr && event.GetActive()) - m_plater->on_activate(); + if (m_plater != nullptr) + m_plater->on_activate(event.GetActive()); event.Skip(); }); @@ -404,17 +404,11 @@ void MainFrame::update_layout() { m_plater->Reparent(m_tabpanel); m_plater->Layout(); -// m_tabpanel->InsertNewPage(0, m_plater, _L("Plater"), std::string("plater"), true); m_main_sizer->Add(m_tabpanel, 1, wxEXPAND | wxTOP, 1); m_plater->Show(); m_tabpanel->ShowFull(); m_tmp_top_bar->Hide(); - - // update Tabs - if (old_layout == ESettingsLayout::Dlg) - if (int sel = m_tabpanel->GetSelection(); sel != wxNOT_FOUND) - m_tabpanel->SetSelection(sel+1);// call SetSelection to correct layout after switching from Dlg to Old mode break; } case ESettingsLayout::Dlg: @@ -749,6 +743,7 @@ void MainFrame::create_preset_tabs() void MainFrame::add_connect_webview_tab() { if (m_connect_webview_added) { + m_connect_webview->resend_config(); return; } // parameters of InsertNewPage (to prevent ambigous overloaded function) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b48edca87c..7fe362f5ea 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -963,7 +963,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->q->Bind(EVT_UA_AVATAR_SUCCESS, [this](UserAccountSuccessEvent& evt) { boost::filesystem::path path = user_account->get_avatar_path(true); FILE* file; - file = fopen(path.string().c_str(), "wb"); + file = boost::nowide::fopen(path.generic_string().c_str(), "wb"); + if (file == NULL) { + BOOST_LOG_TRIVIAL(error) << "Failed to create file to store avatar picture at: " << path; + return; + } fwrite(evt.data.c_str(), 1, evt.data.size(), file); fclose(file); this->main_frame->refresh_account_menu(true); @@ -971,6 +975,17 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) wxGetApp().update_login_dialog(); #endif // 0 }); + this->q->Bind(EVT_UA_PRUSACONNECT_PRINTER_DATA_SUCCESS, [this](UserAccountSuccessEvent& evt) { + this->user_account->set_current_printer_data(evt.data); + wxGetApp().handle_connect_request_printer_select_inner(evt.data); + }); + this->q->Bind(EVT_UA_PRUSACONNECT_PRINTER_DATA_FAIL, [this](UserAccountFailEvent& evt) { + BOOST_LOG_TRIVIAL(error) << "Failed communication with Prusa Account: " << evt.data; + user_account->on_communication_fail(); + std::string msg = _u8L("Failed to select printer from PrusaConnect."); + this->notification_manager->close_notification_of_type(NotificationType::SelectFilamentFromConnect); + this->notification_manager->push_notification(NotificationType::SelectFilamentFromConnect, NotificationManager::NotificationLevel::WarningNotificationLevel, msg); + }); } wxGetApp().other_instance_message_handler()->init(this->q); @@ -5873,160 +5888,53 @@ void Plater::connect_gcode() { assert(p->user_account->is_logged()); std::string dialog_msg; - if(PrinterPickWebViewDialog(this, dialog_msg).ShowModal() != wxID_OK) { - return; - } + { + PrinterPickWebViewDialog dialog(this, dialog_msg); + if (dialog.ShowModal() != wxID_OK) { + return; + } + } if (dialog_msg.empty()) { show_error(this, _L("Failed to select a printer. PrusaConnect did not return a value.")); return; } BOOST_LOG_TRIVIAL(debug) << "Message from Printer pick webview: " << dialog_msg; - PresetBundle* preset_bundle = wxGetApp().preset_bundle; - // Connect data - std::vector compatible_printers; - p->user_account->fill_supported_printer_models_from_json(dialog_msg, compatible_printers); - std::string connect_nozzle = p->user_account->get_nozzle_from_json(dialog_msg); +/* +{ + set_ready: boolean, // uzivatel potvrdil ze je tiskarne ready a muze se tisknout, pouziva se pro tisknout ted a odlozeny tisk + position: -1 | 0, // -1 = posledni ve fronte, 0 = prvni ve fronte + wait_until: number | undefined, // timestamp pro odlozeny tisk + file_name: string, // tady budeme predavat jak se uzivatel rozhodl soubor pojmenovat, kdyz ho neprejmenuje, tak vratime to stejne co nam predtim posle slicer + printer_uuid: string // uuid vybrane tiskarny +} +*/ + const Preset* selected_printer_preset = &wxGetApp().preset_bundle->printers.get_selected_preset(); - std::vector connect_materials; - p->user_account->fill_material_from_json(dialog_msg, connect_materials); - - std::vector compatible_printer_presets; - for (const std::string& cp : compatible_printers) { - const Preset* found_preset = preset_bundle->printers.find_system_preset_by_model_and_variant(cp, connect_nozzle); - if (found_preset) { - compatible_printer_presets.emplace_back(found_preset); - } - } - if (compatible_printer_presets.empty()) { - show_error(this, _L("No compatible printer presets found.")); - return; - } - // Selected profiles - const Preset* selected_printer_preset = &preset_bundle->printers.get_selected_preset(); - const std::string selected_printer_model_serialized = selected_printer_preset->config.option("printer_model")->serialize(); - - bool selected_filament_ok = true; - if (Preset::printer_technology(selected_printer_preset->config) == ptFFF) { - size_t extruder_count = preset_bundle->extruders_filaments.size(); - for (size_t i = 0; i < extruder_count; i++) { - if (connect_materials.size() <= i) { - selected_filament_ok = false; - break; - } - const Preset* selected_filament_preset = preset_bundle->extruders_filaments[i].get_selected_preset(); - if (selected_filament_preset && selected_filament_preset->config.has("filament_type") - && selected_filament_preset->config.option("filament_type")->serialize() != connect_materials[i]) - { - selected_filament_ok = false; - break; - } - } - } - - - bool is_first = compatible_printer_presets.front()->name == selected_printer_preset->name; - bool found = false; - for (const Preset* connect_preset : compatible_printer_presets) { - if (!connect_preset) { - continue; - } - if (selected_printer_preset->name == connect_preset->name) { - found = true; - break; - } - } - // Dialog to select action - if (!found) { - wxString line1 = _L("The printer you've selected for upload is not compatible with profiles selected for slicing."); - wxString line2 = GUI::format_wxstr(_L("PrusaSlicer Profile:\n%1%"), selected_printer_preset->name); - wxString line3 = _L("Known profiles compatible with printer selected for upload:"); - wxString printers_line; - for (const Preset* connect_preset : compatible_printer_presets) { - if (!connect_preset) { - continue; - } - printers_line += GUI::format_wxstr(_L("\n%1%"), connect_preset->name); - } - wxString line4 = _L("Do you still wish to upload?"); - wxString message = GUI::format_wxstr("%1%\n\n%2%\n\n%3%%4%\n\n%5%", line1, line2, line3, printers_line,line4); - MessageDialog msg_dialog(this, message, _L("Do you wish to upload?"), wxYES_NO); - auto modal_res = msg_dialog.ShowModal(); - if (modal_res != wxID_YES) { - return; - } - } else if (!is_first) { - wxString line1 = _L("The printer you've selected for upload might not be compatible with profiles selected for slicing."); - wxString line2 = GUI::format_wxstr(_L("PrusaSlicer Profile:\n%1%"), selected_printer_preset->name); - wxString line3 = _L("Known profiles compatible with printer selected for upload:"); - wxString printers_line; - for (const Preset* connect_preset : compatible_printer_presets) { - if (!connect_preset) { - continue; - } - printers_line += GUI::format_wxstr(_L("\n%1%"), connect_preset->name); - } - wxString line4 = _L("Do you still wish to upload?"); - wxString message = GUI::format_wxstr("%1%\n\n%2%\n\n%3%%4%\n\n%5%", line1, line2, line3, printers_line, line4); - MessageDialog msg_dialog(this, message, _L("Do you wish to upload?"), wxYES_NO); - auto modal_res = msg_dialog.ShowModal(); - if (modal_res != wxID_YES) { - return; - } - } - - if (!connect_materials.empty() && !selected_filament_ok) { - wxString line1 = _L("The printer you've selected has different filament type than filament profile selected for slicing."); - wxString connect_filament_types = "\n"; - for (size_t i = 0; i < connect_materials.size(); i++) { - connect_filament_types += GUI::format_wxstr(_L("Extruder %1%: %2%\n"), i + 1, connect_materials[i]); - } - wxString line2 = GUI::format_wxstr(_L("PrusaConnect Filament Type: %1%"), connect_filament_types); - - wxString selected_filament_types = "\n"; - for (size_t i = 0; i < preset_bundle->extruders_filaments.size(); i++) { - const Preset* selected_filament_preset = preset_bundle->extruders_filaments[i].get_selected_preset(); - std::string filament_serialized; - if (selected_filament_preset && selected_filament_preset->config.has("filament_type")) { - filament_serialized = selected_filament_preset->config.option("filament_type")->serialize(); - } - selected_filament_types += GUI::format_wxstr(_L("Extruder %1%: %2%\n"), i + 1, filament_serialized); - } - wxString line3 = GUI::format_wxstr(_L("PrusaSlicer Filament Type: %1%"), selected_filament_types); - wxString line4 = _L("Do you still wish to upload?"); - wxString message = GUI::format_wxstr("%1%\n\n%2%\n%3%\n\n%4%", line1, line2, line3, line4); - MessageDialog msg_dialog(this, message, _L("Do you wish to upload?"), wxYES_NO); - auto modal_res = msg_dialog.ShowModal(); - if (modal_res != wxID_YES) { - return; - } - } - - const std::string connect_state = p->user_account->get_keyword_from_json(dialog_msg, "connect_state"); - const std::string printer_state = p->user_account->get_keyword_from_json(dialog_msg, "printer_state"); - const std::map& printer_state_table = p->user_account->get_printer_state_table(); - const auto state = printer_state_table.find(connect_state); - assert(state != printer_state_table.end()); - // TODO: all states that does not allow to upload - if (state->second == ConnectPrinterState::CONNECT_PRINTER_OFFLINE) { - show_error(this, _L("Failed to select a printer. Chosen printer is in offline state.")); - return; - } - - const std::string uuid = p->user_account->get_keyword_from_json(dialog_msg, "uuid"); + const std::string set_ready = p->user_account->get_keyword_from_json(dialog_msg, "set_ready"); + const std::string position = p->user_account->get_keyword_from_json(dialog_msg, "position"); + const std::string wait_until = p->user_account->get_keyword_from_json(dialog_msg, "wait_until"); + const std::string filename = p->user_account->get_keyword_from_json(dialog_msg, "filename"); + const std::string printer_uuid = p->user_account->get_keyword_from_json(dialog_msg, "printer_uuid"); const std::string team_id = p->user_account->get_keyword_from_json(dialog_msg, "team_id"); - if (uuid.empty() || team_id.empty()) { - show_error(this, _L("Failed to select a printer. Missing data (uuid and team id) for chosen printer.")); - return; - } + PhysicalPrinter ph_printer("connect_temp_printer", wxGetApp().preset_bundle->physical_printers.default_config(), *selected_printer_preset); ph_printer.config.set_key_value("host_type", new ConfigOptionEnum(htPrusaConnectNew)); // use existing structures to pass data ph_printer.config.opt_string("printhost_apikey") = team_id; - ph_printer.config.opt_string("print_host") = uuid; + ph_printer.config.opt_string("print_host") = printer_uuid; DynamicPrintConfig* physical_printer_config = &ph_printer.config; - send_gcode_inner(physical_printer_config); + PrintHostJob upload_job(physical_printer_config); + assert(!upload_job.empty()); + + upload_job.upload_data.set_ready = set_ready; + upload_job.upload_data.position = position; + upload_job.upload_data.wait_until = wait_until; + upload_job.upload_data.upload_path = boost::filesystem::path(filename); + + p->export_gcode(fs::path(), false, std::move(upload_job)); + } void Plater::send_gcode() @@ -6066,6 +5974,32 @@ void Plater::send_gcode() send_gcode_inner(physical_printer_config); } +std::string Plater::get_upload_filename() +{ + // Obtain default output path + fs::path default_output_file; + try { + // Update the background processing, so that the placeholder parser will get the correct values for the ouput file template. + // Also if there is something wrong with the current configuration, a pop-up dialog will be shown and the export will not be performed. + unsigned int state = this->p->update_restart_background_process(false, false); + if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) + return {}; + default_output_file = this->p->background_process.output_filepath_for_project(into_path(get_project_filename(".3mf"))); + } + catch (const Slic3r::PlaceholderParserError& ex) { + // Show the error with monospaced font. + show_error(this, ex.what(), true); + return {}; + } + catch (const std::exception& ex) { + show_error(this, ex.what(), false); + return {}; + } + default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); + + return default_output_file.filename().string(); +} + void Plater::send_gcode_inner(DynamicPrintConfig* physical_printer_config) { PrintHostJob upload_job(physical_printer_config); @@ -6366,9 +6300,12 @@ void Plater::force_print_bed_update() p->config->opt_string("printer_model", true) = "\x01\x00\x01"; } -void Plater::on_activate() +void Plater::on_activate(bool active) { - this->p->show_delayed_error_message(); + this->p->user_account->on_activate_window(active); + if (active) { + this->p->show_delayed_error_message(); + } } // Get vector of extruder colors considering filament color, if extruder color is undefined. diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 462c875e2e..28c33b13c3 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -227,6 +227,7 @@ public: void send_gcode_inner(DynamicPrintConfig* physical_printer_config); void eject_drive(); void connect_gcode(); + std::string get_upload_filename(); void take_snapshot(const std::string &snapshot_name); void take_snapshot(const wxString &snapshot_name); @@ -252,7 +253,7 @@ public: void force_filament_cb_update(); void force_print_bed_update(); // On activating the parent window. - void on_activate(); + void on_activate(bool active); std::vector get_extruder_colors_from_plater_config(const GCodeProcessorResult* const result = nullptr) const; std::vector get_colors_for_color_print(const GCodeProcessorResult* const result = nullptr) const; diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 0c57f8ce9f..9d42a80a65 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -932,19 +932,11 @@ static std::string get_connect_state_suffix_for_printer(const Preset& printer_pr // process real data from Connect if (auto printer_state_map = wxGetApp().plater()->get_user_account()->get_printer_state_map(); !printer_state_map.empty()) { - // printer_state_map has only one nozzle value. Take a first value from "nozzle_diameter" opt. - std::string nozzle_diameter_serialized; - if (printer_preset.config.has("nozzle_diameter")) { - nozzle_diameter_serialized = dynamic_cast(printer_preset.config.option("nozzle_diameter"))->serialize(); - if (size_t comma = nozzle_diameter_serialized.find(','); comma != std::string::npos) - nozzle_diameter_serialized = nozzle_diameter_serialized.substr(0, comma); - } for (const auto& [printer_model_nozzle_pair, states] : printer_state_map) { if (printer_model_nozzle_pair.first == printer_preset.config.opt_string("printer_model") - && (printer_model_nozzle_pair.second.empty() - || printer_model_nozzle_pair.second == nozzle_diameter_serialized) - ) { + && printer_model_nozzle_pair.second == printer_preset.config.opt_string("printer_variant")) + { PrinterStatesCount states_cnt = get_printe_states_count(states); if (states_cnt.available_cnt > 0) @@ -963,26 +955,17 @@ static wxString get_connect_info_line(const Preset& printer_preset) { if (auto printer_state_map = wxGetApp().plater()->get_user_account()->get_printer_state_map(); !printer_state_map.empty()) { - // printer_state_map has only one nozzle value. Take a first value from "nozzle_diameter" opt. - std::string nozzle_diameter_serialized; - if (printer_preset.config.has("nozzle_diameter")) { - nozzle_diameter_serialized = dynamic_cast(printer_preset.config.option("nozzle_diameter"))->serialize(); - if (size_t comma = nozzle_diameter_serialized.find(','); comma != std::string::npos) - nozzle_diameter_serialized = nozzle_diameter_serialized.substr(0, comma); - } for (const auto& [printer_model_nozzle_pair, states] : printer_state_map) { if (printer_model_nozzle_pair.first == printer_preset.config.opt_string("printer_model") - && (printer_model_nozzle_pair.second.empty() - || printer_model_nozzle_pair.second == nozzle_diameter_serialized) - ) { + && printer_model_nozzle_pair.second == printer_preset.config.opt_string("printer_variant")) + { PrinterStatesCount states_cnt = get_printe_states_count(states); - return format_wxstr(_L("Available: %1%, Offline: %2%, Busy: %3%. Total: %4% printers"), + return format_wxstr(_L("Available: %1%, Offline: %2%, Busy: %3%"), format("%1%" , states_cnt.available_cnt), format("%1%" , states_cnt.offline_cnt), - format("%1%", states_cnt.busy_cnt), - format("%1%", states_cnt.total)); + format("%1%", states_cnt.busy_cnt)); } } } diff --git a/src/slic3r/GUI/UserAccount.cpp b/src/slic3r/GUI/UserAccount.cpp index 992fc39b00..8102c810f6 100644 --- a/src/slic3r/GUI/UserAccount.cpp +++ b/src/slic3r/GUI/UserAccount.cpp @@ -1,6 +1,7 @@ #include "UserAccount.hpp" #include "format.hpp" +#include "GUI.hpp" #include "libslic3r/Utils.hpp" @@ -78,7 +79,7 @@ boost::filesystem::path UserAccount::get_avatar_path(bool logged) const { if (logged) { const std::string filename = "prusaslicer-avatar-" + m_instance_hash + m_avatar_extension; - return boost::filesystem::path(wxStandardPaths::Get().GetTempDir().utf8_str().data()) / filename; + return into_path(wxStandardPaths::Get().GetTempDir()) / filename; } else { return boost::filesystem::path(resources_dir()) / "icons" / "user.svg"; } @@ -96,6 +97,10 @@ void UserAccount::enqueue_avatar_action() { m_communication->enqueue_avatar_action(m_account_user_data["avatar"]); } +void UserAccount::enqueue_printer_data_action(const std::string& uuid) +{ + m_communication->enqueue_printer_data_action(uuid); +} bool UserAccount::on_login_code_recieved(const std::string& url_message) { @@ -193,6 +198,24 @@ namespace { } 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) @@ -303,6 +326,36 @@ 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 +{ + if (m_current_printer_data_json_from_connect.empty() || m_current_printer_uuid_from_connect.empty()) { + return {}; + } + + pt::ptree ptree; + try { + std::stringstream ss(m_current_printer_data_json_from_connect); + pt::read_json(ss, ptree); + } + catch (const std::exception& e) { + BOOST_LOG_TRIVIAL(error) << "Could not parse Printer data from Connect. " << e.what(); + return {}; + } + + std::string data_uuid = parse_tree_for_param(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); + if (compatible_printers.empty()) { + return {}; + } + + 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; @@ -353,21 +406,7 @@ void UserAccount::fill_supported_printer_models_from_json(const std::string& jso pt::ptree ptree; pt::read_json(ss, ptree); - 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()); - } - - } + 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(); diff --git a/src/slic3r/GUI/UserAccount.hpp b/src/slic3r/GUI/UserAccount.hpp index 9d597acf1c..533fdff970 100644 --- a/src/slic3r/GUI/UserAccount.hpp +++ b/src/slic3r/GUI/UserAccount.hpp @@ -45,7 +45,7 @@ public: void enqueue_connect_status_action(); void enqueue_connect_printer_models_action(); void enqueue_avatar_action(); - + void enqueue_printer_data_action(const std::string& uuid); // Clears all data and connections, called on logout or EVT_UA_RESET void clear(); @@ -58,6 +58,8 @@ public: bool on_connect_printers_success(const std::string& data, AppConfig* app_config, bool& out_printers_changed); bool on_connect_uiid_map_success(const std::string& data, AppConfig* app_config, bool& out_printers_changed); + void on_activate_window(bool active) { m_communication->on_activate_window(active); } + std::string get_username() const { return m_username; } std::string get_access_token(); std::string get_shared_session_key(); @@ -72,6 +74,10 @@ public: 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; } + std::string get_current_printer_uuid_from_connect(const std::string& selected_printer_id) const; + + void set_current_printer_data(const std::string& data) { m_current_printer_data_json_from_connect = data; } private: void set_username(const std::string& username); @@ -86,6 +92,9 @@ private: size_t m_fail_counter { 0 }; std::string m_avatar_extension; + std::string m_current_printer_uuid_from_connect; + std::string m_current_printer_data_json_from_connect; + const std::map printer_state_table = { {"OFFLINE" , ConnectPrinterState::CONNECT_PRINTER_OFFLINE}, {"PRINTING" , ConnectPrinterState::CONNECT_PRINTER_PRINTING}, diff --git a/src/slic3r/GUI/UserAccountCommunication.cpp b/src/slic3r/GUI/UserAccountCommunication.cpp index 6d8045d2b7..2796ae525e 100644 --- a/src/slic3r/GUI/UserAccountCommunication.cpp +++ b/src/slic3r/GUI/UserAccountCommunication.cpp @@ -333,6 +333,21 @@ void UserAccountCommunication::enqueue_avatar_action(const std::string& url) } wakeup_session_thread(); } + +void UserAccountCommunication::enqueue_printer_data_action(const std::string& uuid) +{ + { + std::lock_guard lock(m_session_mutex); + if (!m_session->is_initialized()) { + BOOST_LOG_TRIVIAL(error) << "Connect Printers endpoint connection failed - Not Logged in."; + return; + } + m_session->enqueue_action(UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_DATA_FROM_UUID, nullptr, nullptr, uuid); + } + wakeup_session_thread(); +} + + void UserAccountCommunication::init_session_thread() { m_thread = std::thread([this]() { @@ -340,11 +355,15 @@ void UserAccountCommunication::init_session_thread() // Wait for 5 seconds or wakeup call { std::unique_lock lck(m_thread_stop_mutex); - m_thread_stop_condition.wait_for(lck, std::chrono::seconds(5), [this] { return m_thread_stop || m_thread_wakeup; }); + m_thread_stop_condition.wait_for(lck, std::chrono::seconds(10), [this] { return m_thread_stop || m_thread_wakeup; }); } if (m_thread_stop) // Stop the worker thread. break; + // Do not process_action_queue if window is not active and thread was not forced to wakeup + if (!m_window_is_active && !m_thread_wakeup) { + continue; + } m_thread_wakeup = false; { std::lock_guard lock(m_session_mutex); @@ -354,6 +373,12 @@ void UserAccountCommunication::init_session_thread() }); } +void UserAccountCommunication::on_activate_window(bool active) +{ + std::lock_guard lck(m_thread_stop_mutex); + m_window_is_active = active; +} + void UserAccountCommunication::wakeup_session_thread() { { diff --git a/src/slic3r/GUI/UserAccountCommunication.hpp b/src/slic3r/GUI/UserAccountCommunication.hpp index 15fc41aece..b630b95ec2 100644 --- a/src/slic3r/GUI/UserAccountCommunication.hpp +++ b/src/slic3r/GUI/UserAccountCommunication.hpp @@ -43,6 +43,7 @@ public: void enqueue_connect_printer_models_action(); void enqueue_avatar_action(const std::string& url); void enqueue_test_connection(); + void enqueue_printer_data_action(const std::string& uuid); // Callbacks - called from UI after receiving Event from Session thread. Some might use Session thread. // @@ -50,6 +51,7 @@ public: // Exchanges code for tokens and shared_session_key void on_login_code_recieved(const std::string& url_message); + void on_activate_window(bool active); void set_username(const std::string& username); void set_remember_session(bool b); @@ -70,6 +72,7 @@ private: std::condition_variable m_thread_stop_condition; bool m_thread_stop { false }; bool m_thread_wakeup{ false }; + bool m_window_is_active{ true }; std::string m_code_verifier; wxEvtHandler* m_evt_handler; AppConfig* m_app_config; diff --git a/src/slic3r/GUI/UserAccountSession.cpp b/src/slic3r/GUI/UserAccountSession.cpp index 65bfc670ab..69c974001f 100644 --- a/src/slic3r/GUI/UserAccountSession.cpp +++ b/src/slic3r/GUI/UserAccountSession.cpp @@ -25,8 +25,10 @@ wxDEFINE_EVENT(EVT_UA_SUCCESS, UserAccountSuccessEvent); wxDEFINE_EVENT(EVT_UA_PRUSACONNECT_STATUS_SUCCESS, UserAccountSuccessEvent); wxDEFINE_EVENT(EVT_UA_PRUSACONNECT_PRINTER_MODELS_SUCCESS, UserAccountSuccessEvent); wxDEFINE_EVENT(EVT_UA_AVATAR_SUCCESS, UserAccountSuccessEvent); +wxDEFINE_EVENT(EVT_UA_PRUSACONNECT_PRINTER_DATA_SUCCESS, UserAccountSuccessEvent); wxDEFINE_EVENT(EVT_UA_FAIL, UserAccountFailEvent); wxDEFINE_EVENT(EVT_UA_RESET, UserAccountFailEvent); +wxDEFINE_EVENT(EVT_UA_PRUSACONNECT_PRINTER_DATA_FAIL, UserAccountFailEvent); void UserActionPost::perform(/*UNUSED*/ wxEvtHandler* evt_handler, /*UNUSED*/ const std::string& access_token, UserActionSuccessFn success_callback, UserActionFailFn fail_callback, const std::string& input) const { diff --git a/src/slic3r/GUI/UserAccountSession.hpp b/src/slic3r/GUI/UserAccountSession.hpp index eaaafac0c1..e465b6e17b 100644 --- a/src/slic3r/GUI/UserAccountSession.hpp +++ b/src/slic3r/GUI/UserAccountSession.hpp @@ -23,8 +23,10 @@ wxDECLARE_EVENT(EVT_UA_SUCCESS, UserAccountSuccessEvent); wxDECLARE_EVENT(EVT_UA_PRUSACONNECT_STATUS_SUCCESS, UserAccountSuccessEvent); wxDECLARE_EVENT(EVT_UA_PRUSACONNECT_PRINTER_MODELS_SUCCESS, UserAccountSuccessEvent); wxDECLARE_EVENT(EVT_UA_AVATAR_SUCCESS, UserAccountSuccessEvent); +wxDECLARE_EVENT(EVT_UA_PRUSACONNECT_PRINTER_DATA_SUCCESS, UserAccountSuccessEvent); wxDECLARE_EVENT(EVT_UA_FAIL, UserAccountFailEvent); // Soft fail - clears only after some number of fails wxDECLARE_EVENT(EVT_UA_RESET, UserAccountFailEvent); // Hard fail - clears all +wxDECLARE_EVENT(EVT_UA_PRUSACONNECT_PRINTER_DATA_FAIL, UserAccountFailEvent); // Failed to get data for printer to select, soft fail, action does not repeat typedef std::function UserActionSuccessFn; @@ -41,6 +43,7 @@ enum class UserAccountActionID { USER_ACCOUNT_ACTION_CONNECT_STATUS, // status of all printers by UUID USER_ACCOUNT_ACTION_CONNECT_PRINTER_MODELS, // status of all printers by UUID with printer_model. Should be called once to save printer models. USER_ACCOUNT_ACTION_AVATAR, + USER_ACCOUNT_ACTION_CONNECT_DATA_FROM_UUID, }; class UserAction { @@ -115,6 +118,7 @@ public: m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS] = std::make_unique("CONNECT_STATUS", "https://connect.prusa3d.com/slicer/status", EVT_UA_PRUSACONNECT_STATUS_SUCCESS, EVT_UA_FAIL); m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_PRINTER_MODELS] = std::make_unique("CONNECT_PRINTER_MODELS", "https://connect.prusa3d.com/slicer/printer_list", EVT_UA_PRUSACONNECT_PRINTER_MODELS_SUCCESS, EVT_UA_FAIL); m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_AVATAR] = std::make_unique("AVATAR", "https://media.printables.com/media/", EVT_UA_AVATAR_SUCCESS, EVT_UA_FAIL); + m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_DATA_FROM_UUID] = std::make_unique("USER_ACCOUNT_ACTION_CONNECT_DATA_FROM_UUID", "https://connect.prusa3d.com/app/printers/", EVT_UA_PRUSACONNECT_PRINTER_DATA_SUCCESS, EVT_UA_FAIL); } ~UserAccountSession() { @@ -126,6 +130,7 @@ public: m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_TEST_CONNECTION].reset(nullptr); m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS].reset(nullptr); m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_AVATAR].reset(nullptr); + m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_DATA_FROM_UUID].reset(nullptr); } void clear() { m_access_token.clear(); diff --git a/src/slic3r/GUI/WebView.cpp b/src/slic3r/GUI/WebView.cpp index f980556c3d..5a97802506 100644 --- a/src/slic3r/GUI/WebView.cpp +++ b/src/slic3r/GUI/WebView.cpp @@ -1,12 +1,13 @@ #include "WebView.hpp" #include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/GUI.hpp" #include #include #include -wxWebView* WebView::CreateWebView(wxWindow * parent, const wxString& url) +wxWebView* WebView::CreateWebView(wxWindow * parent, const wxString& url, std::vector& message_handlers) { #if wxUSE_WEBVIEW_EDGE bool backend_available = wxWebView::IsBackendAvailable(wxWebViewBackendEdge); @@ -21,8 +22,8 @@ wxWebView* WebView::CreateWebView(wxWindow * parent, const wxString& url) if (webView) { wxString correct_url = url.empty() ? wxString("") : wxURI(url).BuildURI(); -#ifdef __WIN32__ - webView->SetUserAgent(wxString::Format("PrusaSlicer/v%s", SLIC3R_VERSION)); +#ifdef __WIN32_ + webView->SetUserAgent(SLIC3R_APP_FULL_NAME); webView->Create(parent, wxID_ANY, correct_url, wxDefaultPosition, wxDefaultSize); //We register the wxfs:// protocol for testing purposes //webView->RegisterHandler(wxSharedPtr(new wxWebViewArchiveHandler("wxfs"))); @@ -34,15 +35,17 @@ wxWebView* WebView::CreateWebView(wxWindow * parent, const wxString& url) // And the memory: file system //webView->RegisterHandler(wxSharedPtr(new wxWebViewFSHandler("memory"))); webView->Create(parent, wxID_ANY, correct_url, wxDefaultPosition, wxDefaultSize); - webView->SetUserAgent(wxString::Format("PrusaSlicer/v%s", SLIC3R_VERSION)); + webView->SetUserAgent(wxString::FromUTF8(SLIC3R_APP_FULL_NAME)); #endif #ifndef __WIN32__ - Slic3r::GUI::wxGetApp().CallAfter([webView] { + Slic3r::GUI::wxGetApp().CallAfter([message_handlers, webView] { #endif - if (!webView->AddScriptMessageHandler("_prusaSlicer")) { - // TODO: dialog to user !!! - //wxLogError("Could not add script message handler"); - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Could not add script message handler"; + for (const std::string& handler : message_handlers) { + if (!webView->AddScriptMessageHandler(Slic3r::GUI::into_u8(handler))) { + // TODO: dialog to user !!! + //wxLogError("Could not add script message handler"); + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Could not add script message handler " << handler; + } } #ifndef __WIN32__ }); diff --git a/src/slic3r/GUI/WebView.hpp b/src/slic3r/GUI/WebView.hpp index 40ea745f10..b391662c1a 100644 --- a/src/slic3r/GUI/WebView.hpp +++ b/src/slic3r/GUI/WebView.hpp @@ -7,7 +7,7 @@ class wxString; namespace WebView { - wxWebView *CreateWebView(wxWindow *parent, const wxString& url); + wxWebView *CreateWebView(wxWindow *parent, const wxString& url, std::vector& message_handlers); }; #endif // !slic3r_GUI_WebView_hpp_ diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp index 06d34fab59..3804ec4ea3 100644 --- a/src/slic3r/GUI/WebViewDialog.cpp +++ b/src/slic3r/GUI/WebViewDialog.cpp @@ -22,10 +22,11 @@ namespace Slic3r { namespace GUI { -WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url, const std::string& loading_html/* = "loading"*/) +WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url, const std::vector& message_handler_names, const std::string& loading_html/* = "loading"*/) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) , m_default_url (default_url) , m_loading_html(loading_html) + , m_script_message_hadler_names(message_handler_names) { wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL); #ifdef DEBUG_URL_PANEL @@ -70,7 +71,7 @@ WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url, const SetSizer(topsizer); // Create the webview - m_browser = WebView::CreateWebView(this, /*m_default_url*/ GUI::format_wxstr("file://%1%/web/%2%.html", boost::filesystem::path(resources_dir()).generic_string(), m_loading_html)); + m_browser = WebView::CreateWebView(this, /*m_default_url*/ GUI::format_wxstr("file://%1%/web/%2%.html", boost::filesystem::path(resources_dir()).generic_string(), m_loading_html), m_script_message_hadler_names); if (!m_browser) { wxStaticText* text = new wxStaticText(this, wxID_ANY, _L("Failed to load a web browser.")); topsizer->Add(text, 0, wxALIGN_LEFT | wxBOTTOM, 10); @@ -95,8 +96,6 @@ WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url, const m_dev_tools = m_tools_menu->AppendCheckItem(wxID_ANY, _L("Enable Dev Tools")); #endif - //Zoom - m_zoomFactor = 100; Bind(wxEVT_SHOW, &WebViewPanel::on_show, this); @@ -124,8 +123,6 @@ WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url, const #endif //Connect the idle events Bind(wxEVT_IDLE, &WebViewPanel::on_idle, this); - Bind(wxEVT_CLOSE_WINDOW, &WebViewPanel::on_close, this); - } WebViewPanel::~WebViewPanel() @@ -247,11 +244,6 @@ void WebViewPanel::on_reload_button(wxCommandEvent& WXUNUSED(evt)) m_browser->Reload(); } -void WebViewPanel::on_close(wxCloseEvent& evt) -{ - this->Hide(); -} - void WebViewPanel::on_script_message(wxWebViewEvent& evt) { } @@ -438,7 +430,7 @@ case type: \ WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_OTHER); } - BOOST_LOG_TRIVIAL(error) << "WebView error: " << category; + BOOST_LOG_TRIVIAL(error) << "WebViewPanel error: " << category; load_error_page(); #ifdef DEBUG_URL_PANEL m_info->ShowMessage(_L("An error occurred loading ") + evt.GetURL() + "\n" + @@ -471,10 +463,13 @@ SourceViewDialog::SourceViewDialog(wxWindow* parent, wxString source) : ConnectRequestHandler::ConnectRequestHandler() { - m_actions["REQUEST_ACCESS_TOKEN"] = std::bind(&ConnectRequestHandler::on_request_access_token, this); - m_actions["REQUEST_CONFIG"] = std::bind(&ConnectRequestHandler::on_request_config, this); - m_actions["UPDATE_SELECTED_PRINTER"] = std::bind(&ConnectRequestHandler::on_request_update_selected_printer_action, this); - m_actions["WEBAPP_READY"] = std::bind(&ConnectRequestHandler::request_compatible_printers, this); + m_actions["REQUEST_ACCESS_TOKEN"] = std::bind(&ConnectRequestHandler::on_connect_action_request_access_token, this); + m_actions["REQUEST_CONFIG"] = std::bind(&ConnectRequestHandler::on_connect_action_request_config, this); + m_actions["WEBAPP_READY"] = std::bind(&ConnectRequestHandler::on_connect_action_webapp_ready, this); + m_actions["SELECT_PRINTER"] = std::bind(&ConnectRequestHandler::on_connect_action_select_printer, this); + m_actions["PRINT"] = std::bind(&ConnectRequestHandler::on_connect_action_print, this); + // obsolete + //m_actions["REQUEST_SELECTED_PRINTER"] = std::bind(&ConnectRequestHandler::on_connect_action_print, this); } ConnectRequestHandler::~ConnectRequestHandler() { @@ -516,17 +511,17 @@ void ConnectRequestHandler::handle_message(const std::string& message) void ConnectRequestHandler::resend_config() { - on_request_config(); + on_connect_action_request_config(); } -void ConnectRequestHandler::on_request_access_token() +void ConnectRequestHandler::on_connect_action_request_access_token() { std::string token = wxGetApp().plater()->get_user_account()->get_access_token(); wxString script = GUI::format_wxstr("window._prusaConnect_v1.setAccessToken(\'%1%\')", token); run_script_bridge(script); } -void ConnectRequestHandler::on_request_config() +void ConnectRequestHandler::on_connect_action_request_config() { /* accessToken?: string; @@ -535,7 +530,6 @@ void ConnectRequestHandler::on_request_config() language?: ConnectLanguage; sessionId?: string; */ - const std::string token = wxGetApp().plater()->get_user_account()->get_access_token(); //const std::string sesh = wxGetApp().plater()->get_user_account()->get_shared_session_key(); const std::string dark_mode = wxGetApp().dark_mode() ? "DARK" : "LIGHT"; @@ -548,7 +542,7 @@ void ConnectRequestHandler::on_request_config() } ConnectWebViewPanel::ConnectWebViewPanel(wxWindow* parent) - : WebViewPanel(parent, L"https://connect.prusa3d.com/connect-slicer-app/", "connect_loading") + : WebViewPanel(parent, L"https://connect.prusa3d.com/", { "_prusaSlicer" }, "connect_loading") { } @@ -569,15 +563,19 @@ void ConnectWebViewPanel::sys_color_changed() resend_config(); } -void ConnectWebViewPanel::on_request_update_selected_printer_action() +void ConnectWebViewPanel::on_connect_action_select_printer() { assert(!m_message_data.empty()); - wxGetApp().handle_connect_request_printer_pick(m_message_data); + wxGetApp().handle_connect_request_printer_select(m_message_data); +} +void ConnectWebViewPanel::on_connect_action_print() +{ + // PRINT request is not defined for ConnectWebViewPanel + assert(true); } - PrinterWebViewPanel::PrinterWebViewPanel(wxWindow* parent, const wxString& default_url) - : WebViewPanel(parent, default_url) + : WebViewPanel(parent, default_url, {}) { if (!m_browser) return; @@ -650,16 +648,51 @@ void PrinterWebViewPanel::sys_color_changed() { } -WebViewDialog::WebViewDialog(wxWindow* parent, const wxString& url, const wxString& dialog_name, const wxSize& size, const std::string& loading_html/* = "loading"*/) +WebViewDialog::WebViewDialog(wxWindow* parent, const wxString& url, const wxString& dialog_name, const wxSize& size, const std::vector& message_handler_names, const std::string& loading_html/* = "loading"*/) : wxDialog(parent, wxID_ANY, dialog_name, wxDefaultPosition, size, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) , m_loading_html(loading_html) + , m_script_message_hadler_names (message_handler_names) { wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL); +#ifdef DEBUG_URL_PANEL + // Create the button + bSizer_toolbar = new wxBoxSizer(wxHORIZONTAL); + + m_button_back = new wxButton(this, wxID_ANY, wxT("Back"), wxDefaultPosition, wxDefaultSize, 0); + m_button_back->Enable(false); + bSizer_toolbar->Add(m_button_back, 0, wxALL, 5); + + m_button_forward = new wxButton(this, wxID_ANY, wxT("Forward"), wxDefaultPosition, wxDefaultSize, 0); + m_button_forward->Enable(false); + bSizer_toolbar->Add(m_button_forward, 0, wxALL, 5); + + m_button_stop = new wxButton(this, wxID_ANY, wxT("Stop"), wxDefaultPosition, wxDefaultSize, 0); + + bSizer_toolbar->Add(m_button_stop, 0, wxALL, 5); + + m_button_reload = new wxButton(this, wxID_ANY, wxT("Reload"), wxDefaultPosition, wxDefaultSize, 0); + bSizer_toolbar->Add(m_button_reload, 0, wxALL, 5); + + m_url = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + bSizer_toolbar->Add(m_url, 1, wxALL | wxEXPAND, 5); + + m_button_tools = new wxButton(this, wxID_ANY, wxT("Tools"), wxDefaultPosition, wxDefaultSize, 0); + bSizer_toolbar->Add(m_button_tools, 0, wxALL, 5); + + // Create panel for find toolbar. + wxPanel* panel = new wxPanel(this); + topsizer->Add(bSizer_toolbar, 0, wxEXPAND, 0); + topsizer->Add(panel, wxSizerFlags().Expand()); + + // Create sizer for panel. + wxBoxSizer* panel_sizer = new wxBoxSizer(wxVERTICAL); + panel->SetSizer(panel_sizer); +#endif topsizer->SetMinSize(size); SetSizerAndFit(topsizer); // Create the webview - m_browser = WebView::CreateWebView(this, GUI::format_wxstr("file://%1%/web/%2%.html", boost::filesystem::path(resources_dir()).generic_string(), m_loading_html)); + m_browser = WebView::CreateWebView(this, GUI::format_wxstr("file://%1%/web/%2%.html", boost::filesystem::path(resources_dir()).generic_string(), m_loading_html), m_script_message_hadler_names); if (!m_browser) { wxStaticText* text = new wxStaticText(this, wxID_ANY, _L("Failed to load a web browser.")); topsizer->Add(text, 0, wxALIGN_LEFT | wxBOTTOM, 10); @@ -668,27 +701,349 @@ WebViewDialog::WebViewDialog(wxWindow* parent, const wxString& url, const wxStri topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); +#ifdef DEBUG_URL_PANEL + // Create the Tools menu + m_tools_menu = new wxMenu(); + wxMenuItem* viewSource = m_tools_menu->Append(wxID_ANY, _L("View Source")); + wxMenuItem* viewText = m_tools_menu->Append(wxID_ANY, _L("View Text")); + m_tools_menu->AppendSeparator(); + + wxMenu* script_menu = new wxMenu; + + m_script_custom = script_menu->Append(wxID_ANY, "Custom script"); + m_tools_menu->AppendSubMenu(script_menu, _L("Run Script")); + wxMenuItem* addUserScript = m_tools_menu->Append(wxID_ANY, _L("Add user script")); + wxMenuItem* setCustomUserAgent = m_tools_menu->Append(wxID_ANY, _L("Set custom user agent")); + + m_context_menu = m_tools_menu->AppendCheckItem(wxID_ANY, _L("Enable Context Menu")); + m_dev_tools = m_tools_menu->AppendCheckItem(wxID_ANY, _L("Enable Dev Tools")); + +#endif + Bind(wxEVT_SHOW, &WebViewDialog::on_show, this); Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WebViewDialog::on_script_message, this, m_browser->GetId()); + + // Connect the webview events + Bind(wxEVT_WEBVIEW_ERROR, &WebViewDialog::on_error, this, m_browser->GetId()); + //Connect the idle events + Bind(wxEVT_IDLE, &WebViewDialog::on_idle, this); +#ifdef DEBUG_URL_PANEL + // Connect the button events + Bind(wxEVT_BUTTON, &WebViewDialog::on_back_button, this, m_button_back->GetId()); + Bind(wxEVT_BUTTON, &WebViewDialog::on_forward_button, this, m_button_forward->GetId()); + Bind(wxEVT_BUTTON, &WebViewDialog::on_stop_button, this, m_button_stop->GetId()); + Bind(wxEVT_BUTTON, &WebViewDialog::on_reload_button, this, m_button_reload->GetId()); + Bind(wxEVT_BUTTON, &WebViewDialog::on_tools_clicked, this, m_button_tools->GetId()); + Bind(wxEVT_TEXT_ENTER, &WebViewDialog::on_url, this, m_url->GetId()); + + // Connect the menu events + Bind(wxEVT_MENU, &WebViewDialog::on_view_source_request, this, viewSource->GetId()); + Bind(wxEVT_MENU, &WebViewDialog::on_view_text_request, this, viewText->GetId()); + Bind(wxEVT_MENU, &WebViewDialog::On_enable_context_menu, this, m_context_menu->GetId()); + Bind(wxEVT_MENU, &WebViewDialog::On_enable_dev_tools, this, m_dev_tools->GetId()); + + Bind(wxEVT_MENU, &WebViewDialog::on_run_script_custom, this, m_script_custom->GetId()); + Bind(wxEVT_MENU, &WebViewDialog::on_add_user_script, this, addUserScript->GetId()); +#endif + + Bind(wxEVT_CLOSE_WINDOW, ([this](wxCloseEvent& evt) { EndModal(wxID_CANCEL); })); m_browser->LoadURL(url); +#ifdef DEBUG_URL_PANEL + m_url->SetLabelText(url); +#endif } WebViewDialog::~WebViewDialog() { } +void WebViewDialog::on_idle(wxIdleEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + if (m_browser->IsBusy()) { + wxSetCursor(wxCURSOR_ARROWWAIT); + } else { + wxSetCursor(wxNullCursor); + if (m_load_error_page) { + m_load_error_page = false; + m_browser->LoadURL(GUI::format_wxstr("file://%1%/web/connection_failed.html", boost::filesystem::path(resources_dir()).generic_string())); + } + } +#ifdef DEBUG_URL_PANEL + m_button_stop->Enable(m_browser->IsBusy()); +#endif +} + +/** + * Callback invoked when user entered an URL and pressed enter + */ +void WebViewDialog::on_url(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; +#ifdef DEBUG_URL_PANEL + m_browser->LoadURL(m_url->GetValue()); + m_browser->SetFocus(); +#endif +} + +/** + * Callback invoked when user pressed the "back" button + */ +void WebViewDialog::on_back_button(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + m_browser->GoBack(); +} + +/** + * Callback invoked when user pressed the "forward" button + */ +void WebViewDialog::on_forward_button(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + m_browser->GoForward(); +} + +/** + * Callback invoked when user pressed the "stop" button + */ +void WebViewDialog::on_stop_button(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + m_browser->Stop(); +} + +/** + * Callback invoked when user pressed the "reload" button + */ +void WebViewDialog::on_reload_button(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + m_browser->Reload(); +} + +void WebViewDialog::on_script_message(wxWebViewEvent& evt) +{ +} + +/** + * Invoked when user selects the "View Source" menu item + */ +void WebViewDialog::on_view_source_request(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + + SourceViewDialog dlg(this, m_browser->GetPageSource()); + dlg.ShowModal(); +} + +/** + * Invoked when user selects the "View Text" menu item + */ +void WebViewDialog::on_view_text_request(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + + wxDialog textViewDialog(this, wxID_ANY, "Page Text", + wxDefaultPosition, wxSize(700, 500), + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + + wxTextCtrl* text = new wxTextCtrl(this, wxID_ANY, m_browser->GetPageText(), + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | + wxTE_RICH | + wxTE_READONLY); + + wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); + sizer->Add(text, 1, wxEXPAND); + SetSizer(sizer); + textViewDialog.ShowModal(); +} + +/** + * Invoked when user selects the "Menu" item + */ +void WebViewDialog::on_tools_clicked(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + +#ifdef DEBUG_URL_PANEL + m_context_menu->Check(m_browser->IsContextMenuEnabled()); + m_dev_tools->Check(m_browser->IsAccessToDevToolsEnabled()); + + wxPoint position = ScreenToClient(wxGetMousePosition()); + PopupMenu(m_tools_menu, position.x, position.y); +#endif +} + + +void WebViewDialog::on_run_script_custom(wxCommandEvent& WXUNUSED(evt)) +{ + wxTextEntryDialog dialog + ( + this, + "Please enter JavaScript code to execute", + wxGetTextFromUserPromptStr, + m_javascript, + wxOK | wxCANCEL | wxCENTRE | wxTE_MULTILINE + ); + if (dialog.ShowModal() != wxID_OK) + return; + + run_script(dialog.GetValue()); +} + +void WebViewDialog::on_add_user_script(wxCommandEvent& WXUNUSED(evt)) +{ + wxString userScript = "window.wx_test_var = 'wxWidgets webview sample';"; + wxTextEntryDialog dialog + ( + this, + "Enter the JavaScript code to run as the initialization script that runs before any script in the HTML document.", + wxGetTextFromUserPromptStr, + userScript, + wxOK | wxCANCEL | wxCENTRE | wxTE_MULTILINE + ); + if (dialog.ShowModal() != wxID_OK) + return; + + if (!m_browser->AddUserScript(dialog.GetValue())) + wxLogError("Could not add user script"); +} + +void WebViewDialog::on_set_custom_user_agent(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + + wxString customUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1"; + wxTextEntryDialog dialog + ( + this, + "Enter the custom user agent string you would like to use.", + wxGetTextFromUserPromptStr, + customUserAgent, + wxOK | wxCANCEL | wxCENTRE + ); + if (dialog.ShowModal() != wxID_OK) + return; + + if (!m_browser->SetUserAgent(customUserAgent)) + wxLogError("Could not set custom user agent"); +} + +void WebViewDialog::on_clear_selection(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + + m_browser->ClearSelection(); +} + +void WebViewDialog::on_delete_selection(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + + m_browser->DeleteSelection(); +} + +void WebViewDialog::on_select_all(wxCommandEvent& WXUNUSED(evt)) +{ + if (!m_browser) + return; + + m_browser->SelectAll(); +} + +void WebViewDialog::On_enable_context_menu(wxCommandEvent& evt) +{ + if (!m_browser) + return; + + m_browser->EnableContextMenu(evt.IsChecked()); +} +void WebViewDialog::On_enable_dev_tools(wxCommandEvent& evt) +{ + if (!m_browser) + return; + + m_browser->EnableAccessToDevTools(evt.IsChecked()); +} + +/** + * Callback invoked when a loading error occurs + */ +void WebViewDialog::on_error(wxWebViewEvent& evt) +{ +#define WX_ERROR_CASE(type) \ +case type: \ + category = #type; \ + break; + + wxString category; + switch (evt.GetInt()) + { + WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_CONNECTION); + WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_CERTIFICATE); + WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_AUTH); + WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_SECURITY); + WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_NOT_FOUND); + WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_REQUEST); + WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_USER_CANCELLED); + WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_OTHER); + } + + BOOST_LOG_TRIVIAL(error) << "WebViewDialog error: " << category; + load_error_page(); +} + +void WebViewDialog::load_error_page() +{ + if (!m_browser) + return; + + m_browser->Stop(); + m_load_error_page = true; +} + void WebViewDialog::run_script(const wxString& javascript) { - if (!m_browser) + if (!m_browser) return; + // Remember the script we run in any case, so the next time the user opens + // the "Run Script" dialog box, it is shown there for convenient updating. + m_javascript = javascript; + BOOST_LOG_TRIVIAL(debug) << "RunScript " << javascript; m_browser->RunScriptAsync(javascript); } +void WebViewDialog::EndModal(int retCode) +{ + if (m_browser) { + for (const std::string& handler : m_script_message_hadler_names) { + m_browser->RemoveScriptMessageHandler(GUI::into_u8(handler)); + } + } + + wxDialog::EndModal(retCode); +} + PrinterPickWebViewDialog::PrinterPickWebViewDialog(wxWindow* parent, std::string& ret_val) : WebViewDialog(parent - , L"https://connect.prusa3d.com/connect-slicer-app/printer-list" + , L"https://connect.prusa3d.com/slicer-select-printer" , _L("Choose a printer") , wxSize(std::max(parent->GetClientSize().x / 2, 100 * wxGetApp().em_unit()), std::max(parent->GetClientSize().y / 2, 50 * wxGetApp().em_unit())) + ,{"_prusaSlicer"} , "connect_loading") , m_ret_val(ret_val) { @@ -710,13 +1065,18 @@ void PrinterPickWebViewDialog::on_script_message(wxWebViewEvent& evt) handle_message(into_u8(evt.GetString())); } -void PrinterPickWebViewDialog::on_request_update_selected_printer_action() +void PrinterPickWebViewDialog::on_connect_action_select_printer() +{ + // SELECT_PRINTER request is not defined for PrinterPickWebViewDialog + assert(true); +} +void PrinterPickWebViewDialog::on_connect_action_print() { m_ret_val = m_message_data; this->EndModal(wxID_OK); } -void PrinterPickWebViewDialog::request_compatible_printers() +void PrinterPickWebViewDialog::on_connect_action_webapp_ready() { if (Preset::printer_technology(wxGetApp().preset_bundle->printers.get_selected_preset().config) == ptFFF) { @@ -732,24 +1092,24 @@ void PrinterPickWebViewDialog::request_compatible_printers_FFF() //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(); - std::string nozzle_diameter_serialized = dynamic_cast(selected_printer.config.option("nozzle_diameter"))->serialize(); - // Sending only first nozzle diamenter for now. - if (size_t comma = nozzle_diameter_serialized.find(','); comma != std::string::npos) - nozzle_diameter_serialized = nozzle_diameter_serialized.substr(0, comma); + std::string nozzle_diameter_serialized = selected_printer.config.opt_string("printer_variant"); // 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 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( "{" + "\"printerUuid\": \"%4%\", " "\"printerModel\": \"%3%\", " "\"nozzleDiameter\": %2%, " - "\"material\": \"%1%\" " - "}", filament_type_serialized, nozzle_diameter_serialized, printer_model_serialized); + "\"material\": \"%1%\", " + "\"filename\": \"%5%\" " + "}", filament_type_serialized, nozzle_diameter_serialized, printer_model_serialized, uuid, filename); wxString script = GUI::format_wxstr("window._prusaConnect_v1.requestCompatiblePrinter(%1%)", request); run_script(script); @@ -760,11 +1120,15 @@ void PrinterPickWebViewDialog::request_compatible_printers_SLA() const std::string printer_model_serialized = selected_printer.config.option("printer_model")->serialize(); 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); + const std::string filename = wxGetApp().plater()->get_upload_filename(); const std::string request = GUI::format( "{" + "\"printerUuid\": \"%3%\", " "\"material\": \"%1%\", " - "\"printerModel\": \"%2%\" " - "}", material_type_serialized, printer_model_serialized); + "\"printerModel\": \"%2%\", " + "\"filename\": \"%4%\" " + "}", material_type_serialized, printer_model_serialized, uuid, filename); wxString script = GUI::format_wxstr("window._prusaConnect_v1.requestCompatiblePrinter(%1%)", request); run_script(script); diff --git a/src/slic3r/GUI/WebViewDialog.hpp b/src/slic3r/GUI/WebViewDialog.hpp index f25ec21399..6b95ff8975 100644 --- a/src/slic3r/GUI/WebViewDialog.hpp +++ b/src/slic3r/GUI/WebViewDialog.hpp @@ -16,7 +16,7 @@ namespace GUI { class WebViewPanel : public wxPanel { public: - WebViewPanel(wxWindow *parent, const wxString& default_url, const std::string& loading_html = "loading"); + WebViewPanel(wxWindow *parent, const wxString& default_url, const std::vector& message_handler_names, const std::string& loading_html = "loading"); virtual ~WebViewPanel(); void load_url(const wxString& url); @@ -47,7 +47,6 @@ public: void on_select_all(wxCommandEvent& evt); void On_enable_context_menu(wxCommandEvent& evt); void On_enable_dev_tools(wxCommandEvent& evt); - void on_close(wxCloseEvent& evt); wxString get_default_url() const { return m_default_url; } void set_default_url(const wxString& url) { m_default_url = url; } @@ -55,7 +54,7 @@ public: virtual void sys_color_changed(); protected: - wxWebView* m_browser; + wxWebView* m_browser { nullptr }; bool m_load_default_url { false }; #ifdef DEBUG_URL_PANEL @@ -76,7 +75,6 @@ protected: wxMenuItem* m_context_menu; wxMenuItem* m_dev_tools; #endif - long m_zoomFactor; // Last executed JavaScript snippet, for convenience. wxString m_javascript; @@ -88,8 +86,77 @@ protected: bool m_load_error_page { false }; bool m_shown { false }; + + std::vector m_script_message_hadler_names; }; + +class WebViewDialog : public wxDialog +{ +public: + WebViewDialog(wxWindow* parent, const wxString& url, const wxString& dialog_name, const wxSize& size, const std::vector& message_handler_names, const std::string& loading_html = "loading"); + virtual ~WebViewDialog(); + + virtual void on_show(wxShowEvent& evt) = 0; + virtual void on_script_message(wxWebViewEvent& evt) = 0; + + void on_idle(wxIdleEvent& evt); + void on_url(wxCommandEvent& evt); + void on_back_button(wxCommandEvent& evt); + void on_forward_button(wxCommandEvent& evt); + void on_stop_button(wxCommandEvent& evt); + void on_reload_button(wxCommandEvent& evt); + + void on_view_source_request(wxCommandEvent& evt); + void on_view_text_request(wxCommandEvent& evt); + void on_tools_clicked(wxCommandEvent& evt); + void on_error(wxWebViewEvent& evt); + + void on_run_script_custom(wxCommandEvent& evt); + void on_add_user_script(wxCommandEvent& evt); + void on_set_custom_user_agent(wxCommandEvent& evt); + void on_clear_selection(wxCommandEvent& evt); + void on_delete_selection(wxCommandEvent& evt); + void on_select_all(wxCommandEvent& evt); + void On_enable_context_menu(wxCommandEvent& evt); + void On_enable_dev_tools(wxCommandEvent& evt); + + void run_script(const wxString& javascript); + + void load_error_page(); + + virtual void EndModal(int retCode) wxOVERRIDE; +protected: + wxWebView* m_browser {nullptr}; + std::string m_loading_html; + + bool m_load_error_page{ false }; +#ifdef DEBUG_URL_PANEL + + wxBoxSizer* bSizer_toolbar; + wxButton* m_button_back; + wxButton* m_button_forward; + wxButton* m_button_stop; + wxButton* m_button_reload; + wxTextCtrl* m_url; + wxButton* m_button_tools; + + wxMenu* m_tools_menu; + wxMenuItem* m_script_custom; + + wxStaticText* m_info_text; + + wxMenuItem* m_context_menu; + wxMenuItem* m_dev_tools; +#endif + // Last executed JavaScript snippet, for convenience. + wxString m_javascript; + wxString m_response_js; + wxString m_default_url; + + std::vector m_script_message_hadler_names; +}; + class ConnectRequestHandler { public: @@ -100,11 +167,12 @@ public: void resend_config(); protected: // action callbacs stored in m_actions - virtual void on_request_access_token(); - virtual void on_request_config(); - virtual void on_request_update_selected_printer_action() = 0; + virtual void on_connect_action_request_access_token(); + virtual void on_connect_action_request_config(); + virtual void on_connect_action_select_printer() = 0; + virtual void on_connect_action_print() = 0; virtual void run_script_bridge(const wxString& script) = 0; - virtual void request_compatible_printers() = 0; + virtual void on_connect_action_webapp_ready() = 0; std::map> m_actions; std::string m_message_data; @@ -119,8 +187,9 @@ public: void logout(); void sys_color_changed() override; protected: - void on_request_update_selected_printer_action() override; - void request_compatible_printers() override {} + void on_connect_action_select_printer() override; + void on_connect_action_print() override; + void on_connect_action_webapp_ready() override {} void run_script_bridge(const wxString& script) override {run_script(script); } }; @@ -144,23 +213,6 @@ private: bool m_api_key_sent {false}; }; - -class WebViewDialog : public wxDialog -{ -public: - WebViewDialog(wxWindow* parent, const wxString& url, const wxString& dialog_name, const wxSize& size, const std::string& loading_html = "loading"); - virtual ~WebViewDialog(); - - virtual void on_show(wxShowEvent& evt) = 0; - virtual void on_script_message(wxWebViewEvent& evt) = 0; - - void run_script(const wxString& javascript); - -protected: - wxWebView* m_browser; - std::string m_loading_html; -}; - class PrinterPickWebViewDialog : public WebViewDialog, public ConnectRequestHandler { public: @@ -168,11 +220,13 @@ public: void on_show(wxShowEvent& evt) override; void on_script_message(wxWebViewEvent& evt) override; protected: - void on_request_update_selected_printer_action() override; - void request_compatible_printers() override; + void on_connect_action_select_printer() override; + void on_connect_action_print() override; + void on_connect_action_webapp_ready() override; void request_compatible_printers_FFF(); void request_compatible_printers_SLA(); void run_script_bridge(const wxString& script) override { run_script(script); } + private: std::string& m_ret_val; }; diff --git a/src/slic3r/Utils/PrintHost.hpp b/src/slic3r/Utils/PrintHost.hpp index 89f0e1168a..f7b3a5175c 100644 --- a/src/slic3r/Utils/PrintHost.hpp +++ b/src/slic3r/Utils/PrintHost.hpp @@ -41,6 +41,10 @@ struct PrintHostUpload std::string storage; PrintHostPostUploadAction post_action { PrintHostPostUploadAction::None }; + + std::string set_ready; + std::string position; + std::string wait_until; }; class PrintHost diff --git a/src/slic3r/Utils/PrusaConnect.cpp b/src/slic3r/Utils/PrusaConnect.cpp index 87f367ffb5..19da1cb832 100644 --- a/src/slic3r/Utils/PrusaConnect.cpp +++ b/src/slic3r/Utils/PrusaConnect.cpp @@ -90,8 +90,8 @@ bool PrusaConnectNew::init_upload(PrintHostUpload upload_data, std::string& out) const std::string name = get_name(); const std::string file_size = std::to_string(size); const std::string access_token = GUI::wxGetApp().plater()->get_user_account()->get_access_token(); - const std::string escaped_upload_path = escape_path_by_element(upload_data.upload_path); - const std::string escaped_upload_filename = escape_path_by_element(upload_data.upload_path.filename()); + //const std::string upload_path = upload_data.upload_path.generic_string(); + const std::string upload_filename = upload_data.upload_path.filename().string(); std::string url = GUI::format("%1%/app/users/teams/%2%/uploads", get_host(), m_team_id); const std::string request_body_json = GUI::format( "{" @@ -101,9 +101,9 @@ bool PrusaConnectNew::init_upload(PrintHostUpload upload_data, std::string& out) "\"force\": true, " "\"printer_uuid\": \"%4%\"" "}" - , escaped_upload_filename + , upload_filename , file_size - , upload_data.storage + "/" + escaped_upload_path + , upload_data.upload_path.generic_string() , m_uuid ); @@ -156,10 +156,20 @@ bool PrusaConnectNew::upload(PrintHostUpload upload_data, ProgressFn progress_fn } const std::string name = get_name(); const std::string access_token = GUI::wxGetApp().plater()->get_user_account()->get_access_token(); - const std::string escaped_upload_path = escape_string(upload_data.storage + "/" + upload_data.upload_path.string()); - const std::string to_print = upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false"; - const std::string to_queue = upload_data.post_action == PrintHostPostUploadAction::QueuePrint ? "true" : "false"; - std::string url = GUI::format("%1%/app/teams/%2%/files/raw?upload_id=%3%&force=true&printer_uuid=%4%&path=%5%&to_print=%6%&to_queue=%7%", get_host(), m_team_id, upload_id, m_uuid, escaped_upload_path, to_print, to_queue); + const std::string escaped_upload_path = upload_data.storage + "/" + escape_path_by_element(upload_data.upload_path.string()); + const std::string set_ready = upload_data.set_ready.empty() ? "" : "&set_ready=" + upload_data.set_ready; + const std::string position = upload_data.position.empty() ? "" : "&position=" + upload_data.position; + const std::string wait_until = upload_data.wait_until.empty() ? "" : "&wait_until=" + upload_data.wait_until; + const std::string url = GUI::format( + "%1%/app/teams/%2%/files/raw" + "?upload_id=%3%" + "&force=true" + "&printer_uuid=%4%" + "&path=%5%" + "%6%" + "%7%" + "%8%" + , get_host(), m_team_id, upload_id, m_uuid, escaped_upload_path, set_ready, position, wait_until); bool res = true; BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3%, filename: %4%, path: %5%, print: %6%")