[rkward/work/generalized_preview] rkward: First draft of the R support functions for data and custom previews.
Thomas Friedrichsmeier
thomas.friedrichsmeier at ruhr-uni-bochum.de
Sun Dec 13 20:03:21 UTC 2015
Git commit f434a6c09406cb783f1798adb96566f4ba0d07b9 by Thomas Friedrichsmeier.
Committed on 13/12/2015 at 20:01.
Pushed by tfry into branch 'work/generalized_preview'.
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.
M +24 -16 rkward/plugin/rkpreviewbox.cpp
M +9 -4 rkward/plugin/rkpreviewbox.h
M +0 -19 rkward/rbackend/rpackages/rkward/R/internal.R
M +3 -2 rkward/rbackend/rpackages/rkward/R/rk.filename-functions.R
M +72 -0 rkward/rbackend/rpackages/rkward/R/rk.plugin-functions.R
http://commits.kde.org/rkward/f434a6c09406cb783f1798adb96566f4ba0d07b9
diff --git a/rkward/plugin/rkpreviewbox.cpp b/rkward/plugin/rkpreviewbox.cpp
index db98265..7bf9731 100644
--- a/rkward/plugin/rkpreviewbox.cpp
+++ b/rkward/plugin/rkpreviewbox.cpp
@@ -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"));
diff --git a/rkward/plugin/rkpreviewbox.h b/rkward/plugin/rkpreviewbox.h
index 4803fbc..11029ea 100644
--- a/rkward/plugin/rkpreviewbox.h
+++ b/rkward/plugin/rkpreviewbox.h
@@ -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
diff --git a/rkward/rbackend/rpackages/rkward/R/internal.R b/rkward/rbackend/rpackages/rkward/R/internal.R
index 0448ad5..82ce60a 100644
--- a/rkward/rbackend/rpackages/rkward/R/internal.R
+++ b/rkward/rbackend/rpackages/rkward/R/internal.R
@@ -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)
-}
diff --git a/rkward/rbackend/rpackages/rkward/R/rk.filename-functions.R b/rkward/rbackend/rpackages/rkward/R/rk.filename-functions.R
index 05ef5dc..8cce2c7 100644
--- a/rkward/rbackend/rpackages/rkward/R/rk.filename-functions.R
+++ b/rkward/rbackend/rpackages/rkward/R/rk.filename-functions.R
@@ -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.
diff --git a/rkward/rbackend/rpackages/rkward/R/rk.plugin-functions.R b/rkward/rbackend/rpackages/rkward/R/rk.plugin-functions.R
index 674a1b6..ad70b7d 100644
--- a/rkward/rbackend/rpackages/rkward/R/rk.plugin-functions.R
+++ b/rkward/rbackend/rpackages/rkward/R/rk.plugin-functions.R
@@ -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)
+}
More information about the rkward-tracker
mailing list