diff --git a/resources/icons/Slic3r_32px.png b/resources/icons/Slic3r_32px.png new file mode 100644 index 0000000000..6bf5a9cd14 Binary files /dev/null and b/resources/icons/Slic3r_32px.png differ diff --git a/resources/icons/overlay/sla_support_points_hover.png b/resources/icons/overlay/sla_support_points_hover.png index 6303232b24..55955f3d6f 100644 Binary files a/resources/icons/overlay/sla_support_points_hover.png and b/resources/icons/overlay/sla_support_points_hover.png differ diff --git a/resources/icons/overlay/sla_support_points_off.png b/resources/icons/overlay/sla_support_points_off.png index b654366d57..7bf84a3e64 100644 Binary files a/resources/icons/overlay/sla_support_points_off.png and b/resources/icons/overlay/sla_support_points_off.png differ diff --git a/resources/icons/overlay/sla_support_points_on.png b/resources/icons/overlay/sla_support_points_on.png index 8c1e695650..879b9b2412 100644 Binary files a/resources/icons/overlay/sla_support_points_on.png and b/resources/icons/overlay/sla_support_points_on.png differ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 7facc36232..3c4debba04 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1549,7 +1549,7 @@ void GLCanvas3D::Selection::start_dragging() _set_caches(); } -void GLCanvas3D::Selection::translate(const Vec3d& displacement) +void GLCanvas3D::Selection::translate(const Vec3d& displacement, bool local) { if (!m_valid) return; @@ -1559,7 +1559,7 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement) #if ENABLE_MODELVOLUME_TRANSFORM if ((m_mode == Volume) || (*m_volumes)[i]->is_wipe_tower) { - if (_requires_local_axes()) + if (local) (*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + displacement); else { @@ -1614,7 +1614,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) else if (is_single_volume() || is_single_modifier()) #if ENABLE_WORLD_ROTATIONS { - if (_requires_local_axes()) + if (requires_local_axes()) (*m_volumes)[i]->set_volume_rotation(rotation); else { @@ -2118,6 +2118,11 @@ void GLCanvas3D::Selection::render_sidebar_hints(const std::string& sidebar_fiel } #endif // ENABLE_SIDEBAR_VISUAL_HINTS +bool GLCanvas3D::Selection::requires_local_axes() const +{ + return (m_mode == Volume) && is_from_single_instance(); +} + void GLCanvas3D::Selection::_update_valid() { m_valid = (m_volumes != nullptr) && (m_model != nullptr); @@ -2746,11 +2751,6 @@ void GLCanvas3D::Selection::_ensure_on_bed() } #endif // ENABLE_ENSURE_ON_BED_WHILE_SCALING -bool GLCanvas3D::Selection::_requires_local_axes() const -{ - return (m_mode == Volume) && is_from_single_instance(); -} - const float GLCanvas3D::Gizmos::OverlayIconsScale = 1.0f; const float GLCanvas3D::Gizmos::OverlayBorder = 5.0f; const float GLCanvas3D::Gizmos::OverlayGapY = 5.0f * OverlayIconsScale; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 54e546c78c..413d625f1d 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -578,7 +578,7 @@ public: void start_dragging(); - void translate(const Vec3d& displacement); + void translate(const Vec3d& displacement, bool local = false); void rotate(const Vec3d& rotation, bool local); void flattening_rotate(const Vec3d& normal); void scale(const Vec3d& scale, bool local); @@ -597,6 +597,8 @@ public: void render_sidebar_hints(const std::string& sidebar_field) const; #endif // ENABLE_SIDEBAR_VISUAL_HINTS + bool requires_local_axes() const; + private: void _update_valid(); void _update_type(); @@ -626,7 +628,6 @@ public: #if ENABLE_ENSURE_ON_BED_WHILE_SCALING void _ensure_on_bed(); #endif // ENABLE_ENSURE_ON_BED_WHILE_SCALING - bool _requires_local_axes() const; }; class ClippingPlane diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 88c77c1937..bbba1d93ba 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -137,7 +137,7 @@ bool GUI_App::OnInit() std::cerr << "Creating main frame..." << std::endl; if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr) wxImage::AddHandler(new wxPNGHandler()); - mainframe = new MainFrame(no_plater, false); + mainframe = new MainFrame(); sidebar().obj_list()->init_objects(); // propagate model objects to object list update_mode(); SetTopWindow(mainframe); @@ -277,8 +277,8 @@ void GUI_App::recreate_GUI() { std::cerr << "recreate_GUI" << std::endl; - auto topwindow = GetTopWindow(); - mainframe = new MainFrame(no_plater,false); + MainFrame* topwindow = dynamic_cast(GetTopWindow()); + mainframe = new MainFrame(); sidebar().obj_list()->init_objects(); // propagate model objects to object list update_mode(); @@ -287,6 +287,20 @@ void GUI_App::recreate_GUI() topwindow->Destroy(); } + m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg())); + + CallAfter([this]() { + // temporary workaround for the correct behavior of the Scrolled sidebar panel + auto& panel = sidebar(); + if (panel.obj_list()->GetMinHeight() > 200) { + wxWindowUpdateLocker noUpdates_sidebar(&panel); + panel.obj_list()->SetMinSize(wxSize(-1, 200)); + panel.Layout(); + } + }); + + mainframe->Show(true); + // On OSX the UI was not initialized correctly if the wizard was called // before the UI was up and running. CallAfter([]() { @@ -434,7 +448,7 @@ bool GUI_App::select_language( wxArrayString & names, m_wxLocale = new wxLocale; m_wxLocale->Init(identifiers[index]); m_wxLocale->AddCatalogLookupPathPrefix(localization_dir()); - m_wxLocale->AddCatalog(GetAppName()); + m_wxLocale->AddCatalog(/*GetAppName()*/"Slic3rPE"); wxSetlocale(LC_NUMERIC, "C"); Preset::update_suffix_modified(); return true; @@ -461,7 +475,7 @@ bool GUI_App::load_language() m_wxLocale = new wxLocale; m_wxLocale->Init(identifiers[i]); m_wxLocale->AddCatalogLookupPathPrefix(localization_dir()); - m_wxLocale->AddCatalog(GetAppName()); + m_wxLocale->AddCatalog(/*GetAppName()*/"Slic3rPE"); wxSetlocale(LC_NUMERIC, "C"); Preset::update_suffix_modified(); return true; @@ -504,7 +518,8 @@ void GUI_App::get_installed_languages(wxArrayString & names, wxArrayLong & ident { auto full_file_name = dir.GetName() + wxFileName::GetPathSeparator() + filename + wxFileName::GetPathSeparator() + - GetAppName() + wxT(".mo"); + /*GetAppName()*/"Slic3rPE" + + wxT(".mo"); if (wxFileExists(full_file_name)) { names.Add(langinfo->Description); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 81175b7cac..bd64a3ac57 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -71,7 +71,6 @@ static wxString dots("…", wxConvUTF8); class GUI_App : public wxApp { - bool no_plater{ false }; bool app_conf_exists{ false }; // Lock to guard the callback stack diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index ddf699c2cd..8cc2362e82 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -361,8 +361,9 @@ void ObjectManipulation::update_rotation_value(const Vec3d& rotation) void ObjectManipulation::change_position_value(const Vec3d& position) { auto canvas = wxGetApp().plater()->canvas3D(); - canvas->get_selection().start_dragging(); - canvas->get_selection().translate(position - cache_position); + GLCanvas3D::Selection& selection = canvas->get_selection(); + selection.start_dragging(); + selection.translate(position - cache_position, selection.requires_local_axes()); canvas->do_move(); cache_position = position; diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 579cd7e5ec..988a7b6a13 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -586,7 +586,8 @@ void Preview::create_double_slider() auto& config = wxGetApp().preset_bundle->project_config; ((config.option("colorprint_heights"))->values) = (m_slider->GetTicksValues()); m_schedule_background_process(); - int type = m_choice_view_type->FindString(_(L("Color Print"))); + bool color_print = !config.option("colorprint_heights")->values.empty(); + int type = m_choice_view_type->FindString(color_print ? _(L("Color Print")) : _(L("Feature type")) ); if (m_choice_view_type->GetSelection() != type) { m_choice_view_type->SetSelection(type); if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types)) diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 87010f0817..b3edbc9a8b 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -23,7 +23,7 @@ KBShortcutsDialog::KBShortcutsDialog() wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); font.SetPointSize(10); - const wxFont bold_font = font.Bold(); + wxFont bold_font = font.Bold(); #ifdef __WXOSX__ font.SetPointSize(12); bold_font.SetPointSize(14); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 2211023f06..871d50a3d0 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -28,10 +28,8 @@ namespace Slic3r { namespace GUI { -MainFrame::MainFrame(const bool no_plater, const bool loaded) : +MainFrame::MainFrame() : wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE), - m_no_plater(no_plater), - m_loaded(loaded), m_printhost_queue_dlg(new PrintHostQueueDialog(this)) { // Load the icon either from the exe, or from the ico file. @@ -125,11 +123,9 @@ void MainFrame::init_tabpanel() } }); - if (!m_no_plater) { - m_plater = new Slic3r::GUI::Plater(m_tabpanel, this); - wxGetApp().plater_ = m_plater; - m_tabpanel->AddPage(m_plater, _(L("Plater"))); - } + m_plater = new Slic3r::GUI::Plater(m_tabpanel, this); + wxGetApp().plater_ = m_plater; + m_tabpanel->AddPage(m_plater, _(L("Plater"))); // The following event is emited by Tab implementation on config value change. Bind(EVT_TAB_VALUE_CHANGED, &MainFrame::on_value_changed, this); diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index fab6aea908..e0411b6dad 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -42,10 +42,7 @@ struct PresetTab { class MainFrame : public wxFrame { - bool m_no_plater; - bool m_loaded; - int m_lang_ch_event; - int m_preferences_event; + bool m_loaded {false}; wxString m_qs_last_input_file = wxEmptyString; wxString m_qs_last_output_file = wxEmptyString; @@ -71,8 +68,7 @@ class MainFrame : public wxFrame bool can_delete_all() const; public: - MainFrame() {} - MainFrame(const bool no_plater, const bool loaded); + MainFrame(); ~MainFrame() {} Plater* plater() { return m_plater; } diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index 8ac8615a84..586fe3d835 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -102,7 +102,7 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent) job_list->AppendTextColumn("Filename", wxDATAVIEW_CELL_INERT); auto *btnsizer = new wxBoxSizer(wxHORIZONTAL); - auto *btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected"))); + auto *btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected"))); // TODO: enable based on status ("show error" for failed jobs) auto *btn_close = new wxButton(this, wxID_CANCEL, _(L("Close"))); btnsizer->Add(btn_cancel, 0, wxRIGHT, SPACING); btnsizer->AddStretchSpacer(); @@ -140,7 +140,13 @@ void PrintHostQueueDialog::on_error(Event &evt) { wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list"); - // TODO + job_list->SetValue(wxVariant(0), evt.job_id, 1); + job_list->SetValue(wxVariant(_(L("Error"))), evt.job_id, 2); + + // TODO: keep the error for repeated display + + auto errormsg = wxString::Format("%s\n%s", _(L("Error uploading to print host:")), evt.error); + GUI::show_error(nullptr, std::move(errormsg)); } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0b59a21aba..5a212d4ee2 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1551,7 +1551,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) auto printhost_browse = [this, optgroup] (wxWindow* parent) { - // TODO: SLA + // TODO: SLA Bonjour auto btn = m_printhost_browse_btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT); btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG)); @@ -1562,6 +1562,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) BonjourDialog dialog(parent); if (dialog.show_and_lookup()) { optgroup->set_value("print_host", std::move(dialog.get_selected()), true); + // FIXME: emit killfocus on the edit widget } }); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 787c2a2a2a..dc917f8755 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2058,7 +2058,7 @@ void PrusaDoubleSlider::enter_window(wxMouseEvent& event, const bool enter) // - value decrease (if wxSL_HORIZONTAL) void PrusaDoubleSlider::move_current_thumb(const bool condition) { - m_is_one_layer = wxGetKeyState(WXK_CONTROL); +// m_is_one_layer = wxGetKeyState(WXK_CONTROL); int delta = condition ? -1 : 1; if (is_horizontal()) delta *= -1; diff --git a/src/slic3r/Utils/Duet.cpp b/src/slic3r/Utils/Duet.cpp index 1772ae8ef4..fd77fc1300 100644 --- a/src/slic3r/Utils/Duet.cpp +++ b/src/slic3r/Utils/Duet.cpp @@ -46,7 +46,7 @@ bool Duet::test(wxString &msg) const wxString Duet::get_test_ok_msg () const { - return wxString::Format("%s", _(L("Connection to Duet works correctly."))); + return _(L("Connection to Duet works correctly.")); } wxString Duet::get_test_failed_msg (wxString &msg) const @@ -135,7 +135,7 @@ wxString Duet::get_test_failed_msg (wxString &msg) const // return res; // } -bool Duet::upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const +bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const { // XXX: TODO throw "unimplemented"; diff --git a/src/slic3r/Utils/Duet.hpp b/src/slic3r/Utils/Duet.hpp index 0608f85a58..e053f91eff 100644 --- a/src/slic3r/Utils/Duet.hpp +++ b/src/slic3r/Utils/Duet.hpp @@ -19,12 +19,12 @@ public: Duet(DynamicPrintConfig *config); virtual ~Duet(); - bool test(wxString &curl_msg) const; - wxString get_test_ok_msg () const; - wxString get_test_failed_msg (wxString &msg) const; - bool upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const; - bool has_auto_discovery() const; - bool can_test() const; + virtual bool test(wxString &curl_msg) const; + virtual wxString get_test_ok_msg () const; + virtual wxString get_test_failed_msg (wxString &msg) const; + virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const; + virtual bool has_auto_discovery() const; + virtual bool can_test() const; virtual std::string get_host() const { return host; } private: std::string host; diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 6e6c9ed44b..30478cb01b 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -32,6 +32,7 @@ class CurlGlobalInit struct Http::priv { enum { + DEFAULT_TIMEOUT = 10, DEFAULT_SIZE_LIMIT = 5 * 1024 * 1024, }; @@ -63,6 +64,7 @@ struct Http::priv static int xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow); static size_t form_file_read_cb(char *buffer, size_t size, size_t nitems, void *userp); + void set_timeout(long timeout); void form_add_file(const char *name, const fs::path &path, const char* filename); void set_post_body(const fs::path &path); @@ -84,6 +86,7 @@ Http::priv::priv(const std::string &url) throw std::runtime_error(std::string("Could not construct Curl object")); } + set_timeout(DEFAULT_TIMEOUT); ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // curl makes a copy internally ::curl_easy_setopt(curl, CURLOPT_USERAGENT, SLIC3R_FORK_NAME "/" SLIC3R_VERSION); ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer.front()); @@ -167,6 +170,12 @@ size_t Http::priv::form_file_read_cb(char *buffer, size_t size, size_t nitems, v return stream->gcount(); } +void Http::priv::set_timeout(long timeout) +{ + ::curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout); + ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); +} + void Http::priv::form_add_file(const char *name, const fs::path &path, const char* filename) { // We can't use CURLFORM_FILECONTENT, because curl doesn't support Unicode filenames on Windows @@ -203,10 +212,10 @@ void Http::priv::set_post_body(const fs::path &path) std::string Http::priv::curl_error(CURLcode curlcode) { - return (boost::format("%1% (%2%): %3%") + return (boost::format("%1%:\n%2%\n[Error %3%]") % ::curl_easy_strerror(curlcode) + % error_buffer.c_str() % curlcode - % error_buffer ).str(); } @@ -293,6 +302,13 @@ Http::~Http() } +Http& Http::timeout(long timeout) +{ + if (timeout < 1) { timeout = priv::DEFAULT_TIMEOUT; } + if (p) { p->set_timeout(timeout); } + return *this; +} + Http& Http::size_limit(size_t sizeLimit) { if (p) { p->limit = sizeLimit; } diff --git a/src/slic3r/Utils/Http.hpp b/src/slic3r/Utils/Http.hpp index fd3f8830dd..9406a82f2e 100644 --- a/src/slic3r/Utils/Http.hpp +++ b/src/slic3r/Utils/Http.hpp @@ -55,6 +55,8 @@ public: Http& operator=(const Http &) = delete; Http& operator=(Http &&) = delete; + // Sets a maximum connection timeout in seconds + Http& timeout(long timeout); // Sets a maximum size of the data that can be received. // A value of zero sets the default limit, which is is 5MB. Http& size_limit(size_t sizeLimit); diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index cbb81c54f8..af9d6e4f0e 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -1,8 +1,12 @@ #include "OctoPrint.hpp" #include +#include #include #include +#include +#include +#include #include @@ -12,6 +16,7 @@ namespace fs = boost::filesystem; +namespace pt = boost::property_tree; namespace Slic3r { @@ -41,11 +46,29 @@ bool OctoPrint::test(wxString &msg) const res = false; msg = format_error(body, error, status); }) - .on_complete([&](std::string body, unsigned) { + .on_complete([&, this](std::string body, unsigned) { BOOST_LOG_TRIVIAL(debug) << boost::format("Octoprint: Got version: %1%") % body; - // TODO: parse body, call validate_version_text + try { + std::stringstream ss(body); + pt::ptree ptree; + pt::read_json(ss, ptree); + if (! ptree.get_optional("api")) { + res = false; + return; + } + + const auto text = ptree.get_optional("text"); + res = validate_version_text(text); + if (! res) { + msg = wxString::Format(_(L("Mismatched type of print host: %s")), text ? *text : "OctoPrint"); + } + } + catch (...) { + res = false; + msg = "Could not parse server response"; + } }) .perform_sync(); @@ -54,28 +77,24 @@ bool OctoPrint::test(wxString &msg) const wxString OctoPrint::get_test_ok_msg () const { - return wxString::Format("%s", _(L("Connection to OctoPrint works correctly."))); + return _(L("Connection to OctoPrint works correctly.")); } wxString OctoPrint::get_test_failed_msg (wxString &msg) const { return wxString::Format("%s: %s\n\n%s", - _(L("Could not connect to OctoPrint")), msg, _(L("Note: OctoPrint version at least 1.1.0 is required."))); + _(L("Could not connect to OctoPrint")), msg, _(L("Note: OctoPrint version at least 1.1.0 is required."))); } -bool OctoPrint::upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const +bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const { const auto upload_filename = upload_data.upload_path.filename(); const auto upload_parent_path = upload_data.upload_path.parent_path(); wxString test_msg; if (! test(test_msg)) { - - // TODO: - - // auto errormsg = wxString::Format("%s: %s", errortitle, test_msg); - // GUI::show_error(&progress_dialog, std::move(errormsg)); - // return false; + error_fn(std::move(test_msg)); + return false; } bool res = true; @@ -99,7 +118,8 @@ bool OctoPrint::upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn }) .on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << boost::format("Octoprint: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body; - error_fn(std::move(body), std::move(error), status); + // error_fn(std::move(body), std::move(error), status); + error_fn(format_error(body, error, status)); res = false; }) .on_progress([&](Http::Progress progress, bool &cancel) { @@ -125,10 +145,9 @@ bool OctoPrint::can_test() const return true; } -bool OctoPrint::validate_version_text(const std::string &version_text) +bool OctoPrint::validate_version_text(const boost::optional &version_text) const { - // FIXME - return true; + return version_text ? boost::starts_with(*version_text, "OctoPrint") : true; } void OctoPrint::set_auth(Http &http) const @@ -164,14 +183,23 @@ wxString OctoPrint::format_error(const std::string &body, const std::string &err } -// SL1 +// SLAHost -SL1Host::~SL1Host() {} +SLAHost::~SLAHost() {} -bool SL1Host::validate_version_text(const std::string &version_text) +wxString SLAHost::get_test_ok_msg () const { - // FIXME - return true; + return _(L("Connection to Prusa SLA works correctly.")); +} + +wxString SLAHost::get_test_failed_msg (wxString &msg) const +{ + return wxString::Format("%s: %s", _(L("Could not connect to Prusa SLA")), msg); +} + +bool SLAHost::validate_version_text(const boost::optional &version_text) const +{ + return version_text ? boost::starts_with(*version_text, "Prusa SLA") : false; } diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index 4d6555e13f..1e739c99d7 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "PrintHost.hpp" @@ -19,16 +20,16 @@ public: OctoPrint(DynamicPrintConfig *config); virtual ~OctoPrint(); - bool test(wxString &curl_msg) const; - wxString get_test_ok_msg () const; - wxString get_test_failed_msg (wxString &msg) const; - bool upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const; - bool has_auto_discovery() const; - bool can_test() const; + virtual bool test(wxString &curl_msg) const; + virtual wxString get_test_ok_msg () const; + virtual wxString get_test_failed_msg (wxString &msg) const; + virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const; + virtual bool has_auto_discovery() const; + virtual bool can_test() const; virtual std::string get_host() const { return host; } protected: - virtual bool validate_version_text(const std::string &version_text); + virtual bool validate_version_text(const boost::optional &version_text) const; private: std::string host; @@ -41,14 +42,16 @@ private: }; -class SL1Host: public OctoPrint +class SLAHost: public OctoPrint { public: - SL1Host(DynamicPrintConfig *config) : OctoPrint(config) {} - virtual ~SL1Host(); + SLAHost(DynamicPrintConfig *config) : OctoPrint(config) {} + virtual ~SLAHost(); + virtual wxString get_test_ok_msg () const; + virtual wxString get_test_failed_msg (wxString &msg) const; protected: - virtual bool validate_version_text(const std::string &version_text); + virtual bool validate_version_text(const boost::optional &version_text) const; }; diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index cdd0c107ef..934436a190 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -2,10 +2,12 @@ #include #include +#include #include #include #include +#include #include #include "libslic3r/PrintConfig.hpp" @@ -30,8 +32,8 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) switch (opt->value) { case htOctoPrint: return new OctoPrint(config); - case htSL1: return new SL1Host(config); case htDuet: return new Duet(config); + case htSL1: return new SLAHost(config); default: return nullptr; } } @@ -58,7 +60,6 @@ struct PrintHostJobQueue::priv void start_bg_thread(); void bg_thread_main(); void progress_fn(Http::Progress progress, bool &cancel); - void error_fn(std::string body, std::string error, unsigned http_status); void perform_job(PrintHostJob the_job); }; @@ -100,6 +101,9 @@ void PrintHostJobQueue::priv::bg_thread_main() } job_id++; } + } catch (const std::exception &e) { + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_ERROR, queue_dialog->GetId(), job_id, e.what()); + wxQueueEvent(queue_dialog, evt); } catch (...) { wxTheApp->OnUnhandledException(); } @@ -136,28 +140,28 @@ void PrintHostJobQueue::priv::progress_fn(Http::Progress progress, bool &cancel) } } -void PrintHostJobQueue::priv::error_fn(std::string body, std::string error, unsigned http_status) -{ - // TODO -} - void PrintHostJobQueue::priv::perform_job(PrintHostJob the_job) { if (bg_exit || the_job.empty()) { return; } - BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue/bg_thread: Got job: `%1%` -> `%1%`") + BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue/bg_thread: Got job: `%1%` -> `%2%`") % the_job.upload_data.upload_path % the_job.printhost->get_host(); const fs::path gcode_path = the_job.upload_data.source_path; - the_job.printhost->upload(std::move(the_job.upload_data), + bool success = the_job.printhost->upload(std::move(the_job.upload_data), [this](Http::Progress progress, bool &cancel) { this->progress_fn(std::move(progress), cancel); }, - [this](std::string body, std::string error, unsigned http_status) { this->error_fn(std::move(body), std::move(error), http_status); } + [this](wxString error) { + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_ERROR, queue_dialog->GetId(), job_id, std::move(error)); + wxQueueEvent(queue_dialog, evt); + } ); - auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, 100); - wxQueueEvent(queue_dialog, evt); + if (success) { + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, 100); + wxQueueEvent(queue_dialog, evt); + } boost::system::error_code ec; fs::remove(gcode_path, ec); diff --git a/src/slic3r/Utils/PrintHost.hpp b/src/slic3r/Utils/PrintHost.hpp index 52ef380589..a6c7a47238 100644 --- a/src/slic3r/Utils/PrintHost.hpp +++ b/src/slic3r/Utils/PrintHost.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -28,10 +29,13 @@ class PrintHost public: virtual ~PrintHost(); + typedef Http::ProgressFn ProgressFn; + typedef std::function ErrorFn; + virtual bool test(wxString &curl_msg) const = 0; virtual wxString get_test_ok_msg () const = 0; virtual wxString get_test_failed_msg (wxString &msg) const = 0; - virtual bool upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const = 0; + virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const = 0; virtual bool has_auto_discovery() const = 0; virtual bool can_test() const = 0; virtual std::string get_host() const = 0;