~ubuntu-branches/ubuntu/karmic/rkward/karmic

« back to all changes in this revision

Viewing changes to rkward/rbackend/rinterface.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Friedrichsmeier
  • Date: 2006-11-06 16:30:00 UTC
  • mfrom: (1.2.1 upstream) (3.1.1 feisty)
  • Revision ID: james.westby@ubuntu.com-20061106163000-qi8ju75eqecrfay7
* new upstream release
* depend on either php4-cli or php5-cli

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
#include "../settings/rksettingsmoduler.h"
25
25
#include "../settings/rksettingsmodulegeneral.h"
26
26
#include "../core/robjectlist.h"
 
27
#include "../core/renvironmentobject.h"
27
28
#include "../core/rkmodificationtracker.h"
28
29
#include "../dialogs/rkloadlibsdialog.h"
 
30
#include "../dialogs/rkreadlinedialog.h"
29
31
#include "../agents/showedittextfileagent.h"
30
32
#include "../windows/rcontrolwindow.h"
 
33
#include "../windows/rkworkplace.h"
31
34
 
32
35
#include "rkwindowcatcher.h"
33
36
#ifndef DISABLE_RKWINDOWCATCHER
39
42
#include "../debug.h"
40
43
 
41
44
#include <kmessagebox.h>
42
 
#include <kinputdialog.h>
43
45
#include <kfiledialog.h>
44
46
#include <klocale.h>
45
47
 
79
81
        flush_timer = new QTimer (this);
80
82
        connect (flush_timer, SIGNAL (timeout ()), this, SLOT (flushOutput ()));
81
83
        flush_timer->start (FLUSH_INTERVAL);
82
 
 
83
 
        r_thread->start ();
84
84
}
85
85
 
86
86
void RInterface::issueCommand (const QString &command, int type, const QString &rk_equiv, RCommandReceiver *receiver, int flags, RCommandChain *chain) {
88
88
        issueCommand (new RCommand (command, type, rk_equiv, receiver, flags), chain);
89
89
}
90
90
 
91
 
 
92
91
RInterface::~RInterface(){
93
92
        RK_TRACE (RBACKEND);
94
93
        
111
110
        delete watch;
112
111
}
113
112
 
 
113
void RInterface::startThread () {
 
114
        RK_TRACE (RBACKEND);
 
115
        r_thread->start ();
 
116
}
 
117
 
 
118
RCommand *RInterface::runningCommand () {
 
119
         return r_thread->current_command;
 
120
}
 
121
 
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
123
 
                MUTEX_LOCK;
124
 
                qApp->processEvents ();
125
 
                MUTEX_UNLOCK;
126
 
*/
 
128
 
 
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);
 
135
                }
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 ()));
135
144
                        out->type = ROutput::Error;
136
145
                        out->output = ("--- interrupted ---");
137
146
                        command->output_list.append (out);
138
 
                        if (command->receiver && (command->type () & RCommand::ImmediateOutput)) {
139
 
                                command->receiver->newOutput (command, out);
140
 
                        }
 
147
                        command->newOutput (out);
141
148
                        if (running_command_canceled) {
142
149
                                RK_ASSERT (command == running_command_canceled);
143
150
                                running_command_canceled = 0;
146
153
                        }
147
154
                }
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 ();
153
159
                }
154
160
                delete command;
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);
251
259
        // clear reply object
252
260
        issueCommand (".rk.rkreply <- NULL", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
253
261
        if (!request->call_length) {
 
262
                RK_ASSERT (false);
254
263
                closeChain (request->in_chain);
255
264
                return;
256
265
        }
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") {
278
 
                RObject *obj = 0;
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);
 
288
 
 
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);
 
292
                        if (obj) {
 
293
                                RK_DO (qDebug ("triggering update for symbol %s", object_name.latin1 ()), RBACKEND, DL_DEBUG);
 
294
                                obj->markDataDirty ();
 
295
                                obj->updateFromR (request->in_chain);
 
296
                        } else {
 
297
                                RK_DO (qDebug ("lookup failed for changed symbol %s", object_name.latin1 ()), RBACKEND, DL_WARNING);
 
298
                        }
282
299
                }
283
 
                if (obj) {
284
 
                        RObject::ChangeSet *set = new RObject::ChangeSet;
285
 
                        set->from_index = -1;
286
 
                        set->to_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);
290
 
                        
291
 
                        issueCommand (".rk.rkreply <- \"Sync scheduled for object '" + obj->getFullName () + "'\"", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
292
 
                } else {
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);
 
302
 
 
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);
 
307
 
 
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);
 
312
 
 
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));
 
318
                        }
294
319
                }
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);
301
327
                } else {
302
328
                        issueCommand (".rk.rkreply <- \"Too few arguments in call to require.\"", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
303
329
                }
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) {
334
 
                bool ok;
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);
337
 
                delete dummy;
338
 
                res = res.left (args->int_a - 2) + "\n";
339
 
                qstrcpy (*(args->chars_b), res.latin1 ());
340
 
 
341
 
                if (!ok) cancelCommand (runningCommand ());
 
360
                QString result;
 
361
 
 
362
                bool ok = RKReadLineDialog::readLine (0, i18n ("R backend requests information"), *(args->chars_a), runningCommand (), &result);
 
363
 
 
364
                result = result.left (args->int_a - 2) + '\n';
 
365
                qstrcpy (*(args->chars_b), result.local8Bit ());
 
366
 
 
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]);
348
374
                        }
349
375
                } else {
350
376
                        ShowEditTextFileAgent::showEditFiles (args);
372
398
                r_thread->terminate ();
373
399
        }
374
400
 
375
 
        MUTEX_LOCK;
376
401
        args->done = true;
377
 
        MUTEX_UNLOCK;
378
402
}
379
403
 
380
404
#include "rinterface.moc"