Changeset View
Standalone View
src/backends/qalculate/qalculatesession.cpp
Context not available. | |||||
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 | 29 | | |||
30 | #include <libqalculate/Calculator.h> | 30 | #include <libqalculate/Calculator.h> | ||
31 | #include <libqalculate/ExpressionItem.h> | 31 | #include <libqalculate/ExpressionItem.h> | ||
Context not available. | |||||
38 | 38 | | |||
39 | QalculateSession::QalculateSession( Cantor::Backend* backend) | 39 | QalculateSession::QalculateSession( Cantor::Backend* backend) | ||
40 | : Session(backend), | 40 | : Session(backend), | ||
41 | m_variableModel(new Cantor::DefaultVariableModel(this)) | 41 | m_variableModel(new Cantor::DefaultVariableModel(this)), | ||
42 | m_process(0), | ||||
43 | m_currentExpression(0) | ||||
42 | { | 44 | { | ||
45 | /* | ||||
46 | qalc does all of this by default, so we don't have to do this anymore | ||||
47 | but we might need this when plotting graphs. | ||||
48 | */ | ||||
49 | | ||||
43 | if ( !CALCULATOR ) { | 50 | if ( !CALCULATOR ) { | ||
44 | new Calculator(); | 51 | new Calculator(); | ||
45 | CALCULATOR->loadGlobalDefinitions(); | 52 | CALCULATOR->loadGlobalDefinitions(); | ||
46 | CALCULATOR->loadLocalDefinitions(); | 53 | CALCULATOR->loadLocalDefinitions(); | ||
47 | CALCULATOR->loadExchangeRates(); | 54 | CALCULATOR->loadExchangeRates(); | ||
48 | } | 55 | } | ||
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 | } | 56 | } | ||
61 | 57 | | |||
62 | QalculateSession::~QalculateSession() | 58 | QalculateSession::~QalculateSession() | ||
63 | { | 59 | { | ||
64 | CALCULATOR->abort(); | 60 | CALCULATOR->abort(); | ||
61 | if(m_process) | ||||
62 | m_process->kill(); | ||||
65 | } | 63 | } | ||
66 | 64 | | |||
67 | void QalculateSession::login() | 65 | void QalculateSession::login() | ||
68 | { | 66 | { | ||
69 | if(!QalculateSettings::autorunScripts().isEmpty()){ | | |||
70 | QString autorunScripts = QalculateSettings::self()->autorunScripts().join(QLatin1String("\n")); | | |||
71 | 67 | | |||
72 | evaluateExpression(autorunScripts, QalculateExpression::DeleteOnFinish); | 68 | /* we will , most probably, use autoscripts for setting the mode , evaulate options, print options etc */ | ||
69 | | ||||
70 | // if(!QalculateSettings::autorunScripts().isEmpty()){ | ||||
71 | // QString autorunScripts = QalculateSettings::self()->autorunScripts().join(QLatin1String("\n")); | ||||
72 | // | ||||
73 | // evaluateExpression(autorunScripts, QalculateExpression::DeleteOnFinish); | ||||
74 | // } | ||||
75 | | ||||
76 | /* | ||||
77 | set up the process here. The program path , arguments(if any),channel modes , and connections should all be set up here. | ||||
78 | once the setup is complete, start the process and inform the worksheet that we are ready | ||||
79 | */ | ||||
80 | m_process = new QProcess(this); | ||||
81 | | ||||
82 | m_process->setProgram(QStandardPaths::findExecutable(QLatin1String("qalc"))); | ||||
83 | m_process->setProcessChannelMode(QProcess::SeparateChannels); | ||||
84 | | ||||
85 | connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput())); | ||||
86 | connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(readError())); | ||||
87 | connect(m_process, SIGNAL(started()), this, SLOT(processStarted())); | ||||
88 | | ||||
89 | m_process->start(); | ||||
90 | } | ||||
91 | | ||||
92 | void QalculateSession::readOutput() | ||||
93 | { | ||||
94 | while(m_process->bytesAvailable()) { | ||||
95 | m_output.append(QString::fromLocal8Bit(m_process->readLine())); | ||||
96 | } | ||||
97 | | ||||
98 | if(m_currentExpression && !m_output.isEmpty() && m_output.trimmed().endsWith(QLatin1String(">"))) { | ||||
99 | | ||||
100 | // check if the commandQueue is empty or not . if it's not empty run the "runCommandQueue" function. | ||||
101 | // store the output in finalOutput and clear m_output | ||||
102 | m_output = m_output.trimmed(); | ||||
103 | m_output.remove(m_currentCommand); | ||||
104 | m_output.replace(QLatin1String("\n"), QLatin1String("")); | ||||
105 | m_finalOutput.append(m_output); | ||||
106 | m_finalOutput.append(QLatin1String("\n\n")); | ||||
107 | m_output.clear(); | ||||
108 | if (!m_commandQueue.isEmpty()) | ||||
109 | runCommandQueue(); | ||||
110 | else { | ||||
111 | qDebug () << "parsing output: " << m_finalOutput << endl; | ||||
112 | m_currentExpression->parseOutput(m_finalOutput); | ||||
113 | m_finalOutput.clear(); | ||||
114 | } | ||||
115 | | ||||
116 | | ||||
117 | } | ||||
118 | } | ||||
119 | | ||||
120 | void QalculateSession::readError() | ||||
121 | { | ||||
122 | | ||||
123 | QString error = QLatin1String(m_process->readAllStandardError()); | ||||
124 | if(m_currentExpression) { | ||||
125 | m_currentExpression->parseError(error); | ||||
73 | } | 126 | } | ||
127 | } | ||||
74 | 128 | | |||
75 | changeStatus(Cantor::Session::Done); | 129 | void QalculateSession::processStarted() | ||
130 | { | ||||
131 | qDebug() << "process started " << m_process->program() << m_process->processId() << endl; | ||||
76 | emit ready(); | 132 | emit ready(); | ||
chinmoyr: comment out? | |||||
77 | } | 133 | } | ||
78 | 134 | | |||
79 | void QalculateSession::logout() | 135 | void QalculateSession::logout() | ||
80 | { | 136 | { | ||
137 | qDebug () << "logging out " << endl; | ||||
138 | if(m_process) { | ||||
139 | m_process->write("quit\n"); | ||||
140 | if(!m_process->waitForFinished(1000)) | ||||
141 | m_process->kill(); | ||||
142 | } | ||||
81 | } | 143 | } | ||
82 | 144 | | |||
83 | void QalculateSession::interrupt() | 145 | void QalculateSession::interrupt() | ||
84 | { | 146 | { | ||
85 | changeStatus(Cantor::Session::Done); | 147 | qDebug () << "interrupting .... " << endl; | ||
chinmoyr: this and also others following this. | |||||
148 | if(m_currentExpression) | ||||
149 | m_currentExpression->interrupt(); | ||||
150 | | ||||
151 | m_commandQueue.clear(); | ||||
152 | m_expressionQueue.clear(); | ||||
153 | m_output.clear(); | ||||
154 | m_finalOutput.clear(); | ||||
155 | m_currentCommand.clear(); | ||||
156 | | ||||
157 | } | ||||
158 | | ||||
159 | void QalculateSession::runExpression() | ||||
160 | { | ||||
161 | | ||||
162 | QString command = m_currentExpression->command(); | ||||
163 | foreach(const QString& cmd, command.split(QLatin1Char('\n'))) { | ||||
chinmoyr: const QString | |||||
164 | m_commandQueue.enqueue(cmd); | ||||
165 | } | ||||
166 | runCommandQueue(); | ||||
167 | | ||||
168 | } | ||||
169 | | ||||
170 | | ||||
171 | void QalculateSession::runCommandQueue() | ||||
172 | { | ||||
173 | if (!m_commandQueue.isEmpty()) { | ||||
174 | m_currentCommand = m_commandQueue.dequeue(); | ||||
175 | m_currentCommand = m_currentCommand.trimmed(); | ||||
176 | m_currentCommand += QLatin1String("\n"); | ||||
177 | m_process->write(m_currentCommand.toLocal8Bit()); | ||||
178 | } | ||||
179 | } | ||||
180 | | ||||
181 | void QalculateSession::currentExpressionStatusChanged(Cantor::Expression::Status status) | ||||
182 | { | ||||
183 | // depending on the status of the expression change the status of the session; | ||||
184 | switch (status) { | ||||
185 | | ||||
186 | case Cantor::Expression::Computing: | ||||
187 | break; | ||||
188 | case Cantor::Expression::Interrupted: | ||||
189 | changeStatus(Cantor::Session::Done); | ||||
190 | break; | ||||
191 | case Cantor::Expression::Done: | ||||
192 | case Cantor::Expression::Error: | ||||
193 | qDebug() << " ****** STATUS " << status; | ||||
194 | changeStatus(Cantor::Session::Done); | ||||
195 | m_expressionQueue.dequeue(); | ||||
196 | if(!m_expressionQueue.isEmpty()) | ||||
197 | runExpressionQueue(); | ||||
198 | } | ||||
86 | } | 199 | } | ||
87 | 200 | | |||
88 | Cantor::Expression* QalculateSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave) | 201 | Cantor::Expression* QalculateSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave) | ||
89 | { | 202 | { | ||
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… | |||||
90 | QalculateExpression* expr = new QalculateExpression(this); | 203 | | ||
91 | expr->setFinishingBehavior(behave); | 204 | qDebug() << " ** evaluating expression: " << cmd << endl; | ||
chinmoyr: comment out. | |||||
205 | qDebug() << " size of expression queue: " << m_expressionQueue.size() << endl; | ||||
92 | 206 | | |||
93 | changeStatus(Cantor::Session::Running); | 207 | changeStatus(Cantor::Session::Running); | ||
208 | | ||||
209 | QalculateExpression* expr = new QalculateExpression(this); | ||||
210 | expr->setFinishingBehavior(behave); | ||||
94 | expr->setCommand(cmd); | 211 | expr->setCommand(cmd); | ||
95 | expr->evaluate(); | 212 | | ||
96 | changeStatus(Cantor::Session::Done); | 213 | m_expressionQueue.enqueue(expr); | ||
214 | runExpressionQueue(); | ||||
97 | 215 | | |||
chinmoyr: I think `return currentCmd.clear()` also does the same thing | |||||
rishabhg: Yes. I don't know why I did this | |||||
98 | return expr; | 216 | return expr; | ||
217 | | ||||
218 | } | ||||
219 | | ||||
220 | void QalculateSession::runExpressionQueue() | ||||
221 | { | ||||
222 | if(!m_expressionQueue.isEmpty()) { | ||||
223 | | ||||
224 | if(!m_currentExpression or m_currentExpression->status() == Cantor::Expression::Done or m_currentExpression->status() == Cantor::Expression::Error) { | ||||
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… | |||||
225 | m_currentExpression = m_expressionQueue.head(); | ||||
226 | connect(m_currentExpression, SIGNAL(statusChanged(Cantor::Expression::Status)), this, SLOT(currentExpressionStatusChanged(Cantor::Expression::Status))); | ||||
227 | // start processing the expression | ||||
228 | m_currentExpression->evaluate(); | ||||
229 | } | ||||
230 | } | ||||
99 | } | 231 | } | ||
100 | 232 | | |||
233 | | ||||
101 | Cantor::CompletionObject* QalculateSession::completionFor(const QString& command, int index) | 234 | Cantor::CompletionObject* QalculateSession::completionFor(const QString& command, int index) | ||
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. | |||||
102 | { | 235 | { | ||
103 | return new QalculateCompletionObject(command, index, this); | 236 | return new QalculateCompletionObject(command, index, this); | ||
chinmoyr: Use QStringLiteral | |||||
Do something like this currentCmd = QStringLiteral(...).arg(...); return currentCmd; chinmoyr: Do something like this
```currentCmd = QStringLiteral(...).arg(...);
return currentCmd;```
| |||||
Context not available. | |||||
113 | return new QalculateHighlighter(parent); | 246 | return new QalculateHighlighter(parent); | ||
114 | } | 247 | } | ||
chinmoyr: Use currentCmd + QStringLiteral combination. | |||||
115 | 248 | | |||
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 | 249 | | |||
124 | QAbstractItemModel* QalculateSession::variableModel() | 250 | QAbstractItemModel* QalculateSession::variableModel() | ||
125 | { | 251 | { | ||
Context not available. | |||||
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. |
comment out?