Merge of pull request Add support for RepetierServer #4384 by @docbobo

with the following refactorings:

1) Removed the "printhost_slug" config from the Printer config
   and from all the Printer config related spots.
2) "printhost_slug" renamed to "printhost_port". Slug sounds nasty.
3) Improved error reporting of RepetierHost class.
4) Refactored for the new "Physical Printers"

Following refactorings were done independently of the Repetier pull request:
1) Removed PrintHost static print config.
2) Clean-up after conversion of print host configuration
   from Printer config to Physical Printer config.
3) Fixed some issues, where the Printer config was still queried for
   host configuration. Vojtech believes that this should not happen
   after the host configuration is converted to physical printers.

Vojtech still feels that more refactoring is needed in regard to porting
the host configuration from Printer profile to the new Physical Printer
profile.
This commit is contained in:
Vojtech Bubnik 2020-10-28 09:51:05 +01:00
parent 0798fa8185
commit 7c571c1d9d
24 changed files with 556 additions and 200 deletions

View file

@ -1048,13 +1048,33 @@ void Choice::set_values(const std::vector<std::string>& values)
auto value = ww->GetValue();
ww->Clear();
ww->Append("");
for (auto el : values)
for (const auto &el : values)
ww->Append(wxString(el));
ww->SetValue(value);
m_disable_change_event = false;
}
void Choice::set_values(const wxArrayString &values)
{
if (values.empty())
return;
m_disable_change_event = true;
// # it looks that Clear() also clears the text field in recent wxWidgets versions,
// # but we want to preserve it
auto ww = dynamic_cast<wxBitmapComboBox*>(window);
auto value = ww->GetValue();
ww->Clear();
ww->Append("");
for (const auto &el : values)
ww->Append(el);
ww->SetValue(value);
m_disable_change_event = false;
}
boost::any& Choice::get_value()
{
wxBitmapComboBox* field = dynamic_cast<wxBitmapComboBox*>(window);

View file

@ -405,6 +405,7 @@ public:
void set_value(const std::string& value, bool change_event = false);
void set_value(const boost::any& value, bool change_event = false);
void set_values(const std::vector<std::string> &values);
void set_values(const wxArrayString &values);
boost::any& get_value() override;
void msw_rescale(bool rescale_sidetext = false) override;

View file

@ -750,14 +750,11 @@ bool MainFrame::can_export_gcode() const
bool MainFrame::can_send_gcode() const
{
if (m_plater == nullptr)
return false;
if (m_plater->model().objects.empty())
return false;
const auto print_host_opt = wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionString>("print_host");
return print_host_opt != nullptr && !print_host_opt->value.empty();
if (m_plater && ! m_plater->model().objects.empty())
if (const DynamicPrintConfig *cfg = wxGetApp().preset_bundle->physical_printers.get_selected_printer_config(); cfg)
if (const auto *print_host_opt = cfg->option<ConfigOptionString>("print_host"); print_host_opt)
return ! print_host_opt->value.empty();
return false;
}
bool MainFrame::can_export_gcode_sd() const

View file

@ -32,10 +32,6 @@
#include "BitmapCache.hpp"
#include "BonjourDialog.hpp"
using Slic3r::GUI::format_wxstr;
//static const std::pair<unsigned int, unsigned int> THUMBNAIL_SIZE_3MF = { 256, 256 };
namespace Slic3r {
namespace GUI {
@ -248,10 +244,30 @@ PhysicalPrinterDialog::~PhysicalPrinterDialog()
}
}
void PhysicalPrinterDialog::update_printers()
{
wxBusyCursor wait;
std::unique_ptr<PrintHost> host(PrintHost::get_print_host(m_config));
wxArrayString printers;
Field *rs = m_optgroup->get_field("printhost_port");
try {
if (! host->get_printers(printers))
printers.clear();
} catch (const HostNetworkError &err) {
printers.clear();
show_error(this, _L("Querying printers connected to a print host failed.") + "\n\n" + from_u8(err.what()));
}
Choice *choice = dynamic_cast<Choice*>(rs);
choice->set_values(printers);
printers.empty() ? rs->disable() : rs->enable();
}
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 == "printhost_authorization_type")
if (opt_key == "host_type" || opt_key == "printhost_authorization_type")
this->update();
};
@ -291,17 +307,30 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
return;
}
wxString msg;
if (host->test(msg)) {
bool result;
{
// Show a wait cursor during the connection test, as it is blocking UI.
wxBusyCursor wait;
result = host->test(msg);
}
if (result)
show_info(this, host->get_test_ok_msg(), _L("Success!"));
}
else {
else
show_error(this, host->get_test_failed_msg(msg));
}
});
return sizer;
};
auto print_host_printers = [this, create_sizer_with_btn](wxWindow* parent) {
//add_scaled_button(parent, &m_printhost_port_browse_btn, "browse", _(L("Refresh Printers")), wxBU_LEFT | wxBU_EXACTFIT);
auto sizer = create_sizer_with_btn(parent, &m_printhost_port_browse_btn, "browse", _(L("Refresh Printers")));
ScalableButton* btn = m_printhost_port_browse_btn;
btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent e) { update_printers(); });
return sizer;
};
// Set a wider width for a better alignment
Option option = m_optgroup->get_option("print_host");
option.opt.width = Field::def_width_wider();
@ -316,6 +345,12 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
option.opt.width = Field::def_width_wider();
m_optgroup->append_single_option_line(option);
option = m_optgroup->get_option("printhost_port");
option.opt.width = Field::def_width_wider();
Line port_line = m_optgroup->create_single_option_line(option);
port_line.append_widget(print_host_printers);
m_optgroup->append_line(port_line);
const auto ca_file_hint = _u8L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate.");
if (Http::ca_file_supported()) {
@ -377,6 +412,14 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
}
m_optgroup->activate();
// Always fill in the "printhost_port" combo box from the config and select it.
{
Choice* choice = dynamic_cast<Choice*>(m_optgroup->get_field("printhost_port"));
choice->set_values({ m_config->opt_string("printhost_port") });
choice->set_selection();
}
update();
}
@ -386,11 +429,14 @@ void PhysicalPrinterDialog::update()
const PrinterTechnology tech = Preset::printer_technology(*m_config);
// Only offer the host type selection for FFF, for SLA it's always the SL1 printer (at the moment)
bool supports_multiple_printers = false;
if (tech == ptFFF) {
m_optgroup->show_field("host_type");
m_optgroup->hide_field("printhost_authorization_type");
for (const std::string& opt_key : std::vector<std::string>{ "printhost_user", "printhost_password" })
m_optgroup->hide_field(opt_key);
const auto opt = m_config->option<ConfigOptionEnum<PrintHostType>>("host_type");
supports_multiple_printers = opt && opt->value == htRepetier;
}
else {
m_optgroup->set_value("host_type", int(PrintHostType::htOctoPrint), false);
@ -401,10 +447,12 @@ void PhysicalPrinterDialog::update()
AuthorizationType auth_type = m_config->option<ConfigOptionEnum<AuthorizationType>>("printhost_authorization_type")->value;
m_optgroup->show_field("printhost_apikey", auth_type == AuthorizationType::atKeyPassword);
for (const std::string& opt_key : std::vector<std::string>{ "printhost_user", "printhost_password" })
for (const char *opt_key : { "printhost_user", "printhost_password" })
m_optgroup->show_field(opt_key, auth_type == AuthorizationType::atUserPassword);
}
m_optgroup->show_field("printhost_port", supports_multiple_printers);
m_printhost_port_browse_btn->Show(supports_multiple_printers);
this->Layout();
}

