diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index bb5a4e2af56..c42068a2a5a 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -433,17 +433,25 @@ void MainWindow::evaluate_script(QString script, const bool quiet) { QScriptValue value = script_engine->evaluate(script, filename); if(script_engine->hasUncaughtException()) { + QScriptValue js_exception = script_engine->uncaughtException(); + QScriptValue js_bt =js_exception.property("backtrace"); + QStringList bt = script_engine->uncaughtExceptionBacktrace(); + if(js_bt.isValid()) { + QStringList other_bt; + qScriptValueToSequence(js_bt, other_bt); + if(!other_bt.isEmpty()) bt = other_bt; + } if(!quiet) { QTextStream err(stderr); err << "Qt Script exception:\n" - << script_engine->uncaughtException().toString() + << js_exception.toString() << "\nBacktrace:\n"; - Q_FOREACH(QString line, script_engine->uncaughtExceptionBacktrace()) { + Q_FOREACH(QString line, bt) { err << " " << line << "\n"; } } throw CGAL::Three::Script_exception - (script_engine->uncaughtException().toString().toStdString()); + (script_engine->uncaughtException().toString(), bt); } else if(!quiet && !value.isNull() && !value.isUndefined()) { QTextStream(stderr) << "Qt Script evaluated to \"" @@ -468,6 +476,10 @@ void MainWindow::enableScriptDebugger(bool b /* = true */) if(b) { debugger->action(QScriptEngineDebugger::InterruptAction)->trigger(); } + else { + std::cerr << "Detach the script debugger\n"; + debugger->detach(); + } } return; # endif @@ -1389,6 +1401,13 @@ bool MainWindow::loadScript(QFileInfo info) return false; } +void MainWindow::throw_exception() { + wrap_a_call_to_cpp([]() { + throw std::runtime_error("Exception thrown in " + "MainWindow::throw_exception()"); + }, this, __FILE__, __LINE__); +} + void MainWindow::on_actionLoadScript_triggered() { #if defined(QT_SCRIPT_LIB) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.h b/Polyhedron/demo/Polyhedron/MainWindow.h index 5da16e3ce9a..64724f88ca5 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.h +++ b/Polyhedron/demo/Polyhedron/MainWindow.h @@ -210,6 +210,8 @@ public Q_SLOTS: */ void enableScriptDebugger(bool = true); + /// This slot is used to test exception handling in Qt Scripts. + void throw_exception(); protected Q_SLOTS: //!Gets the new selected item(s) from the sceneView and updates the scene diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/Trivial_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PCA/Trivial_plugin.cpp index 395c03a2737..a6b8a23fc12 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PCA/Trivial_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/Trivial_plugin.cpp @@ -139,13 +139,11 @@ private: }; #include -#include using namespace CGAL::Three; class Polyhedron_demo_trivial_plugin : public QObject, - public Polyhedron_demo_plugin_interface, - protected QScriptable + public Polyhedron_demo_plugin_interface { Q_OBJECT Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) @@ -163,13 +161,6 @@ public: return false;} public Q_SLOTS: - /// This slot is used to test exception handling in Qt Scripts. - void throw_exception() { - wrap_a_call_to_cpp([]() { - throw std::runtime_error("Exception thrown in " - "Trivial_plugin::throw_exception()"); - }, this, __FILE__, __LINE__); - } void bbox(); void enableAction(); diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo.cpp index 3225d641353..45add22401f 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo.cpp @@ -47,11 +47,12 @@ Polyhedron_demo::Polyhedron_demo(int& argc, char **argv, QCommandLineOption no_try_catch("no-try-catch", tr("Do not catch uncaught exceptions.")); parser.addOption(no_try_catch); -#ifdef QT_SCRIPTTOOLS_LIB QCommandLineOption debug_scripts("debug-scripts", tr("Use the scripts debugger.")); parser.addOption(debug_scripts); -#endif + QCommandLineOption no_debug_scripts("no-debug-scripts", + tr("Do not use the scripts debugger.")); + parser.addOption(no_debug_scripts); QCommandLineOption no_autostart("no-autostart", tr("Ignore the autostart.js file, if any.")); parser.addOption(no_autostart); @@ -74,7 +75,16 @@ Polyhedron_demo::Polyhedron_demo(int& argc, char **argv, if(parser.isSet(debug_scripts)) { mainWindow.enableScriptDebugger(); } + if(parser.isSet(no_debug_scripts)) { + mainWindow.enableScriptDebugger(false); + } +#else + if(parser.isSet(debug_scripts)) { + std::cerr << "Qt Script Tools have not been configured!"; + abort(); + } #endif + mainWindow.loadScript(":/cgal/Polyhedron_3/javascript/lib.js"); QFileInfo autostart_js("autostart.js"); if(!parser.isSet(no_autostart) && autostart_js.exists()) { diff --git a/Three/include/CGAL/Three/exceptions.h b/Three/include/CGAL/Three/exceptions.h index 2512d261eb3..5f3aeda5a75 100644 --- a/Three/include/CGAL/Three/exceptions.h +++ b/Three/include/CGAL/Three/exceptions.h @@ -26,17 +26,23 @@ #include #include #include +#include namespace CGAL{ namespace Three{ -struct Script_exception : public std::runtime_error { - Script_exception(const std::string& what_arg) - : std::runtime_error(what_arg) - {} - Script_exception(QString what_arg) +class Script_exception : public std::runtime_error { + QStringList bt; +public: + Script_exception(QString what_arg, + QStringList backtrace) : std::runtime_error(what_arg.toStdString()) + , bt(backtrace) {} + + QStringList backtrace() const { + return bt; + } }; template @@ -73,14 +79,41 @@ wrap_a_call_to_cpp(Callable f, return f(); } catch(const std::exception& e) { + const Script_exception* se = dynamic_cast(&e); QScriptContext* context = qs->context(); - if(c == PARENT_CONTEXT) context = context->parentContext(); - QString error = QObject::tr("Error"); - if(file != 0) error += QObject::tr(" at file %1").arg(file); - if(line != -1) error += QString(":%1").arg(line); - error += QString(":\n%1").arg(e.what()); + QStringList qt_bt = context->backtrace(); + if(se) qt_bt = se->backtrace(); + std::cerr << "Backtrace:\n"; + Q_FOREACH(QString s, qt_bt) + { + std::cerr << " " << qPrintable(s) << std::endl; + } + context = context->parentContext(); + if(c == PARENT_CONTEXT) { + std::cerr << "> parent"; + context = context->parentContext(); + } else { + std::cerr << "> current"; + } + std::cerr << " context: " + << qPrintable(context->toString()) << std::endl; + QString error; + if(se) { + error = se->what(); + } else { + error = QObject::tr("Error"); + QString context; + if(file != 0) context += QObject::tr(" at file %1").arg(file); + if(line != -1) context += QString(":%1").arg(line); + if(!context.isNull()) { + error += context; + qt_bt.push_front(QObject::tr("") + context); + } + error += QString(": %1").arg(e.what()); + } QScriptValue v = context->throwError(error); - v.setProperty("backtrace", context->backtrace().join(";")); + v.setProperty("backtrace", + qScriptValueFromSequence(context->engine(), qt_bt)); std::cerr << "result after throwError: " << qPrintable(v.toString()) << std::endl; return Return_type();