diff --git a/src/backend/core/column/ColumnPrivate.h b/src/backend/core/column/ColumnPrivate.h --- a/src/backend/core/column/ColumnPrivate.h +++ b/src/backend/core/column/ColumnPrivate.h @@ -139,6 +139,7 @@ AbstractColumn::PlotDesignation m_plot_designation{AbstractColumn::NoDesignation}; int m_width{0}; //column width in the view Column* m_owner; + QVector m_connectionsUpdateFormula; }; #endif diff --git a/src/backend/core/column/ColumnPrivate.cpp b/src/backend/core/column/ColumnPrivate.cpp --- a/src/backend/core/column/ColumnPrivate.cpp +++ b/src/backend/core/column/ColumnPrivate.cpp @@ -30,6 +30,7 @@ #include "ColumnPrivate.h" #include "ColumnStringIO.h" #include "Column.h" +#include "backend/spreadsheet/Spreadsheet.h" #include "backend/core/datatypes/filter.h" #include "backend/gsl/ExpressionParser.h" @@ -162,7 +163,7 @@ */ void ColumnPrivate::setColumnMode(AbstractColumn::ColumnMode mode) { DEBUG("ColumnPrivate::setColumnMode() " << ENUM_TO_STRING(AbstractColumn, ColumnMode, m_column_mode) - << " -> " << ENUM_TO_STRING(AbstractColumn, ColumnMode, mode)); + << " -> " << ENUM_TO_STRING(AbstractColumn, ColumnMode, mode)) if (mode == m_column_mode) return; void* old_data = m_data; @@ -897,13 +898,12 @@ m_formulaVariableColumns = variableColumns; m_formulaAutoUpdate = autoUpdate; - //TODO: doesn't work - disconnect(m_owner, SLOT(updateFormula())); + for (auto connection: m_connectionsUpdateFormula) + disconnect(connection); if (autoUpdate) { - QVector columns; for (auto column : variableColumns) - connect(column, &Column::dataChanged, m_owner, &Column::updateFormula); + m_connectionsUpdateFormula << connect(column, &Column::dataChanged, m_owner, &Column::updateFormula); } } @@ -936,14 +936,10 @@ * \sa FunctionValuesDialog::generate() */ void ColumnPrivate::updateFormula() { - //TODO: this check shouldn't be required, but the disconnect in - //ColumnPrivate::setFormula() doesn't seem to work - if (!m_formulaAutoUpdate) - return; - //determine variable names and the data vectors of the specified columns QVector*> xVectors; QVector*> xNewVectors; + int maxRowCount = 0; for (auto column : m_formulaVariableColumns) { if (column->columnMode() == AbstractColumn::Integer) { @@ -956,20 +952,35 @@ xVectors << xVector; } else xVectors << static_cast* >(column->data()); + + if (column->rowCount() > maxRowCount) + maxRowCount = column->rowCount(); } + //resize the spreadsheet if one of the data vectors from + //other spreadsheet(s) has more elements than the parent spreadsheet + Spreadsheet* spreadsheet = dynamic_cast(m_owner->parentAspect()); + Q_ASSERT(spreadsheet); + if (spreadsheet->rowCount() < maxRowCount) + spreadsheet->setRowCount(maxRowCount); + //create new vector for storing the calculated values //the vectors with the variable data can be smaller then the result vector. So, not all values in the result vector might get initialized. //->"clean" the result vector first - QVector new_data(rowCount()); - for (auto& d : new_data) - d = NAN; + QVector new_data(rowCount(), NAN); //evaluate the expression for f(x_1, x_2, ...) and write the calculated values into a new vector. ExpressionParser* parser = ExpressionParser::getInstance(); parser->evaluateCartesian(m_formula, m_formulaVariableNames, xVectors, &new_data); replaceValues(0, new_data); + // initialize remaining rows with NAN + int remainingRows = rowCount() - maxRowCount; + if (remainingRows > 0) { + QVector emptyRows(remainingRows, NAN); + replaceValues(maxRowCount, emptyRows); + } + //delete help vectors created for the conversion from int to double for (auto* vector : xNewVectors) delete vector; diff --git a/src/backend/spreadsheet/Spreadsheet.h b/src/backend/spreadsheet/Spreadsheet.h --- a/src/backend/spreadsheet/Spreadsheet.h +++ b/src/backend/spreadsheet/Spreadsheet.h @@ -69,6 +69,8 @@ int colY(int col); QString text(int row, int col) const; + void updateColumnValues(QVector& columns, const QString expression, QStringList& variableNames, QVector& variableColumns, bool autoUpdate); + void copy(Spreadsheet* other); void save(QXmlStreamWriter*) const override; diff --git a/src/backend/spreadsheet/Spreadsheet.cpp b/src/backend/spreadsheet/Spreadsheet.cpp --- a/src/backend/spreadsheet/Spreadsheet.cpp +++ b/src/backend/spreadsheet/Spreadsheet.cpp @@ -668,6 +668,18 @@ return c->asStringColumn()->textAt(row); } +void Spreadsheet::updateColumnValues(QVector& columns, const QString expression, QStringList& variableNames, QVector& variableColumns, bool autoUpdate) { + + //set the new values and store the expression, variable names and the used data columns + for (auto* col : columns) { + if (col->columnMode() != AbstractColumn::Numeric) + col->setColumnMode(AbstractColumn::Numeric); + + col->setFormula(expression, variableNames, variableColumns, autoUpdate); + col->updateFormula(); + } +} + /*! * This slot is, indirectly, called when a child of \c Spreadsheet (i.e. column) was selected in \c ProjectExplorer. * Emits the signal \c columnSelected that is handled in \c SpreadsheetView. diff --git a/src/kdefrontend/spreadsheet/FunctionValuesDialog.cpp b/src/kdefrontend/spreadsheet/FunctionValuesDialog.cpp --- a/src/kdefrontend/spreadsheet/FunctionValuesDialog.cpp +++ b/src/kdefrontend/spreadsheet/FunctionValuesDialog.cpp @@ -29,7 +29,6 @@ #include "backend/core/AspectTreeModel.h" #include "backend/core/column/Column.h" #include "backend/core/Project.h" -#include "backend/gsl/ExpressionParser.h" #include "backend/lib/macros.h" #include "backend/spreadsheet/Spreadsheet.h" #include "commonfrontend/widgets/TreeViewComboBox.h" @@ -333,10 +332,7 @@ //determine variable names and the data vectors of the specified columns QStringList variableNames; - QVector columns; - QVector*> xVectors; - QVector*> xNewVectors; - int maxRowCount = m_spreadsheet->rowCount(); + QVector variableColumns; for (int i = 0; i < m_variableNames.size(); ++i) { variableNames << m_variableNames.at(i)->text().simplified(); @@ -344,53 +340,21 @@ Q_ASSERT(aspect); auto* column = dynamic_cast(aspect); Q_ASSERT(column); - columns << column; - if (column->columnMode() == AbstractColumn::Integer) { - //convert integers to doubles first - auto* xVector = new QVector(column->rowCount()); - for (int i = 0; irowCount(); ++i) - xVector->operator[](i) = column->valueAt(i); - - xNewVectors << xVector; - xVectors << xVector; - } else - xVectors << static_cast* >(column->data()); - - if (column->rowCount() > maxRowCount) - maxRowCount = column->rowCount(); + variableColumns << column; } - //resize the spreadsheet if one of the data vectors from other spreadsheet(s) has more elements then the current spreadsheet. - if (m_spreadsheet->rowCount() < maxRowCount) - m_spreadsheet->setRowCount(maxRowCount); - - //create new vector for storing the calculated values - //the vectors with the variable data can be smaller then the result vector. So, not all values in the result vector might get initialized. - //->"clean" the result vector first - QVector new_data(maxRowCount); - for (auto& d : new_data) - d = NAN; - - //evaluate the expression for f(x_1, x_2, ...) and write the calculated values into a new vector. - ExpressionParser* parser = ExpressionParser::getInstance(); - const QString& expression = ui.teEquation->toPlainText(); - parser->evaluateCartesian(expression, variableNames, xVectors, &new_data); - //set the new values and store the expression, variable names and the used data columns + const QString& expression = ui.teEquation->toPlainText(); bool autoUpdate = (ui.chkAutoUpdate->checkState() == Qt::Checked); for (auto* col : m_columns) { if (col->columnMode() != AbstractColumn::Numeric) col->setColumnMode(AbstractColumn::Numeric); - col->setFormula(expression, variableNames, columns, autoUpdate); - col->replaceValues(0, new_data); + col->setFormula(expression, variableNames, variableColumns, autoUpdate); + col->updateFormula(); } m_spreadsheet->endMacro(); - //delete help vectors created for the conversion from int to double - for (auto* vector : xNewVectors) - delete vector; - RESET_CURSOR; }