R Console exceptions

.. don't crash when cannot initialise (e.g. when RInside not
   available or R is not installed)

.. handle messaging via signals to trap 'late' messages from
   the R Runtime
This commit is contained in:
Mark Liversedge
2016-04-14 21:16:13 +01:00
parent 24861bdf10
commit 9effcfeef1
5 changed files with 108 additions and 77 deletions

View File

@@ -33,6 +33,7 @@ RConsole::RConsole(Context *context, QWidget *parent)
putData(GCColor::invertColor(GColor(CPLOTBACKGROUND)), "\n> ");
connect(context, SIGNAL(configChanged(qint32)), this, SLOT(configChanged(qint32)));
connect(context, SIGNAL(rMessage(QString)), this, SLOT(rMessage(QString)));
// history position
hpos=0;
@@ -52,6 +53,11 @@ RConsole::configChanged(qint32)
setStyleSheet(TabView::ourStyleSheet());
}
void
RConsole::rMessage(QString x)
{
putData(GColor(CPLOTMARKER), x);
}
void RConsole::putData(QColor color, QString string)
{
@@ -133,7 +139,7 @@ void RConsole::keyPressEvent(QKeyEvent *e)
SEXP ret = rtool->R->parseEval(line.toStdString());
// if this isn't an assignment then print the result
if(!line.contains("<-")) Rcpp::print(ret);
if(!Rf_isNull(ret) && !line.contains("<-")) Rcpp::print(ret);
QStringList &response = rtool->callbacks->getConsoleOutput();
putData(GColor(CPLOTMARKER), response.join(""));
@@ -216,20 +222,24 @@ RChart::RChart(Context *context) : GcChartWindow(context)
mainLayout->setContentsMargins(2,0,2,2);
setChartLayout(mainLayout);
splitter = new QSplitter(Qt::Horizontal, this);
splitter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
splitter->setHandleWidth(1);
mainLayout->addWidget(splitter);
// if we failed to startup the RInside properly
// then disable the RConsole altogether.
if (rtool->R) {
splitter = new QSplitter(Qt::Horizontal, this);
splitter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
splitter->setHandleWidth(1);
mainLayout->addWidget(splitter);
console = new RConsole(context, this);
splitter->addWidget(console);
QWidget *surface = new QSvgWidget(this);
surface->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
splitter->addWidget(surface);
console = new RConsole(context, this);
splitter->addWidget(console);
QWidget *surface = new QSvgWidget(this);
surface->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
splitter->addWidget(surface);
QPalette p = palette();
p.setColor(QPalette::Base, GColor(CPLOTBACKGROUND));
p.setColor(QPalette::Text, GCColor::invertColor(GColor(CPLOTBACKGROUND)));
surface->setPalette(p);
QPalette p = palette();
p.setColor(QPalette::Base, GColor(CPLOTBACKGROUND));
p.setColor(QPalette::Text, GCColor::invertColor(GColor(CPLOTBACKGROUND)));
surface->setPalette(p);
}
}

View File

