1 #include "PhysicalPrinterDialog.hpp"
2 #include "PresetComboBoxes.hpp"
3 
4 #include <cstddef>
5 #include <vector>
6 #include <string>
7 #include <boost/algorithm/string.hpp>
8 
9 #include <wx/sizer.h>
10 #include <wx/stattext.h>
11 #include <wx/textctrl.h>
12 #include <wx/button.h>
13 #include <wx/statbox.h>
14 #include <wx/wupdlock.h>
15 
16 #include "libslic3r/libslic3r.h"
17 #include "libslic3r/PrintConfig.hpp"
18 #include "libslic3r/PresetBundle.hpp"
19 
20 #include "GUI.hpp"
21 #include "GUI_App.hpp"
22 #include "MainFrame.hpp"
23 #include "format.hpp"
24 #include "Tab.hpp"
25 #include "wxExtensions.hpp"
26 #include "PrintHostDialogs.hpp"
27 #include "../Utils/ASCIIFolding.hpp"
28 #include "../Utils/PrintHost.hpp"
29 #include "../Utils/FixModelByWin10.hpp"
30 #include "../Utils/UndoRedo.hpp"
31 #include "RemovableDriveManager.hpp"
32 #include "BitmapCache.hpp"
33 #include "BonjourDialog.hpp"
34 
35 namespace Slic3r {
36 namespace GUI {
37 
38 #define BORDER_W 10
39 
40 //------------------------------------------
41 //          PresetForPrinter
42 //------------------------------------------
43 
PresetForPrinter(PhysicalPrinterDialog * parent,const std::string & preset_name)44 PresetForPrinter::PresetForPrinter(PhysicalPrinterDialog* parent, const std::string& preset_name) :
45     m_parent(parent)
46 {
47     m_sizer = new wxBoxSizer(wxVERTICAL);
48 
49     m_delete_preset_btn = new ScalableButton(parent, wxID_ANY, "cross", "", wxDefaultSize, wxDefaultPosition, /*wxBU_LEFT | */wxBU_EXACTFIT);
50     m_delete_preset_btn->SetFont(wxGetApp().normal_font());
51     m_delete_preset_btn->SetToolTip(_L("Delete this preset from this printer device"));
52     m_delete_preset_btn->Bind(wxEVT_BUTTON, &PresetForPrinter::DeletePreset, this);
53 
54     m_presets_list = new PresetComboBox(parent, Preset::TYPE_PRINTER);
55     m_presets_list->set_printer_technology(parent->get_printer_technology());
56 
57     m_presets_list->set_selection_changed_function([this](int selection) {
58         std::string selected_string = Preset::remove_suffix_modified(m_presets_list->GetString(selection).ToUTF8().data());
59         Preset* preset = wxGetApp().preset_bundle->printers.find_preset(selected_string);
60         assert(preset);
61         Preset& edited_preset = wxGetApp().preset_bundle->printers.get_edited_preset();
62         if (preset->name == edited_preset.name)
63             preset = &edited_preset;
64 
65         // if created physical printer doesn't have any settings, use the settings from the selected preset
66         if (m_parent->get_printer()->has_empty_config()) {
67             // update Print Host upload from the selected preset
68             m_parent->get_printer()->update_from_preset(*preset);
69             // update values in parent (PhysicalPrinterDialog)
70             m_parent->update(true);
71 
72         }
73 
74         // update PrinterTechnology if it was changed
75         if (m_presets_list->set_printer_technology(preset->printer_technology()))
76             m_parent->set_printer_technology(preset->printer_technology());
77 
78         update_full_printer_name();
79     });
80     m_presets_list->update(preset_name);
81 
82     m_info_line = new wxStaticText(parent, wxID_ANY, _L("This printer will be shown in the presets list as") + ":");
83 
84     m_full_printer_name = new wxStaticText(parent, wxID_ANY, "");
85     m_full_printer_name->SetFont(wxGetApp().bold_font());
86 
87     wxBoxSizer* preset_sizer = new wxBoxSizer(wxHORIZONTAL);
88     preset_sizer->Add(m_presets_list        , 1, wxEXPAND);
89     preset_sizer->Add(m_delete_preset_btn   , 0, wxEXPAND | wxLEFT, BORDER_W);
90 
91     wxBoxSizer* name_sizer = new wxBoxSizer(wxHORIZONTAL);
92     name_sizer->Add(m_info_line, 0, wxEXPAND);
93     name_sizer->Add(m_full_printer_name, 0, wxEXPAND | wxLEFT, BORDER_W);
94 
95     m_sizer->Add(preset_sizer   , 0, wxEXPAND);
96     m_sizer->Add(name_sizer, 0, wxEXPAND);
97 }
98 
~PresetForPrinter()99 PresetForPrinter::~PresetForPrinter()
100 {
101     m_presets_list->Destroy();
102     m_delete_preset_btn->Destroy();
103     m_info_line->Destroy();
104     m_full_printer_name->Destroy();
105 }
106 
DeletePreset(wxEvent & event)107 void PresetForPrinter::DeletePreset(wxEvent& event)
108 {
109     m_parent->DeletePreset(this);
110 }
111 
update_full_printer_name()112 void PresetForPrinter::update_full_printer_name()
113 {
114     wxString printer_name   = m_parent->get_printer_name();
115     wxString preset_name    = m_presets_list->GetString(m_presets_list->GetSelection());
116 
117     m_full_printer_name->SetLabelText(printer_name + " * " + preset_name);
118 }
119 
get_preset_name()120 std::string PresetForPrinter::get_preset_name()
121 {
122     return into_u8(m_presets_list->GetString(m_presets_list->GetSelection()));
123 }
124 
SuppressDelete()125 void PresetForPrinter::SuppressDelete()
126 {
127     m_delete_preset_btn->Enable(false);
128 
129     // this case means that now we have only one related preset for the printer
130     // So, allow any selection
131     m_presets_list->set_printer_technology(ptAny);
132     m_presets_list->update();
133 }
134 
AllowDelete()135 void PresetForPrinter::AllowDelete()
136 {
137     if (!m_delete_preset_btn->IsEnabled())
138         m_delete_preset_btn->Enable();
139 
140     m_presets_list->set_printer_technology(m_parent->get_printer_technology());
141     m_presets_list->update();
142 }
143 
msw_rescale()144 void PresetForPrinter::msw_rescale()
145 {
146     m_presets_list->msw_rescale();
147     m_delete_preset_btn->msw_rescale();
148 }
149 
150 
151 //------------------------------------------
152 //          PhysicalPrinterDialog
153 //------------------------------------------
154 
PhysicalPrinterDialog(wxWindow * parent,wxString printer_name)155 PhysicalPrinterDialog::PhysicalPrinterDialog(wxWindow* parent, wxString printer_name) :
156     DPIDialog(parent, wxID_ANY, _L("Physical Printer"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
157     m_printer("", wxGetApp().preset_bundle->physical_printers.default_config()),
158     had_all_mk3(!printer_name.empty())
159 {
160     SetFont(wxGetApp().normal_font());
161     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
162 
163     m_default_name = _L("Type here the name of your printer device");
164     bool new_printer = true;
165 
166     if (printer_name.IsEmpty())
167         printer_name = m_default_name;
168     else {
169         std::string full_name = into_u8(printer_name);
170         printer_name = from_u8(PhysicalPrinter::get_short_name(full_name));
171         new_printer = false;
172     }
173 
174     wxStaticText* label_top = new wxStaticText(this, wxID_ANY, _L("Descriptive name for the printer") + ":");
175 
176     m_add_preset_btn = new ScalableButton(this, wxID_ANY, "add_copies", "", wxDefaultSize, wxDefaultPosition, /*wxBU_LEFT | */wxBU_EXACTFIT);
177     m_add_preset_btn->SetFont(wxGetApp().normal_font());
178     m_add_preset_btn->SetToolTip(_L("Add preset for this printer device"));
179     m_add_preset_btn->Bind(wxEVT_BUTTON, &PhysicalPrinterDialog::AddPreset, this);
180 
181     m_printer_name    = new wxTextCtrl(this, wxID_ANY, printer_name, wxDefaultPosition, wxDefaultSize);
182     m_printer_name->Bind(wxEVT_TEXT, [this](wxEvent&) { this->update_full_printer_names(); });
183 
184     PhysicalPrinterCollection& printers = wxGetApp().preset_bundle->physical_printers;
185     PhysicalPrinter* printer = printers.find_printer(into_u8(printer_name));
186     if (!printer) {
187         const Preset& preset = wxGetApp().preset_bundle->printers.get_edited_preset();
188         m_printer = PhysicalPrinter(into_u8(printer_name), m_printer.config, preset);
189         // if printer_name is empty it means that new printer is created, so enable all items in the preset list
190         m_presets.emplace_back(new PresetForPrinter(this, preset.name));
191     }
192     else
193     {
194         m_printer = *printer;
195         const std::set<std::string>& preset_names = printer->get_preset_names();
196         for (const std::string& preset_name : preset_names)
197             m_presets.emplace_back(new PresetForPrinter(this, preset_name));
198     }
199 
200     if (m_presets.size() == 1)
201         m_presets.front()->SuppressDelete();
202 
203     update_full_printer_names();
204 
205     m_config = &m_printer.config;
206 
207     m_optgroup = new ConfigOptionsGroup(this, _L("Print Host upload"), m_config);
208     build_printhost_settings(m_optgroup);
209 
210     wxStdDialogButtonSizer* btns = this->CreateStdDialogButtonSizer(wxOK | wxCANCEL);
211     wxButton* btnOK = static_cast<wxButton*>(this->FindWindowById(wxID_OK, this));
212     btnOK->Bind(wxEVT_BUTTON, &PhysicalPrinterDialog::OnOK, this);
213 
214     wxBoxSizer* nameSizer = new wxBoxSizer(wxHORIZONTAL);
215     nameSizer->Add(m_printer_name, 1, wxEXPAND);
216     nameSizer->Add(m_add_preset_btn, 0, wxEXPAND | wxLEFT, BORDER_W);
217 
218     m_presets_sizer = new wxBoxSizer(wxVERTICAL);
219     for (PresetForPrinter* preset : m_presets)
220         m_presets_sizer->Add(preset->sizer(), 1, wxEXPAND | wxTOP, BORDER_W);
221 
222     wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
223 
224     topSizer->Add(label_top           , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, BORDER_W);
225     topSizer->Add(nameSizer           , 0, wxEXPAND | wxLEFT | wxRIGHT, BORDER_W);
226     topSizer->Add(m_presets_sizer     , 0, wxEXPAND | wxLEFT | wxRIGHT, BORDER_W);
227     topSizer->Add(m_optgroup->sizer   , 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, BORDER_W);
228     topSizer->Add(btns                , 0, wxEXPAND | wxALL, BORDER_W);
229 
230     SetSizer(topSizer);
231     topSizer->SetSizeHints(this);
232 
233     if (new_printer) {
234         m_printer_name->SetFocus();
235         m_printer_name->SelectAll();
236     }
237 
238     this->CenterOnScreen();
239 }
240 
~PhysicalPrinterDialog()241 PhysicalPrinterDialog::~PhysicalPrinterDialog()
242 {
243     for (PresetForPrinter* preset : m_presets) {
244         delete preset;
245         preset = nullptr;
246     }
247 }
248 
update_printers()249 void PhysicalPrinterDialog::update_printers()
250 {
251     wxBusyCursor wait;
252 
253     std::unique_ptr<PrintHost> host(PrintHost::get_print_host(m_config));
254 
255     wxArrayString printers;
256     Field *rs = m_optgroup->get_field("printhost_port");
257     try {
258         if (! host->get_printers(printers))
259             printers.clear();
260     } catch (const HostNetworkError &err) {
261         printers.clear();
262         show_error(this, _L("Connection to printers connected via the print host failed.") + "\n\n" + from_u8(err.what()));
263     }
264     Choice *choice = dynamic_cast<Choice*>(rs);
265     choice->set_values(printers);
266     printers.empty() ? rs->disable() : rs->enable();
267 }
268 
build_printhost_settings(ConfigOptionsGroup * m_optgroup)269 void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgroup)
270 {
271     m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
272         if (opt_key == "host_type" || opt_key == "printhost_authorization_type")
273             this->update();
274         if (opt_key == "print_host")
275             this->update_printhost_buttons();
276     };
277 
278     m_optgroup->append_single_option_line("host_type");
279 
280     auto create_sizer_with_btn = [this](wxWindow* parent, ScalableButton** btn, const std::string& icon_name, const wxString& label) {
281         *btn = new ScalableButton(parent, wxID_ANY, icon_name, label, wxDefaultSize, wxDefaultPosition, wxBU_LEFT | wxBU_EXACTFIT);
282         (*btn)->SetFont(wxGetApp().normal_font());
283 
284         auto sizer = new wxBoxSizer(wxHORIZONTAL);
285         sizer->Add(*btn);
286         return sizer;
287     };
288 
289     auto printhost_browse = [=](wxWindow* parent)
290     {
291         auto sizer = create_sizer_with_btn(parent, &m_printhost_browse_btn, "browse", _L("Browse") + " " + dots);
292         m_printhost_browse_btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent& e) {
293             BonjourDialog dialog(this, Preset::printer_technology(m_printer.config));
294             if (dialog.show_and_lookup()) {
295                 m_optgroup->set_value("print_host", std::move(dialog.get_selected()), true);
296                 m_optgroup->get_field("print_host")->field_changed();
297             }
298         });
299 
300         return sizer;
301     };
302 
303     auto print_host_test = [=](wxWindow* parent) {
304         auto sizer = create_sizer_with_btn(parent, &m_printhost_test_btn, "test", _L("Test"));
305 
306         m_printhost_test_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
307             std::unique_ptr<PrintHost> host(PrintHost::get_print_host(m_config));
308             if (!host) {
309                 const wxString text = _L("Could not get a valid Printer Host reference");
310                 show_error(this, text);
311                 return;
312             }
313             wxString msg;
314             bool result;
315             {
316                 // Show a wait cursor during the connection test, as it is blocking UI.
317                 wxBusyCursor wait;
318                 result = host->test(msg);
319             }
320             if (result)
321                 show_info(this, host->get_test_ok_msg(), _L("Success!"));
322             else
323                 show_error(this, host->get_test_failed_msg(msg));
324             });
325 
326         return sizer;
327     };
328 
329     auto print_host_printers = [this, create_sizer_with_btn](wxWindow* parent) {
330         //add_scaled_button(parent, &m_printhost_port_browse_btn, "browse", _(L("Refresh Printers")), wxBU_LEFT | wxBU_EXACTFIT);
331         auto sizer = create_sizer_with_btn(parent, &m_printhost_port_browse_btn, "browse", _(L("Refresh Printers")));
332         ScalableButton* btn = m_printhost_port_browse_btn;
333         btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
334         btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent e) { update_printers(); });
335         return sizer;
336     };
337 
338     // Set a wider width for a better alignment
339     Option option = m_optgroup->get_option("print_host");
340     option.opt.width = Field::def_width_wider();
341     Line host_line = m_optgroup->create_single_option_line(option);
342     host_line.append_widget(printhost_browse);
343     host_line.append_widget(print_host_test);
344     m_optgroup->append_line(host_line);
345 
346     m_optgroup->append_single_option_line("printhost_authorization_type");
347 
348     option = m_optgroup->get_option("printhost_apikey");
349     option.opt.width = Field::def_width_wider();
350     m_optgroup->append_single_option_line(option);
351 
352     option = m_optgroup->get_option("printhost_port");
353     option.opt.width = Field::def_width_wider();
354     Line port_line = m_optgroup->create_single_option_line(option);
355     port_line.append_widget(print_host_printers);
356     m_optgroup->append_line(port_line);
357 
358     const auto ca_file_hint = _u8L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate.");
359 
360     if (Http::ca_file_supported()) {
361         option = m_optgroup->get_option("printhost_cafile");
362         option.opt.width = Field::def_width_wider();
363         Line cafile_line = m_optgroup->create_single_option_line(option);
364 
365         auto printhost_cafile_browse = [=](wxWindow* parent) {
366             auto sizer = create_sizer_with_btn(parent, &m_printhost_cafile_browse_btn, "browse", _L("Browse") + " " + dots);
367             m_printhost_cafile_browse_btn->Bind(wxEVT_BUTTON, [this, m_optgroup](wxCommandEvent e) {
368                 static const auto filemasks = _L("Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*");
369                 wxFileDialog openFileDialog(this, _L("Open CA certificate file"), "", "", filemasks, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
370                 if (openFileDialog.ShowModal() != wxID_CANCEL) {
371                     m_optgroup->set_value("printhost_cafile", std::move(openFileDialog.GetPath()), true);
372                     m_optgroup->get_field("printhost_cafile")->field_changed();
373                 }
374                 });
375 
376             return sizer;
377         };
378 
379         cafile_line.append_widget(printhost_cafile_browse);
380         m_optgroup->append_line(cafile_line);
381 
382         Line cafile_hint{ "", "" };
383         cafile_hint.full_width = 1;
384         cafile_hint.widget = [this, ca_file_hint](wxWindow* parent) {
385             auto txt = new wxStaticText(parent, wxID_ANY, ca_file_hint);
386             auto sizer = new wxBoxSizer(wxHORIZONTAL);
387             sizer->Add(txt);
388             return sizer;
389         };
390         m_optgroup->append_line(cafile_hint);
391     }
392     else {
393         Line line{ "", "" };
394         line.full_width = 1;
395 
396         line.widget = [ca_file_hint](wxWindow* parent) {
397             std::string info = _u8L("HTTPS CA File") + ":\n\t" +
398                 (boost::format(_u8L("On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain.")) % SLIC3R_APP_NAME).str() +
399                 "\n\t" + _u8L("To use a custom CA file, please import your CA file into Certificate Store / Keychain.");
400 
401             //auto txt = new wxStaticText(parent, wxID_ANY, from_u8((boost::format("%1%\n\n\t%2%") % info % ca_file_hint).str()));
402             auto txt = new wxStaticText(parent, wxID_ANY, from_u8((boost::format("%1%\n\t%2%") % info % ca_file_hint).str()));
403             txt->SetFont(wxGetApp().normal_font());
404             auto sizer = new wxBoxSizer(wxHORIZONTAL);
405             sizer->Add(txt, 1, wxEXPAND);
406             return sizer;
407         };
408 
409         m_optgroup->append_line(line);
410     }
411 
412     for (const std::string& opt_key : std::vector<std::string>{ "printhost_user", "printhost_password" }) {
413         option = m_optgroup->get_option(opt_key);
414         option.opt.width = Field::def_width_wider();
415         m_optgroup->append_single_option_line(option);
416     }
417 
418     m_optgroup->activate();
419 
420     Field* printhost_field = m_optgroup->get_field("print_host");
421     if (printhost_field)
422     {
423         wxTextCtrl* temp = dynamic_cast<wxTextCtrl*>(printhost_field->getWindow());
424         if (temp)
425             temp->Bind(wxEVT_TEXT, ([this, printhost_field, temp](wxEvent& e)
426             {
427 #ifndef __WXGTK__
428                 e.Skip();
429                 temp->GetToolTip()->Enable(true);
430 #endif // __WXGTK__
431                 TextCtrl* field = dynamic_cast<TextCtrl*>(printhost_field);
432                 if (field)
433                     field->propagate_value();
434             }), temp->GetId());
435     }
436 
437     // Always fill in the "printhost_port" combo box from the config and select it.
438     {
439         Choice* choice = dynamic_cast<Choice*>(m_optgroup->get_field("printhost_port"));
440         choice->set_values({ m_config->opt_string("printhost_port") });
441         choice->set_selection();
442     }
443 
444     update();
445 }
446 
update_printhost_buttons()447 void PhysicalPrinterDialog::update_printhost_buttons()
448 {
449     std::unique_ptr<PrintHost> host(PrintHost::get_print_host(m_config));
450     m_printhost_test_btn->Enable(!m_config->opt_string("print_host").empty() && host->can_test());
451     m_printhost_browse_btn->Enable(host->has_auto_discovery());
452 }
453 
update(bool printer_change)454 void PhysicalPrinterDialog::update(bool printer_change)
455 {
456     m_optgroup->reload_config();
457 
458     const PrinterTechnology tech = Preset::printer_technology(*m_config);
459     // Only offer the host type selection for FFF, for SLA it's always the SL1 printer (at the moment)
460     bool supports_multiple_printers = false;
461     if (tech == ptFFF) {
462         update_host_type(printer_change);
463         const auto opt = m_config->option<ConfigOptionEnum<PrintHostType>>("host_type");
464         m_optgroup->show_field("host_type");
465         if (opt->value == htPrusaLink)
466         {
467             m_optgroup->show_field("printhost_authorization_type");
468             AuthorizationType auth_type = m_config->option<ConfigOptionEnum<AuthorizationType>>("printhost_authorization_type")->value;
469             m_optgroup->show_field("printhost_apikey", auth_type == AuthorizationType::atKeyPassword);
470             for (const char* opt_key : { "printhost_user", "printhost_password" })
471                 m_optgroup->show_field(opt_key, auth_type == AuthorizationType::atUserPassword);
472         } else {
473             m_optgroup->hide_field("printhost_authorization_type");
474             m_optgroup->show_field("printhost_apikey", true);
475             for (const std::string& opt_key : std::vector<std::string>{ "printhost_user", "printhost_password" })
476                 m_optgroup->hide_field(opt_key);
477             supports_multiple_printers = opt && opt->value == htRepetier;
478         }
479 
480     }
481     else {
482         m_optgroup->set_value("host_type", int(PrintHostType::htOctoPrint), false);
483         m_optgroup->hide_field("host_type");
484 
485         m_optgroup->show_field("printhost_authorization_type");
486 
487         AuthorizationType auth_type = m_config->option<ConfigOptionEnum<AuthorizationType>>("printhost_authorization_type")->value;
488         m_optgroup->show_field("printhost_apikey", auth_type == AuthorizationType::atKeyPassword);
489 
490         for (const char *opt_key : { "printhost_user", "printhost_password" })
491             m_optgroup->show_field(opt_key, auth_type == AuthorizationType::atUserPassword);
492     }
493 
494     m_optgroup->show_field("printhost_port", supports_multiple_printers);
495     m_printhost_port_browse_btn->Show(supports_multiple_printers);
496 
497     update_printhost_buttons();
498 
499     this->SetSize(this->GetBestSize());
500     this->Layout();
501 }
502 
update_host_type(bool printer_change)503 void PhysicalPrinterDialog::update_host_type(bool printer_change)
504 {
505     if (m_presets.empty())
506         return;
507     bool all_presets_are_from_mk3_family = true;
508 
509     for (PresetForPrinter* prstft : m_presets) {
510         std::string preset_name = prstft->get_preset_name();
511         if (Preset* preset = wxGetApp().preset_bundle->printers.find_preset(preset_name)) {
512             std::string model_id = preset->config.opt_string("printer_model");
513             if (preset->vendor && preset->vendor->name == "Prusa Research") {
514                 const std::vector<VendorProfile::PrinterModel>& models = preset->vendor->models;
515                 auto it = std::find_if(models.begin(), models.end(),
516                     [model_id](const VendorProfile::PrinterModel& model) { return model.id == model_id; });
517                 if (it != models.end() && it->family == "MK3")
518                     continue;
519             } else if (!preset->vendor && model_id.rfind("MK3", 0) == 0) {
520                 continue;
521             }
522 
523         }
524         all_presets_are_from_mk3_family = false;
525         break;
526     }
527 
528     Field* ht = m_optgroup->get_field("host_type");
529 
530     wxArrayString types;
531     // Append localized enum_labels
532     assert(ht->m_opt.enum_labels.size() == ht->m_opt.enum_values.size());
533     for (size_t i = 0; i < ht->m_opt.enum_labels.size(); i++) {
534         if (ht->m_opt.enum_values[i] == "prusalink" && !all_presets_are_from_mk3_family)
535             continue;
536         types.Add(_(ht->m_opt.enum_labels[i]));
537     }
538 
539     Choice* choice = dynamic_cast<Choice*>(ht);
540     choice->set_values(types);
541     auto set_to_choice_and_config = [this, choice](PrintHostType type) {
542         choice->set_value(static_cast<int>(type));
543         m_config->set_key_value("host_type", new ConfigOptionEnum<PrintHostType>(type));
544     };
545     if ((printer_change && all_presets_are_from_mk3_family) || (!had_all_mk3 && all_presets_are_from_mk3_family))
546         set_to_choice_and_config(htPrusaLink);
547     else if ((printer_change && !all_presets_are_from_mk3_family) || (!all_presets_are_from_mk3_family && m_config->option<ConfigOptionEnum<PrintHostType>>("host_type")->value == htPrusaLink))
548         set_to_choice_and_config(htOctoPrint);
549     else
550         choice->set_value(m_config->option("host_type")->getInt());
551     had_all_mk3 = all_presets_are_from_mk3_family;
552 }
553 
554 
get_printer_name()555 wxString PhysicalPrinterDialog::get_printer_name()
556 {
557     return m_printer_name->GetValue();
558 }
559 
update_full_printer_names()560 void PhysicalPrinterDialog::update_full_printer_names()
561 {
562     for (PresetForPrinter* preset : m_presets)
563         preset->update_full_printer_name();
564 
565     this->Layout();
566 }
567 
set_printer_technology(PrinterTechnology pt)568 void PhysicalPrinterDialog::set_printer_technology(PrinterTechnology pt)
569 {
570     m_config->set_key_value("printer_technology", new ConfigOptionEnum<PrinterTechnology>(pt));
571     update();
572 }
573 
get_printer_technology()574 PrinterTechnology PhysicalPrinterDialog::get_printer_technology()
575 {
576     return m_printer.printer_technology();
577 }
578 
on_dpi_changed(const wxRect & suggested_rect)579 void PhysicalPrinterDialog::on_dpi_changed(const wxRect& suggested_rect)
580 {
581     const int& em = em_unit();
582 
583     m_add_preset_btn->msw_rescale();
584     m_printhost_browse_btn->msw_rescale();
585     m_printhost_test_btn->msw_rescale();
586     if (m_printhost_cafile_browse_btn)
587         m_printhost_cafile_browse_btn->msw_rescale();
588 
589     m_optgroup->msw_rescale();
590 
591     msw_buttons_rescale(this, em, { wxID_OK, wxID_CANCEL });
592 
593     for (PresetForPrinter* preset : m_presets)
594         preset->msw_rescale();
595 
596     const wxSize& size = wxSize(45 * em, 35 * em);
597     SetMinSize(size);
598 
599     Fit();
600     Refresh();
601 }
602 
OnOK(wxEvent & event)603 void PhysicalPrinterDialog::OnOK(wxEvent& event)
604 {
605     wxString printer_name = m_printer_name->GetValue();
606     if (printer_name.IsEmpty()) {
607         warning_catcher(this, _L("The supplied name is empty. It can't be saved."));
608         return;
609     }
610     if (printer_name == m_default_name) {
611         warning_catcher(this, _L("You should change the name of your printer device."));
612         return;
613     }
614 
615     PhysicalPrinterCollection& printers = wxGetApp().preset_bundle->physical_printers;
616     const PhysicalPrinter* existing = printers.find_printer(into_u8(printer_name), false);
617     if (existing && into_u8(printer_name) != printers.get_selected_printer_name())
618     {
619         wxString msg_text = from_u8((boost::format(_u8L("Printer with name \"%1%\" already exists.")) % existing->name/*printer_name*/).str());
620         msg_text += "\n" + _L("Replace?");
621         wxMessageDialog dialog(nullptr, msg_text, _L("Warning"), wxICON_WARNING | wxYES | wxNO);
622 
623         if (dialog.ShowModal() == wxID_NO)
624             return;
625 
626         m_printer.name = existing->name;
627     }
628 
629     std::set<std::string> repeat_presets;
630     m_printer.reset_presets();
631     for (PresetForPrinter* preset : m_presets) {
632         if (!m_printer.add_preset(preset->get_preset_name()))
633             repeat_presets.emplace(preset->get_preset_name());
634     }
635 
636     if (!repeat_presets.empty())
637     {
638         wxString repeatable_presets = "\n";
639         for (const std::string& preset_name : repeat_presets)
640             repeatable_presets += "    " + from_u8(preset_name) + "\n";
641         repeatable_presets += "\n";
642 
643         wxString msg_text = from_u8((boost::format(_u8L("Following printer preset(s) is duplicated:%1%"
644                                                         "The above preset for printer \"%2%\" will be used just once.")) % repeatable_presets % printer_name).str());
645         wxMessageDialog dialog(nullptr, msg_text, _L("Warning"), wxICON_WARNING | wxOK | wxCANCEL);
646         if (dialog.ShowModal() == wxID_CANCEL)
647             return;
648     }
649 
650     std::string renamed_from;
651     // temporary save previous printer name if it was edited
652     if (m_printer.name != into_u8(m_default_name) &&
653         m_printer.name != into_u8(printer_name))
654         renamed_from = m_printer.name;
655 
656     //update printer name, if it was changed
657     m_printer.set_name(into_u8(printer_name));
658 
659     // save new physical printer
660     printers.save_printer(m_printer, renamed_from);
661 
662     if (m_printer.preset_names.find(printers.get_selected_printer_preset_name()) == m_printer.preset_names.end()) {
663         // select first preset for this printer
664         printers.select_printer(m_printer);
665         // refresh preset list on Printer Settings Tab
666         wxGetApp().get_tab(Preset::TYPE_PRINTER)->select_preset(printers.get_selected_printer_preset_name());
667     }
668     else
669         wxGetApp().get_tab(Preset::TYPE_PRINTER)->update_preset_choice();
670 
671     event.Skip();
672 }
673 
AddPreset(wxEvent & event)674 void PhysicalPrinterDialog::AddPreset(wxEvent& event)
675 {
676     m_presets.emplace_back(new PresetForPrinter(this));
677     // enable DELETE button for the first preset, if was disabled
678     m_presets.front()->AllowDelete();
679 
680     m_presets_sizer->Add(m_presets.back()->sizer(), 1, wxEXPAND | wxTOP, BORDER_W);
681     update_full_printer_names();
682     this->Fit();
683 
684     update_host_type(true);
685 }
686 
DeletePreset(PresetForPrinter * preset_for_printer)687 void PhysicalPrinterDialog::DeletePreset(PresetForPrinter* preset_for_printer)
688 {
689     if (m_presets.size() == 1) {
690         wxString msg_text = _L("It's not possible to delete the last related preset for the printer.");
691         wxMessageDialog dialog(nullptr, msg_text, _L("Information"), wxICON_INFORMATION | wxOK);
692         dialog.ShowModal();
693         return;
694     }
695 
696     assert(preset_for_printer);
697     auto it = std::find(m_presets.begin(), m_presets.end(), preset_for_printer);
698     if (it == m_presets.end())
699         return;
700 
701     const int remove_id = it - m_presets.begin();
702     m_presets_sizer->Remove(remove_id);
703     delete preset_for_printer;
704     m_presets.erase(it);
705 
706     if (m_presets.size() == 1)
707         m_presets.front()->SuppressDelete();
708 
709     this->Layout();
710     this->Fit();
711 
712     update_host_type(true);
713 }
714 
715 }}    // namespace Slic3r::GUI
716