GUI initialization extracted from PrusaSlicer.cpp to GUI_Init.cpp/hpp.

Implemented try/catch blocks for Slic3r exceptions and std::exceptions
with GUI error reporting. This is extremely important to report
corruption of PrusaSlicer.ini.
This commit is contained in:
Vojtech Bubnik 2020-10-22 16:28:49 +02:00
parent 0f9faeda98
commit 027ab4fb02
8 changed files with 163 additions and 131 deletions

View File

@ -27,6 +27,7 @@ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
src/slic3r/GUI/GUI.cpp
src/slic3r/GUI/GUI_App.cpp
src/slic3r/GUI/GUI_Init.cpp
src/slic3r/GUI/GUI_ObjectLayers.cpp
src/slic3r/GUI/GUI_ObjectList.cpp
src/slic3r/GUI/GUI_ObjectManipulation.cpp

View File

@ -45,18 +45,12 @@
#include "libslic3r/Format/OBJ.hpp"
#include "libslic3r/Format/SL1.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/AppConfig.hpp"
#include "libslic3r/Thread.hpp"
#include "PrusaSlicer.hpp"
#ifdef SLIC3R_GUI
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/3DScene.hpp"
#include "slic3r/GUI/InstanceCheck.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/GUI_Init.hpp"
#endif /* SLIC3R_GUI */
using namespace Slic3r;
@ -578,75 +572,20 @@ int CLI::run(int argc, char **argv)
if (start_gui) {
#ifdef SLIC3R_GUI
// #ifdef USE_WX
#if ENABLE_GCODE_VIEWER
GUI::GUI_App* gui = new GUI::GUI_App(start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor);
if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) {
// G-code viewer is currently not performing instance check, a new G-code viewer is started every time.
bool gui_single_instance_setting = gui->app_config->get("single_instance") == "1";
if (Slic3r::instance_check(argc, argv, gui_single_instance_setting)) {
//TODO: do we have delete gui and other stuff?
return -1;
}
}
#else
GUI::GUI_App *gui = new GUI::GUI_App();
#endif // ENABLE_GCODE_VIEWER
// gui->autosave = m_config.opt_string("autosave");
GUI::GUI_App::SetInstance(gui);
#if ENABLE_GCODE_VIEWER
gui->after_init_loads.set_params(load_configs, m_extra_config, m_input_files, start_as_gcodeviewer);
#else
gui->after_init_loads.set_params(load_configs, m_extra_config, m_input_files);
#endif // ENABLE_GCODE_VIEWER
/*
#if ENABLE_GCODE_VIEWER
gui->CallAfter([gui, this, &load_configs, start_as_gcodeviewer] {
#else
gui->CallAfter([gui, this, &load_configs] {
#endif // ENABLE_GCODE_VIEWER
if (!gui->initialized()) {
return;
}
#if ENABLE_GCODE_VIEWER
if (start_as_gcodeviewer) {
if (!m_input_files.empty())
gui->plater()->load_gcode(wxString::FromUTF8(m_input_files[0].c_str()));
} else {
#endif // ENABLE_GCODE_VIEWER_AS
#if 0
// Load the cummulative config over the currently active profiles.
//FIXME if multiple configs are loaded, only the last one will have an effect.
// We need to decide what to do about loading of separate presets (just print preset, just filament preset etc).
// As of now only the full configs are supported here.
if (!m_print_config.empty())
gui->mainframe->load_config(m_print_config);
#endif
if (!load_configs.empty())
// Load the last config to give it a name at the UI. The name of the preset may be later
// changed by loading an AMF or 3MF.
//FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config.
gui->mainframe->load_config_file(load_configs.back());
// If loading a 3MF file, the config is loaded from the last one.
if (!m_input_files.empty())
gui->plater()->load_files(m_input_files, true, true);
if (!m_extra_config.empty())
gui->mainframe->load_config(m_extra_config);
#if ENABLE_GCODE_VIEWER
}
#endif // ENABLE_GCODE_VIEWER
});
*/
int result = wxEntry(argc, argv);
return result;
#else /* SLIC3R_GUI */
Slic3r::GUI::GUI_InitParams params;
params.argc = argc;
params.argv = argv;
params.load_configs = load_configs;
params.extra_config = std::move(m_extra_config);
params.input_files = std::move(m_input_files);
params.start_as_gcodeviewer = start_as_gcodeviewer;
return Slic3r::GUI::GUI_Run(params);
#else // SLIC3R_GUI
// No GUI support. Just print out a help.
this->print_help(false);
// If started without a parameter, consider it to be OK, otherwise report an error code (no action etc).
return (argc == 0) ? 0 : 1;
#endif /* SLIC3R_GUI */
#endif // SLIC3R_GUI
}
return 0;