@@ -33,39 +33,6 @@
#include "Context.h"
#include "Athlete.h"
class RInside;
class RCallbacks;
class QString;
extern RInside *gc_RInside;
extern RCallbacks *gc_RCallbacks;
extern QString gc_RVersion;
extern Context *gc_RContext;
// global singleton catches output from R interpreter
// first come first served on output
class RCallbacks : public Callbacks {
public:
// see inst/includes/Callbacks.h for a list of all overrideable methods
virtual void WriteConsole(const std::string& line, int type) {
//qDebug()<<"Console>>" <<type<< QString::fromStdString(line);
strings << QString::fromStdString(line);
};
virtual void ShowMessage(const char* message) {
//qDebug()<<"M:" << QString(message);
strings << QString(message);
}
virtual bool has_ShowMessage() { return true; }
virtual bool has_WriteConsole() { return true; }
QStringList &getConsoleOutput() {
return strings;
}
private:
QStringList strings;
};
// a console widget to type commands and display response
class RConsole : public QTextEdit {
@@ -77,6 +44,7 @@ signals:
public slots:
void configChanged(qint32);
void rMessage(QString);
public:
explicit RConsole(Context *context, QWidget *parent = 0);

View File

@@ -31,39 +31,58 @@
RTool::RTool(int argc, char**argv)
{
// setup the R runtime elements
R = new RInside(argc,argv);
callbacks = new RCallbacks;
R->set_callbacks(callbacks);
bool failed = false;
try {
// lets get the version early for the about dialog
R->parseEvalNT("print(R.version.string)");
QStringList &strings = callbacks->getConsoleOutput();
if (strings.count() == 3) {
QRegExp exp("^.*([0-9]+\\.[0-9]+\\.[0-9]+).*$");
if (exp.exactMatch(strings[1])) version = exp.cap(1);
else version = strings[1];
R = new RInside(argc,argv);
callbacks = new RCallbacks;
R->set_callbacks(callbacks);
// lets get the version early for the about dialog
R->parseEvalNT("print(R.version.string)");
QStringList &strings = callbacks->getConsoleOutput();
if (strings.count() == 3) {
QRegExp exp("^.*([0-9]+\\.[0-9]+\\.[0-9]+).*$");
if (exp.exactMatch(strings[1])) version = exp.cap(1);
else version = strings[1];
}
strings.clear();
// set the "GC" object and methods
context = NULL;
(*R)["GC.version"] = VERSION_STRING;
(*R)["GC.build"] = VERSION_LATEST;
// Access into the GC data
(*R)["GC.activities"] = Rcpp::InternalFunction(RTool::activities);
(*R)["GC.activity"] = Rcpp::InternalFunction(RTool::activity);
// TBD
// GC.metrics - list of activities and their metrics
// GC.activity - single activity and its data series
// GC.seasons - configured seasons
// GC.season - currently selected season
// GC.config - configuration (zones, units etc)
// the following are already set in RChart on a per call basis
// "GC.athlete" "GC.athlete.home"
} catch(std::exception& ex) {
qDebug()<<"RInside error:" << ex.what();
failed = true;
} catch(...) {
failed = true;
}
strings.clear();
// set the "GC" object and methods
context = NULL;
(*R)["GC.version"] = VERSION_STRING;
(*R)["GC.build"] = VERSION_LATEST;
// Access into the GC data
(*R)["GC.activities"] = Rcpp::InternalFunction(RTool::activities);
(*R)["GC.activity"] = Rcpp::InternalFunction(RTool::activity);
// TBD
// GC.metrics - list of activities and their metrics
// GC.activity - single activity and its data series
// GC.seasons - configured seasons
// GC.season - currently selected season
// GC.config - configuration (zones, units etc)
// the following are already set in RChart on a per call basis
// "GC.athlete" "GC.athlete.home"
// ack, disable R runtime
if (failed) {
qDebug() << "RInside/Rcpp failed to start, RConsole disabled.";
version = "none";
R = NULL;
}
}
Rcpp::DatetimeVector

View File

@@ -21,6 +21,7 @@
#ifndef _GC_RTool_h
class RCallbacks;
class RTool {
public:
@@ -35,5 +36,34 @@ class RTool {
static Rcpp::DatetimeVector activities();
};
// there is a global instance created in main
extern RTool *rtool;
// global singleton catches output from R interpreter
// first come first served on output
class RCallbacks : public Callbacks {
public:
// see inst/includes/Callbacks.h for a list of all overrideable methods
virtual void WriteConsole(const std::string& line, int type) {
//qDebug()<<"Console>>" <<type<< QString::fromStdString(line);
if (rtool && rtool->context) rtool->context->notifyRMessage(QString::fromStdString(line));
else strings << QString::fromStdString(line);
};
//virtual void ShowMessage(const char* message) {
//qDebug()<<"M:" << QString(message);
//strings << QString(message);
//}
//virtual bool has_ShowMessage() { return true; }
virtual bool has_WriteConsole() { return true; }
QStringList &getConsoleOutput() {
return strings;
}
private:
QStringList strings;
};
#endif

View File

@@ -190,6 +190,7 @@ class Context : public QObject
void notifyRefreshEnd() { emit refreshEnd(); }
void notifyRefreshUpdate(QDate date) { emit refreshUpdate(date); }
void notifyRMessage(QString x) { emit rMessage(x); }
void notifyCompareIntervals(bool state);
void notifyCompareIntervalsChanged();
@@ -261,6 +262,9 @@ class Context : public QObject
void pause();
void stop();
// R messages
void rMessage(QString);
// comparing things
void compareIntervalsStateChanged(bool);
void compareIntervalsChanged();