File indexing completed on 2024-05-12 11:32:35

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-or-later
0003     SPDX-FileCopyrightText: 2018 Nikita Sirgienko <warquark@gmail.com>
0004 */
0005 
0006 #include "rvariablemodel.h"
0007 #include "rkeywords.h"
0008 #include "rsession.h"
0009 
0010 #include <result.h>
0011 
0012 using namespace Cantor;
0013 
0014 RVariableModel::RVariableModel(RSession* session) : DefaultVariableModel(session)
0015 {
0016 }
0017 
0018 RVariableModel::~RVariableModel()
0019 {
0020     if (m_expression)
0021         m_expression->setFinishingBehavior(Expression::FinishingBehavior::DeleteOnFinish);
0022 }
0023 
0024 void RVariableModel::update()
0025 {
0026     if (m_expression)
0027         return;
0028 
0029     m_expression = session()->evaluateExpression(QLatin1String("%model update"), Expression::FinishingBehavior::DoNotDelete, true);
0030     connect(m_expression, &Expression::statusChanged, this, &RVariableModel::parseResult);
0031 }
0032 
0033 void RVariableModel::parseResult(Cantor::Expression::Status status)
0034 {
0035     switch(status)
0036     {
0037         case Expression::Status::Done:
0038         {
0039             if (!m_expression->result())
0040                 break;
0041 
0042             const QChar recordSep(30);
0043             const QChar unitSep(31);
0044 
0045             const QString output = m_expression->result()->data().toString();
0046 
0047             const QStringList& names = output.section(unitSep, 0, 0).split(recordSep, QString::SkipEmptyParts);
0048             const QStringList& values = output.section(unitSep, 1, 1).split(recordSep, QString::SkipEmptyParts);
0049             QStringList funcs = output.section(unitSep, 2, 2).split(recordSep, QString::SkipEmptyParts);
0050             const QStringList& constants = output.section(unitSep, 3, 3).split(recordSep, QString::SkipEmptyParts);
0051 
0052             QList<Variable> vars;
0053             if (!values.isEmpty()) // Variables management disabled
0054                 for (int i = 0; i < names.size(); i++)
0055                 {
0056                     if (i < values.size())
0057                         vars.append(Variable{names.at(i), values.at(i)});
0058                     else
0059                         vars.append(Variable{names.at(i), QString()});
0060                 }
0061             else
0062                 for (int i = 0; i < names.size(); i++)
0063                     vars.append(Variable{names.at(i), QString()});
0064 
0065             setVariables(vars);
0066 
0067             // Remove primitive function "(" because it not function for user calling (i guess)
0068             // And the function with name like this make highlighting worse actually
0069             funcs.removeOne(QLatin1String("("));
0070 
0071             // Also removes syntax keywords from functions list, like "function"
0072             for (const QString& keyword: RKeywords::instance()->keywords())
0073                 funcs.removeOne(keyword);
0074 
0075             setFunctions(funcs);
0076             setConstants(constants);
0077             break;
0078         }
0079         case Expression::Status::Error:
0080             qWarning() << "R code for update variable model finishs with error message: " << m_expression->errorMessage();
0081             break;
0082 
0083         case Expression::Status::Interrupted:
0084             break;
0085 
0086         default:
0087             return;
0088     }
0089 
0090     m_expression->deleteLater();
0091     m_expression = nullptr;
0092 }
0093 
0094 void RVariableModel::setConstants(QStringList newConstants)
0095 {
0096     QStringList addedConstants;
0097     QStringList removedConstants;
0098 
0099     //remove the old variables
0100     int i = 0;
0101     while (i < m_constants.size())
0102     {
0103         //check if this var is present in the new variables
0104         bool found = false;
0105         for (const QString& constant : newConstants)
0106             if(m_constants[i] == constant)
0107             {
0108                 found=true;
0109                 break;
0110             }
0111 
0112         if(!found)
0113         {
0114             removedConstants << m_constants[i];
0115             m_constants.removeAt(i);
0116         }
0117         else
0118             i++;
0119     }
0120 
0121     for (const QString& constant : newConstants)
0122     {
0123         if (!m_constants.contains(constant))
0124         {
0125             addedConstants << constant;
0126             m_constants.append(constant);
0127         }
0128     }
0129 
0130     emit constantsAdded(addedConstants);
0131     emit constantsRemoved(removedConstants);
0132 }