View File

@ -73,6 +73,8 @@ set(SLIC3R_GUI_SOURCES
GUI/PresetHints.hpp
GUI/GUI.cpp
GUI/GUI.hpp
GUI/GUI_Init.cpp
GUI/GUI_Init.hpp
GUI/GUI_Preview.cpp
GUI/GUI_Preview.hpp
GUI/GUI_App.cpp

View File

@ -45,7 +45,7 @@ bool SlicingProcessCompletedEvent::critical_error() const
{
try {
this->rethrow_exception();
} catch (const Slic3r::SlicingError &ex) {
} catch (const Slic3r::SlicingError &) {
// Exception derived from SlicingError is non-critical.
return false;
} catch (...) {

View File

@ -1,5 +1,6 @@
#include "libslic3r/Technologies.hpp"
#include "GUI_App.hpp"
#include "GUI_Init.hpp"
#include "GUI_ObjectList.hpp"
#include "GUI_ObjectManipulation.hpp"
#include "I18N.hpp"
@ -538,15 +539,16 @@ static void generic_exception_handle()
}
}
void GUI_App::AfterInitLoads::on_loads(GUI_App* gui)
void GUI_App::post_init()
{
if (!gui->initialized())
return;
assert(initialized());
if (! this->initialized())
throw Slic3r::RuntimeError("Calling post_init() while not yet initialized");
#if ENABLE_GCODE_VIEWER
if (m_start_as_gcodeviewer) {
if (!m_input_files.empty())
gui->plater()->load_gcode(wxString::FromUTF8(m_input_files[0].c_str()));
if (this->init_params->start_as_gcodeviewer) {
if (! this->init_params->input_files.empty())
this->plater()->load_gcode(wxString::FromUTF8(this->init_params->input_files[0].c_str()));
}
else {
#endif // ENABLE_GCODE_VIEWER_AS
@ -556,22 +558,22 @@ void GUI_App::AfterInitLoads::on_loads(GUI_App* gui)
// We need to decide what to do about loading of separate presets (just print preset, just filament preset etc).
// As of now only the full configs are supported here.
if (!m_print_config.empty())
gui->mainframe->load_config(m_print_config);
this->gui->mainframe->load_config(m_print_config);
#endif
if (!m_load_configs.empty())
if (! this->init_params->load_configs.empty())
// Load the last config to give it a name at the UI. The name of the preset may be later
// changed by loading an AMF or 3MF.
//FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config.
gui->mainframe->load_config_file(m_load_configs.back());
this->mainframe->load_config_file(this->init_params->load_configs.back());
// If loading a 3MF file, the config is loaded from the last one.
if (!m_input_files.empty())
gui->plater()->load_files(m_input_files, true, true);
if (!m_extra_config.empty())
gui->mainframe->load_config(m_extra_config);
if (! this->init_params->input_files.empty())
this->plater()->load_files(this->init_params->input_files, true, true);
if (! this->init_params->extra_config.empty())
this->mainframe->load_config(this->init_params->extra_config);
#if ENABLE_GCODE_VIEWER
}
#endif // ENABLE_GCODE_VIEWER
}
}
IMPLEMENT_APP(GUI_App)
@ -647,7 +649,6 @@ void GUI_App::init_app_config()
m_app_conf_exists = app_config->exists();
if (m_app_conf_exists) {
std::string error = app_config->load();
#if ENABLE_GCODE_VIEWER
if (!error.empty()) {
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
if (is_editor()) {
@ -663,14 +664,6 @@ void GUI_App::init_app_config()
"\n\n" + app_config->config_path() + "\n\n" + error);
}
}
#else
if (!error.empty())
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
throw Slic3r::RuntimeError(
_u8L("Error parsing PrusaSlicer config file, it is probably corrupted. "
"Try to manually delete the file to recover from the error. Your user profiles will not be affected.") +
"\n\n" + AppConfig::config_path() + "\n\n" + error);
#endif // ENABLE_GCODE_VIEWER
}
}
@ -855,7 +848,7 @@ bool GUI_App::on_init_inner()
#ifdef WIN32
this->mainframe->register_win32_callbacks();
#endif
this->after_init_loads.on_loads(this);
this->post_init();
}
// Preset updating & Configwizard are done after the above initializations,

