diff --git a/src/libslic3r/Exception.hpp b/src/libslic3r/Exception.hpp index 1b8ad50a7..e796e3cc1 100644 --- a/src/libslic3r/Exception.hpp +++ b/src/libslic3r/Exception.hpp @@ -24,7 +24,17 @@ SLIC3R_DERIVE_EXCEPTION(HostNetworkError, IOError); 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); +//SLIC3R_DERIVE_EXCEPTION(SlicingError, Exception); +class SlicingError : public Exception +{ +public: + using Exception::Exception; + SlicingError(std::string const &msg, size_t objectId) : Exception(msg), objectId_(objectId) {} + size_t objectId() const { return objectId_; } + +private: + size_t objectId_ = 0; +}; #undef SLIC3R_DERIVE_EXCEPTION } // namespace Slic3r diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 97d35e000..4c8c12dea 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -677,8 +677,7 @@ std::vector GCode::collect_layers_to_print(const PrintObjec // first layer may result in skirt/brim in the air and maybe other issues. if (layers_to_print.size() == 1u) { if (!has_extrusions) - throw Slic3r::SlicingError(_(L("One object has empty initial layer and can't be printed. Please Cut the bottom or enable supports.")) + "\n" + - _(L("Object")) + ": " + object.model_object()->name); + throw Slic3r::SlicingError(_(L("One object has empty initial layer and can't be printed. Please Cut the bottom or enable supports.")), object.id().id); } // In case there are extrusions on this layer, check there is a layer to lay it on. diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 4f62c33e6..fa1c60811 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -69,10 +69,10 @@ bool SlicingProcessCompletedEvent::invalidate_plater() const return false; } -std::pair SlicingProcessCompletedEvent::format_error_message() const +std::pair SlicingProcessCompletedEvent::format_error_message() const { std::string error; - bool monospace = false; + size_t monospace = 0; try { this->rethrow_exception(); } catch (const std::bad_alloc &ex) { @@ -84,7 +84,10 @@ std::pair SlicingProcessCompletedEvent::format_error_message( _u8L("Please save project and restart the program. "); } catch (PlaceholderParserError &ex) { error = ex.what(); - monospace = true; + monospace = 1; + } catch (SlicingError &ex) { + error = ex.what(); + monospace = ex.objectId(); } catch (std::exception &ex) { error = ex.what(); } catch (...) { diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index d369b010b..c2a1cf280 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -60,7 +60,7 @@ public: void rethrow_exception() const { assert(this->error()); assert(m_exception); std::rethrow_exception(m_exception); } // Produce a human readable message to be displayed by a notification or a message box. // 2nd parameter defines whether the output should be displayed with a monospace font. - std::pair format_error_message() const; + std::pair format_error_message() const; private: StatusType m_status; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 96c86d970..9bdc07a22 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -8413,7 +8413,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) break; case SLICING_ERROR: if (state) - notification_manager.push_slicing_error_notification(text); + notification_manager.push_slicing_error_notification(text, nullptr); else notification_manager.close_slicing_error_notification(text); break; diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 0b51436a6..7317fb97b 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -7,6 +7,7 @@ #include "ObjectDataViewModel.hpp" #include "GUI_ObjectList.hpp" #include "ParamsPanel.hpp" +#include "MainFrame.hpp" #include "libslic3r/Config.hpp" #include "format.hpp" @@ -1582,7 +1583,9 @@ void NotificationManager::push_validate_error_notification(StringObjectException if (iter != objects.end()) wxGetApp().params_panel()->switch_to_object(); wxGetApp().sidebar().jump_to_option(opt, Preset::TYPE_PRINT, L""); - } + } else { + wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); + } return false; } : std::function(); auto link = (mo || !error.opt_key.empty()) ? _u8L("Jump to") : ""; @@ -1592,10 +1595,21 @@ void NotificationManager::push_validate_error_notification(StringObjectException set_slicing_progress_hidden(); } -void NotificationManager::push_slicing_error_notification(const std::string& text) +void NotificationManager::push_slicing_error_notification(const std::string &text, ModelObject const *obj) { - set_all_slicing_errors_gray(false); - push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotificationLevel, 0, _u8L("Error:") + "\n" + text }, 0); + auto callback = obj ? [id = obj->id()](wxEvtHandler *) { + auto & objects = wxGetApp().model().objects; + auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }); + if (iter != objects.end()) { + wxGetApp().obj_list()->select_items({{*iter, nullptr}}); + wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); + } + return false; + } : std::function(); + auto link = callback ? _u8L("Jump to") : ""; + if (obj) link += std::string(" [") + obj->name + "]"; + set_all_slicing_errors_gray(false); + push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotificationLevel, 0, _u8L("Error:") + "\n" + text, link, callback }, 0); set_slicing_progress_hidden(); } void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, ModelObject const * obj, ObjectID oid, int warning_step, int warning_msg_id) @@ -1603,8 +1617,10 @@ void NotificationManager::push_slicing_warning_notification(const std::string& t auto callback = obj ? [id = obj->id()](wxEvtHandler *) { auto & objects = wxGetApp().model().objects; auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }); - if (iter != objects.end()) + if (iter != objects.end()) { wxGetApp().obj_list()->select_items({{*iter, nullptr}}); + wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); + } return false; } : std::function(); auto link = callback ? _u8L("Jump to") : ""; diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index e5e89ef5b..00947b233 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -188,7 +188,7 @@ public: void upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host); void upload_job_notification_show_error(int id, const std::string& filename, const std::string& host); // Creates Slicing Error notification with a custom text and no fade out. - void push_slicing_error_notification(const std::string& text); + void push_slicing_error_notification(const std::string &text, ModelObject const *obj); // Creates Slicing Warning notification with a custom text and no fade out. void push_slicing_warning_notification(const std::string &text, bool gray, ModelObject const *obj, ObjectID oid, int warning_step, int warning_msg_id); // marks slicing errors as gray diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 6fd82c6cb..b861ba38b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5519,18 +5519,22 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt) // This bool stops showing export finished notification even when process_completed_with_error is false bool has_error = false; if (evt.error()) { - std::pair message = evt.format_error_message(); + std::pair message = evt.format_error_message(); if (evt.critical_error()) { if (q->m_tracking_popup_menu) { // We don't want to pop-up a message box when tracking a pop-up menu. // We postpone the error message instead. q->m_tracking_popup_menu_error_message = message.first; } else { - show_error(q, message.first, message.second); + show_error(q, message.first, message.second != 0); notification_manager->set_slicing_progress_hidden(); } - } else - notification_manager->push_slicing_error_notification(message.first); + } else { + ModelObject const *model_object = nullptr; + const PrintObject *print_object = this->background_process.m_fff_print->get_object(ObjectID(message.second)); + if (print_object) model_object = print_object->model_object(); + notification_manager->push_slicing_error_notification(message.first, model_object); + } if (evt.invalidate_plater()) { // BBS