View file

@ -73,6 +73,7 @@ class PhysicalPrinterDialog : public DPIDialog
ScalableButton* m_printhost_browse_btn {nullptr};
ScalableButton* m_printhost_test_btn {nullptr};
ScalableButton* m_printhost_cafile_browse_btn {nullptr};
ScalableButton* m_printhost_port_browse_btn {nullptr};
wxBoxSizer* m_presets_sizer {nullptr};
@ -85,6 +86,7 @@ public:
~PhysicalPrinterDialog();
void update();
void update_printers();
wxString get_printer_name();
void update_full_printer_names();
PhysicalPrinter* get_printer() {return &m_printer; }

View file

@ -1819,8 +1819,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
, main_frame(main_frame)
, config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({
"bed_shape", "bed_custom_texture", "bed_custom_model", "complete_objects", "duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance",
"brim_width", "variable_layer_height", "serial_port", "serial_speed", "host_type", "print_host",
"printhost_apikey", "printhost_cafile", "nozzle_diameter", "single_extruder_multi_material",
"brim_width", "variable_layer_height", "nozzle_diameter", "single_extruder_multi_material",
"wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle",
"extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology",
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.
@ -4292,11 +4291,8 @@ void Plater::priv::show_action_buttons(const bool ready_to_slice) const
wxWindowUpdateLocker noUpdater(sidebar);
DynamicPrintConfig* selected_printer_config = wxGetApp().preset_bundle->physical_printers.get_selected_printer_config();
if (!selected_printer_config)
selected_printer_config = config;
const auto prin_host_opt = selected_printer_config->option<ConfigOptionString>("print_host");
const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty();
const auto print_host_opt = selected_printer_config ? selected_printer_config->option<ConfigOptionString>("print_host") : nullptr;
const bool send_gcode_shown = print_host_opt != nullptr && !print_host_opt->value.empty();
// when a background processing is ON, export_btn and/or send_btn are showing
if (wxGetApp().app_config->get("background_processing") == "1")
@ -5304,12 +5300,14 @@ void Plater::reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &
void Plater::send_gcode()
{
if (p->model.objects.empty()) { return; }
// if physical_printer is selected, send gcode for this printer
DynamicPrintConfig* physical_printer_config = wxGetApp().preset_bundle->physical_printers.get_selected_printer_config();
PrintHostJob upload_job(physical_printer_config ? physical_printer_config : p->config);
if (upload_job.empty()) { return; }
if (! physical_printer_config || p->model.objects.empty())
return;
PrintHostJob upload_job(physical_printer_config);
if (upload_job.empty())
return;
// Obtain default output path
fs::path default_output_file;
@ -5327,11 +5325,18 @@ void Plater::send_gcode()
}
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
PrintHostSendDialog dlg(default_output_file, upload_job.printhost->can_start_print());
// Repetier specific: Query the server for the list of file groups.
wxArrayString groups;
{
wxBusyCursor wait;
upload_job.printhost->get_groups(groups);
}
PrintHostSendDialog dlg(default_output_file, upload_job.printhost->can_start_print(), groups);
if (dlg.ShowModal() == wxID_OK) {
upload_job.upload_data.upload_path = dlg.filename();
upload_job.upload_data.start_print = dlg.start_print();
upload_job.upload_data.group = dlg.group();
p->export_gcode(fs::path(), false, std::move(upload_job));
}
}

View file

@ -28,18 +28,20 @@ namespace GUI {
static const char *CONFIG_KEY_PATH = "printhost_path";
static const char *CONFIG_KEY_PRINT = "printhost_print";
static const char *CONFIG_KEY_GROUP = "printhost_group";
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_print)
: MsgDialog(nullptr, _(L("Send G-Code to printer host")), _(L("Upload to Printer Host with the following filename:")), wxID_NONE)
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_print, const wxArrayString &groups)
: MsgDialog(nullptr, _L("Send G-Code to printer host"), _L("Upload to Printer Host with the following filename:"), wxID_NONE)
, txt_filename(new wxTextCtrl(this, wxID_ANY))
, box_print(can_start_print ? new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload"))) : nullptr)
, box_print(can_start_print ? new wxCheckBox(this, wxID_ANY, _L("Start printing after upload")) : nullptr)
, combo_groups(!groups.IsEmpty() ? new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, groups, wxCB_READONLY) : nullptr)
{
#ifdef __APPLE__
txt_filename->OSXDisableAllSmartSubstitutions();
#endif
const AppConfig *app_config = wxGetApp().app_config;
auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _(L("Use forward slashes ( / ) as a directory separator if needed.")));
auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _L("Use forward slashes ( / ) as a directory separator if needed."));
label_dir_hint->Wrap(CONTENT_WIDTH * wxGetApp().em_unit());
content_sizer->Add(txt_filename, 0, wxEXPAND);
@ -49,10 +51,19 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
content_sizer->Add(box_print, 0, wxBOTTOM, 2*VERT_SPACING);
box_print->SetValue(app_config->get("recent", CONFIG_KEY_PRINT) == "1");
}
if (combo_groups != nullptr) {
// Repetier specific: Show a selection of file groups.
auto *label_group = new wxStaticText(this, wxID_ANY, _L("Group"));
content_sizer->Add(label_group);
content_sizer->Add(combo_groups, 0, wxBOTTOM, 2*VERT_SPACING);
wxString recent_group = from_u8(app_config->get("recent", CONFIG_KEY_GROUP));
if (! recent_group.empty())
combo_groups->SetValue(recent_group);
}
btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL));
wxString recent_path = from_u8(app_config->get("recent", CONFIG_KEY_PATH));
if (recent_path.Length() > 0 && recent_path[recent_path.Length() - 1] != '/') {
recent_path += '/';
@ -64,7 +75,7 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
txt_filename->SetValue(recent_path);
txt_filename->SetFocus();
Fit();
Bind(wxEVT_SHOW, [=](const wxShowEvent &) {
@ -86,6 +97,16 @@ bool PrintHostSendDialog::start_print() const
return box_print != nullptr ? box_print->GetValue() : false;
}
std::string PrintHostSendDialog::group() const
{
if (combo_groups == nullptr) {
return "";
} else {
wxString group = combo_groups->GetValue();
return into_u8(group);
}
}
void PrintHostSendDialog::EndModal(int ret)
{
if (ret == wxID_OK) {
@ -96,9 +117,15 @@ void PrintHostSendDialog::EndModal(int ret)
path.clear();
else
path = path.SubString(0, last_slash);
AppConfig *app_config = wxGetApp().app_config;
app_config->set("recent", CONFIG_KEY_PATH, into_u8(path));
app_config->set("recent", CONFIG_KEY_PRINT, start_print() ? "1" : "0");
if (combo_groups != nullptr) {
wxString group = combo_groups->GetValue();
app_config->set("recent", CONFIG_KEY_GROUP, into_u8(group));
}
}
MsgDialog::EndModal(ret);
@ -133,7 +160,7 @@ wxEvent *PrintHostQueueDialog::Event::Clone() const
}
PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent)
: DPIDialog(parent, wxID_ANY, _(L("Print host upload queue")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
: DPIDialog(parent, wxID_ANY, _L("Print host upload queue"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
, on_progress_evt(this, EVT_PRINTHOST_PROGRESS, &PrintHostQueueDialog::on_progress, this)
, on_error_evt(this, EVT_PRINTHOST_ERROR, &PrintHostQueueDialog::on_error, this)
, on_cancel_evt(this, EVT_PRINTHOST_CANCEL, &PrintHostQueueDialog::on_cancel, this)
@ -144,19 +171,20 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent)
job_list = new wxDataViewListCtrl(this, wxID_ANY);
// Note: Keep these in sync with Column
job_list->AppendTextColumn(_(L("ID")), wxDATAVIEW_CELL_INERT);
job_list->AppendProgressColumn(_(L("Progress")), wxDATAVIEW_CELL_INERT);
job_list->AppendTextColumn(_(L("Status")), wxDATAVIEW_CELL_INERT);
job_list->AppendTextColumn(_(L("Host")), wxDATAVIEW_CELL_INERT);
job_list->AppendTextColumn(_(L("Filename")), wxDATAVIEW_CELL_INERT);
job_list->AppendTextColumn(_(L("Error Message")), wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER, wxDATAVIEW_COL_HIDDEN);
job_list->AppendTextColumn(_L("ID"), wxDATAVIEW_CELL_INERT);
job_list->AppendProgressColumn(_L("Progress"), wxDATAVIEW_CELL_INERT);
job_list->AppendTextColumn(_L("Status"), wxDATAVIEW_CELL_INERT);
job_list->AppendTextColumn(_L("Host"), wxDATAVIEW_CELL_INERT);
job_list->AppendTextColumn(_L("Filename"), wxDATAVIEW_CELL_INERT);
job_list->AppendTextColumn(_L("Error Message"), wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER, wxDATAVIEW_COL_HIDDEN);
auto *btnsizer = new wxBoxSizer(wxHORIZONTAL);
btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected")));
btn_cancel = new wxButton(this, wxID_DELETE, _L("Cancel selected"));
btn_cancel->Disable();
btn_error = new wxButton(this, wxID_ANY, _(L("Show error message")));
btn_error = new wxButton(this, wxID_ANY, _L("Show error message"));
btn_error->Disable();
auto *btn_close = new wxButton(this, wxID_CANCEL, _(L("Close"))); // Note: The label needs to be present, otherwise we get accelerator bugs on Mac
// Note: The label needs to be present, otherwise we get accelerator bugs on Mac
auto *btn_close = new wxButton(this, wxID_CANCEL, _L("Close"));
btnsizer->Add(btn_cancel, 0, wxRIGHT, SPACING);
btnsizer->Add(btn_error, 0);
btnsizer->AddStretchSpacer();
@ -195,7 +223,7 @@ void PrintHostQueueDialog::append_job(const PrintHostJob &job)
wxVector<wxVariant> fields;
fields.push_back(wxVariant(wxString::Format("%d", job_list->GetItemCount() + 1)));
fields.push_back(wxVariant(0));
fields.push_back(wxVariant(_(L("Enqueued"))));
fields.push_back(wxVariant(_L("Enqueued")));
fields.push_back(wxVariant(job.printhost->get_host()));
fields.push_back(wxVariant(job.upload_data.upload_path.string()));
fields.push_back(wxVariant(""));
@ -226,12 +254,12 @@ void PrintHostQueueDialog::set_state(int idx, JobState state)
job_list->SetItemData(job_list->RowToItem(idx), static_cast<wxUIntPtr>(state));
switch (state) {
case ST_NEW: job_list->SetValue(_(L("Enqueued")), idx, COL_STATUS); break;
case ST_PROGRESS: job_list->SetValue(_(L("Uploading")), idx, COL_STATUS); break;
case ST_ERROR: job_list->SetValue(_(L("Error")), idx, COL_STATUS); break;
case ST_CANCELLING: job_list->SetValue(_(L("Cancelling")), idx, COL_STATUS); break;
case ST_CANCELLED: job_list->SetValue(_(L("Cancelled")), idx, COL_STATUS); break;
case ST_COMPLETED: job_list->SetValue(_(L("Completed")), idx, COL_STATUS); break;
case ST_NEW: job_list->SetValue(_L("Enqueued"), idx, COL_STATUS); break;
case ST_PROGRESS: job_list->SetValue(_L("Uploading"), idx, COL_STATUS); break;
case ST_ERROR: job_list->SetValue(_L("Error"), idx, COL_STATUS); break;
case ST_CANCELLING: job_list->SetValue(_L("Cancelling"), idx, COL_STATUS); break;
case ST_CANCELLED: job_list->SetValue(_L("Cancelled"), idx, COL_STATUS); break;
case ST_COMPLETED: job_list->SetValue(_L("Completed"), idx, COL_STATUS); break;
}
}

View file

@ -15,6 +15,7 @@
class wxButton;
class wxTextCtrl;
class wxComboBox;
class wxCheckBox;
class wxDataViewListCtrl;
@ -29,14 +30,16 @@ namespace GUI {
class PrintHostSendDialog : public GUI::MsgDialog
{
public:
PrintHostSendDialog(const boost::filesystem::path &path, bool can_start_print);
PrintHostSendDialog(const boost::filesystem::path &path, bool can_start_print, const wxArrayString& groups);
boost::filesystem::path filename() const;
bool start_print() const;
std::string group() const;
virtual void EndModal(int ret) override;
private:
wxTextCtrl *txt_filename;
wxCheckBox *box_print;
wxComboBox *combo_groups;
};

View file

@ -435,9 +435,6 @@ private:
std::vector<PageShp> m_pages_sla;
public:
wxButton* m_serial_test_btn = nullptr;
ScalableButton* m_print_host_test_btn = nullptr;
ScalableButton* m_printhost_browse_btn = nullptr;
ScalableButton* m_reset_to_filament_color = nullptr;
size_t m_extruders_count;