! * unit-testable helper function that is creating the new target spreadsheet and doing the actual flattening */
| 164 | * unit-testable helper function that is creating the new target spreadsheet and doing the actual flattening |
| 165 | */ |
| 166 | void FlattenColumnsDialog::flatten(const Spreadsheet* sourceSpreadsheet, const QVector<Column*>& valueColumns, const QVector<Column*>& referenceColumns) const { |
| 167 | // create target spreadsheet |
| 168 | const int referenceColumnCount = referenceColumns.count(); |
| 169 | auto* targetSpreadsheet = new Spreadsheet(i18n("Flatten of %1", m_spreadsheet->name())); |
| 170 | targetSpreadsheet->setColumnCount(referenceColumnCount + 2); |
| 171 | const auto& targetColumns = targetSpreadsheet->children<Column>(); |
| 172 | |
| 173 | // set the names and modes for the reference columns in the target spreadsheet |
| 174 | for (int i = 0; i < referenceColumnCount; ++i) { |
| 175 | auto* source = referenceColumns.at(i); |
| 176 | auto* target = targetSpreadsheet->column(i); |
| 177 | target->setName(source->name()); |
| 178 | target->setColumnMode(source->columnMode()); |
| 179 | } |
| 180 | |
| 181 | // add "Category" and "Value" columns which will contain the flattened data |
| 182 | auto* categoryColumn = targetSpreadsheet->column(referenceColumnCount); |
| 183 | categoryColumn->setName(i18n("Category")); |
| 184 | categoryColumn->setColumnMode(AbstractColumn::ColumnMode::Text); |
| 185 | categoryColumn->setPlotDesignation(AbstractColumn::PlotDesignation::X); |
| 186 | |
| 187 | auto* valueColumn = targetSpreadsheet->column(referenceColumnCount + 1); |
| 188 | valueColumn->setName(i18n("Value")); |
| 189 | auto valueColumnMode = valueColumns.at(0)->columnMode(); |
| 190 | valueColumn->setColumnMode(valueColumnMode); |
| 191 | |
| 192 | // flatten |
| 193 | int row = 0; // current row in the target spreadsheet |
| 194 | for (int i = 0; i < sourceSpreadsheet->rowCount(); ++i) { |
| 195 | for (int j = 0; j < valueColumns.count(); ++j) { |
| 196 | auto* sourceColumn = valueColumns.at(j); |
| 197 | |
| 198 | // skip the current row if there are now source values to be flattened |
| 199 | if (sourceColumn->asStringColumn()->textAt(i).isEmpty()) |
| 200 | continue; |
| 201 | |
| 202 | // skip the current row if there is not a single reference value |
| 203 | bool hasReferenceValues = false; |
| 204 | for (auto* col : referenceColumns) { |
| 205 | if (!col->asStringColumn()->textAt(i).isEmpty()) { |
| 206 | hasReferenceValues = true; |
| 207 | break; |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | if (referenceColumnCount > 0 && !hasReferenceValues) |
| 212 | continue; |
| 213 | |
| 214 | // add reference values for every source column to be flattened |
| 215 | int refIndex = 0; |
| 216 | for (auto* col : referenceColumns) { |
| 217 | switch (col->columnMode()) { |
| 218 | case AbstractColumn::ColumnMode::Double: { |
| 219 | auto value = col->valueAt(i); |
| 220 | targetColumns.at(refIndex)->setValueAt(row, value); |
| 221 | break; |
| 222 | } |
| 223 | case AbstractColumn::ColumnMode::Integer: { |
nothing calls this directly
no test coverage detected