View File

@ -24,6 +24,7 @@ class wxNotebook;
struct wxLanguageInfo;
namespace Slic3r {
class AppConfig;
class PresetBundle;
class PresetUpdater;
@ -32,6 +33,7 @@ class PrintHostJobQueue;
class Model;
namespace GUI{
class RemovableDriveManager;
class OtherInstanceMessageHandler;
class MainFrame;
@ -41,6 +43,7 @@ class ObjectSettings;
class ObjectList;
class ObjectLayers;
class Plater;
struct GUI_InitParams;
@ -142,37 +145,6 @@ private:
std::string m_instance_hash_string;
size_t m_instance_hash_int;
// parameters needed for the after OnInit() loads
struct AfterInitLoads
{
std::vector<std::string> m_load_configs;
DynamicPrintConfig m_extra_config;
std::vector<std::string> m_input_files;
#if ENABLE_GCODE_VIEWER
bool m_start_as_gcodeviewer;
#endif // ENABLE_GCODE_VIEWER
void set_params(
const std::vector<std::string>& load_configs,
const DynamicPrintConfig& extra_config,
#if ENABLE_GCODE_VIEWER
const std::vector<std::string>& input_files,
bool start_as_gcodeviewer
#else
const std::vector<std::string>& input_files
#endif // ENABLE_GCODE_VIEWER
) {
m_load_configs = load_configs;
m_extra_config = extra_config;
m_input_files = input_files;
#if ENABLE_GCODE_VIEWER
m_start_as_gcodeviewer = start_as_gcodeviewer;
#endif // ENABLE_GCODE_VIEWER
}
void on_loads(GUI_App* gui);
};
public:
bool OnInit() override;
bool initialized() const { return m_initialized; }
@ -191,9 +163,13 @@ public:
bool is_recreating_gui() const { return m_is_recreating_gui; }
#endif // ENABLE_GCODE_VIEWER
// To be called after the GUI is fully built up.
// Process command line parameters cached in this->init_params,
// load configs, STLs etc.
void post_init();
static std::string get_gl_info(bool format_as_html, bool extensions);
wxGLContext* init_glcontext(wxGLCanvas& canvas);
bool init_opengl();
wxGLContext* init_glcontext(wxGLCanvas& canvas);
bool init_opengl();
static unsigned get_colour_approx_luma(const wxColour &colour);
static bool dark_mode();
@ -267,12 +243,14 @@ public:
Model& model();
// Parameters extracted from the command line to be passed to GUI after initialization.
const GUI_InitParams* init_params { nullptr };
AppConfig* app_config{ nullptr };
PresetBundle* preset_bundle{ nullptr };
PresetUpdater* preset_updater{ nullptr };
MainFrame* mainframe{ nullptr };
Plater* plater_{ nullptr };
AfterInitLoads after_init_loads;
PresetUpdater* get_preset_updater() { return preset_updater; }

View File

@ -0,0 +1,95 @@
#include "GUI_Init.hpp"
#include "libslic3r/AppConfig.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/3DScene.hpp"
#include "slic3r/GUI/InstanceCheck.hpp"
#include "slic3r/GUI/format.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/GUI/Plater.hpp"
// To show a message box if GUI initialization ends up with an exception thrown.
#include <wx/msgdlg.h>
#include <boost/nowide/iostream.hpp>
namespace Slic3r {
namespace GUI {
int GUI_Run(GUI_InitParams &params)
{
try {
#if ENABLE_GCODE_VIEWER
GUI::GUI_App* gui = new GUI::GUI_App(params.start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor);
if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) {
// G-code viewer is currently not performing instance check, a new G-code viewer is started every time.
bool gui_single_instance_setting = gui->app_config->get("single_instance") == "1";
if (Slic3r::instance_check(params.argc, params.argv, gui_single_instance_setting)) {
//TODO: do we have delete gui and other stuff?
return -1;
}
}
#else
GUI::GUI_App *gui = new GUI::GUI_App();
#endif // ENABLE_GCODE_VIEWER
// gui->autosave = m_config.opt_string("autosave");
GUI::GUI_App::SetInstance(gui);
gui->init_params = &params;
/*
#if ENABLE_GCODE_VIEWER
gui->CallAfter([gui, this, &load_configs, params.start_as_gcodeviewer] {
#else
gui->CallAfter([gui, this, &load_configs] {
#endif // ENABLE_GCODE_VIEWER
if (!gui->initialized()) {
return;
}
#if ENABLE_GCODE_VIEWER
if (params.start_as_gcodeviewer) {
if (!m_input_files.empty())
gui->plater()->load_gcode(wxString::FromUTF8(m_input_files[0].c_str()));
} else {
#endif // ENABLE_GCODE_VIEWER_AS
#if 0
// Load the cummulative config over the currently active profiles.
//FIXME if multiple configs are loaded, only the last one will have an effect.
// We need to decide what to do about loading of separate presets (just print preset, just filament preset etc).
// As of now only the full configs are supported here.
if (!m_print_config.empty())
gui->mainframe->load_config(m_print_config);
#endif
if (!load_configs.empty())
// Load the last config to give it a name at the UI. The name of the preset may be later
// changed by loading an AMF or 3MF.
//FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config.
gui->mainframe->load_config_file(load_configs.back());
// If loading a 3MF file, the config is loaded from the last one.
if (!m_input_files.empty())
gui->plater()->load_files(m_input_files, true, true);
if (!m_extra_config.empty())
gui->mainframe->load_config(m_extra_config);
#if ENABLE_GCODE_VIEWER
}
#endif // ENABLE_GCODE_VIEWER
});
*/
int result = wxEntry(params.argc, params.argv);
return result;
} catch (const Slic3r::Exception &ex) {
boost::nowide::cerr << ex.what() << std::endl;
wxMessageBox(boost::nowide::widen(ex.what()), _L("PrusaSlicer GUI initialization failed"), wxICON_STOP);
} catch (const std::exception &ex) {
boost::nowide::cerr << "PrusaSlicer GUI initialization failed: " << ex.what() << std::endl;
wxMessageBox(format_wxstr(_L("Fatal error, exception catched: %1%"), ex.what()), _L("PrusaSlicer GUI initialization failed"), wxICON_STOP);
}
// error
return 1;
}
}
}

View File

@ -0,0 +1,24 @@
#ifndef slic3r_GUI_Init_hpp_
#define slic3r_GUI_Init_hpp_
namespace Slic3r {
namespace GUI {
struct GUI_InitParams
{
int argc;
char **argv;
std::vector<std::string> load_configs;
DynamicPrintConfig extra_config;
std::vector<std::string> input_files;
bool start_as_gcodeviewer;
};
int GUI_Run(GUI_InitParams &params);
} // namespace GUI
} // namespace Slic3r
#endif slic3r_GUI_Init_hpp_