diff --git a/src/libslic3r/Exception.hpp b/src/libslic3r/Exception.hpp index 287905533..fababa47d 100644 --- a/src/libslic3r/Exception.hpp +++ b/src/libslic3r/Exception.hpp @@ -20,7 +20,8 @@ SLIC3R_DERIVE_EXCEPTION(OutOfRange, LogicError); SLIC3R_DERIVE_EXCEPTION(IOError, CriticalException); SLIC3R_DERIVE_EXCEPTION(FileIOError, IOError); SLIC3R_DERIVE_EXCEPTION(HostNetworkError, IOError); -SLIC3R_DERIVE_EXCEPTION(ExportError, CriticalException); +SLIC3R_DERIVE_EXCEPTION(ExportError, CriticalException); +SLIC3R_DERIVE_EXCEPTION(PlaceholderParserError, RuntimeError); // Runtime exception produced by Slicer. Such exception cancels the slicing process and it shall be shown in notifications. SLIC3R_DERIVE_EXCEPTION(SlicingError, Exception); #undef SLIC3R_DERIVE_EXCEPTION diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ee9f06687..743c3f535 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -756,7 +756,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re msg += " !!!!! Failed to process the custom G-code template ...\n"; msg += "and\n"; msg += " !!!!! End of an error report for the custom G-code template ...\n"; - throw Slic3r::RuntimeError(msg); + throw Slic3r::PlaceholderParserError(msg); } BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info(); diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 0434e3a0a..9bbc2cd8d 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -1304,7 +1304,7 @@ static std::string process_macro(const std::string &templ, client::MyContext &co if (!context.error_message.empty()) { if (context.error_message.back() != '\n' && context.error_message.back() != '\r') context.error_message += '\n'; - throw Slic3r::RuntimeError(context.error_message); + throw Slic3r::PlaceholderParserError(context.error_message); } return output; } diff --git a/src/libslic3r/PlaceholderParser.hpp b/src/libslic3r/PlaceholderParser.hpp index 14be020ac..40a7d5b53 100644 --- a/src/libslic3r/PlaceholderParser.hpp +++ b/src/libslic3r/PlaceholderParser.hpp @@ -40,11 +40,11 @@ public: const DynamicConfig* external_config() const { return m_external_config; } // Fill in the template using a macro processing language. - // Throws Slic3r::RuntimeError on syntax or runtime error. + // Throws Slic3r::PlaceholderParserError on syntax or runtime error. std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr) const; // Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax. - // Throws Slic3r::RuntimeError on syntax or runtime error. + // Throws Slic3r::PlaceholderParserError on syntax or runtime error. static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr); // Update timestamp, year, month, day, hour, minute, second variables at the provided config. diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index 7cdf6448c..fb5e102c1 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -69,7 +69,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str filename = boost::filesystem::change_extension(filename, default_ext); return filename.string(); } catch (std::runtime_error &err) { - throw Slic3r::RuntimeError(L("Failed processing of the output_filename_format template.") + "\n" + err.what()); + throw Slic3r::PlaceholderParserError(L("Failed processing of the output_filename_format template.") + "\n" + err.what()); } } diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index d822c9873..dc7ffe152 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -221,16 +221,16 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt } } -void show_error(wxWindow* parent, const wxString& message) +void show_error(wxWindow* parent, const wxString& message, bool monospaced_font) { - ErrorDialog msg(parent, message); + ErrorDialog msg(parent, message, monospaced_font); msg.ShowModal(); } -void show_error(wxWindow* parent, const char* message) +void show_error(wxWindow* parent, const char* message, bool monospaced_font) { assert(message); - show_error(parent, wxString::FromUTF8(message)); + show_error(parent, wxString::FromUTF8(message), monospaced_font); } void show_error_id(int id, const std::string& message) diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index cf133971e..a90115933 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -39,9 +39,11 @@ extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_ // Change option value in config void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); -void show_error(wxWindow* parent, const wxString& message); -void show_error(wxWindow* parent, const char* message); -inline void show_error(wxWindow* parent, const std::string& message) { show_error(parent, message.c_str()); } +// If monospaced_font is true, the error message is displayed using html
tags, +// so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser. +void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false); +void show_error(wxWindow* parent, const char* message, bool monospaced_font = false); +inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) { show_error(parent, message.c_str(), monospaced_font); } void show_error_id(int id, const std::string& message); // For Perl void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString()); void show_info(wxWindow* parent, const char* message, const char* title = nullptr); diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index 5b583ba2a..5ca8aa49d 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -64,12 +64,9 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he SetSizerAndFit(topsizer); } -MsgDialog::~MsgDialog() {} - - // ErrorDialog -ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) +ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg, bool monospaced_font) : MsgDialog(parent, wxString::Format(_(L("%s error")), SLIC3R_APP_NAME), wxString::Format(_(L("%s has encountered an error")), SLIC3R_APP_NAME), wxID_NONE) @@ -80,17 +77,21 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) { html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), -1)); wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + wxFont monospace = wxSystemSettings::GetFont(wxSYS_ANSI_FIXED_FONT); wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue()); auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()); const int font_size = font.GetPointSize()-1; int size[] = {font_size, font_size, font_size, font_size, font_size, font_size, font_size}; - html->SetFonts(font.GetFaceName(), font.GetFaceName(), size); + html->SetFonts(font.GetFaceName(), monospace.GetFaceName(), size); html->SetBorders(2); std::string msg_escaped = xml_escape(msg.ToUTF8().data()); boost::replace_all(msg_escaped, "\r\n", "
"); boost::replace_all(msg_escaped, "\n", "
"); + if (monospaced_font) + // Code formatting will be preserved. This is useful for reporting errors from the placeholder parser. + msg_escaped = std::string("
") + msg_escaped + "
"; html->SetPage("" + wxString::FromUTF8(msg_escaped.data()) + ""); content_sizer->Add(html, 1, wxEXPAND); } @@ -105,9 +106,5 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) Fit(); } -ErrorDialog::~ErrorDialog() {} - - - } } diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index 5a4929849..70032089b 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -25,7 +25,7 @@ struct MsgDialog : wxDialog MsgDialog(const MsgDialog &) = delete; MsgDialog &operator=(MsgDialog &&) = delete; MsgDialog &operator=(const MsgDialog &) = delete; - virtual ~MsgDialog(); + virtual ~MsgDialog() = default; // TODO: refactor with CreateStdDialogButtonSizer usage @@ -52,12 +52,14 @@ protected: class ErrorDialog : public MsgDialog { public: - ErrorDialog(wxWindow *parent, const wxString &msg); + // If monospaced_font is true, the error message is displayed using html
tags, + // so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser. + ErrorDialog(wxWindow *parent, const wxString &msg, bool courier_font); ErrorDialog(ErrorDialog &&) = delete; ErrorDialog(const ErrorDialog &) = delete; ErrorDialog &operator=(ErrorDialog &&) = delete; ErrorDialog &operator=(const ErrorDialog &) = delete; - virtual ~ErrorDialog(); + virtual ~ErrorDialog() = default; private: wxString msg; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8c4f8eed2..178644af4 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3652,7 +3652,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt) else show_error(q, message); } else - notification_manager->push_slicing_error_notification(message, *q->get_current_canvas3D()); + notification_manager->push_slicing_error_notification(message, *q->get_current_canvas3D()); this->statusbar()->set_status_text(from_u8(message)); if (evt.invalidate_plater()) { @@ -5216,9 +5216,12 @@ void Plater::export_gcode(bool prefer_removable) if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) return; default_output_file = this->p->background_process.output_filepath_for_project(into_path(get_project_filename(".3mf"))); - } - catch (const std::exception &ex) { - show_error(this, ex.what()); + } catch (const Slic3r::PlaceholderParserError &ex) { + // Show the error with monospaced font. + show_error(this, ex.what(), true); + return; + } catch (const std::exception &ex) { + show_error(this, ex.what(), false); return; } default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); @@ -5576,9 +5579,12 @@ void Plater::send_gcode() if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) return; default_output_file = this->p->background_process.output_filepath_for_project(into_path(get_project_filename(".3mf"))); - } - catch (const std::exception &ex) { - show_error(this, ex.what()); + } catch (const Slic3r::PlaceholderParserError& ex) { + // Show the error with monospaced font. + show_error(this, ex.what(), true); + return; + } catch (const std::exception& ex) { + show_error(this, ex.what(), false); return; } default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));