113
void RInterface::startThread () {
118
RCommand *RInterface::runningCommand () {
119
return r_thread->current_command;
114
122
void RInterface::customEvent (QCustomEvent *e) {
115
123
RK_TRACE (RBACKEND);
116
124
if (e->type () == RCOMMAND_OUTPUT_EVENT) {
117
125
RThread::ROutputContainer *container = (static_cast <RThread::ROutputContainer *> (e->data ()));
118
// we've already made sure, there is an existing receiver in RThread
119
container->command->receiver->newOutput (container->command, container->output);
126
container->command->newOutput (container->output);
120
127
delete container;
121
/* TODO: not quite good, yet, but something like this should be done:
122
// output events can easily stack up in the hundreds, not allowing GUI events to get through. Let's block further output events for a minute (using MUTEX_LOCK) and then catch up with the event queue
124
qApp->processEvents ();
129
// TODO: not quite good, yet, leads to staggering output (but overall throughput is the same):
130
// output events can easily stack up in the hundreds, not allowing GUI events to get through. Let's block further output events for a minute and then catch up with the event queue
131
if (qApp->hasPendingEvents ()) {
132
r_thread->pauseOutput (true);
133
qApp->processEvents ();
134
r_thread->pauseOutput (false);
127
136
} else if (e->type () == RCOMMAND_IN_EVENT) {
128
137
watch->addInput (static_cast <RCommand *> (e->data ()));
129
138
RKGlobals::controlWindow ()->setCommandRunning (static_cast <RCommand *> (e->data ()));
148
155
RKGlobals::controlWindow ()->removeCommand (command);
149
watch->addOutput (command);
150
156
command->finished ();
151
157
if (command->type () & RCommand::DirectToOutput) {
152
RKGlobals::rkApp ()->newOutput ();
158
RKWorkplace::mainWorkplace ()->newOutput ();
155
161
} else if ((e->type () == RIDLE_EVENT)) {
156
RKGlobals::rkApp ()->setRStatus (false);
162
RKwardApp::getApp ()->setRStatus (false);
157
163
} else if ((e->type () == RBUSY_EVENT)) {
158
RKGlobals::rkApp ()->setRStatus (true);
164
RKwardApp::getApp ()->setRStatus (true);
159
165
} else if ((e->type () == R_EVAL_REQUEST_EVENT)) {
166
r_thread->pauseOutput (false); // we may be recursing downwards into event loops here. Hence we need to make sure, we don't create a deadlock
160
167
processREvalRequest (static_cast<REvalRequest *> (e->data ()));
161
168
} else if ((e->type () == R_CALLBACK_REQUEST_EVENT)) {
169
r_thread->pauseOutput (false); // see above
162
170
processRCallbackRequest (static_cast<RCallbackArgs *> (e->data ()));
163
171
} else if ((e->type () == RSTARTED_EVENT)) {
164
172
r_thread->unlock (RThread::Startup);
275
284
// TODO: make more generic, get filename sanely
276
285
issueCommand (".rk.rkreply <- \"" + dir.filePath ("rk_out.html") + "\"", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
277
286
} else if (call == "sync") {
279
if (request->call_length >= 2) {
280
QString object_name = request->call[1];
281
obj = RKGlobals::rObjectList ()->findObject (object_name);
287
RK_ASSERT (request->call_length >= 2);
289
for (int i = 1; i < request->call_length; ++i) {
290
QString object_name = request->call[i];
291
RObject *obj = RObjectList::getObjectList ()->findObject (object_name);
293
RK_DO (qDebug ("triggering update for symbol %s", object_name.latin1 ()), RBACKEND, DL_DEBUG);
294
obj->markDataDirty ();
295
obj->updateFromR (request->in_chain);
297
RK_DO (qDebug ("lookup failed for changed symbol %s", object_name.latin1 ()), RBACKEND, DL_WARNING);
284
RObject::ChangeSet *set = new RObject::ChangeSet;
285
set->from_index = -1;
287
// for now a complete update is needed, in case new objects were added
288
RKGlobals::rObjectList ()->updateFromR ();
289
RKGlobals::tracker ()->objectDataChanged (obj, set);
291
issueCommand (".rk.rkreply <- \"Sync scheduled for object '" + obj->getFullName () + "'\"", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
293
issueCommand (".rk.rkreply <- \"Object not recognized or not specified in call to sync. Ignoring\"", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
300
} else if (call == "syncall") {
301
RK_ASSERT (request->call_length == 1);
303
RK_DO (qDebug ("triggering update of object list"), RBACKEND, DL_DEBUG);
304
RObjectList::getObjectList ()->updateFromR (request->in_chain);
305
} else if (call == "syncglobal") {
306
RK_ASSERT (request->call_length == 1);
308
RK_DO (qDebug ("triggering update of globalenv"), RBACKEND, DL_DEBUG);
309
RObjectList::getGlobalEnv ()->updateFromR (request->in_chain);
310
} else if (call == "edit") {
311
RK_ASSERT (request->call_length >= 2);
313
for (int i = 1; i < request->call_length; ++i) {
314
QString object_name = request->call[i];
315
RObject *obj = RObjectList::getObjectList ()->findObject (object_name);
316
if (!(obj && RKWorkplace::mainWorkplace()->editObject (obj, false))) {
317
KMessageBox::information (0, i18n ("The object '%1', could not be opened for editing. Either it does not exist, or RKWard does not support editing this type of object, yet.").arg (object_name), i18n ("Cannot edit '%1'").arg (object_name));
295
320
} else if (call == "require") {
296
321
if (request->call_length >= 2) {
297
322
QString lib_name = request->call[1];
323
issueCommand (".rk.rkreply <- NULL", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
298
324
KMessageBox::information (0, i18n ("The R-backend has indicated that in order to carry out the current task it needs the package '%1', which is not currently installed. We'll open the package-management tool, and there you can try to locate and install the needed package.").arg (lib_name), i18n ("Require package '%1'").arg (lib_name));
299
RKLoadLibsDialog::showInstallPackagesModal (0, request->in_chain);
325
RKLoadLibsDialog::showInstallPackagesModal (0, request->in_chain, lib_name);
300
326
issueCommand (".rk.rkreply <- \"\"", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
302
328
issueCommand (".rk.rkreply <- \"Too few arguments in call to require.\"", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
304
330
} else if (call == "quit") {
305
RKGlobals::rkApp ()->close ();
331
RKwardApp::getApp ()->close ();
306
332
// if we're still alive, quitting was cancelled
307
333
issueCommand (".rk.rkreply <- \"Quitting was cancelled\"", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
308
334
#ifndef DISABLE_RKWINDOWCATCHER
331
357
if (type == RCallbackArgs::RShowMessage) {
332
358
KMessageBox::information (0, QString (*(args->chars_a)), i18n ("Message from the R backend"));
333
359
} else if (type == RCallbackArgs::RReadConsole) {
335
QRegExpValidator *dummy = new QRegExpValidator (QRegExp (".*"), 0); // needed to allow empty strings in KInputDialog::getText
336
QString res = KInputDialog::getText (i18n ("R backend requests information"), QString (*(args->chars_a)), QString::null, &ok, 0, 0, dummy);
338
res = res.left (args->int_a - 2) + "\n";
339
qstrcpy (*(args->chars_b), res.latin1 ());
341
if (!ok) cancelCommand (runningCommand ());
362
bool ok = RKReadLineDialog::readLine (0, i18n ("R backend requests information"), *(args->chars_a), runningCommand (), &result);
364
result = result.left (args->int_a - 2) + '\n';
365
qstrcpy (*(args->chars_b), result.local8Bit ());
367
if (!ok) args->int_c = 0; // will be cancelled deep inside REmbedInternal, where it's safest
342
368
} else if ((type == RCallbackArgs::RShowFiles) || (type == RCallbackArgs::REditFiles)) {
343
369
if ((type == RCallbackArgs::RShowFiles) && (QString (*(args->chars_d)) == "rkwardhtml")) {
344
370
// not to worry, just some help file to display
345
371
// TODO: maybe move this to ShowEditTextFileAgent instead
346
372
for (int n=0; n < args->int_a; ++n) {
347
RKGlobals::rkApp ()->openHTML (args->chars_a[n]);
373
RKwardApp::getApp ()->openHTML (args->chars_a[n]);
350
376
ShowEditTextFileAgent::showEditFiles (args);