diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0b0b3c0eef..ca57ca5531 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -106,9 +106,9 @@ if (MINGW) set_target_properties(PrusaSlicer PROPERTIES PREFIX "") endif (MINGW) -if (NOT WIN32) - # Binary name on unix like systems (OSX, Linux) - set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer") +if (NOT WIN32 AND NOT APPLE) + # Binary name on unix like systems (Linux, Unix) + set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer") endif () target_link_libraries(PrusaSlicer libslic3r cereal) @@ -209,20 +209,34 @@ if (WIN32) add_custom_target(PrusaSlicerDllsCopy ALL DEPENDS PrusaSlicer) prusaslicer_copy_dlls(PrusaSlicerDllsCopy) -elseif (XCODE) - # Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level - add_custom_command(TARGET PrusaSlicer POST_BUILD - COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/resources" - COMMENT "Symlinking the resources directory into the build tree" - VERBATIM - ) else () + if (APPLE) + # On OSX, the name of the binary matches the name of the Application. + add_custom_command(TARGET PrusaSlicer POST_BUILD + COMMAND ln -sf PrusaSlicer prusa-slicer + COMMAND ln -sf PrusaSlicer prusa-gcodeviewer + COMMAND ln -sf PrusaSlicer PrusaGCodeViewer + WORKING_DIRECTORY "$" + COMMENT "Symlinking the G-code viewer to PrusaSlicer, symlinking to prusa-slicer and prusa-gcodeviewer" + VERBATIM) + else () + add_custom_command(TARGET PrusaSlicer POST_BUILD + COMMAND ln -sf prusa-slicer prusa-gcodeviewer + WORKING_DIRECTORY "$" + COMMENT "Symlinking the G-code viewer to PrusaSlicer" + VERBATIM) + endif () + if (XCODE) + # Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level + set(BIN_RESOURCES_DIR "${CMAKE_CURRENT_BINARY_DIR}/resources") + else () + set(BIN_RESOURCES_DIR "${CMAKE_CURRENT_BINARY_DIR}/../resources") + endif () add_custom_command(TARGET PrusaSlicer POST_BUILD - COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/../resources" + COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${BIN_RESOURCES_DIR}" COMMENT "Symlinking the resources directory into the build tree" - VERBATIM - ) -endif() + VERBATIM) +endif () # Slic3r binary install target if (WIN32) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index ea56124e6a..9874a9d4d7 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -101,8 +102,14 @@ int CLI::run(int argc, char **argv) std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() && std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() && std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end(); - bool start_as_gcodeviewer = false; - + bool start_as_gcodeviewer = +#ifdef _WIN32 + false; +#else + // On Unix systems, the prusa-slicer binary may be symlinked to give the application a different meaning. + boost::algorithm::iends_with(boost::filesystem::path(argv[0]).filename().string(), "gcodeviewer"); +#endif // _WIN32 + const std::vector &load_configs = m_config.option("load", true)->values; // load config files supplied via --load diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 7aaa96c8cf..284c37435a 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1365,9 +1365,10 @@ const std::vector& PhysicalPrinter::printer_options() "print_host", "printhost_apikey", "printhost_cafile", - "authorization_type", - "login", - "password" + "printhost_authorization_type", + // HTTP digest authentization (RFC 2617) + "printhost_user", + "printhost_password" }; } return s_opts; @@ -1412,11 +1413,11 @@ const std::set& PhysicalPrinter::get_preset_names() const bool PhysicalPrinter::has_empty_config() const { - return config.opt_string("print_host" ).empty() && - config.opt_string("printhost_apikey").empty() && - config.opt_string("printhost_cafile").empty() && - config.opt_string("login" ).empty() && - config.opt_string("password" ).empty(); + return config.opt_string("print_host" ).empty() && + config.opt_string("printhost_apikey" ).empty() && + config.opt_string("printhost_cafile" ).empty() && + config.opt_string("printhost_user" ).empty() && + config.opt_string("printhost_password").empty(); } void PhysicalPrinter::update_preset_names_in_config() @@ -1441,7 +1442,7 @@ void PhysicalPrinter::save(const std::string& file_name_from, const std::string& void PhysicalPrinter::update_from_preset(const Preset& preset) { - config.apply_only(preset.config, printer_options(), false); + config.apply_only(preset.config, printer_options(), true); // add preset names to the options list auto ret = preset_names.emplace(preset.name); update_preset_names_in_config(); @@ -1476,8 +1477,8 @@ bool PhysicalPrinter::delete_preset(const std::string& preset_name) return preset_names.erase(preset_name) > 0; } -PhysicalPrinter::PhysicalPrinter(const std::string& name, const Preset& preset) : - name(name) +PhysicalPrinter::PhysicalPrinter(const std::string& name, const DynamicPrintConfig &default_config, const Preset& preset) : + name(name), config(default_config) { update_from_preset(preset); } @@ -1514,6 +1515,13 @@ std::string PhysicalPrinter::get_preset_name(std::string name) PhysicalPrinterCollection::PhysicalPrinterCollection( const std::vector& keys) { + // Default config for a physical printer containing all key/value pairs of PhysicalPrinter::printer_options(). + for (const std::string &key : keys) { + const ConfigOptionDef *opt = print_config_def.get(key); + assert(opt); + assert(opt->default_value); + m_default_config.set_key_value(key, opt->default_value->clone()); + } } // Load all printers found in dir_path. @@ -1539,7 +1547,7 @@ void PhysicalPrinterCollection::load_printers(const std::string& dir_path, const continue; } try { - PhysicalPrinter printer(name); + PhysicalPrinter printer(name, this->default_config()); printer.file = dir_entry.path().string(); // Load the preset file, apply preset values on top of defaults. try { @@ -1590,7 +1598,7 @@ void PhysicalPrinterCollection::load_printers_from_presets(PrinterPresetCollecti new_printer_name = (boost::format("Printer %1%") % ++cnt).str(); // create new printer from this preset - PhysicalPrinter printer(new_printer_name, preset); + PhysicalPrinter printer(new_printer_name, this->default_config(), preset); printer.loaded = true; save_printer(printer); } diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index 30edfc859a..ec11d59fae 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -460,8 +460,7 @@ private: // If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name. std::deque::iterator find_preset_internal(const std::string &name) { - Preset key(m_type, name); - auto it = std::lower_bound(m_presets.begin() + m_num_default_presets, m_presets.end(), key); + auto it = Slic3r::lower_bound_by_predicate(m_presets.begin() + m_num_default_presets, m_presets.end(), [&name](const auto& l) { return l.name < name; }); if (it == m_presets.end() || it->name != name) { // Preset has not been not found in the sorted list of non-default presets. Try the defaults. for (size_t i = 0; i < m_num_default_presets; ++ i) @@ -539,9 +538,8 @@ namespace PresetUtils { class PhysicalPrinter { public: - PhysicalPrinter() {} - PhysicalPrinter(const std::string& name) : name(name){} - PhysicalPrinter(const std::string& name, const Preset& preset); + PhysicalPrinter(const std::string& name, const DynamicPrintConfig &default_config) : name(name), config(default_config) {} + PhysicalPrinter(const std::string& name, const DynamicPrintConfig &default_config, const Preset& preset); void set_name(const std::string &name); // Name of the Physical Printer, usually derived form the file name. @@ -698,6 +696,8 @@ public: // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. std::string path_from_name(const std::string& new_name) const; + const DynamicPrintConfig& default_config() const { return m_default_config; } + private: PhysicalPrinterCollection& operator=(const PhysicalPrinterCollection& other); @@ -707,9 +707,7 @@ private: // If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name. std::deque::iterator find_printer_internal(const std::string& name) { - PhysicalPrinter printer(name); - auto it = std::lower_bound(m_printers.begin(), m_printers.end(), printer); - return it; + return Slic3r::lower_bound_by_predicate(m_printers.begin(), m_printers.end(), [&name](const auto& l) { return l.name < name; }); } std::deque::const_iterator find_printer_internal(const std::string& name) const { @@ -723,6 +721,9 @@ private: // so that the addresses of the presets don't change during resizing of the container. std::deque m_printers; + // Default config for a physical printer containing all key/value pairs of PhysicalPrinter::printer_options(). + DynamicPrintConfig m_default_config; + // Selected printer. size_t m_idx_selected = size_t(-1); // The name of the preset which is currently select for this printer diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 770983ad59..239969a1d2 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -133,13 +133,13 @@ void PrintConfigDef::init_common_params() // Options used by physical printers - def = this->add("login", coString); - def->label = L("Login"); + def = this->add("printhost_user", coString); + def->label = L("User"); // def->tooltip = L(""); def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); - def = this->add("password", coString); + def = this->add("printhost_password", coString); def->label = L("Password"); // def->tooltip = L(""); def->mode = comAdvanced; @@ -151,7 +151,7 @@ void PrintConfigDef::init_common_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); - def = this->add("authorization_type", coEnum); + def = this->add("printhost_authorization_type", coEnum); def->label = L("Authorization Type"); // def->tooltip = L(""); def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 5681ed66db..1c30078102 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -195,6 +195,8 @@ set(SLIC3R_GUI_SOURCES Utils/Bonjour.hpp Utils/PresetUpdater.cpp Utils/PresetUpdater.hpp + Utils/Process.cpp + Utils/Process.hpp Utils/Profile.hpp Utils/UndoRedo.cpp Utils/UndoRedo.hpp diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 9cb3d726de..a21826205b 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1080,7 +1080,7 @@ boost::any& Choice::get_value() m_value = static_cast(ret_enum); else if (m_opt_id.compare("support_pillar_connection_mode") == 0) m_value = static_cast(ret_enum); - else if (m_opt_id == "authorization_type") + else if (m_opt_id == "printhost_authorization_type") m_value = static_cast(ret_enum); } else if (m_opt.gui_type == "f_enum_open") { diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 913716dfd7..6c76b62272 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -194,7 +194,7 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if(opt_key.compare("support_pillar_connection_mode") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); - else if(opt_key == "authorization_type") + else if(opt_key == "printhost_authorization_type") config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); } break; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 151648740d..5e3fe4cde1 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -9,7 +9,6 @@ #include //#include #include -#include #include #include @@ -31,6 +30,7 @@ #include "I18N.hpp" #include "GLCanvas3D.hpp" #include "Plater.hpp" +#include "../Utils/Process.hpp" #include #include "GUI_App.hpp" @@ -40,12 +40,6 @@ #include #endif // _WIN32 -// For starting another PrusaSlicer instance on OSX. -// Fails to compile on Windows on the build server. -#ifdef __APPLE__ - #include -#endif - namespace Slic3r { namespace GUI { @@ -1098,9 +1092,9 @@ void MainFrame::init_menubar() append_menu_item(fileMenu, wxID_ANY, _L("&Repair STL file") + dots, _L("Automatically repair an STL file"), [this](wxCommandEvent&) { repair_stl(); }, "wrench", nullptr, [this]() { return true; }, this); + fileMenu->AppendSeparator(); #if ENABLE_GCODE_VIEWER #if !ENABLE_GCODE_VIEWER_AS_STANDALONE_APPLICATION - fileMenu->AppendSeparator(); append_menu_item(fileMenu, wxID_ANY, _L("&G-code preview"), _L("Switch to G-code preview mode"), [this](wxCommandEvent&) { if (m_plater->model().objects.empty() || @@ -1110,6 +1104,8 @@ void MainFrame::init_menubar() }, "", nullptr); #endif // !ENABLE_GCODE_VIEWER_AS_STANDALONE_APPLICATION #endif // ENABLE_GCODE_VIEWER + append_menu_item(fileMenu, wxID_ANY, _L("&G-code preview") + dots, _L("Open G-code viewer"), + [this](wxCommandEvent&) { start_new_gcodeviewer_open_file(this); }, "", nullptr); fileMenu->AppendSeparator(); append_menu_item(fileMenu, wxID_EXIT, _L("&Quit"), wxString::Format(_L("Quit %s"), SLIC3R_APP_NAME), [this](wxCommandEvent&) { Close(false); }); @@ -1226,20 +1222,11 @@ void MainFrame::init_menubar() windowMenu->AppendSeparator(); append_menu_item(windowMenu, wxID_ANY, _L("Print &Host Upload Queue") + "\tCtrl+J", _L("Display the Print Host Upload Queue window"), - [this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue", nullptr, - [this]() {return true; }, this); + [this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue", nullptr, [this]() {return true; }, this); windowMenu->AppendSeparator(); append_menu_item(windowMenu, wxID_ANY, _(L("Open new instance")) + "\tCtrl+I", _(L("Open a new PrusaSlicer instance")), - [this](wxCommandEvent&) { - wxString path = wxStandardPaths::Get().GetExecutablePath(); -#ifdef __APPLE__ - boost::process::spawn((const char*)path.c_str()); -#else - wxExecute(wxStandardPaths::Get().GetExecutablePath(), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER); -#endif - }, "upload_queue", nullptr, - [this]() {return true; }, this); + [this](wxCommandEvent&) { start_new_slicer(); }, "", nullptr); } // View menu diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index cc10d815fc..dd00b3d688 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -755,7 +755,7 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config else if (opt_key == "support_pillar_connection_mode") { ret = static_cast(config.option>(opt_key)->value); } - else if (opt_key == "authorization_type") { + else if (opt_key == "printhost_authorization_type") { ret = static_cast(config.option>(opt_key)->value); } } diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 12d1cd2871..ca2d625561 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -155,8 +155,9 @@ void PresetForPrinter::msw_rescale() // PhysicalPrinterDialog //------------------------------------------ -PhysicalPrinterDialog::PhysicalPrinterDialog(wxString printer_name) - : DPIDialog(NULL, wxID_ANY, _L("Physical Printer"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +PhysicalPrinterDialog::PhysicalPrinterDialog(wxString printer_name) : + DPIDialog(NULL, wxID_ANY, _L("Physical Printer"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), + m_printer("", wxGetApp().preset_bundle->physical_printers.default_config()) { SetFont(wxGetApp().normal_font()); SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); @@ -186,7 +187,8 @@ PhysicalPrinterDialog::PhysicalPrinterDialog(wxString printer_name) PhysicalPrinter* printer = printers.find_printer(into_u8(printer_name)); if (!printer) { const Preset& preset = wxGetApp().preset_bundle->printers.get_edited_preset(); - printer = new PhysicalPrinter(into_u8(printer_name), preset); + //FIXME Vojtech: WTF??? Memory leak? + printer = new PhysicalPrinter(into_u8(printer_name), m_printer.config, preset); // if printer_name is empty it means that new printer is created, so enable all items in the preset list m_presets.emplace_back(new PresetForPrinter(this, preset.name)); } @@ -249,7 +251,7 @@ PhysicalPrinterDialog::~PhysicalPrinterDialog() void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgroup) { m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { - if (opt_key == "authorization_type") + if (opt_key == "printhost_authorization_type") this->update(); }; @@ -308,7 +310,7 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr host_line.append_widget(print_host_test); m_optgroup->append_line(host_line); - m_optgroup->append_single_option_line("authorization_type"); + m_optgroup->append_single_option_line("printhost_authorization_type"); option = m_optgroup->get_option("printhost_apikey"); option.opt.width = Field::def_width_wider(); @@ -368,7 +370,7 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr m_optgroup->append_line(line); } - for (const std::string& opt_key : std::vector{ "login", "password" }) { + for (const std::string& opt_key : std::vector{ "printhost_user", "printhost_password" }) { option = m_optgroup->get_option(opt_key); option.opt.width = Field::def_width_wider(); m_optgroup->append_single_option_line(option); @@ -385,20 +387,20 @@ void PhysicalPrinterDialog::update() // Only offer the host type selection for FFF, for SLA it's always the SL1 printer (at the moment) if (tech == ptFFF) { m_optgroup->show_field("host_type"); - m_optgroup->hide_field("authorization_type"); - for (const std::string& opt_key : std::vector{ "login", "password" }) + m_optgroup->hide_field("printhost_authorization_type"); + for (const std::string& opt_key : std::vector{ "printhost_user", "printhost_password" }) m_optgroup->hide_field(opt_key); } else { m_optgroup->set_value("host_type", int(PrintHostType::htOctoPrint), false); m_optgroup->hide_field("host_type"); - m_optgroup->show_field("authorization_type"); + m_optgroup->show_field("printhost_authorization_type"); - AuthorizationType auth_type = m_config->option>("authorization_type")->value; + AuthorizationType auth_type = m_config->option>("printhost_authorization_type")->value; m_optgroup->show_field("printhost_apikey", auth_type == AuthorizationType::atKeyPassword); - for (const std::string& opt_key : std::vector{ "login", "password" }) + for (const std::string& opt_key : std::vector{ "printhost_user", "printhost_password" }) m_optgroup->show_field(opt_key, auth_type == AuthorizationType::atUserPassword); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 09640ebaf4..061084f57d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2835,7 +2835,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool if (this->preview != nullptr) { // If the preview is not visible, the following line just invalidates the preview, // but the G-code paths or SLA preview are calculated first once the preview is made visible. - this->preview->get_canvas3d()->reset_gcode_toolpaths(); + reset_gcode_toolpaths(); this->preview->reload_print(); } #else @@ -5408,7 +5408,8 @@ void Plater::on_config_change(const DynamicPrintConfig &config) this->set_printer_technology(config.opt_enum(opt_key)); // print technology is changed, so we should to update a search list p->sidebar->update_searcher(); - } + p->reset_gcode_toolpaths(); + } else if ((opt_key == "bed_shape") || (opt_key == "bed_custom_texture") || (opt_key == "bed_custom_model")) { bed_shape_changed = true; update_scheduled = true; diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index a16aac5b5b..e55c21fe17 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -415,6 +415,16 @@ Http& Http::remove_header(std::string name) return *this; } +// Authorization by HTTP digest, based on RFC2617. +Http& Http::auth_digest(const std::string &user, const std::string &password) +{ + curl_easy_setopt(p->curl, CURLOPT_USERNAME, user.c_str()); + curl_easy_setopt(p->curl, CURLOPT_PASSWORD, password.c_str()); + curl_easy_setopt(p->curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); + + return *this; +} + Http& Http::ca_file(const std::string &name) { if (p && priv::ca_file_supported(p->curl)) { diff --git a/src/slic3r/Utils/Http.hpp b/src/slic3r/Utils/Http.hpp index f162362796..ae3660fbfe 100644 --- a/src/slic3r/Utils/Http.hpp +++ b/src/slic3r/Utils/Http.hpp @@ -64,6 +64,8 @@ public: Http& header(std::string name, const std::string &value); // Removes a header field. Http& remove_header(std::string name); + // Authorization by HTTP digest, based on RFC2617. + Http& auth_digest(const std::string &user, const std::string &password); // Sets a CA certificate file for usage with HTTPS. This is only supported on some backends, // specifically, this is supported with OpenSSL and NOT supported with Windows and OS X native certificate store. // See also ca_file_supported(). diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index ee87f822fa..82d8a6bb63 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -170,6 +170,13 @@ std::string OctoPrint::make_url(const std::string &path) const } } +SL1Host::SL1Host(DynamicPrintConfig *config) : + OctoPrint(config), + authorization_type(dynamic_cast*>(config->option("printhost_authorization_type"))->value), + username(config->opt_string("printhost_user")), + password(config->opt_string("printhost_password")) +{ +} // SL1Host const char* SL1Host::get_name() const { return "SL1Host"; } @@ -191,4 +198,20 @@ bool SL1Host::validate_version_text(const boost::optional &version_ return version_text ? boost::starts_with(*version_text, "Prusa SLA") : false; } +void SL1Host::set_auth(Http &http) const +{ + switch (authorization_type) { + case atKeyPassword: + http.header("X-Api-Key", get_apikey()); + break; + case atUserPassword: + http.auth_digest(username, password); + break; + } + + if (! get_cafile().empty()) { + http.ca_file(get_cafile()); + } +} + } diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index 965019d859..4f8e4819fc 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -29,6 +29,8 @@ public: bool can_test() const override { return true; } bool can_start_print() const override { return true; } std::string get_host() const override { return host; } + const std::string& get_apikey() const { return apikey; } + const std::string& get_cafile() const { return cafile; } protected: virtual bool validate_version_text(const boost::optional &version_text) const; @@ -38,14 +40,14 @@ private: std::string apikey; std::string cafile; - void set_auth(Http &http) const; + virtual void set_auth(Http &http) const; std::string make_url(const std::string &path) const; }; class SL1Host: public OctoPrint { public: - SL1Host(DynamicPrintConfig *config) : OctoPrint(config) {} + SL1Host(DynamicPrintConfig *config); ~SL1Host() override = default; const char* get_name() const override; @@ -56,6 +58,15 @@ public: protected: bool validate_version_text(const boost::optional &version_text) const override; + +private: + void set_auth(Http &http) const override; + + // Host authorization type. + AuthorizationType authorization_type; + // username and password for HTTP Digest Authentization (RFC RFC2617) + std::string username; + std::string password; }; } diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp new file mode 100644 index 0000000000..561971b139 --- /dev/null +++ b/src/slic3r/Utils/Process.cpp @@ -0,0 +1,129 @@ +#include "Process.hpp" + +#include + +#include "../GUI/GUI.hpp" +// for file_wildcards() +#include "../GUI/GUI_App.hpp" +// localization +#include "../GUI/I18N.hpp" + +#include +#include + +#include +#include + +// For starting another PrusaSlicer instance on OSX. +// Fails to compile on Windows on the build server. +#ifdef __APPLE__ + #include + #include +#endif + +#include + +namespace Slic3r { +namespace GUI { + +enum class NewSlicerInstanceType { + Slicer, + GCodeViewer +}; + +// Start a new Slicer process instance either in a Slicer mode or in a G-code mode. +// Optionally load a 3MF, STL or a G-code on start. +static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance_type, const wxString *path_to_open) +{ +#ifdef _WIN32 + wxString path; + wxFileName::SplitPath(wxStandardPaths::Get().GetExecutablePath(), &path, nullptr, nullptr, wxPATH_NATIVE); + path += "\\"; + path += (instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer.exe" : "prusa-gcodeviewer.exe"; + std::vector args; + args.reserve(3); + args.emplace_back(path.wc_str()); + if (path_to_open != nullptr) + args.emplace_back(path_to_open->wc_str()); + args.emplace_back(nullptr); + BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << into_u8(path) << "\""; + if (wxExecute(const_cast(args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER) <= 0) + BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << into_u8(path); +#else + // Own executable path. + boost::filesystem::path bin_path = into_path(wxStandardPaths::Get().GetExecutablePath()); + #if defined(__APPLE__) + { + bin_path = bin_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "PrusaSlicer" : "PrusaGCodeViewer"); + // On Apple the wxExecute fails, thus we use boost::process instead. + BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << bin_path.string() << "\""; + try { + std::vector args; + if (path_to_open) + args.emplace_back(into_u8(*path_to_open)); + boost::process::spawn(bin_path, args); + } catch (const std::exception &ex) { + BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what(); + } + } + #else // Linux or Unix + { + std::vector args; + args.reserve(3); + #ifdef __linux + static const char *gcodeviewer_param = "--gcodeviewer"; + { + // If executed by an AppImage, start the AppImage, not the main process. + // see https://docs.appimage.org/packaging-guide/environment-variables.html#id2 + const char *appimage_binary = std::getenv("APPIMAGE"); + if (appimage_binary) { + args.emplace_back(appimage_binary); + if (instance_type == NewSlicerInstanceType::GCodeViewer) + args.emplace_back(gcodeviewer_param); + } + } + #endif // __linux + std::string my_path; + if (args.empty()) { + // Binary path was not set to the AppImage in the Linux specific block above, call the application directly. + my_path = (bin_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "prusa-slicer" : "prusa-gcodeviewer")).string(); + args.emplace_back(my_path.c_str()); + } + std::string to_open; + if (path_to_open) { + to_open = into_u8(*path_to_open); + args.emplace_back(to_open.c_str()); + } + args.emplace_back(nullptr); + BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << args[0] << "\""; + if (wxExecute(const_cast(args.data()), wxEXEC_ASYNC | wxEXEC_HIDE_CONSOLE | wxEXEC_MAKE_GROUP_LEADER) <= 0) + BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << args[0]; + } + #endif // Linux or Unix +#endif // Win32 +} + +void start_new_slicer(const wxString *path_to_open) +{ + start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::Slicer, path_to_open); +} + +void start_new_gcodeviewer(const wxString *path_to_open) +{ + start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::GCodeViewer, path_to_open); +} + +void start_new_gcodeviewer_open_file(wxWindow *parent) +{ + wxFileDialog dialog(parent ? parent : wxGetApp().GetTopWindow(), + _L("Open G-code file:"), + from_u8(wxGetApp().app_config->get_last_dir()), wxString(), + file_wildcards(FT_GCODE), wxFD_OPEN | wxFD_FILE_MUST_EXIST); + if (dialog.ShowModal() == wxID_OK) { + wxString path = dialog.GetPath(); + start_new_gcodeviewer(&path); + } +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/Utils/Process.hpp b/src/slic3r/Utils/Process.hpp new file mode 100644 index 0000000000..c6acaa643e --- /dev/null +++ b/src/slic3r/Utils/Process.hpp @@ -0,0 +1,19 @@ +#ifndef GUI_PROCESS_HPP +#define GUI_PROCESS_HPP + +class wxWindow; + +namespace Slic3r { +namespace GUI { + +// Start a new slicer instance, optionally with a file to open. +void start_new_slicer(const wxString *path_to_open = nullptr); +// Start a new G-code viewer instance, optionally with a file to open. +void start_new_gcodeviewer(const wxString *path_to_open = nullptr); +// Open a file dialog, ask the user to select a new G-code to open, start a new G-code viewer. +void start_new_gcodeviewer_open_file(wxWindow *parent = nullptr); + +} // namespace GUI +} // namespace Slic3r + +#endif // GUI_PROCESS_HPP diff --git a/src/slic3r/Utils/Thread.hpp b/src/slic3r/Utils/Thread.hpp index e9c76d2aba..194971c9eb 100644 --- a/src/slic3r/Utils/Thread.hpp +++ b/src/slic3r/Utils/Thread.hpp @@ -1,5 +1,5 @@ -#ifndef THREAD_HPP -#define THREAD_HPP +#ifndef GUI_THREAD_HPP +#define GUI_THREAD_HPP #include #include @@ -25,4 +25,4 @@ template inline boost::thread create_thread(Fn &&fn) } -#endif // THREAD_HPP +#endif // GUI_THREAD_HPP