Commit f434a6c0 authored by Thomas Friedrichsmeier's avatar Thomas Friedrichsmeier
Browse files

First draft of the R support functions for data and custom previews.

The idea is that the preview box will operate in three different modes:
"plot", as before. "data" for a simple way to send preview data through rk.edi(),
and "custom" to cover all other needs.

Frontend side is not yet done.
parent c84fd672
......@@ -37,20 +37,20 @@ RKPreviewBox::RKPreviewBox (const QDomElement &element, RKComponent *parent_comp
RK_TRACE (PLUGIN);
preview_active = false;
last_plot_done = true;
new_plot_pending = false;
prior_preview_done = true;
new_preview_pending = false;
dev_num = 0;
// get xml-helper
XMLHelper *xml = parent_component->xmlHelper ();
preview_mode = (PreviewMode) xml->getMultiChoiceAttribute (element, "mode", "plot;data;custom", 0);
idprop = RObject::rQuote (QString ().sprintf ("%p", this));
// create and add property
addChild ("state", state = new RKComponentPropertyBool (this, true, preview_active, "active", "inactive"));
state->setInternal (true); // restoring this does not make sense.
connect (state, SIGNAL (valueChanged(RKComponentPropertyBase*)), this, SLOT (changedState(RKComponentPropertyBase*)));
idprop = new RKComponentPropertyBase (this, false);
idprop->setValue (RObject::rQuote (QString ().sprintf ("%p", this)));
addChild ("id", idprop);
// create checkbox
QVBoxLayout *vbox = new QVBoxLayout (this);
......@@ -89,6 +89,14 @@ RKPreviewBox::~RKPreviewBox () {
killPreview ();
}
QVariant RKPreviewBox::value(const QString& modifier) {
if (modifier == "id") {
return idprop;
}
return (state->value (modifier));
}
void RKPreviewBox::changedState (RKComponentPropertyBase *) {
RK_TRACE (PLUGIN);
......@@ -141,19 +149,19 @@ void RKPreviewBox::tryPreviewNow () {
return;
}
if (!last_plot_done) { // if the last plot is not done, yet, wait before starting the next.
new_plot_pending = true;
if (!prior_preview_done) { // if the last plot is not done, yet, wait before starting the next.
new_preview_pending = true;
updateStatusLabel ();
return;
}
preview_active = true;
RKGlobals::rInterface ()->issueCommand (".rk.startPreviewDevice (" + idprop->value ().toString () + ')', RCommand::Plugin | RCommand::Sync | RCommand::GetIntVector, QString (), this, START_DEVICE);
RKGlobals::rInterface ()->issueCommand (".rk.startPreviewDevice (" + idprop + ')', RCommand::Plugin | RCommand::Sync | RCommand::GetIntVector, QString (), this, START_DEVICE);
RKCaughtX11Window::setStatusMessage (dev_num, i18n ("Preview updating"));
RKGlobals::rInterface ()->issueCommand ("local({\n" + code_property->preview () + "})\n", RCommand::Plugin | RCommand::Sync, QString (), this, DO_PLOT);
last_plot_done = false;
new_plot_pending = false;
prior_preview_done = false;
new_preview_pending = false;
updateStatusLabel ();
}
......@@ -163,17 +171,17 @@ void RKPreviewBox::killPreview () {
if (!preview_active) return;
preview_active = false;
RKGlobals::rInterface ()->issueCommand (".rk.killPreviewDevice (" + idprop->value ().toString () + ')', RCommand::Plugin | RCommand::Sync);
RKGlobals::rInterface ()->issueCommand (".rk.killPreviewDevice (" + idprop + ')', RCommand::Plugin | RCommand::Sync);
last_plot_done = true;
new_plot_pending = false;
prior_preview_done = true;
new_preview_pending = false;
}
void RKPreviewBox::rCommandDone (RCommand *command) {
RK_TRACE (PLUGIN);
last_plot_done = true;
if (new_plot_pending) tryPreview ();
prior_preview_done = true;
if (new_preview_pending) tryPreview ();
if (command->getFlags () == START_DEVICE) {
int old_devnum = dev_num;
......@@ -198,7 +206,7 @@ void RKPreviewBox::updateStatusLabel () {
status_label->setText (i18n ("Preview disabled"));
} else {
if (parentComponent ()->isSatisfied ()) {
if (last_plot_done && (!new_plot_pending)) {
if (prior_preview_done && (!new_preview_pending)) {
status_label->setText (i18n ("Preview up to date"));
} else {
status_label->setText (i18n ("Preview updating"));
......
......@@ -41,7 +41,7 @@ public:
~RKPreviewBox ();
int type () { return ComponentPreviewBox; };
RKComponentPropertyBool *state;
QVariant value (const QString &modifier=QString ()) { return (state->value (modifier)); };
QVariant value (const QString &modifier=QString ()) override;
public slots:
void changedState (int);
void changedState (RKComponentPropertyBase *);
......@@ -53,17 +53,22 @@ protected:
private:
bool updating; // prevent recursion
bool preview_active;
bool last_plot_done;
bool new_plot_pending;
bool prior_preview_done;
bool new_preview_pending;
void tryPreview ();
void killPreview ();
void updateStatusLabel ();
int dev_num;
enum PreviewMode {
PlotPreview,
DataPreview,
CustomPreview
} preview_mode;
QTimer *update_timer;
QCheckBox *toggle_preview_box;
QLabel *status_label;
RKComponentPropertyCode *code_property;
RKComponentPropertyBase *idprop;
QString idprop;
};
#endif
......@@ -447,22 +447,3 @@ assign("available.packages.cache", NULL, envir=.rk.variables)
# call separate assignments functions:
if (exists (".rk.fix.assignments.graphics")) eval (body (.rk.fix.assignments.graphics)) # internal_graphics.R
}
assign(".rk.preview.data", list (), envir=.rk.variables)
# TODO document, move somewhere appropriate
".rk.create.preview.data" <- function (id) {
pdata <- .rk.variables$.rk.preview.data
if (is.null (pdata[[id]])) {
pdata[[id]] <- list ()
assign (".rk.preview.data", pdata, envir=.rk.variables)
}
invisible (pdata[[id]])
}
".rk.discard.preview.data" <- function (id) {
pdata <- .rk.variables$.rk.preview.data
pdata[[id]] <- NULL
assign (".rk.preview.data", pdata, envir=.rk.variables)
invisible (NULL)
}
......@@ -33,7 +33,7 @@
#' @param ask Logical: Whether to ask before flushing the output file.
#' @return \code{rk.get.tempfile.name}, \code{rk.get.output.html.file}, and
#' \code{rk.get.workspace.url} return a string while
#' \code{rk.set.output.html.file} returns \code{NULL}.
#' \code{rk.set.output.html.file} returns the \bold{previous} output html file.
#' @author Thomas Friedrichsmeier \email{rkward-devel@@kde.org}
#' @seealso \url{rkward://page/rkward_output}, \link{tempfile}, \link{file},
#' \link{rk.print}
......@@ -79,6 +79,7 @@
#' @rdname rk.get.tempfile.name
"rk.set.output.html.file" <- function (x, additional.header.contents = getOption ("rk.html.header.additions")) {
stopifnot (is.character (x))
oldfile <- rk.get.output.html.file ()
assign (".rk.output.html.file", x, .rk.variables)
if (!file.exists (x)) {
......@@ -159,7 +160,7 @@
# needs to come after initialization, so initialization alone does not trigger an update during startup
.rk.do.plain.call ("set.output.file", x, synchronous=FALSE)
invisible (NULL)
invisible (oldfile)
}
# Internal helper function to extract file names of images used in html files.
......
......@@ -181,3 +181,75 @@
.rk.do.plain.call ("setPluginStatus", c (id, context, visible))
invisible (NULL)
}
assign(".rk.preview.data", list (), envir=.rk.variables)
#' Manage (shortly) persistent data for previews (for use in RKWard plugins wishing to provide custom previews)
#'
#' \code{rk.assign.preview.data} stores data associated with a specific "id". Usually this id is
#' provided by the <preview>-feature of a plugin.
#' \code{rk.get.preview.data} retrieves data previously stored with \code{rk.assign.preview.data}
#' \code{rk.discard.preview.data} discards data previously stored with \code{rk.assign.preview.data}.
#' This gets called by the <preview>-box of the plugin, automtically, when the plugin dialog is closed.
#' You do not generally have to call it manually. See the notes for running custom clearnup code, below.
#'
#' @param id (character). Id associated with the data. Usually this will be the 'id' value of the <preview>-box.
#' @param value. The value to assign. If this is a list, and contains a function named "on.delete", this function
#' will be run by rk.discard.preview.data (with the \code{id} as argument. This is useful for running custom clearnup
#' code, such as removing temporary files, etc.
#'
#' @return \code{rk.assign.preview.data} amd \code{rk.get.preview.data} returns the preview data (newly) associated
#' with the given id. \code{rk.discard.preview.data} returns \code{NULL}, invisibly.
#'
#' \bold{Note}: Plugins that want to produce a single plot, or open a single object via \code{\link{rk.edit}()} do \bold{not}
#' have to call these functions, manually. See the chapter on providing previews in the Introduction to
#' writing plugins for RKWard.
#'
#' @author Thomas Friedrichsmeier \email{rkward-devel@@kde.org}
#' @keywords utilities
#'
#' @examples
#' ## To be generated in the preview() code section of a plugin
#'
#' ## NOT RUN
#' outfile <- rk.get.tempfile.name(prefix="preview", extension=".html")
#' rk.assign.preview.data("SOMEID", list(filename=outfile, on.delete=function (id) {
#' unlink(rk.get.preview.data(id)$filename)
#' }))
#' oldfile <- rk.set.output.html.file(f)
#' try ({
#' rk.header("This is a preview of what will happen")
#' rk.show.html(rk.get.output.html.file())
#' rk.flush.output()
#' })
#' rk.set.output.html.file(outfile)
#' ## END NOT RUN
#'
#' @export
#' @rdname rk.assign.preview.data
#' @aliases rk.get.preview.data .rk.discard.preview.data
"rk.assign.preview.data" <- function (id, value=list ()) {
pdata <- .rk.variables$.rk.preview.data
if (is.null (pdata[[id]])) {
pdata[[id]] <- value
assign (".rk.preview.data", pdata, envir=.rk.variables)
rk.sync (.rk.variables$.rk.preview.data)
}
invisible (pdata[[id]])
}
#' @export
#' @rdname rk.assign.preview.data
"rk.get.preview.data" <- function (id) {
.rk.variables$.rk.preview.data[[id]]
}
#' @export
#' @rdname rk.assign.preview.data
"rk.discard.preview.data" <- function (id) {
pdata <- .rk.variables$.rk.preview.data
if (!is.null (pdata[[id]]) && !is.null (pdata[[id]]$on.exit)) pdata[[id]]$on.delete (id)
pdata[[id]] <- NULL
assign (".rk.preview.data", pdata, envir=.rk.variables)
invisible (NULL)
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment