Changeset View
Standalone View
src/backends/qalculate/qalculatesession.cpp
Show All 14 Lines | |||||
15 | * You should have received a copy of the GNU General Public License * | 15 | * You should have received a copy of the GNU General Public License * | ||
16 | * along with this program; if not, write to the Free Software * | 16 | * along with this program; if not, write to the Free Software * | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * | 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * | ||
18 | *************************************************************************************/ | 18 | *************************************************************************************/ | ||
19 | 19 | | |||
20 | #include "settings.h" | 20 | #include "settings.h" | ||
21 | 21 | | |||
22 | #include "qalculatesession.h" | 22 | #include "qalculatesession.h" | ||
23 | #include "qalculateexpression.h" | | |||
24 | #include "qalculatecompletionobject.h" | 23 | #include "qalculatecompletionobject.h" | ||
25 | #include "qalculatehighlighter.h" | 24 | #include "qalculatehighlighter.h" | ||
26 | #include "defaultvariablemodel.h" | 25 | #include "defaultvariablemodel.h" | ||
27 | 26 | | |||
28 | #include <QTextEdit> | 27 | #include <QTextEdit> | ||
28 | #include <QProcess> | ||||
29 | #include <QRegExp> | ||||
30 | #include <QRegularExpression> | ||||
29 | 31 | | |||
30 | #include <libqalculate/Calculator.h> | 32 | #include <libqalculate/Calculator.h> | ||
31 | #include <libqalculate/ExpressionItem.h> | 33 | #include <libqalculate/ExpressionItem.h> | ||
32 | #include <libqalculate/Unit.h> | 34 | #include <libqalculate/Unit.h> | ||
33 | #include <libqalculate/Prefix.h> | 35 | #include <libqalculate/Prefix.h> | ||
34 | #include <libqalculate/Variable.h> | 36 | #include <libqalculate/Variable.h> | ||
35 | #include <libqalculate/Function.h> | 37 | #include <libqalculate/Function.h> | ||
36 | 38 | | |||
37 | #include "qalculatesyntaxhelpobject.h" | 39 | #include "qalculatesyntaxhelpobject.h" | ||
38 | 40 | | |||
39 | QalculateSession::QalculateSession( Cantor::Backend* backend) | 41 | QalculateSession::QalculateSession( Cantor::Backend* backend) | ||
40 | : Session(backend), | 42 | : Session(backend), | ||
41 | m_variableModel(new Cantor::DefaultVariableModel(this)) | 43 | m_variableModel(new Cantor::DefaultVariableModel(this)), | ||
42 | { | 44 | m_process(0), | ||
45 | m_currentExpression(0), | ||||
46 | m_isSaveCommand(false) | ||||
47 | { | ||||
48 | /* | ||||
49 | qalc does all of this by default but we still need the CALCULATOR instance for plotting | ||||
50 | graphs | ||||
51 | */ | ||||
52 | | ||||
43 | if ( !CALCULATOR ) { | 53 | if ( !CALCULATOR ) { | ||
44 | new Calculator(); | 54 | new Calculator(); | ||
45 | CALCULATOR->loadGlobalDefinitions(); | 55 | CALCULATOR->loadGlobalDefinitions(); | ||
46 | CALCULATOR->loadLocalDefinitions(); | 56 | CALCULATOR->loadLocalDefinitions(); | ||
47 | CALCULATOR->loadExchangeRates(); | 57 | CALCULATOR->loadExchangeRates(); | ||
48 | } | 58 | } | ||
49 | // from qalc.cc in libqalculate | | |||
50 | std::string ansName = "ans"; | | |||
51 | // m_undefined is not a variable in this class, but is defined in | | |||
52 | // libqalculate/includes.h | | |||
53 | m_ansVariables.append(static_cast<KnownVariable*>(CALCULATOR->addVariable(new KnownVariable("Temporary", ansName, m_undefined, "Last Answer", false)))); | | |||
54 | m_ansVariables[0]->addName("answer"); | | |||
55 | m_ansVariables[0]->addName(ansName + "1"); | | |||
56 | m_ansVariables.append(static_cast<KnownVariable*>(CALCULATOR->addVariable(new KnownVariable("Temporary", ansName+"2", m_undefined, "Answer 2", false)))); | | |||
57 | m_ansVariables.append(static_cast<KnownVariable*>(CALCULATOR->addVariable(new KnownVariable("Temporary", ansName+"3", m_undefined, "Answer 3", false)))); | | |||
58 | m_ansVariables.append(static_cast<KnownVariable*>(CALCULATOR->addVariable(new KnownVariable("Temporary", ansName+"4", m_undefined, "Answer 4", false)))); | | |||
59 | m_ansVariables.append(static_cast<KnownVariable*>(CALCULATOR->addVariable(new KnownVariable("Temporary", ansName+"5", m_undefined, "Answer 5", false)))); | | |||
60 | } | 59 | } | ||
61 | 60 | | |||
62 | QalculateSession::~QalculateSession() | 61 | QalculateSession::~QalculateSession() | ||
63 | { | 62 | { | ||
64 | CALCULATOR->abort(); | 63 | CALCULATOR->abort(); | ||
64 | if(m_process) | ||||
65 | m_process->kill(); | ||||
65 | } | 66 | } | ||
66 | 67 | | |||
67 | void QalculateSession::login() | 68 | void QalculateSession::login() | ||
68 | { | 69 | { | ||
69 | if(!QalculateSettings::autorunScripts().isEmpty()){ | | |||
70 | QString autorunScripts = QalculateSettings::self()->autorunScripts().join(QLatin1String("\n")); | | |||
71 | 70 | | |||
72 | evaluateExpression(autorunScripts, QalculateExpression::DeleteOnFinish); | 71 | /* we will , most probably, use autoscripts for setting the mode , evaulate options, print options etc */ | ||
72 | | ||||
73 | // if(!QalculateSettings::autorunScripts().isEmpty()){ | ||||
74 | // QString autorunScripts = QalculateSettings::self()->autorunScripts().join(QLatin1String("\n")); | ||||
75 | // | ||||
76 | // evaluateExpression(autorunScripts, QalculateExpression::DeleteOnFinish); | ||||
77 | // } | ||||
78 | | ||||
79 | /* | ||||
80 | set up the process here. The program path , arguments(if any),channel modes , and connections should all be set up here. | ||||
81 | once the setup is complete, start the process and inform the worksheet that we are ready | ||||
82 | */ | ||||
83 | m_process = new QProcess(this); | ||||
84 | | ||||
85 | m_process->setProgram(QStandardPaths::findExecutable(QLatin1String("qalc"))); | ||||
86 | m_process->setProcessChannelMode(QProcess::SeparateChannels); | ||||
87 | | ||||
88 | connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput())); | ||||
89 | connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(readError())); | ||||
90 | connect(m_process, SIGNAL(started()), this, SLOT(processStarted())); | ||||
91 | | ||||
92 | m_process->start(); | ||||
73 | } | 93 | } | ||
74 | 94 | | |||
75 | changeStatus(Cantor::Session::Done); | 95 | void QalculateSession::readOutput() | ||
96 | { | ||||
97 | while(m_process->bytesAvailable()) { | ||||
98 | m_output.append(QString::fromLocal8Bit(m_process->readLine())); | ||||
99 | qDebug() << m_output << endl; | ||||
100 | } | ||||
101 | | ||||
102 | if(m_currentExpression && !m_output.isEmpty() && m_output.trimmed().endsWith(QLatin1String(">"))) { | ||||
103 | | ||||
104 | // check if the commandQueue is empty or not . if it's not empty run the "runCommandQueue" function. | ||||
105 | // store the output in finalOutput and clear m_output | ||||
106 | | ||||
107 | if(m_currentCommand.trimmed().isEmpty()) | ||||
108 | m_output.clear(); | ||||
109 | | ||||
110 | if(!m_output.toLower().contains(QLatin1String("error")) && m_isSaveCommand) { | ||||
111 | storeVariables(m_currentCommand, m_output); | ||||
112 | m_isSaveCommand = false; | ||||
113 | } | ||||
114 | | ||||
115 | m_output = m_output.trimmed(); | ||||
116 | m_output.remove(m_currentCommand); | ||||
117 | if (!m_output.isEmpty()) | ||||
118 | m_finalOutput.append(m_output); | ||||
119 | | ||||
120 | // we tried to perform a save operation but failed(see parseSaveCommand()).In such a case | ||||
121 | // m_output will be empty but m_saveError will contain the error message. | ||||
122 | if(!m_saveError.isEmpty()) { | ||||
123 | m_finalOutput.append(m_saveError); | ||||
124 | m_saveError.clear(); | ||||
125 | } | ||||
126 | | ||||
127 | m_finalOutput.append(QLatin1String("\n")); | ||||
128 | m_output.clear(); | ||||
129 | | ||||
130 | | ||||
131 | | ||||
132 | if (!m_commandQueue.isEmpty()) | ||||
133 | runCommandQueue(); | ||||
134 | else { | ||||
chinmoyr: comment out? | |||||
135 | qDebug () << "parsing output: " << m_finalOutput << endl; | ||||
136 | m_currentExpression->parseOutput(m_finalOutput); | ||||
137 | m_finalOutput.clear(); | ||||
138 | } | ||||
139 | | ||||
140 | | ||||
141 | } | ||||
142 | } | ||||
143 | | ||||
144 | void QalculateSession::storeVariables(QString& currentCmd, QString output) | ||||
145 | { | ||||
146 | | ||||
147 | // internally we pass save(value,variable) command to qlac to save the variables. see parseSaveCommand() | ||||
148 | // TODO: if the user if trying to override a default variable(constansts etc) or an existing variable, ask the user if he/she wants to override it or not. | ||||
149 | | ||||
chinmoyr: this and also others following this. | |||||
150 | qDebug() << "save command " << currentCmd << endl; | ||||
151 | | ||||
152 | /** | ||||
153 | if we have reached here, we expect our variable model to be updated with new variables. | ||||
154 | In case the variable model is not updated, it most probably because we were not able to successfully parse the | ||||
155 | current command and ouput to extract variable and value | ||||
156 | | ||||
157 | This is probably not the best way to get the variable and value. | ||||
158 | But since qalc does not provide a way to get the list of variables, we will have to stick to parsing | ||||
159 | **/ | ||||
160 | QString value; | ||||
161 | QString var; | ||||
162 | QRegExp regex; | ||||
163 | // find the value | ||||
164 | regex.setPattern(QLatin1String("[\\s\\w\\W]+=\\s*([\\w\\W]+)")); | ||||
165 | if(regex.exactMatch(output)) { | ||||
166 | int pos = regex.indexIn(output); | ||||
167 | if (pos > -1) { | ||||
168 | value = regex.cap(1); | ||||
169 | value = value.trimmed(); | ||||
170 | value.replace(QLatin1String("\n"), QLatin1String("")); | ||||
171 | value.remove(QLatin1String(">")); | ||||
172 | } | ||||
173 | } | ||||
174 | | ||||
175 | //find the varaiable. | ||||
176 | // ex1: currentCmd = save(10, var_1,category, title): var_1 = variable | ||||
177 | // ex2: currentCmd = save(planet(jupter,mass), jupiter_mass, category, title): jupiter_mass = variable | ||||
178 | // Not the best regex. Cab be improved | ||||
179 | regex.setPattern(QLatin1String("\\s*save\\s*\\(\\s*[\\s\\w]+\\s*,([\\s\\w]+),*[\\w\\W]*\\)\\s*;*$|\\s*save\\s*\\(\\s*[\\s\\w\\W]+\\)\\s*,([\\s\\w]+),*[\\w\\W]*\\)\\s*;*$")); | ||||
180 | if(regex.exactMatch(currentCmd)) { | ||||
181 | int pos = regex.indexIn(currentCmd); | ||||
182 | if (pos > -1) { | ||||
183 | if(!regex.cap(1).trimmed().isEmpty()) | ||||
184 | var = regex.cap(1).trimmed(); | ||||
185 | else | ||||
186 | var = regex.cap(2).trimmed(); | ||||
187 | | ||||
188 | var = var.trimmed(); | ||||
189 | var.replace(QLatin1String("\n"), QLatin1String("")); | ||||
190 | var.remove(QLatin1String(">")); | ||||
191 | } | ||||
192 | } | ||||
193 | if(!value.isEmpty() && !var.isEmpty()) | ||||
194 | variables.insert(var, value); | ||||
195 | | ||||
196 | } | ||||
197 | | ||||
198 | void QalculateSession::readError() | ||||
199 | { | ||||
200 | | ||||
201 | QString error = QLatin1String(m_process->readAllStandardError()); | ||||
202 | if(m_currentExpression) { | ||||
203 | m_currentExpression->parseError(error); | ||||
204 | } | ||||
205 | } | ||||
206 | | ||||
207 | void QalculateSession::processStarted() | ||||
208 | { | ||||
209 | qDebug() << "process started " << m_process->program() << m_process->processId() << endl; | ||||
76 | emit ready(); | 210 | emit ready(); | ||
77 | } | 211 | } | ||
78 | 212 | | |||
79 | void QalculateSession::logout() | 213 | void QalculateSession::logout() | ||
80 | { | 214 | { | ||
215 | qDebug () << "logging out " << endl; | ||||
216 | if(m_process) { | ||||
217 | m_process->write("quit\n"); | ||||
218 | if(!m_process->waitForFinished(1000)) | ||||
219 | m_process->kill(); | ||||
220 | } | ||||
81 | } | 221 | } | ||
82 | 222 | | |||
83 | void QalculateSession::interrupt() | 223 | void QalculateSession::interrupt() | ||
84 | { | 224 | { | ||
225 | qDebug () << "interrupting .... " << endl; | ||||
226 | if(m_currentExpression) | ||||
227 | m_currentExpression->interrupt(); | ||||
228 | | ||||
229 | m_commandQueue.clear(); | ||||
230 | m_expressionQueue.clear(); | ||||
231 | m_output.clear(); | ||||
232 | m_finalOutput.clear(); | ||||
233 | m_currentCommand.clear(); | ||||
234 | m_currentExpression = 0; | ||||
235 | | ||||
236 | } | ||||
237 | | ||||
238 | void QalculateSession::runExpression() | ||||
239 | { | ||||
240 | | ||||
chinmoyr: const QString | |||||
241 | const QString& command = m_currentExpression->command(); | ||||
242 | foreach(const QString& cmd, command.split(QLatin1Char('\n'))) { | ||||
243 | m_commandQueue.enqueue(cmd); | ||||
244 | } | ||||
245 | runCommandQueue(); | ||||
246 | | ||||
247 | } | ||||
248 | | ||||
249 | | ||||
250 | void QalculateSession::runCommandQueue() | ||||
251 | { | ||||
252 | if (!m_commandQueue.isEmpty()) { | ||||
253 | m_currentCommand = m_commandQueue.dequeue(); | ||||
254 | // parse the current command if it's a save/load/store command | ||||
255 | if( m_currentCommand.toLower().trimmed().startsWith(QLatin1String("save")) || | ||||
256 | m_currentCommand.toLower().trimmed().startsWith(QLatin1String("store")) || | ||||
257 | m_currentCommand.trimmed().startsWith(QLatin1String("saveVariables"))) { | ||||
258 | | ||||
259 | m_currentCommand = parseSaveCommand(m_currentCommand); | ||||
260 | } | ||||
261 | | ||||
262 | | ||||
263 | m_currentCommand = m_currentCommand.trimmed(); | ||||
264 | m_currentCommand += QLatin1String("\n"); | ||||
265 | m_process->write(m_currentCommand.toLocal8Bit()); | ||||
266 | | ||||
267 | } | ||||
268 | } | ||||
269 | | ||||
270 | QString QalculateSession::parseSaveCommand(QString& currentCmd) | ||||
271 | { | ||||
272 | /* | ||||
273 | make sure the command is: | ||||
274 | * fomatted correctly. e.g if the command is save(value,variable), we have to make sure that there is no space between save and '(', otherwise qalc | ||||
275 | waits for user input which is not supported by us as of now | ||||
276 | * supported save commands: save(value,variable,[category],[title]), save definitions, save mode, save var, store var, | ||||
277 | saveVariables filename | ||||
278 | */ | ||||
279 | | ||||
IF cantor uses Qt5 then why not switch to QRegularExpression? IIRC it provides some improvements over QRegExp. chinmoyr: IF cantor uses Qt5 then why not switch to QRegularExpression? IIRC it provides some… | |||||
Thanks for pointing out . rishabhg: Thanks for pointing out .
QRegexp is being used through cantor. It will be ported to… | |||||
280 | QRegExp regex; | ||||
281 | regex.setCaseSensitivity(Qt::CaseInsensitive); | ||||
282 | | ||||
283 | regex.setPattern(QLatin1String("\\s*save\\s*definitions\\s*")); | ||||
284 | if(regex.exactMatch(currentCmd)) { | ||||
285 | // save the variables in ~/.cantor/backends/qalculate/definitions | ||||
286 | currentCmd.clear(); | ||||
287 | return currentCmd; | ||||
288 | } | ||||
289 | | ||||
290 | regex.setPattern(QLatin1String("\\s*save\\s*mode\\s*")); | ||||
291 | if(regex.exactMatch(currentCmd)) { | ||||
292 | // save the mode in ~/.cantor/backends/qalculate/cantor_qalc.cfg | ||||
chinmoyr: I think `return currentCmd.clear()` also does the same thing | |||||
rishabhg: Yes. I don't know why I did this | |||||
293 | currentCmd.clear(); | ||||
294 | return currentCmd; | ||||
295 | } | ||||
296 | | ||||
297 | regex.setPattern(QLatin1String("\\s*saveVariables\\s*[\\w\\W]+")); | ||||
298 | if(regex.exactMatch(currentCmd)) { | ||||
299 | // save the variables in a file | ||||
300 | currentCmd.clear(); | ||||
301 | return currentCmd; | ||||
302 | } | ||||
303 | | ||||
304 | | ||||
305 | regex.setPattern(QLatin1String("\\s*store\\s*([a-zA-Z_]+[\\w]*)|\\s*save\\s*([a-zA-Z_]+[\\w]*)")); | ||||
306 | if(regex.exactMatch(currentCmd)) { | ||||
307 | m_isSaveCommand = true; | ||||
308 | int pos = regex.indexIn(currentCmd); | ||||
309 | if(pos > -1) { | ||||
310 | if(!regex.cap(1).trimmed().isEmpty()) | ||||
311 | currentCmd = QStringLiteral("save(%1, %2)").arg(QStringLiteral("ans")).arg(regex.cap(1).trimmed()); | ||||
chinmoyr: Use `QStringLiteral("...").arg(...)` instead. | |||||
Correct. QStringLiteral is less expensive as pointed out here rishabhg: Correct. QStringLiteral is less expensive as pointed out [[ https://woboq. | |||||
312 | else | ||||
313 | currentCmd = QStringLiteral("save(%1, %2)").arg(QStringLiteral("ans")).arg(regex.cap(2).trimmed()); | ||||
chinmoyr: Use QStringLiteral | |||||
314 | | ||||
Do something like this currentCmd = QStringLiteral(...).arg(...); return currentCmd; chinmoyr: Do something like this
```currentCmd = QStringLiteral(...).arg(...);
return currentCmd;```
| |||||
315 | return currentCmd; | ||||
316 | } | ||||
317 | } | ||||
318 | | ||||
319 | regex.setPattern(QLatin1String("\\s*save\\s*(\\([\\w\\W]+\\))\\s*;*$")); | ||||
320 | if(regex.exactMatch(currentCmd)) { | ||||
321 | m_isSaveCommand = true; | ||||
322 | int pos = regex.indexIn(currentCmd); | ||||
323 | if (pos > -1) { | ||||
324 | currentCmd = QStringLiteral("save%1").arg(regex.cap(1).trimmed()); | ||||
chinmoyr: Use currentCmd + QStringLiteral combination. | |||||
325 | return currentCmd; | ||||
326 | } | ||||
327 | } | ||||
328 | | ||||
329 | /* | ||||
330 | If we have not returned by this point, it's because: | ||||
331 | * we did not parse the save command properly. This might be due to malformed regular expressions. | ||||
332 | * or the commnad given by the user is malformed. More likely to happen | ||||
333 | In both these cases we will simply return an empty string because we don't want qalc to run malformed queries, | ||||
334 | else it would wait for user input and hence Qprocess would never return a complete output and the expression will remain in | ||||
335 | 'calculating' state | ||||
336 | */ | ||||
337 | m_saveError = currentCmd + QLatin1String("\nError: Could not save.\n"); | ||||
338 | return QLatin1String(""); | ||||
339 | | ||||
chinmoyr: `return QString();`, though both are same. | |||||
No they both are not same. rishabhg: No they both are not same.
The docs provide good info on both [[ http://doc.qt.io/qt-5/qstring. | |||||
340 | } | ||||
341 | | ||||
342 | void QalculateSession::currentExpressionStatusChanged(Cantor::Expression::Status status) | ||||
343 | { | ||||
344 | // depending on the status of the expression change the status of the session; | ||||
345 | switch (status) { | ||||
346 | | ||||
347 | case Cantor::Expression::Computing: | ||||
348 | break; | ||||
349 | case Cantor::Expression::Interrupted: | ||||
350 | changeStatus(Cantor::Session::Done); | ||||
351 | break; | ||||
352 | case Cantor::Expression::Done: | ||||
353 | case Cantor::Expression::Error: | ||||
354 | qDebug() << " ****** STATUS " << status; | ||||
85 | changeStatus(Cantor::Session::Done); | 355 | changeStatus(Cantor::Session::Done); | ||
356 | if(m_expressionQueue.size() > 0) | ||||
357 | m_expressionQueue.dequeue(); | ||||
358 | if(!m_expressionQueue.isEmpty()) | ||||
359 | runExpressionQueue(); | ||||
360 | } | ||||
86 | } | 361 | } | ||
87 | 362 | | |||
88 | Cantor::Expression* QalculateSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave) | 363 | Cantor::Expression* QalculateSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave) | ||
89 | { | 364 | { | ||
90 | QalculateExpression* expr = new QalculateExpression(this); | 365 | | ||
91 | expr->setFinishingBehavior(behave); | 366 | qDebug() << " ** evaluating expression: " << cmd << endl; | ||
367 | qDebug() << " size of expression queue: " << m_expressionQueue.size() << endl; | ||||
chinmoyr: comment out. | |||||
92 | 368 | | |||
93 | changeStatus(Cantor::Session::Running); | 369 | changeStatus(Cantor::Session::Running); | ||
370 | | ||||
371 | QalculateExpression* expr = new QalculateExpression(this); | ||||
372 | expr->setFinishingBehavior(behave); | ||||
94 | expr->setCommand(cmd); | 373 | expr->setCommand(cmd); | ||
95 | expr->evaluate(); | 374 | | ||
96 | changeStatus(Cantor::Session::Done); | 375 | m_expressionQueue.enqueue(expr); | ||
376 | runExpressionQueue(); | ||||
97 | 377 | | |||
98 | return expr; | 378 | return expr; | ||
379 | | ||||
380 | } | ||||
381 | | ||||
382 | void QalculateSession::runExpressionQueue() | ||||
383 | { | ||||
384 | if(!m_expressionQueue.isEmpty()) { | ||||
385 | | ||||
386 | if(!m_currentExpression) | ||||
Unfortunately we are not able to use or or and expressions yet, so change it to old logic operators syntax. In addition, could you provide parentheses for this verification? It is really bad to read (and it is creating an error message during building). filipesaraiva: Unfortunately we are not able to use `or` or `and` expressions yet, so change it to old logic… | |||||
I have changed the logic here a bit and have tried to improve the overall readability. There were no build errors on my side. Please check if the new code works fine on your system rishabhg: I have changed the logic here a bit and have tried to improve the overall readability.
There… | |||||
387 | m_currentExpression = m_expressionQueue.head(); | ||||
388 | | ||||
389 | else { | ||||
390 | /* there was some expression that was being executed by cantor. We run the new expression only | ||||
391 | if the current expression's status is 'Done' or 'Error', if not , we simply return | ||||
392 | */ | ||||
393 | Cantor::Expression::Status expr_status = m_currentExpression->status(); | ||||
394 | if(expr_status != Cantor::Expression::Done && expr_status != Cantor::Expression::Error) | ||||
395 | return; | ||||
396 | } | ||||
397 | | ||||
398 | m_currentExpression = m_expressionQueue.head(); | ||||
399 | connect(m_currentExpression, SIGNAL(statusChanged(Cantor::Expression::Status)), this, SLOT(currentExpressionStatusChanged(Cantor::Expression::Status))); | ||||
400 | // start processing the expression | ||||
401 | m_currentExpression->evaluate(); | ||||
402 | | ||||
99 | } | 403 | } | ||
404 | } | ||||
405 | | ||||
100 | 406 | | |||
101 | Cantor::CompletionObject* QalculateSession::completionFor(const QString& command, int index) | 407 | Cantor::CompletionObject* QalculateSession::completionFor(const QString& command, int index) | ||
102 | { | 408 | { | ||
103 | return new QalculateCompletionObject(command, index, this); | 409 | return new QalculateCompletionObject(command, index, this); | ||
104 | } | 410 | } | ||
105 | 411 | | |||
106 | Cantor::SyntaxHelpObject* QalculateSession::syntaxHelpFor(const QString& cmd) | 412 | Cantor::SyntaxHelpObject* QalculateSession::syntaxHelpFor(const QString& cmd) | ||
107 | { | 413 | { | ||
108 | return new QalculateSyntaxHelpObject(cmd, this); | 414 | return new QalculateSyntaxHelpObject(cmd, this); | ||
109 | } | 415 | } | ||
110 | 416 | | |||
111 | QSyntaxHighlighter* QalculateSession::syntaxHighlighter(QObject* parent) | 417 | QSyntaxHighlighter* QalculateSession::syntaxHighlighter(QObject* parent) | ||
112 | { | 418 | { | ||
113 | return new QalculateHighlighter(parent); | 419 | return new QalculateHighlighter(parent); | ||
114 | } | 420 | } | ||
115 | 421 | | |||
116 | void QalculateSession::setLastResult(MathStructure result) | | |||
117 | { | | |||
118 | for (int i = m_ansVariables.size()-1; i >0 ; --i) { | | |||
119 | m_ansVariables[i]->set(m_ansVariables[i-1]->get()); | | |||
120 | } | | |||
121 | m_ansVariables[0]->set(result); | | |||
122 | } | | |||
123 | 422 | | |||
124 | QAbstractItemModel* QalculateSession::variableModel() | 423 | QAbstractItemModel* QalculateSession::variableModel() | ||
125 | { | 424 | { | ||
126 | return m_variableModel; | 425 | return m_variableModel; | ||
127 | } | 426 | } |
comment out?