Changeset View
Changeset View
Standalone View
Standalone View
src/backends/R/rsession.cpp
Context not available. | |||||
25 | 25 | | |||
---|---|---|---|---|---|
26 | #include <QTimer> | 26 | #include <QTimer> | ||
27 | #include <QDebug> | 27 | #include <QDebug> | ||
28 | #include <KProcess> | 28 | #include <QProcess> | ||
29 | #include <QStandardPaths> | ||||
30 | | ||||
29 | 31 | | |||
30 | #include <signal.h> | 32 | #include <signal.h> | ||
31 | 33 | | |||
32 | RSession::RSession( Cantor::Backend* backend) : Session(backend) | 34 | RSession::RSession( Cantor::Backend* backend) : Session(backend), | ||
35 | m_Process(0), | ||||
36 | m_CurrentExpression(0) | ||||
33 | { | 37 | { | ||
34 | qDebug(); | | |||
35 | m_rProcess=0; | | |||
36 | } | 38 | } | ||
37 | 39 | | |||
38 | RSession::~RSession() | 40 | RSession::~RSession() | ||
39 | { | 41 | { | ||
40 | qDebug(); | 42 | qDebug(); | ||
41 | m_rProcess->terminate(); | 43 | m_Process->terminate(); | ||
42 | } | 44 | } | ||
43 | 45 | | |||
44 | void RSession::login() | 46 | void RSession::login() | ||
45 | { | 47 | { | ||
46 | qDebug()<<"login"; | 48 | qDebug()<<"login"; | ||
47 | if(m_rProcess) | | |||
48 | m_rProcess->deleteLater(); | | |||
49 | m_rProcess=new KProcess(this); | | |||
50 | m_rProcess->setOutputChannelMode(KProcess::ForwardedChannels); | | |||
51 | 49 | | |||
52 | (*m_rProcess)<<QStandardPaths::findExecutable( QLatin1String("cantor_rserver") ); | | |||
53 | 50 | | |||
54 | m_rProcess->start(); | 51 | m_Process=new QProcess(this); | ||
52 | m_Process->setProcessChannelMode(QProcess::SeparateChannels); | ||||
55 | 53 | | |||
56 | m_rServer=new org::kde::Cantor::R(QString::fromLatin1("org.kde.cantor_rserver-%1").arg(m_rProcess->pid()), QLatin1String("/R"), QDBusConnection::sessionBus(), this); | 54 | QString path = QStandardPaths::findExecutable(QLatin1String("R")); | ||
55 | qDebug() << path; | ||||
57 | 56 | | |||
58 | connect(m_rServer, SIGNAL(statusChanged(int)), this, SLOT(serverChangedStatus(int))); | 57 | if(QStandardPaths::findExecutable(QLatin1String("R")).isEmpty()) | ||
59 | connect(m_rServer,SIGNAL(symbolList(const QStringList&,const QStringList&)),this,SLOT(receiveSymbols(const QStringList&,const QStringList&))); | 58 | qDebug() << "Could not find the R exe" << endl; | ||
60 | 59 | | |||
61 | changeStatus(Cantor::Session::Done); | | |||
62 | 60 | | |||
63 | connect(m_rServer, SIGNAL(ready()), this, SIGNAL(ready())); | 61 | | ||
62 | m_Process->setProgram(QStandardPaths::findExecutable(QLatin1String("R"))); | ||||
63 | QStringList args; | ||||
64 | /* | ||||
65 | * interactive - forcing an interactive session | ||||
66 | * quiet - don't print the startup message | ||||
67 | * no-save - don't save the workspace after the end of session(when users quits). Should the user be allowed to save the session? | ||||
68 | */ | ||||
69 | args.append(QLatin1String("--interactive")); | ||||
70 | args.append(QLatin1String("--quiet")); | ||||
71 | args.append(QLatin1String("--no-save")); | ||||
72 | m_Process->setArguments(args); | ||||
73 | | ||||
74 | connect(m_Process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput())); | ||||
75 | connect(m_Process, SIGNAL(readyReadStandardError()), this, SLOT(readError())); | ||||
76 | connect(m_Process, SIGNAL(started()), this, SLOT(processStarted())); | ||||
77 | | ||||
78 | | ||||
79 | m_Process->start(); | ||||
80 | | ||||
81 | } | ||||
82 | | ||||
83 | | ||||
84 | void RSession::readOutput() | ||||
85 | { | ||||
86 | while(m_Process->bytesAvailable()) { | ||||
87 | m_Output.append(QString::fromLocal8Bit(m_Process->readLine())); | ||||
88 | } | ||||
89 | | ||||
90 | if(m_CurrentExpression && !m_Output.isEmpty() && m_Output.trimmed().endsWith(QLatin1String(">"))) { | ||||
91 | m_CurrentExpression->parseOutput(m_Output); | ||||
92 | m_Output.clear(); | ||||
93 | } | ||||
94 | } | ||||
95 | | ||||
96 | void RSession::readError() | ||||
97 | { | ||||
98 | m_Error = QString::fromLocal8Bit(m_Process->readAllStandardError()); | ||||
99 | m_CurrentExpression->parseError(m_Error); | ||||
100 | m_Error.clear(); | ||||
101 | } | ||||
102 | | ||||
103 | void RSession::processStarted() | ||||
104 | { | ||||
105 | qDebug() << m_Process->program() << " with pid " << m_Process->processId() << " started successfully " << endl; | ||||
106 | emit ready(); | ||||
64 | } | 107 | } | ||
65 | 108 | | |||
66 | void RSession::logout() | 109 | void RSession::logout() | ||
67 | { | 110 | { | ||
68 | qDebug()<<"logout"; | 111 | qDebug()<<"logout" << endl; | ||
69 | m_rProcess->terminate(); | 112 | | ||
113 | // this happens if the user gives quit command | ||||
114 | if(status() == Cantor::Session::Running) | ||||
115 | changeStatus(Cantor::Session::Done); | ||||
116 | | ||||
117 | if(m_Process && m_Process->state() == QProcess::Running){ | ||||
118 | qDebug () << " Killing the process "; | ||||
119 | m_Process->kill(); | ||||
120 | } | ||||
70 | } | 121 | } | ||
71 | 122 | | |||
72 | void RSession::interrupt() | 123 | void RSession::interrupt() | ||
73 | { | 124 | { | ||
74 | qDebug()<<"interrupt" << m_rProcess->pid(); | 125 | qDebug()<<"interrupt" << m_Process->pid(); | ||
75 | if (m_rProcess->pid()) | | |||
76 | kill(m_rProcess->pid(), 2); | | |||
77 | m_expressionQueue.removeFirst(); | | |||
78 | changeStatus(Cantor::Session::Done); | 126 | changeStatus(Cantor::Session::Done); | ||
79 | } | 127 | } | ||
80 | 128 | | |||
81 | Cantor::Expression* RSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave) | 129 | Cantor::Expression* RSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave) | ||
82 | { | 130 | { | ||
83 | qDebug()<<"evaluating: "<<cmd; | 131 | qDebug()<<"evaluating: "<<cmd; | ||
132 | changeStatus(Cantor::Session::Running); | ||||
84 | RExpression* expr=new RExpression(this); | 133 | RExpression* expr=new RExpression(this); | ||
85 | expr->setFinishingBehavior(behave); | 134 | expr->setFinishingBehavior(behave); | ||
86 | expr->setCommand(cmd); | 135 | expr->setCommand(cmd); | ||
87 | 136 | | |||
88 | expr->evaluate(); | 137 | /* start evaluating only if the process is in running state | ||
138 | * imo this is a late check, can this be done somewhere before ? | ||||
139 | */ | ||||
140 | if(m_Process && m_Process->state() == QProcess::NotRunning){ | ||||
141 | changeStatus(Cantor::Session::Done); | ||||
142 | return expr; | ||||
143 | } | ||||
89 | 144 | | |||
90 | changeStatus(Cantor::Session::Running); | 145 | expr->evaluate(); | ||
91 | 146 | | |||
92 | return expr; | 147 | return expr; | ||
93 | } | 148 | } | ||
94 | 149 | | |||
150 | void RSession::runExpression(RExpression* expr) | ||||
151 | { | ||||
152 | m_CurrentExpression = expr; | ||||
153 | connect(m_CurrentExpression, SIGNAL(statusChanged(Cantor::Expression::Status)), this, SLOT(currentExpressionStatusChanged(Cantor::Expression::Status))); | ||||
154 | | ||||
155 | QString currentCmd = m_CurrentExpression->command(); | ||||
156 | currentCmd.trimmed(); | ||||
157 | currentCmd += QLatin1String("\n"); | ||||
158 | | ||||
159 | m_Process->write(currentCmd.toLocal8Bit()); | ||||
160 | | ||||
161 | | ||||
162 | } | ||||
163 | | ||||
164 | void RSession::currentExpressionStatusChanged(Cantor::Expression::Status status) | ||||
165 | { | ||||
166 | switch (status) { | ||||
167 | | ||||
168 | case Cantor::Expression::Computing: | ||||
169 | break; | ||||
170 | case Cantor::Expression::Interrupted: | ||||
171 | changeStatus(Cantor::Session::Done); | ||||
172 | break; | ||||
173 | case Cantor::Expression::Done: | ||||
174 | case Cantor::Expression::Error: | ||||
175 | changeStatus(Cantor::Session::Done); | ||||
176 | | ||||
177 | } | ||||
178 | } | ||||
95 | Cantor::CompletionObject* RSession::completionFor(const QString& command, int index) | 179 | Cantor::CompletionObject* RSession::completionFor(const QString& command, int index) | ||
96 | { | 180 | { | ||
97 | RCompletionObject *cmp=new RCompletionObject(command, index, this); | 181 | /* | ||
98 | connect(m_rServer,SIGNAL(completionFinished(const QString&,const QStringList&)),cmp,SLOT(receiveCompletions(const QString&,const QStringList&))); | 182 | * since we won't be using rserver anymore, we will have to find a different method to make completion work | ||
99 | connect(cmp,SIGNAL(requestCompletion(const QString&)),m_rServer,SLOT(completeCommand(const QString&))); | 183 | * can we use R's command line interface for this ? | ||
100 | return cmp; | 184 | */ | ||
185 | | ||||
186 | // RCompletionObject *cmp=new RCompletionObject(command, index, this); | ||||
187 | // connect(m_rServer,SIGNAL(completionFinished(const QString&,const QStringList&)),cmp,SLOT(receiveCompletions(const QString&,const QStringList&))); | ||||
188 | // connect(cmp,SIGNAL(requestCompletion(const QString&)),m_rServer,SLOT(completeCommand(const QString&))); | ||||
189 | // return cmp; | ||||
190 | return 0; | ||||
101 | } | 191 | } | ||
102 | 192 | | |||
103 | QSyntaxHighlighter* RSession::syntaxHighlighter(QObject* parent) | 193 | QSyntaxHighlighter* RSession::syntaxHighlighter(QObject* parent) | ||
Context not available. | |||||
130 | emit symbolsChanged(); | 220 | emit symbolsChanged(); | ||
131 | } | 221 | } | ||
132 | 222 | | |||
133 | void RSession::queueExpression(RExpression* expr) | | |||
134 | { | | |||
135 | m_expressionQueue.append(expr); | | |||
136 | | ||||
137 | if(status()==Cantor::Session::Done) | | |||
138 | QTimer::singleShot(0, this, SLOT(runNextExpression())); | | |||
139 | } | | |||
140 | | ||||
141 | | ||||
142 | void RSession::serverChangedStatus(int status) | | |||
143 | { | | |||
144 | qDebug()<<"changed status to "<<status; | | |||
145 | if(status==0) | | |||
146 | { | | |||
147 | if(!m_expressionQueue.isEmpty()) | | |||
148 | { | | |||
149 | RExpression* expr=m_expressionQueue.takeFirst(); | | |||
150 | qDebug()<<"done running "<<expr<<" "<<expr->command(); | | |||
151 | } | | |||
152 | | ||||
153 | if(m_expressionQueue.isEmpty()) | | |||
154 | changeStatus(Cantor::Session::Done); | | |||
155 | else | | |||
156 | runNextExpression(); | | |||
157 | } | | |||
158 | else | | |||
159 | changeStatus(Cantor::Session::Running); | | |||
160 | } | | |||
161 | | ||||
162 | void RSession::runNextExpression() | | |||
163 | { | | |||
164 | if (m_expressionQueue.isEmpty()) | | |||
165 | return; | | |||
166 | disconnect(m_rServer, SIGNAL(expressionFinished(int, const QString&)), 0, 0); | | |||
167 | disconnect(m_rServer, SIGNAL(inputRequested(const QString&)), 0, 0); | | |||
168 | disconnect(m_rServer, SIGNAL(showFilesNeeded(const QStringList&)), 0, 0); | | |||
169 | qDebug()<<"size: "<<m_expressionQueue.size(); | | |||
170 | RExpression* expr=m_expressionQueue.first(); | | |||
171 | qDebug()<<"running expression: "<<expr->command(); | | |||
172 | | ||||
173 | connect(m_rServer, SIGNAL(expressionFinished(int, const QString &)), expr, SLOT(finished(int, const QString&))); | | |||
174 | connect(m_rServer, SIGNAL(inputRequested(const QString&)), expr, SIGNAL(needsAdditionalInformation(const QString&))); | | |||
175 | connect(m_rServer, SIGNAL(showFilesNeeded(const QStringList&)), expr, SLOT(showFilesAsResult(const QStringList&))); | | |||
176 | | ||||
177 | m_rServer->runCommand(expr->command()); | | |||
178 | | ||||
179 | } | | |||
180 | | ||||
181 | void RSession::sendInputToServer(const QString& input) | | |||
182 | { | | |||
183 | QString s=input; | | |||
184 | if(!input.endsWith(QLatin1Char('\n'))) | | |||
185 | s+=QLatin1Char('\n'); | | |||
186 | m_rServer->answerRequest(s); | | |||
187 | } | | |||
188 | 223 | | |||
189 | #include "rsession.moc" | 224 | #include "rsession.moc" | ||
Context not available. |