diff --git a/resources/web/connect_loading.html b/resources/web/connect_loading.html
new file mode 100644
index 0000000000..bfe8401d2d
--- /dev/null
+++ b/resources/web/connect_loading.html
@@ -0,0 +1,77 @@
+
+
+
+
+
+ Connect-Slicer integration
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/web/loading.html b/resources/web/loading.html
new file mode 100644
index 0000000000..0f50d68325
--- /dev/null
+++ b/resources/web/loading.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+ Connect-Slicer integration
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index e46274071f..d7b4d4b0aa 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -3132,7 +3132,7 @@ bool GUI_App::may_switch_to_SLA_preset(const wxString& caption)
bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage start_page)
{
wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null");
-
+#if 0
if (!plater()->get_user_account()->is_logged()) {
m_login_dialog = std::make_unique(mainframe, plater()->get_user_account());
m_login_dialog->ShowModal();
@@ -3141,7 +3141,7 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage
// Destructor does not call Destroy
m_login_dialog.reset();
}
-
+#endif // 0
if (reason == ConfigWizard::RR_USER) {
// Cancel sync before starting wizard to prevent two downloads at same time
preset_updater->cancel_sync();
@@ -3171,6 +3171,7 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage
return res;
}
+#if 0
void GUI_App::update_login_dialog()
{
if (!m_login_dialog) {
@@ -3178,6 +3179,7 @@ void GUI_App::update_login_dialog()
}
m_login_dialog->update_account();
}
+#endif // 0
void GUI_App::show_desktop_integration_dialog()
{
@@ -3650,8 +3652,8 @@ void GUI_App::open_wifi_config_dialog(bool forced, const wxString& drive_path/*
}
m_wifi_config_dialog_shown = false;
}
-
-bool GUI_App::select_printer_from_connect(const Preset* preset)
+// Returns true if preset had to be installed.
+bool GUI_App::select_printer_preset(const Preset* preset)
{
assert(preset);
@@ -3675,36 +3677,142 @@ bool GUI_App::select_printer_from_connect(const Preset* preset)
return is_installed;
}
-void GUI_App::handle_connect_request_printer_pick(std::string msg)
+bool GUI_App::select_printer_from_connect(const std::string& msg)
{
- BOOST_LOG_TRIVIAL(error) << "Handling web request: " << msg;
- // return to plater
- this->mainframe->select_tab(size_t(0));
// parse message
- std::vector compatible_printers;
- plater()->get_user_account()->fill_compatible_printers_from_json(msg, compatible_printers);
- std::string model_name;
- if (compatible_printers.empty()) {
- // TODO: This should go away when compatible printers gives right information.
- model_name = plater()->get_user_account()->get_model_from_json(msg);
- } else {
- model_name = compatible_printers.front();
+ std::string model_name = plater()->get_user_account()->get_keyword_from_json(msg, "printer_model");
+ if (model_name.empty()) {
+ std::vector compatible_printers;
+ plater()->get_user_account()->fill_supported_printer_models_from_json(msg, compatible_printers);
+ if (!compatible_printers.empty()) {
+ model_name = compatible_printers.front();
+ }
+ }
+ if (model_name.empty()) {
+ 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);
- assert(!model_name.empty());
- if (model_name.empty())
- return;
-
+ BOOST_LOG_TRIVIAL(info) << "Select printer from Connect. Model: " << model_name << "nozzle: " << nozzle;
// select printer
- const Preset* preset = preset_bundle->printers.find_system_preset_by_model_and_variant(model_name, nozzle);
- bool is_installed = preset && select_printer_from_connect(preset);
+ const Preset* printer_preset = preset_bundle->printers.find_system_preset_by_model_and_variant(model_name, nozzle);
+ bool is_installed = printer_preset && select_printer_preset(printer_preset);
// notification
- std::string out = preset ?
- (is_installed ? GUI::format(_L("Installed and Select Printer:\n%1%"), preset->name) :
- GUI::format(_L("Select Printer:\n%1%"), preset->name) ):
- GUI::format(_L("Printer not found:\n%1%"), model_name);
- this->plater()->get_notification_manager()->close_notification_of_type(NotificationType::UserAccountID);
- this->plater()->get_notification_manager()->push_notification(NotificationType::UserAccountID, NotificationManager::NotificationLevel::ImportantNotificationLevel, out);
+ std::string out = printer_preset ?
+ (is_installed ? GUI::format(_L("Installed and Selected Printer:\n%1%"), printer_preset->name) :
+ GUI::format(_L("Selected Printer:\n%1%"), printer_preset->name)) :
+ GUI::format(_L("Printer not found:\n%1%"), model_name);
+ this->plater()->get_notification_manager()->close_notification_of_type(NotificationType::SelectPrinterFromConnect);
+ this->plater()->get_notification_manager()->push_notification(
+ NotificationType::SelectPrinterFromConnect
+ , printer_preset ? NotificationManager::NotificationLevel::ImportantNotificationLevel : NotificationManager::NotificationLevel::WarningNotificationLevel
+ , out);
+ return printer_preset;
+}
+
+bool GUI_App::select_filament_preset(const Preset* preset, size_t extruder_index)
+{
+ assert(preset && preset->is_compatible);
+
+ if (!preset->is_visible) {
+ // To correct update of presets visibility call select_preset for preset_bundle->filaments()
+ size_t preset_id = preset_bundle->filaments.get_preset_idx_by_name(preset->name);
+ assert(preset_id != size_t(-1));
+ preset_bundle->filaments.select_preset(preset_id);
+ }
+ assert(preset->is_visible);
+ return preset_bundle->extruders_filaments[extruder_index].select_filament(preset->name);
+}
+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;
+ // selected is ok
+ if (config.has("filament_type") && config.option("filament_type")->serialize() == material) {
+ 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
+ && !filament.preset->is_default
+ && filament.preset->is_visible
+ && !filament.preset->vendor->templates_profile
+ && filament.preset->config.has("filament_type")
+ && filament.preset->config.option("filament_type")->serialize() == material
+ && 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 profile to install
+ // try finding Prusament
+ for (const auto& filament : preset_bundle->extruders_filaments[extruder_index]) {
+ if (filament.is_compatible
+ && !filament.preset->is_default
+ && !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 += GUI::format(_L("Extruder %1%: Selected and Installed Filament %2%\n"), extruder_index + 1, filament.preset->name);
+ return;
+ }
+ }
+ out_message += GUI::format(_L("Extruder %2%: Failed to Find and Select Filament type: %1%\n"), material, extruder_index + 1);
+}
+
+void GUI_App::select_filament_from_connect(const std::string& msg)
+{
+ // parse message
+ std::vector materials;
+ plater()->get_user_account()->fill_material_from_json(msg, materials);
+ if (materials.empty()) {
+ BOOST_LOG_TRIVIAL(error) << "Failed to select filament from Connect. No material data.";
+ return;
+ }
+ // test if currently selected is same type
+ size_t extruder_count = preset_bundle->extruders_filaments.size();
+ if (extruder_count != materials.size()) {
+ BOOST_LOG_TRIVIAL(error) << format("Failed to select filament from Connect. Selected printer has %1% extruders while data from Connect contains %2% materials.", extruder_count, materials.size());
+ return;
+ }
+ std::string notification_text;
+ for (size_t i = 0; i < extruder_count; i++) {
+ search_and_select_filaments(materials[i], i, notification_text);
+ }
+
+ // When all filaments are selected/intalled,
+ // then update preset comboboxes on sidebar
+ sidebar().update_presets(Preset::TYPE_FILAMENT);
+ // and filaments tab
+ TabFilament* tab = dynamic_cast(get_tab(Preset::TYPE_FILAMENT));
+ tab->select_preset(preset_bundle->extruders_filaments[tab->get_active_extruder()].get_selected_preset_name());
+
+ if (!notification_text.empty()) {
+ plater()->get_notification_manager()->close_notification_of_type(NotificationType::SelectFilamentFromConnect);
+ plater()->get_notification_manager()->push_notification(NotificationType::SelectFilamentFromConnect, NotificationManager::NotificationLevel::ImportantNotificationLevel, notification_text);
+ }
+}
+
+void GUI_App::handle_connect_request_printer_pick(const std::string& msg)
+{
+ BOOST_LOG_TRIVIAL(debug) << "Handling web request: " << msg;
+ // return to plater
+ this->mainframe->select_tab(size_t(0));
+
+ if (!select_printer_from_connect(msg)) {
+ // If printer was not selected, do not select filament.
+ return;
+ }
+ // TODO: Selecting SLA material
+ if (Preset::printer_technology(preset_bundle->printers.get_selected_preset().config) != ptFFF) {
+ return;
+ }
+ select_filament_from_connect(msg);
}
void GUI_App::show_printer_webview_tab()
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
index 6eb67b47ee..0f2b84a434 100644
--- a/src/slic3r/GUI/GUI_App.hpp
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -371,7 +371,9 @@ public:
void open_web_page_localized(const std::string &http_address);
bool may_switch_to_SLA_preset(const wxString& caption);
bool run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage start_page = ConfigWizard::SP_WELCOME);
+#if 0
void update_login_dialog();
+#endif // 0
void show_desktop_integration_dialog();
void show_downloader_registration_dialog();
@@ -409,10 +411,14 @@ public:
void request_user_login(int online_login) {}
void request_user_logout() {}
int request_user_unbind(std::string dev_id) { return 0; }
- void handle_connect_request_printer_pick(std::string cmd);
+ 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 show_printer_webview_tab();
// return true if preset vas invisible and we have to installed it to make it selectable
- bool select_printer_from_connect(const Preset* printer_preset);
+ bool select_printer_preset(const Preset* printer_preset);
+ bool select_filament_preset(const Preset* filament_preset, size_t extruder_index);
+ void search_and_select_filaments(const std::string& material, size_t extruder_index, std::string& out_message);
void handle_script_message(std::string msg) {}
void request_model_download(std::string import_json) {}
void download_project(std::string project_id) {}
@@ -446,8 +452,9 @@ private:
// change to vector of items when adding more items that require update
//wxMenuItem* m_login_config_menu_item { nullptr };
std::map< ConfigMenuIDs, wxMenuItem*> m_config_menu_updatable_items;
-
+#if 0
std::unique_ptr m_login_dialog;
+#endif // 0
};
DECLARE_APP(GUI_App)
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 99baa4263b..1e77343bdc 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -777,7 +777,7 @@ void MainFrame::remove_connect_webview_tab()
void MainFrame::show_printer_webview_tab(DynamicPrintConfig* dpc)
{
// if physical printer is selected
- if (dpc) {
+ if (dpc && dpc->option>("host_type")->value != htPrusaConnect) {
std::string url = dpc->opt_string("print_host");
if (url.find("http://") != 0 && url.find("https://") != 0) {
diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp
index da0688961a..05dd363dbc 100644
--- a/src/slic3r/GUI/NotificationManager.hpp
+++ b/src/slic3r/GUI/NotificationManager.hpp
@@ -131,6 +131,9 @@ enum class NotificationType
WifiConfigFileDetected,
// Info abouty successful login or logout
UserAccountID,
+ // When in Connect tab "set as current" is selected and selected presets in plater changes
+ SelectPrinterFromConnect,
+ SelectFilamentFromConnect,
// Debug notification for connect communication
PrusaConnectPrinters,
};
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 3ba7588d34..260ef99458 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -837,7 +837,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
// Reset the "dirty project" flag.
m_undo_redo_stack_main.mark_current_as_saved();
dirty_state.update_from_undo_redo_stack(false);
-
+
this->q->Bind(EVT_LOAD_MODEL_OTHER_INSTANCE, [this](LoadFromOtherInstanceEvent& evt) {
BOOST_LOG_TRIVIAL(trace) << "Received load from other instance event.";
wxArrayString input_files;
@@ -847,67 +847,83 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
wxGetApp().mainframe->Raise();
this->q->load_files(input_files);
});
-
- this->q->Bind(EVT_START_DOWNLOAD_OTHER_INSTANCE, [](StartDownloadOtherInstanceEvent& evt) {
- BOOST_LOG_TRIVIAL(trace) << "Received url from other instance event.";
- wxGetApp().mainframe->Raise();
- for (size_t i = 0; i < evt.data.size(); ++i) {
- wxGetApp().start_download(evt.data[i]);
- }
-
- });
- this->q->Bind(EVT_LOGIN_OTHER_INSTANCE, [this](LoginOtherInstanceEvent& evt) {
- BOOST_LOG_TRIVIAL(trace) << "Received login from other instance event.";
- user_account->on_login_code_recieved(evt.data);
- });
-
- this->q->Bind(EVT_INSTANCE_GO_TO_FRONT, [this](InstanceGoToFrontEvent &) {
+ this->q->Bind(EVT_INSTANCE_GO_TO_FRONT, [this](InstanceGoToFrontEvent&) {
bring_instance_forward();
});
-
- this->q->Bind(EVT_OPEN_PRUSAAUTH, [](OpenPrusaAuthEvent& evt) {
- BOOST_LOG_TRIVIAL(info) << "open browser: " << evt.data;
- // first register url to be sure to get the code back
- //auto downloader_worker = new DownloaderUtils::Worker(nullptr);
- DownloaderUtils::Worker::perform_register(wxGetApp().app_config->get("url_downloader_dest"));
-#ifdef __linux__
- if (DownloaderUtils::Worker::perform_registration_linux)
- DesktopIntegrationDialog::perform_downloader_desktop_integration();
-#endif // __linux__
- // than open url
- wxGetApp().open_login_browser_with_dialog(evt.data);
- });
+ // Downloader and USerAccount Events doesnt need to be binded in viewer.
+ // Not binding Account events prevents it from loging in.
+ if (wxGetApp().is_editor()) {
+ this->q->Bind(EVT_START_DOWNLOAD_OTHER_INSTANCE, [](StartDownloadOtherInstanceEvent& evt) {
+ BOOST_LOG_TRIVIAL(trace) << "Received url from other instance event.";
+ wxGetApp().mainframe->Raise();
+ for (size_t i = 0; i < evt.data.size(); ++i) {
+ wxGetApp().start_download(evt.data[i]);
+ }
+ });
+ this->q->Bind(EVT_LOGIN_OTHER_INSTANCE, [this](LoginOtherInstanceEvent& evt) {
+ BOOST_LOG_TRIVIAL(trace) << "Received login from other instance event.";
+ user_account->on_login_code_recieved(evt.data);
+ });
+ this->q->Bind(EVT_OPEN_PRUSAAUTH, [](OpenPrusaAuthEvent& evt) {
+ BOOST_LOG_TRIVIAL(info) << "open browser: " << evt.data;
+ // first register url to be sure to get the code back
+ //auto downloader_worker = new DownloaderUtils::Worker(nullptr);
+ DownloaderUtils::Worker::perform_register(wxGetApp().app_config->get("url_downloader_dest"));
+ #ifdef __linux__
+ if (DownloaderUtils::Worker::perform_registration_linux)
+ DesktopIntegrationDialog::perform_downloader_desktop_integration();
+ #endif // __linux__
+ // than open url
+ wxGetApp().open_login_browser_with_dialog(evt.data);
+ });
- this->q->Bind(EVT_UA_LOGGEDOUT, [this](UserAccountSuccessEvent& evt) {
- user_account->clear();
- std::string text = _u8L("Logged out from Prusa Account.");
- this->notification_manager->close_notification_of_type(NotificationType::UserAccountID);
- this->notification_manager->push_notification(NotificationType::UserAccountID, NotificationManager::NotificationLevel::ImportantNotificationLevel, text);
- this->main_frame->remove_connect_webview_tab();
- this->main_frame->refresh_account_menu(true);
- // Update sidebar printer status
- sidebar->update_printer_presets_combobox();
- wxGetApp().update_login_dialog();
- this->show_action_buttons(this->ready_to_slice);
- });
-
- this->q->Bind(EVT_UA_ID_USER_SUCCESS, [this](UserAccountSuccessEvent& evt) {
- std::string username;
- if (user_account->on_user_id_success(evt.data, username)) {
- // login notification
- std::string text = format(_u8L("Logged to Prusa Account as %1%."), username);
+ this->q->Bind(EVT_UA_LOGGEDOUT, [this](UserAccountSuccessEvent& evt) {
+ user_account->clear();
+ std::string text = _u8L("Logged out from Prusa Account.");
this->notification_manager->close_notification_of_type(NotificationType::UserAccountID);
this->notification_manager->push_notification(NotificationType::UserAccountID, NotificationManager::NotificationLevel::ImportantNotificationLevel, text);
- // show connect tab
- this->main_frame->add_connect_webview_tab();
- // Update User name in TopBar
- this->main_frame->refresh_account_menu();
+ this->main_frame->remove_connect_webview_tab();
+ this->main_frame->refresh_account_menu(true);
+ // Update sidebar printer status
+ sidebar->update_printer_presets_combobox();
+#if 0
wxGetApp().update_login_dialog();
+#endif // 0
this->show_action_buttons(this->ready_to_slice);
- } else {
- // data were corrupt and username was not retrieved
- // procced as if EVT_UA_RESET was recieved
- BOOST_LOG_TRIVIAL(error) << "Reseting Prusa Account communication. Recieved data were corrupt.";
+ });
+
+ this->q->Bind(EVT_UA_ID_USER_SUCCESS, [this](UserAccountSuccessEvent& evt) {
+ std::string username;
+ if (user_account->on_user_id_success(evt.data, username)) {
+ // login notification
+ std::string text = format(_u8L("Logged to Prusa Account as %1%."), username);
+ this->notification_manager->close_notification_of_type(NotificationType::UserAccountID);
+ this->notification_manager->push_notification(NotificationType::UserAccountID, NotificationManager::NotificationLevel::ImportantNotificationLevel, text);
+ // show connect tab
+ this->main_frame->add_connect_webview_tab();
+ // Update User name in TopBar
+ this->main_frame->refresh_account_menu();
+#if 0
+ wxGetApp().update_login_dialog();
+#endif // 0
+ this->show_action_buttons(this->ready_to_slice);
+ } else {
+ // data were corrupt and username was not retrieved
+ // procced as if EVT_UA_RESET was recieved
+ BOOST_LOG_TRIVIAL(error) << "Reseting Prusa Account communication. Recieved data were corrupt.";
+ user_account->clear();
+ this->notification_manager->close_notification_of_type(NotificationType::UserAccountID);
+ this->notification_manager->push_notification(NotificationType::UserAccountID, NotificationManager::NotificationLevel::WarningNotificationLevel, _u8L("Failed to connect to Prusa Account."));
+ this->main_frame->remove_connect_webview_tab();
+ // Update User name in TopBar
+ this->main_frame->refresh_account_menu(true);
+ // Update sidebar printer status
+ sidebar->update_printer_presets_combobox();
+ }
+
+ });
+ this->q->Bind(EVT_UA_RESET, [this](UserAccountFailEvent& evt) {
+ BOOST_LOG_TRIVIAL(error) << "Reseting Prusa Account communication. Error message: " << evt.data;
user_account->clear();
this->notification_manager->close_notification_of_type(NotificationType::UserAccountID);
this->notification_manager->push_notification(NotificationType::UserAccountID, NotificationManager::NotificationLevel::WarningNotificationLevel, _u8L("Failed to connect to Prusa Account."));
@@ -916,45 +932,48 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
this->main_frame->refresh_account_menu(true);
// Update sidebar printer status
sidebar->update_printer_presets_combobox();
- }
-
- });
- this->q->Bind(EVT_UA_RESET, [this](UserAccountFailEvent& evt) {
- BOOST_LOG_TRIVIAL(error) << "Reseting Prusa Account communication. Error message: " << evt.data;
- user_account->clear();
- this->notification_manager->close_notification_of_type(NotificationType::UserAccountID);
- this->notification_manager->push_notification(NotificationType::UserAccountID, NotificationManager::NotificationLevel::WarningNotificationLevel, _u8L("Failed to connect to Prusa Account."));
- this->main_frame->remove_connect_webview_tab();
- // Update User name in TopBar
- this->main_frame->refresh_account_menu(true);
- // Update sidebar printer status
- sidebar->update_printer_presets_combobox();
- });
- this->q->Bind(EVT_UA_FAIL, [this](UserAccountFailEvent& evt) {
- BOOST_LOG_TRIVIAL(error) << "Failed communication with Prusa Account: " << evt.data;
- user_account->on_communication_fail();
- });
- this->q->Bind(EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, [this](UserAccountSuccessEvent& evt) {
- std::string text;
- bool printers_changed = false;
- if (user_account->on_connect_printers_success(evt.data, wxGetApp().app_config, printers_changed)) {
- if (printers_changed) {
- sidebar->update_printer_presets_combobox();
- }
- } else {
- // message was corrupt, procceed like EVT_UA_FAIL
+ });
+ this->q->Bind(EVT_UA_FAIL, [this](UserAccountFailEvent& evt) {
+ BOOST_LOG_TRIVIAL(error) << "Failed communication with Prusa Account: " << evt.data;
user_account->on_communication_fail();
- }
- });
- 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");
- fwrite(evt.data.c_str(), 1, evt.data.size(), file);
- fclose(file);
- this->main_frame->refresh_account_menu(true);
- wxGetApp().update_login_dialog();
- });
+ });
+ this->q->Bind(EVT_UA_PRUSACONNECT_STATUS_SUCCESS, [this](UserAccountSuccessEvent& evt) {
+ std::string text;
+ bool printers_changed = false;
+ if (user_account->on_connect_printers_success(evt.data, wxGetApp().app_config, printers_changed)) {
+ if (printers_changed) {
+ sidebar->update_printer_presets_combobox();
+ }
+ } else {
+ // message was corrupt, procceed like EVT_UA_FAIL
+ user_account->on_communication_fail();
+ }
+ });
+ this->q->Bind(EVT_UA_PRUSACONNECT_PRINTER_MODELS_SUCCESS, [this](UserAccountSuccessEvent& evt) {
+ std::string text;
+ bool printers_changed = false;
+ if (user_account->on_connect_uiid_map_success(evt.data, wxGetApp().app_config, printers_changed)) {
+ if (printers_changed) {
+ sidebar->update_printer_presets_combobox();
+ }
+ }
+ else {
+ // message was corrupt, procceed like EVT_UA_FAIL
+ user_account->on_communication_fail();
+ }
+ });
+ 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");
+ fwrite(evt.data.c_str(), 1, evt.data.size(), file);
+ fclose(file);
+ this->main_frame->refresh_account_menu(true);
+#if 0
+ wxGetApp().update_login_dialog();
+#endif // 0
+ });
+ }
wxGetApp().other_instance_message_handler()->init(this->q);
@@ -5855,20 +5874,46 @@ void Plater::connect_gcode()
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
// Connect data
std::vector compatible_printers;
- p->user_account->fill_compatible_printers_from_json(dialog_msg, 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);
- std::string connect_filament = p->user_account->get_keyword_from_json(dialog_msg, "filament_type");
+
+ 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) {
- compatible_printer_presets.emplace_back(preset_bundle->printers.find_system_preset_by_model_and_variant(cp, connect_nozzle));
+ 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 Preset* selected_filament_preset = &preset_bundle->filaments.get_selected_preset();
- const std::string selected_nozzle_serialized = dynamic_cast(selected_printer_preset->config.option("nozzle_diameter"))->serialize();
- const std::string selected_filament_serialized = selected_filament_preset->config.option("filament_type")->serialize();
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) {
@@ -5880,9 +5925,9 @@ void Plater::connect_gcode()
break;
}
}
- //
+ // Dialog to select action
if (!found) {
- wxString line1 = _L("The printer profile you've selected for upload is not compatible with profiles selected for slicing.");
+ 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;
@@ -5900,7 +5945,7 @@ void Plater::connect_gcode()
return;
}
} else if (!is_first) {
- wxString line1 = _L("The printer profile you've selected for upload might not be compatible with profiles selected for slicing.");
+ 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;
@@ -5918,29 +5963,33 @@ void Plater::connect_gcode()
return;
}
}
- // Commented code with selecting printers in plater
- /*
- // if selected (in connect) preset is not visible, make it visible and selected
- if (!connect_printer_preset->is_visible) {
- size_t preset_id = preset_bundle->printers.get_preset_idx_by_name(connect_printer_preset->name);
- assert(preset_id != size_t(-1));
- preset_bundle->printers.select_preset(preset_id);
- wxGetApp().get_tab(Preset::Type::TYPE_PRINTER)->select_preset(connect_printer_preset->name);
- p->notification_manager->close_notification_of_type(NotificationType::PrusaConnectPrinters);
- p->notification_manager->push_notification(NotificationType::PrusaConnectPrinters, NotificationManager::NotificationLevel::ImportantNotificationLevel, format(_u8L("Changed Printer to %1%."), connect_printer_preset->name));
- select_view_3D("3D");
+
+ 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();
}
- // if selected (in connect) preset is not selected in slicer, select it
- if (preset_bundle->printers.get_selected_preset_name() != connect_printer_preset->name) {
- size_t preset_id = preset_bundle->printers.get_preset_idx_by_name(connect_printer_preset->name);
- assert(preset_id != size_t(-1));
- preset_bundle->printers.select_preset(preset_id);
- wxGetApp().get_tab(Preset::Type::TYPE_PRINTER)->select_preset(connect_printer_preset->name);
- p->notification_manager->close_notification_of_type(NotificationType::PrusaConnectPrinters);
- p->notification_manager->push_notification(NotificationType::PrusaConnectPrinters, NotificationManager::NotificationLevel::ImportantNotificationLevel, format(_u8L("Changed Printer to %1%."), connect_printer_preset->name));
- select_view_3D("3D");
- }
- */
+ 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");
@@ -5959,7 +6008,7 @@ void Plater::connect_gcode()
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(), /**connect_printer_preset*/*selected_printer_preset);
+ 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;
diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp
index 6796bf327f..343d9cab51 100644
--- a/src/slic3r/GUI/PresetComboBoxes.cpp
+++ b/src/slic3r/GUI/PresetComboBoxes.cpp
@@ -374,8 +374,10 @@ void PresetComboBox::edit_physical_printer()
return;
PhysicalPrinterDialog dlg(this->GetParent(),this->GetString(this->GetSelection()));
- if (dlg.ShowModal() == wxID_OK)
+ if (dlg.ShowModal() == wxID_OK) {
update();
+ wxGetApp().show_printer_webview_tab();
+ }
}
void PresetComboBox::add_physical_printer()
@@ -610,6 +612,9 @@ bool PresetComboBox::selection_is_changed_according_to_physical_printers()
else if (dynamic_cast(this)!=nullptr)
wxGetApp().sidebar().update_presets(m_type);
+ // Check and show "Physical printer" page if needed
+ wxGetApp().show_printer_webview_tab();
+
return true;
}
@@ -885,9 +890,11 @@ static std::string get_connect_state_suffix_for_printer(const Preset& printer_pr
if (auto printer_state_map = wxGetApp().plater()->get_user_account()->get_printer_state_map();
!printer_state_map.empty()) {
- for (const auto& [printer_model_id, states] : printer_state_map) {
- if (printer_model_id == printer_preset.config.opt_string("printer_model")) {
-
+ 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 == printer_preset.config.opt_string("nozzle_diamenter"))
+ ) {
PrinterStatesCount states_cnt = get_printe_states_count(states);
if (states_cnt.available_cnt > 0)
@@ -907,9 +914,11 @@ 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()) {
- for (const auto& [printer_model_id, states] : printer_state_map) {
- if (printer_model_id == printer_preset.config.opt_string("printer_model")) {
-
+ 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 == printer_preset.config.opt_string("nozzle_diamenter"))
+ ) {
PrinterStatesCount states_cnt = get_printe_states_count(states);
return format_wxstr(_L("Available: %1%, Offline: %2%, Busy: %3%. Total: %4% printers"),
diff --git a/src/slic3r/GUI/UserAccount.cpp b/src/slic3r/GUI/UserAccount.cpp
index 594febc6d8..bf29e851d2 100644
--- a/src/slic3r/GUI/UserAccount.cpp
+++ b/src/slic3r/GUI/UserAccount.cpp
@@ -84,10 +84,13 @@ boost::filesystem::path UserAccount::get_avatar_path(bool logged) const
}
}
-
-void UserAccount::enqueue_connect_printers_action()
+void UserAccount::enqueue_connect_printer_models_action()
{
- m_communication->enqueue_connect_printers_action();
+ m_communication->enqueue_connect_printer_models_action();
+}
+void UserAccount::enqueue_connect_status_action()
+{
+ m_communication->enqueue_connect_status_action();
}
void UserAccount::enqueue_avatar_action()
{
@@ -137,7 +140,7 @@ bool UserAccount::on_user_id_success(const std::string data, std::string& out_us
BOOST_LOG_TRIVIAL(error) << "User ID message from PrusaAuth did not contain avatar.";
}
// update printers list
- enqueue_connect_printers_action();
+ enqueue_connect_printer_models_action();
return true;
}
@@ -157,15 +160,25 @@ namespace {
for (const auto& section : tree) {
if (section.first == param) {
return section.second.data();
- } else {
- if (std::string res = parse_tree_for_param(section.second, param); !res.empty())
- return res;
}
-
+ if (std::string res = parse_tree_for_param(section.second, param); !res.empty()) {
+ return res;
+ }
}
return {};
}
+ void parse_tree_for_param_vector(const pt::ptree& tree, const std::string& param, std::vector& results)
+ {
+ for (const auto& section : tree) {
+ if (section.first == param) {
+ results.emplace_back(section.second.data());
+ } else {
+ parse_tree_for_param_vector(section.second, param, results);
+ }
+ }
+ }
+
pt::ptree parse_tree_for_subtree(const pt::ptree& tree, const std::string& param)
{
for (const auto& section : tree) {
@@ -194,51 +207,46 @@ bool UserAccount::on_connect_printers_success(const std::string& data, AppConfig
BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what();
return false;
}
- // fill m_printer_map with data from ptree
- // tree string is in format {"result": [{"printer_type": "1.2.3", "states": [{"printer_state": "OFFLINE", "count": 1}, ...]}, {..}]}
-
+ // tree format:
+ /*
+ [{
+ "printer_uuid": "972d2ce7-0967-4555-bff2-330c7fa0a4e1",
+ "printer_state" : "IDLE"
+ }, {
+ "printer_uuid": "15d160fd-c7e4-4b5a-9748-f0e531c7e0f5",
+ "printer_state" : "OFFLINE"
+ }]
+ */
ConnectPrinterStateMap new_printer_map;
-
- assert(ptree.front().first == "result");
- for (const auto& printer_tree : ptree.front().second) {
- // printer_tree is {"printer_type": "1.2.3", "states": [..]}
- std::string name;
- ConnectPrinterState state;
-
- const auto type_opt = printer_tree.second.get_optional("printer_model");
- if (!type_opt) {
+ for (const auto& printer_tree : ptree) {
+ const auto printer_uuid = printer_tree.second.get_optional("printer_uuid");
+ if (!printer_uuid) {
continue;
}
- // printer_type is actually printer_name for now
- name = *type_opt;
- // printer should not appear twice
- assert(new_printer_map.find(name) == new_printer_map.end());
- // prepare all states on 0
- new_printer_map[name].reserve(static_cast(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT));
- for (size_t i = 0; i < static_cast(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT); i++) {
- new_printer_map[name].push_back(0);
+ const auto printer_state = printer_tree.second.get_optional("printer_state");
+ if (!printer_state) {
+ continue;
}
+ ConnectPrinterState state;
+ if (auto pair = printer_state_table.find(*printer_state); pair != printer_state_table.end()) {
+ state = pair->second;
+ } else {
+ assert(true); // On this assert, printer_state_table needs to be updated with *state_opt and correct ConnectPrinterState
+ continue;
+ }
+ if (m_printer_uuid_map.find(*printer_uuid) == m_printer_uuid_map.end()) {
+ BOOST_LOG_TRIVIAL(error) << "Missing printer model for printer uuid: " << *printer_uuid;
+ continue;
+ }
+ std::pair model_nozzle_pair = m_printer_uuid_map[*printer_uuid];
- for (const auto& section : printer_tree.second) {
- // section is "printer_type": "1.2.3" OR "states": [..]}
- if (section.first == "states") {
- for (const auto& subsection : section.second) {
- // subsection is {"printer_state": "OFFLINE", "count": 1}
- const auto state_opt = subsection.second.get_optional("printer_state");
- const auto count_opt = subsection.second.get_optional("count");
- if (!state_opt || ! count_opt) {
- continue;
- }
- if (auto pair = printer_state_table.find(*state_opt); pair != printer_state_table.end()) {
- state = pair->second;
- } else {
- assert(true); // On this assert, printer_state_table needs to be updated with *state_opt and correct ConnectPrinterState
- continue;
- }
- new_printer_map[name][static_cast(state)] = *count_opt;
- }
+ if (new_printer_map.find(model_nozzle_pair) == new_printer_map.end()) {
+ new_printer_map[model_nozzle_pair].reserve(static_cast(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT));
+ for (size_t i = 0; i < static_cast(ConnectPrinterState::CONNECT_PRINTER_STATE_COUNT); i++) {
+ new_printer_map[model_nozzle_pair].push_back(0);
}
}
+ new_printer_map[model_nozzle_pair][static_cast(state)] += 1;
}
// compare new and old printer map and update old map into new
@@ -264,24 +272,35 @@ bool UserAccount::on_connect_printers_success(const std::string& data, AppConfig
return true;
}
-std::string UserAccount::get_model_from_json(const std::string& message) const
+bool UserAccount::on_connect_uiid_map_success(const std::string& data, AppConfig* app_config, bool& out_printers_changed)
{
- std::string out;
+ m_printer_uuid_map.clear();
+ pt::ptree ptree;
try {
- std::stringstream ss(message);
- pt::ptree ptree;
+ std::stringstream ss(data);
pt::read_json(ss, ptree);
-
- std::string printer_type = parse_tree_for_param(ptree, "printer_type");
- if (auto pair = printer_type_and_name_table.find(printer_type); pair != printer_type_and_name_table.end()) {
- out = pair->second;
- }
- //assert(!out.empty());
}
catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what();
+ return false;
}
- return out;
+
+ for (const auto& printer_tree : ptree) {
+ const auto printer_uuid = printer_tree.second.get_optional("printer_uuid");
+ if (!printer_uuid) {
+ continue;
+ }
+ const auto printer_model = printer_tree.second.get_optional("printer_model");
+ if (!printer_model) {
+ continue;
+ }
+ const auto nozzle_diameter_opt = printer_tree.second.get_optional("nozzle_diameter");
+ const std::string nozzle_diameter = nozzle_diameter_opt ? *nozzle_diameter_opt : std::string();
+ std::pair model_nozzle_pair = { *printer_model, nozzle_diameter };
+ m_printer_uuid_map[*printer_uuid] = model_nozzle_pair;
+ }
+ m_communication->on_uuid_map_success();
+ return on_connect_printers_success(data, app_config, out_printers_changed);
}
std::string UserAccount::get_nozzle_from_json(const std::string& message) const
@@ -298,6 +317,15 @@ std::string UserAccount::get_nozzle_from_json(const std::string& message) const
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;
}
@@ -318,20 +346,27 @@ std::string UserAccount::get_keyword_from_json(const std::string& json, const st
return out;
}
-void UserAccount::fill_compatible_printers_from_json(const std::string& json, std::vector& result) const
+void UserAccount::fill_supported_printer_models_from_json(const std::string& json, std::vector& result) const
{
try {
std::stringstream ss(json);
pt::ptree ptree;
pt::read_json(ss, ptree);
- pt::ptree out = parse_tree_for_subtree(ptree, "printer_type_compatible");
+ 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 compatible_printer_type in printer detail.";
+ BOOST_LOG_TRIVIAL(error) << "Failed to find supported_printer_models in printer detail.";
return;
}
for (const auto& sub : out) {
- result.emplace_back(sub.second.data());
+ if (printer_model != sub.second.data()) {
+ result.emplace_back(sub.second.data());
+ }
+
}
}
catch (const std::exception& e) {
@@ -339,18 +374,78 @@ void UserAccount::fill_compatible_printers_from_json(const std::string& json, st
}
}
-
-std::string UserAccount::get_printer_type_from_name(const std::string& printer_name) const
+void UserAccount::fill_material_from_json(const std::string& json, std::vector& result) const
{
-
- for (const auto& pair : printer_type_and_name_table) {
- if (pair.second == printer_name) {
- return pair.first;
+
+ /* 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();
}
- assert(true); // This assert means printer_type_and_name_table needs a update
- return {};
}
-
}} // namespace slic3r::GUI
\ No newline at end of file
diff --git a/src/slic3r/GUI/UserAccount.hpp b/src/slic3r/GUI/UserAccount.hpp
index d70c1bf2f6..9d597acf1c 100644
--- a/src/slic3r/GUI/UserAccount.hpp
+++ b/src/slic3r/GUI/UserAccount.hpp
@@ -24,8 +24,9 @@ enum class ConnectPrinterState {
CONNECT_PRINTER_ERROR,
CONNECT_PRINTER_STATE_COUNT
};
-
-typedef std::map> ConnectPrinterStateMap;
+// is pair of printer_model and nozzle_diameter. std::vector is vector of ConnectPrinterState counters
+typedef std::map, std::vector> ConnectPrinterStateMap;
+typedef std::map< std::string, std::pair> ConnectUUIDToModelNozzleMap;
// Class UserAccount should handle every request for entities outside PrusaSlicer like PrusaAuth or PrusaConnect.
// Outside communication is implemented in class UserAccountCommunication that runs separate thread. Results come back in events to Plater.
// All incoming data shoud be stored in UserAccount.
@@ -41,7 +42,8 @@ public:
void set_remember_session(bool remember);
void toggle_remember_session();
bool get_remember_session();
- void enqueue_connect_printers_action();
+ void enqueue_connect_status_action();
+ void enqueue_connect_printer_models_action();
void enqueue_avatar_action();
// Clears all data and connections, called on logout or EVT_UA_RESET
@@ -54,6 +56,7 @@ public:
// Called on EVT_UA_FAIL, triggers test after several calls
void on_communication_fail();
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);
std::string get_username() const { return m_username; }
std::string get_access_token();
@@ -62,15 +65,13 @@ public:
boost::filesystem::path get_avatar_path(bool logged) const;
// standalone utility methods
- std::string get_model_from_json(const std::string& message) const;
std::string get_nozzle_from_json(const std::string& message) const;
- //std::string get_apikey_from_json(const std::string& message) const;
std::string get_keyword_from_json(const std::string& json, const std::string& keyword) const;
- void fill_compatible_printers_from_json(const std::string& json, std::vector& result) const;
+ void fill_supported_printer_models_from_json(const std::string& json, std::vector& result) const;
+ void fill_material_from_json(const std::string& json, std::vector& result) const;
const std::map& get_printer_state_table() const { return printer_state_table; }
- std::string get_printer_type_from_name(const std::string& printer_name) const;
private:
void set_username(const std::string& username);
@@ -79,41 +80,11 @@ private:
std::unique_ptr m_communication;
ConnectPrinterStateMap m_printer_map;
+ ConnectUUIDToModelNozzleMap m_printer_uuid_map;
std::map m_account_user_data;
std::string m_username;
size_t m_fail_counter { 0 };
- std::string m_avatar_extension;
-
- // first string is "printer_type" code from Connect edpoints
- const std::map printer_type_and_name_table = {
- {"1.2.5", "MK2.5" },
- {"1.2.6", "MK2.5S" },
- {"1.3.0", "MK3" },
- {"1.3.1", "MK3S" },
- {"1.3.5", "MK3.5" },
- {"1.3.9", "MK3.9" },
- {"1.4.0", "MK4" },
- {"2.1.0", "MINI" },
- {"3.1.0", "XL" },
- {"5.1.0", "SL1" },
- // ysFIXME : needs to add Connect ids for next printers
- /*{"0.0.0", "MK4IS" },
- {"0.0.0", "MK3SMMU2S" },
- {"0.0.0", "MK3MMU2" },
- {"0.0.0", "MK2.5SMMU2S" },
- {"0.0.0", "MK2.5MMU2" },
- {"0.0.0", "MK2S" },
- {"0.0.0", "MK2SMM" },
- {"0.0.0", "SL1S" },*/
- };
- /* TODO:
- 4 1 0 iXL
- 6 2 0 Trilab DeltiQ 2
- 6 2 1 Trilab DelriQ 2 Plus
- 7 1 0 Trilab AzteQ
- 7 2 0 Trilab AzteQ Industrial
- 7 2 1 Trilab AzteQ Industrial Plus
- */
+ std::string m_avatar_extension;
const std::map printer_state_table = {
{"OFFLINE" , ConnectPrinterState::CONNECT_PRINTER_OFFLINE},
diff --git a/src/slic3r/GUI/UserAccountCommunication.cpp b/src/slic3r/GUI/UserAccountCommunication.cpp
index 25b6b75c26..6d8045d2b7 100644
--- a/src/slic3r/GUI/UserAccountCommunication.cpp
+++ b/src/slic3r/GUI/UserAccountCommunication.cpp
@@ -214,7 +214,15 @@ void UserAccountCommunication::set_polling_enabled(bool enabled)
{
{
std::lock_guard lock(m_session_mutex);
- return m_session->set_polling_enabled(enabled);
+ return m_session->set_polling_action(enabled ? UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_PRINTER_MODELS : UserAccountActionID::USER_ACCOUNT_ACTION_DUMMY);
+ }
+}
+
+void UserAccountCommunication::on_uuid_map_success()
+{
+ {
+ std::lock_guard lock(m_session_mutex);
+ return m_session->set_polling_action(UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS);
}
}
@@ -228,7 +236,8 @@ void UserAccountCommunication::login_redirect()
std::string code_challenge = ccg.generate_chalenge(m_code_verifier);
BOOST_LOG_TRIVIAL(info) << "code verifier: " << m_code_verifier;
BOOST_LOG_TRIVIAL(info) << "code challenge: " << code_challenge;
- wxString url = GUI::format_wxstr(L"%1%/o/authorize/?client_id=%2%&response_type=code&code_challenge=%3%&code_challenge_method=S256&scope=basic_info&redirect_uri=%4%", AUTH_HOST, CLIENT_ID, code_challenge, REDIRECT_URI);
+
+ wxString url = GUI::format_wxstr(L"%1%/o/authorize/?client_id=%2%&response_type=code&code_challenge=%3%&code_challenge_method=S256&scope=basic_info&redirect_uri=%4%&choose_account=1", AUTH_HOST, CLIENT_ID, code_challenge, REDIRECT_URI);
wxQueueEvent(m_evt_handler,new OpenPrusaAuthEvent(GUI::EVT_OPEN_PRUSAAUTH, std::move(url)));
}
@@ -274,14 +283,25 @@ void UserAccountCommunication::on_login_code_recieved(const std::string& url_mes
wakeup_session_thread();
}
-
-
-void UserAccountCommunication::enqueue_connect_printers_action()
+void UserAccountCommunication::enqueue_connect_printer_models_action()
{
{
std::lock_guard lock(m_session_mutex);
if (!m_session->is_initialized()) {
- BOOST_LOG_TRIVIAL(error) << "Connect Printers endpoint connection failed - Not Logged in.";
+ BOOST_LOG_TRIVIAL(error) << "Connect Printer Models connection failed - Not Logged in.";
+ return;
+ }
+ m_session->enqueue_action(UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_PRINTER_MODELS, nullptr, nullptr, {});
+ }
+ wakeup_session_thread();
+}
+
+void UserAccountCommunication::enqueue_connect_status_action()
+{
+ {
+ std::lock_guard lock(m_session_mutex);
+ if (!m_session->is_initialized()) {
+ BOOST_LOG_TRIVIAL(error) << "Connect Status endpoint connection failed - Not Logged in.";
return;
}
m_session->enqueue_action(UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS, nullptr, nullptr, {});
@@ -296,7 +316,7 @@ void UserAccountCommunication::enqueue_test_connection()
BOOST_LOG_TRIVIAL(error) << "Connect Printers endpoint connection failed - Not Logged in.";
return;
}
- m_session->enqueue_action(UserAccountActionID::USER_ACCOUNT_ACTION_TEST_CONNECTION, nullptr, nullptr, {});
+ m_session->enqueue_test_with_refresh();
}
wakeup_session_thread();
}
diff --git a/src/slic3r/GUI/UserAccountCommunication.hpp b/src/slic3r/GUI/UserAccountCommunication.hpp
index 408861f85d..15fc41aece 100644
--- a/src/slic3r/GUI/UserAccountCommunication.hpp
+++ b/src/slic3r/GUI/UserAccountCommunication.hpp
@@ -39,7 +39,8 @@ public:
void do_logout();
void do_clear();
// Trigger function starts various remote operations
- void enqueue_connect_printers_action();
+ void enqueue_connect_status_action();
+ void enqueue_connect_printer_models_action();
void enqueue_avatar_action(const std::string& url);
void enqueue_test_connection();
@@ -59,7 +60,8 @@ public:
std::string get_shared_session_key();
void set_polling_enabled(bool enabled);
-
+ // we have map of uuids and printer_models - set polling action to lightweight STATUS action
+ void on_uuid_map_success();
private:
std::unique_ptr m_session;
std::thread m_thread;
diff --git a/src/slic3r/GUI/UserAccountSession.cpp b/src/slic3r/GUI/UserAccountSession.cpp
index d5839a6648..65bfc670ab 100644
--- a/src/slic3r/GUI/UserAccountSession.cpp
+++ b/src/slic3r/GUI/UserAccountSession.cpp
@@ -22,7 +22,8 @@ wxDEFINE_EVENT(EVT_OPEN_PRUSAAUTH, OpenPrusaAuthEvent);
wxDEFINE_EVENT(EVT_UA_LOGGEDOUT, UserAccountSuccessEvent);
wxDEFINE_EVENT(EVT_UA_ID_USER_SUCCESS, UserAccountSuccessEvent);
wxDEFINE_EVENT(EVT_UA_SUCCESS, UserAccountSuccessEvent);
-wxDEFINE_EVENT(EVT_UA_PRUSACONNECT_PRINTERS_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_FAIL, UserAccountFailEvent);
wxDEFINE_EVENT(EVT_UA_RESET, UserAccountFailEvent);
@@ -74,11 +75,7 @@ void UserAccountSession::process_action_queue()
return;
if (m_priority_action_queue.empty() && m_action_queue.empty()) {
// update printers periodically
- if (m_polling_enabled) {
- enqueue_action(UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS, nullptr, nullptr, {});
- } else {
- return;
- }
+ enqueue_action(m_polling_action, nullptr, nullptr, {});
}
// priority queue works even when tokens are empty or broken
while (!m_priority_action_queue.empty()) {
diff --git a/src/slic3r/GUI/UserAccountSession.hpp b/src/slic3r/GUI/UserAccountSession.hpp
index f28f195e13..eaaafac0c1 100644
--- a/src/slic3r/GUI/UserAccountSession.hpp
+++ b/src/slic3r/GUI/UserAccountSession.hpp
@@ -20,7 +20,8 @@ wxDECLARE_EVENT(EVT_OPEN_PRUSAAUTH, OpenPrusaAuthEvent);
wxDECLARE_EVENT(EVT_UA_LOGGEDOUT, UserAccountSuccessEvent);
wxDECLARE_EVENT(EVT_UA_ID_USER_SUCCESS, UserAccountSuccessEvent);
wxDECLARE_EVENT(EVT_UA_SUCCESS, UserAccountSuccessEvent);
-wxDECLARE_EVENT(EVT_UA_PRUSACONNECT_PRINTERS_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_FAIL, UserAccountFailEvent); // Soft fail - clears only after some number of fails
wxDECLARE_EVENT(EVT_UA_RESET, UserAccountFailEvent); // Hard fail - clears all
@@ -37,7 +38,8 @@ enum class UserAccountActionID {
USER_ACCOUNT_ACTION_USER_ID,
USER_ACCOUNT_ACTION_TEST_ACCESS_TOKEN,
USER_ACCOUNT_ACTION_TEST_CONNECTION,
- USER_ACCOUNT_ACTION_CONNECT_STATUS, // status of all printers
+ 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,
};
class UserAction
@@ -99,7 +101,7 @@ public:
, m_access_token(access_token)
, m_refresh_token(refresh_token)
, m_shared_session_key(shared_session_key)
- , m_polling_enabled(polling_enabled)
+ , m_polling_action(polling_enabled ? UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_PRINTER_MODELS : UserAccountActionID::USER_ACCOUNT_ACTION_DUMMY)
{
@@ -110,7 +112,8 @@ public:
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_USER_ID] = std::make_unique("USER_ID", "https://account.prusa3d.com/api/v1/me/", EVT_UA_ID_USER_SUCCESS, EVT_UA_RESET);
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_TEST_ACCESS_TOKEN] = std::make_unique("TEST_ACCESS_TOKEN", "https://account.prusa3d.com/api/v1/me/", EVT_UA_ID_USER_SUCCESS, EVT_UA_FAIL);
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_TEST_CONNECTION] = std::make_unique("TEST_CONNECTION", "https://account.prusa3d.com/api/v1/me/", wxEVT_NULL, EVT_UA_RESET);
- m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS] = std::make_unique("CONNECT_STATUS", "https://connect.prusa3d.com/slicer/status", EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, EVT_UA_FAIL);
+ 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);
}
~UserAccountSession()
@@ -143,7 +146,8 @@ public:
std::string get_refresh_token() const { return m_refresh_token; }
std::string get_shared_session_key() const { return m_shared_session_key; }
- void set_polling_enabled(bool enabled) {m_polling_enabled = enabled; }
+ //void set_polling_enabled(bool enabled) {m_polling_action = enabled ? UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_PRINTER_MODELS : UserAccountActionID::USER_ACCOUNT_ACTION_DUMMY; }
+ void set_polling_action(UserAccountActionID action) { m_polling_action = action; }
private:
void enqueue_refresh(const std::string& body);
@@ -156,8 +160,9 @@ private:
// false prevents action queu to be processed - no communication is done
// sets to true by init_with_code or enqueue_action call
bool m_proccessing_enabled {false};
- // triggers CONNECT_PRINTERS action when woken up on idle
- bool m_polling_enabled;
+ // action when woken up on idle - switches between USER_ACCOUNT_ACTION_CONNECT_PRINTER_MODELS and USER_ACCOUNT_ACTION_CONNECT_STATUS
+ // set to USER_ACCOUNT_ACTION_DUMMY to switch off polling
+ UserAccountActionID m_polling_action;
std::string m_access_token;
std::string m_refresh_token;
diff --git a/src/slic3r/GUI/WebView.cpp b/src/slic3r/GUI/WebView.cpp
index c73fe7bc3b..f980556c3d 100644
--- a/src/slic3r/GUI/WebView.cpp
+++ b/src/slic3r/GUI/WebView.cpp
@@ -6,43 +6,6 @@
#include
-
-class FakeWebView : public wxWebView
-{
- virtual bool Create(wxWindow* parent, wxWindowID id, const wxString& url, const wxPoint& pos, const wxSize& size, long style, const wxString& name) override { return false; }
- virtual wxString GetCurrentTitle() const override { return wxString(); }
- virtual wxString GetCurrentURL() const override { return wxString(); }
- virtual bool IsBusy() const override { return false; }
- virtual bool IsEditable() const override { return false; }
- virtual void LoadURL(const wxString& url) override { }
- virtual void Print() override { }
- virtual void RegisterHandler(wxSharedPtr handler) override { }
- virtual void Reload(wxWebViewReloadFlags flags = wxWEBVIEW_RELOAD_DEFAULT) override { }
- virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const override { return false; }
- virtual void SetEditable(bool enable = true) override { }
- virtual void Stop() override { }
- virtual bool CanGoBack() const override { return false; }
- virtual bool CanGoForward() const override { return false; }
- virtual void GoBack() override { }
- virtual void GoForward() override { }
- virtual void ClearHistory() override { }
- virtual void EnableHistory(bool enable = true) override { }
- virtual wxVector> GetBackwardHistory() override { return {}; }
- virtual wxVector> GetForwardHistory() override { return {}; }
- virtual void LoadHistoryItem(wxSharedPtr item) override { }
- virtual bool CanSetZoomType(wxWebViewZoomType type) const override { return false; }
- virtual float GetZoomFactor() const override { return 0.0f; }
- virtual wxWebViewZoomType GetZoomType() const override { return wxWebViewZoomType(); }
- virtual void SetZoomFactor(float zoom) override { }
- virtual void SetZoomType(wxWebViewZoomType zoomType) override { }
- virtual bool CanUndo() const override { return false; }
- virtual bool CanRedo() const override { return false; }
- virtual void Undo() override { }
- virtual void Redo() override { }
- virtual void* GetNativeBackend() const override { return nullptr; }
- virtual void DoSetPage(const wxString& html, const wxString& baseUrl) override { }
-};
-
wxWebView* WebView::CreateWebView(wxWindow * parent, const wxString& url)
{
#if wxUSE_WEBVIEW_EDGE
@@ -87,16 +50,9 @@ wxWebView* WebView::CreateWebView(wxWindow * parent, const wxString& url)
webView->EnableContextMenu(false);
} else {
// TODO: dialog to user !!!
- BOOST_LOG_TRIVIAL(error) << "Failed to create wxWebView object. Using Dummy object instead. Webview won't be working.";
- webView = new FakeWebView;
+ BOOST_LOG_TRIVIAL(error) << "Failed to create wxWebView object.";
}
return webView;
}
-
-bool WebView::run_script(wxWebView *webView, wxString const &javascript)
-{
- webView->RunScriptAsync(javascript);
- return true;
-}
diff --git a/src/slic3r/GUI/WebView.hpp b/src/slic3r/GUI/WebView.hpp
index 6893e8965e..40ea745f10 100644
--- a/src/slic3r/GUI/WebView.hpp
+++ b/src/slic3r/GUI/WebView.hpp
@@ -8,7 +8,6 @@ class wxString;
namespace WebView
{
wxWebView *CreateWebView(wxWindow *parent, const wxString& url);
- bool run_script(wxWebView * webView, const wxString& msg);
};
#endif // !slic3r_GUI_WebView_hpp_
diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp
index c145068c06..06d34fab59 100644
--- a/src/slic3r/GUI/WebViewDialog.cpp
+++ b/src/slic3r/GUI/WebViewDialog.cpp
@@ -22,9 +22,10 @@ namespace Slic3r {
namespace GUI {
-WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url)
+WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url, const std::string& loading_html/* = "loading"*/)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
, m_default_url (default_url)
+ , m_loading_html(loading_html)
{
wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
#ifdef DEBUG_URL_PANEL
@@ -66,17 +67,16 @@ WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url)
topsizer->Add(m_info, wxSizerFlags().Expand());
#endif
- // Create the webview
- m_browser = WebView::CreateWebView(this, /*m_default_url*/ GUI::format_wxstr("file://%1%/web/connection_failed.html", boost::filesystem::path(resources_dir()).generic_string()));
- if (m_browser == nullptr) {
- wxLogError("Could not init m_browser");
- return;
- }
-
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));
+ 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);
+ return;
+ }
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
-
#ifdef DEBUG_URL_PANEL
// Create the Tools menu
m_tools_menu = new wxMenu();
@@ -98,7 +98,6 @@ WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url)
//Zoom
m_zoomFactor = 100;
-
Bind(wxEVT_SHOW, &WebViewPanel::on_show, this);
// Connect the webview events
@@ -127,7 +126,6 @@ WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url)
Bind(wxEVT_IDLE, &WebViewPanel::on_idle, this);
Bind(wxEVT_CLOSE_WINDOW, &WebViewPanel::on_close, this);
- m_LoginUpdateTimer = nullptr;
}
WebViewPanel::~WebViewPanel()
@@ -135,18 +133,15 @@ WebViewPanel::~WebViewPanel()
SetEvtHandlerEnabled(false);
#ifdef DEBUG_URL_PANEL
delete m_tools_menu;
-
- if (m_LoginUpdateTimer != nullptr) {
- m_LoginUpdateTimer->Stop();
- delete m_LoginUpdateTimer;
- m_LoginUpdateTimer = NULL;
- }
#endif
}
void WebViewPanel::load_url(const wxString& url)
{
+ if (!m_browser)
+ return;
+
this->Show();
this->Raise();
#ifdef DEBUG_URL_PANEL
@@ -164,26 +159,36 @@ void WebViewPanel::load_default_url_delayed()
void WebViewPanel::load_error_page()
{
- load_url(GUI::format_wxstr("file://%1%/web/connection_failed.html", boost::filesystem::path(resources_dir()).generic_string()));
+ if (!m_browser)
+ return;
+
+ m_browser->Stop();
+ m_load_error_page = true;
}
void WebViewPanel::on_show(wxShowEvent& evt)
{
- if (evt.IsShown() && m_load_default_url)
- {
+ m_shown = evt.IsShown();
+ if (evt.IsShown() && m_load_default_url) {
m_load_default_url = false;
load_url(m_default_url);
}
- // TODO: add check that any url was loaded
}
void WebViewPanel::on_idle(wxIdleEvent& WXUNUSED(evt))
{
- if (m_browser->IsBusy())
+ if (!m_browser)
+ return;
+ if (m_browser->IsBusy()) {
wxSetCursor(wxCURSOR_ARROWWAIT);
- else
+ } else {
wxSetCursor(wxNullCursor);
+ if (m_shown && m_load_error_page) {
+ m_load_error_page = false;
+ load_url(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
@@ -194,6 +199,8 @@ void WebViewPanel::on_idle(wxIdleEvent& WXUNUSED(evt))
*/
void WebViewPanel::on_url(wxCommandEvent& WXUNUSED(evt))
{
+ if (!m_browser)
+ return;
#ifdef DEBUG_URL_PANEL
m_browser->LoadURL(m_url->GetValue());
m_browser->SetFocus();
@@ -205,6 +212,8 @@ void WebViewPanel::on_url(wxCommandEvent& WXUNUSED(evt))
*/
void WebViewPanel::on_back_button(wxCommandEvent& WXUNUSED(evt))
{
+ if (!m_browser)
+ return;
m_browser->GoBack();
}
@@ -213,6 +222,8 @@ void WebViewPanel::on_back_button(wxCommandEvent& WXUNUSED(evt))
*/
void WebViewPanel::on_forward_button(wxCommandEvent& WXUNUSED(evt))
{
+ if (!m_browser)
+ return;
m_browser->GoForward();
}
@@ -221,6 +232,8 @@ void WebViewPanel::on_forward_button(wxCommandEvent& WXUNUSED(evt))
*/
void WebViewPanel::on_stop_button(wxCommandEvent& WXUNUSED(evt))
{
+ if (!m_browser)
+ return;
m_browser->Stop();
}
@@ -229,28 +242,28 @@ void WebViewPanel::on_stop_button(wxCommandEvent& WXUNUSED(evt))
*/
void WebViewPanel::on_reload_button(wxCommandEvent& WXUNUSED(evt))
{
+ if (!m_browser)
+ return;
m_browser->Reload();
}
-
-
void WebViewPanel::on_close(wxCloseEvent& evt)
{
this->Hide();
}
-
void WebViewPanel::on_script_message(wxWebViewEvent& evt)
{
}
-
-
/**
* Invoked when user selects the "View Source" menu item
*/
void WebViewPanel::on_view_source_request(wxCommandEvent& WXUNUSED(evt))
{
+ if (!m_browser)
+ return;
+
SourceViewDialog dlg(this, m_browser->GetPageSource());
dlg.ShowModal();
}
@@ -260,6 +273,9 @@ void WebViewPanel::on_view_source_request(wxCommandEvent& WXUNUSED(evt))
*/
void WebViewPanel::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);
@@ -281,6 +297,9 @@ void WebViewPanel::on_view_text_request(wxCommandEvent& WXUNUSED(evt))
*/
void WebViewPanel::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());
@@ -292,14 +311,13 @@ void WebViewPanel::on_tools_clicked(wxCommandEvent& WXUNUSED(evt))
void WebViewPanel::run_script(const wxString& javascript)
{
+ if (!m_browser || !m_shown)
+ 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;
-
- if (!m_browser) return;
-
- bool res = WebView::run_script(m_browser, javascript);
- BOOST_LOG_TRIVIAL(debug) << "RunScript " << javascript << " " << res;
+ BOOST_LOG_TRIVIAL(debug) << "RunScript " << javascript;
+ m_browser->RunScriptAsync(javascript);
}
@@ -339,6 +357,9 @@ void WebViewPanel::on_add_user_script(wxCommandEvent& WXUNUSED(evt))
void WebViewPanel::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
(
@@ -357,25 +378,40 @@ void WebViewPanel::on_set_custom_user_agent(wxCommandEvent& WXUNUSED(evt))
void WebViewPanel::on_clear_selection(wxCommandEvent& WXUNUSED(evt))
{
+ if (!m_browser)
+ return;
+
m_browser->ClearSelection();
}
void WebViewPanel::on_delete_selection(wxCommandEvent& WXUNUSED(evt))
{
+ if (!m_browser)
+ return;
+
m_browser->DeleteSelection();
}
void WebViewPanel::on_select_all(wxCommandEvent& WXUNUSED(evt))
{
+ if (!m_browser)
+ return;
+
m_browser->SelectAll();
}
void WebViewPanel::On_enable_context_menu(wxCommandEvent& evt)
{
+ if (!m_browser)
+ return;
+
m_browser->EnableContextMenu(evt.IsChecked());
}
void WebViewPanel::On_enable_dev_tools(wxCommandEvent& evt)
{
+ if (!m_browser)
+ return;
+
m_browser->EnableAccessToDevTools(evt.IsChecked());
}
@@ -446,12 +482,12 @@ ConnectRequestHandler::~ConnectRequestHandler()
void ConnectRequestHandler::handle_message(const std::string& message)
{
// read msg and choose action
- /*
- v0:
- {"type":"request","detail":{"action":"requestAccessToken"}}
- v1:
- {"action":"REQUEST_ACCESS_TOKEN"}
- */
+ /*
+ v0:
+ {"type":"request","detail":{"action":"requestAccessToken"}}
+ v1:
+ {"action":"REQUEST_ACCESS_TOKEN"}
+ */
std::string action_string;
m_message_data = message;
try {
@@ -503,7 +539,8 @@ void ConnectRequestHandler::on_request_config()
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";
- const wxString language = GUI::wxGetApp().current_language_code();
+ wxString language = GUI::wxGetApp().current_language_code();
+ language = language.SubString(0, 1);
const std::string init_options = GUI::format("{\"accessToken\": \"%1%\" , \"clientVersion\": \"%2%\", \"colorMode\": \"%3%\", \"language\": \"%4%\"}", token, SLIC3R_VERSION, dark_mode, language);
wxString script = GUI::format_wxstr("window._prusaConnect_v1.init(%1%)", init_options);
run_script_bridge(script);
@@ -511,13 +548,13 @@ void ConnectRequestHandler::on_request_config()
}
ConnectWebViewPanel::ConnectWebViewPanel(wxWindow* parent)
- : WebViewPanel(parent, L"https://connect.prusa3d.com/connect-slicer-app/")
+ : WebViewPanel(parent, L"https://connect.prusa3d.com/connect-slicer-app/", "connect_loading")
{
}
void ConnectWebViewPanel::on_script_message(wxWebViewEvent& evt)
{
- BOOST_LOG_TRIVIAL(error) << "recieved message from PrusaConnect FE: " << evt.GetString();
+ BOOST_LOG_TRIVIAL(debug) << "recieved message from PrusaConnect FE: " << evt.GetString();
handle_message(into_u8(evt.GetString()));
}
@@ -542,6 +579,9 @@ void ConnectWebViewPanel::on_request_update_selected_printer_action()
PrinterWebViewPanel::PrinterWebViewPanel(wxWindow* parent, const wxString& default_url)
: WebViewPanel(parent, default_url)
{
+ if (!m_browser)
+ return;
+
m_browser->Bind(wxEVT_WEBVIEW_LOADED, &PrinterWebViewPanel::on_loaded, this);
}
@@ -558,7 +598,7 @@ void PrinterWebViewPanel::on_loaded(wxWebViewEvent& evt)
void PrinterWebViewPanel::send_api_key()
{
- if (m_api_key_sent)
+ if (!m_browser || m_api_key_sent)
return;
m_api_key_sent = true;
wxString key = from_u8(m_api_key);
@@ -583,7 +623,7 @@ void PrinterWebViewPanel::send_api_key()
void PrinterWebViewPanel::send_credentials()
{
- if (m_api_key_sent)
+ if (!m_browser || m_api_key_sent)
return;
m_api_key_sent = true;
wxString usr = from_u8(m_usr);
@@ -610,24 +650,28 @@ void PrinterWebViewPanel::sys_color_changed()
{
}
-WebViewDialog::WebViewDialog(wxWindow* parent, const wxString& url, const wxString& dialog_name, const wxSize& size)
+WebViewDialog::WebViewDialog(wxWindow* parent, const wxString& url, const wxString& dialog_name, const wxSize& size, const std::string& loading_html/* = "loading"*/)
: wxDialog(parent, wxID_ANY, dialog_name, wxDefaultPosition, size, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
+ , m_loading_html(loading_html)
{
wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
+ topsizer->SetMinSize(size);
+ SetSizerAndFit(topsizer);
// Create the webview
- m_browser = WebView::CreateWebView(this, url);
- if (m_browser == nullptr) {
- wxLogError("Could not init m_browser");
+ m_browser = WebView::CreateWebView(this, GUI::format_wxstr("file://%1%/web/%2%.html", boost::filesystem::path(resources_dir()).generic_string(), m_loading_html));
+ 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);
return;
}
- SetSizer(topsizer);
-
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
Bind(wxEVT_SHOW, &WebViewDialog::on_show, this);
Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WebViewDialog::on_script_message, this, m_browser->GetId());
+
+ m_browser->LoadURL(url);
}
WebViewDialog::~WebViewDialog()
{
@@ -637,12 +681,15 @@ void WebViewDialog::run_script(const wxString& javascript)
{
if (!m_browser)
return;
- // dk_FIXME: Is it ok to discard the return value?
- /*bool res = */ WebView::run_script(m_browser, javascript);
+ m_browser->RunScriptAsync(javascript);
}
PrinterPickWebViewDialog::PrinterPickWebViewDialog(wxWindow* parent, std::string& ret_val)
- : WebViewDialog(parent, L"https://connect.prusa3d.com/connect-slicer-app/printer-list", _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())))
+ : WebViewDialog(parent
+ , L"https://connect.prusa3d.com/connect-slicer-app/printer-list"
+ , _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()))
+ , "connect_loading")
, m_ret_val(ret_val)
{
Centre();
@@ -670,6 +717,16 @@ void PrinterPickWebViewDialog::on_request_update_selected_printer_action()
}
void PrinterPickWebViewDialog::request_compatible_printers()
+{
+
+ if (Preset::printer_technology(wxGetApp().preset_bundle->printers.get_selected_preset().config) == ptFFF) {
+ request_compatible_printers_FFF();
+ } else {
+ request_compatible_printers_SLA();
+ }
+}
+
+void PrinterPickWebViewDialog::request_compatible_printers_FFF()
{
//PrinterParams: {
//material: Material;
@@ -678,19 +735,37 @@ void PrinterPickWebViewDialog::request_compatible_printers()
//}
const Preset& selected_printer = wxGetApp().preset_bundle->printers.get_selected_preset();
const Preset& selected_filament = wxGetApp().preset_bundle->filaments.get_selected_preset();
- const std::string nozzle_diameter_serialized = dynamic_cast(selected_printer.config.option("nozzle_diameter"))->serialize();
+ 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);
+ // 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 printer_type = wxGetApp().plater()->get_user_account()->get_printer_type_from_name(printer_model_serialized);
+
- // assert(!filament_type_serialized.empty() && !nozzle_diameter_serialized.empty() && !printer_type.empty());
+ const std::string request = GUI::format(
+ "{"
+ "\"printerModel\": \"%3%\", "
+ "\"nozzleDiameter\": %2%, "
+ "\"material\": \"%1%\" "
+ "}", filament_type_serialized, nozzle_diameter_serialized, printer_model_serialized);
+
+ wxString script = GUI::format_wxstr("window._prusaConnect_v1.requestCompatiblePrinter(%1%)", request);
+ run_script(script);
+}
+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();
+ 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 request = GUI::format(
"{"
"\"material\": \"%1%\", "
- "\"nozzleDiameter\": %2%, "
- "\"printerType\": \"%3%\" "
- "}", filament_type_serialized, nozzle_diameter_serialized, printer_type);
-
+ "\"printerModel\": \"%2%\" "
+ "}", material_type_serialized, printer_model_serialized);
+
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 acf2f9d411..f25ec21399 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);
+ WebViewPanel(wxWindow *parent, const wxString& default_url, const std::string& loading_html = "loading");
virtual ~WebViewPanel();
void load_url(const wxString& url);
@@ -49,8 +49,6 @@ public:
void On_enable_dev_tools(wxCommandEvent& evt);
void on_close(wxCloseEvent& evt);
- wxTimer * m_LoginUpdateTimer{nullptr};
-
wxString get_default_url() const { return m_default_url; }
void set_default_url(const wxString& url) { m_default_url = url; }
@@ -85,8 +83,12 @@ protected:
wxString m_response_js;
wxString m_default_url;
+ std::string m_loading_html;
//DECLARE_EVENT_TABLE()
-};
+
+ bool m_load_error_page { false };
+ bool m_shown { false };
+};
class ConnectRequestHandler
{
@@ -146,7 +148,7 @@ private:
class WebViewDialog : public wxDialog
{
public:
- WebViewDialog(wxWindow* parent, const wxString& url, const wxString& dialog_name, const wxSize& size);
+ 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;
@@ -156,6 +158,7 @@ public:
protected:
wxWebView* m_browser;
+ std::string m_loading_html;
};
class PrinterPickWebViewDialog : public WebViewDialog, public ConnectRequestHandler
@@ -167,6 +170,8 @@ public:
protected:
void on_request_update_selected_printer_action() override;
void request_compatible_printers() 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.cpp b/src/slic3r/Utils/PrintHost.cpp
index 2fde630960..03a72e732c 100644
--- a/src/slic3r/Utils/PrintHost.cpp
+++ b/src/slic3r/Utils/PrintHost.cpp
@@ -70,6 +70,10 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config)
default: return nullptr;
}
} else {
+ const auto opt = config->option>("host_type");
+ if (opt != nullptr && opt->value == htPrusaConnectNew) {
+ return new PrusaConnectNew(config);
+ }
return new SL1Host(config);
}
}
diff --git a/src/slic3r/Utils/PrusaConnect.cpp b/src/slic3r/Utils/PrusaConnect.cpp
index eb1ce3b8d8..87f367ffb5 100644
--- a/src/slic3r/Utils/PrusaConnect.cpp
+++ b/src/slic3r/Utils/PrusaConnect.cpp
@@ -60,7 +60,7 @@ bool PrusaConnectNew::test(wxString& curl_msg) const
{
// Test is not used by upload and gets list of files on a device.
const std::string name = get_name();
- std::string url = GUI::format("https://dev.connect.prusa3d.com/app/teams/%1%/files?printer_uuid=%2%", m_team_id, m_uuid);
+ std::string url = GUI::format("https://connect.prusa3d.com/app/teams/%1%/files?printer_uuid=%2%", m_team_id, m_uuid);
const std::string access_token = GUI::wxGetApp().plater()->get_user_account()->get_access_token();
BOOST_LOG_TRIVIAL(info) << GUI::format("%1%: Get files/raw at: %2%", name, url);
bool res = true;
diff --git a/src/slic3r/Utils/PrusaConnect.hpp b/src/slic3r/Utils/PrusaConnect.hpp
index c569f0d566..d60d28bf5e 100644
--- a/src/slic3r/Utils/PrusaConnect.hpp
+++ b/src/slic3r/Utils/PrusaConnect.hpp
@@ -32,7 +32,7 @@ public:
bool has_auto_discovery() const override { return true; }
bool can_test() const override { return true; }
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint | PrintHostPostUploadAction::QueuePrint; }
- std::string get_host() const override { return "https://dev.connect.prusa3d.com"; }
+ std::string get_host() const override { return "https://connect.prusa3d.com"; }
bool get_storage(wxArrayString& storage_path, wxArrayString& storage_name) const override;
//const std::string& get_apikey() const { return m_apikey; }
//const std::string& get_cafile() const { return m_cafile; }