#include "csvparser.h" #include #include #include #include "../../3rdParty/rapidcsv/src/rapidcsv.h" #include "../model/metadata.h" using namespace rapidcsv; QList CsvParser::getItemsFromCSVFile(const QString& fileName) { Document doc(fileName.toStdString()); const bool isCompatible = isCsvCompatible(doc); if (isCompatible) { const QList result = createListItemsFromCsvEntries(doc); return result; } else { return QList(); } } bool CsvParser::exportToCSVFile(const QList& rows, const QString& filePath) { Document doc(std::string(), LabelParams(0, -1)); const QList headerNames = GET_HEADER_NAMES(); for (int column = 0; column < headerNames.size(); ++column) { doc.SetColumnName(column, headerNames.at(column).toStdString()); } for (int row = 0; row < rows.size(); ++row) { QStringList rowValues = rows.at(row); std::vector rowValueStrings; for (int column = 0; column < rowValues.size(); ++column) { rowValueStrings.push_back(rowValues.at(column).toStdString()); } doc.InsertRow(row, rowValueStrings); } doc.Save(filePath.toStdString()); return true; } CsvParser::CsvParser() {} /** A CSV file is compatible if the following is true: * - there is a CSV column for every column in the table model * (except there are optional columns defined in the model) * @brief CsvParser::isCsvCompatible * @param doc * @return */ bool CsvParser::isCsvCompatible(const rapidcsv::Document& doc) { qInfo() << "Checking CSV document for compatiblity..."; const std::vector columnNames = doc.GetColumnNames(); for (const QString& headerName : GET_HEADER_NAMES()) { bool isHeaderNameFound = false; if (std::find(columnNames.begin(), columnNames.end(), headerName) != columnNames.end()) { qDebug() << QString("Header found in column names: %1").arg(headerName); } else { const QString errorString = QString("Couldn't find header name '%1' in CSV file. Aborting...").arg(headerName); qWarning() << errorString; return false; } } return true; } QList CsvParser::createListItemsFromCsvEntries(const rapidcsv::Document& doc) { QList result; const int rowCount = doc.GetRowCount(); const QList headerNames = GET_HEADER_NAMES(); /// get the values for all columns QHash> columnValueMap = extractColumnValues(headerNames, doc); /// get item values for each row for (int row = 0; row < rowCount; ++row) { const ModelItemValues itemValues = getItemValuesForRow(headerNames, columnValueMap, row); result.append(itemValues); } return result; } QHash> CsvParser::extractColumnValues( const QList headerNames, const rapidcsv::Document& doc) { QHash> columnValueMap; for (const QString& columnName : headerNames) { // NEXT add support for optional columns // if (optionalCsvHeaderNames.contains(columnName)) { // const std::vector columnNames = doc.GetColumnNames(); // int columnIdx = doc.GetColumnIdx(columnName.toStdString()); // if (columnIdx == -1) { // continue; // } // } const std::vector columnValues = doc.GetColumn(columnName.toStdString()); columnValueMap.insert(columnName, columnValues); } return columnValueMap; } ModelItemValues CsvParser::getItemValuesForRow( const QList& headerNames, const QHash>& columnValueMap, const int row) { ModelItemValues result; for (const QString& columnName : headerNames) { if (!columnValueMap.contains(columnName)) { continue; } int role = ROLE_NAMES.key(columnName.toLatin1()); std::string valueString = columnValueMap.value(columnName).at(row); QVariant value = parseItemValue(role, valueString); if (value.isValid()) { result[role] = value; } } return result; } QVariant CsvParser::parseItemValue(const int role, const std::string& valueString) { QVariant result; if (STRING_ROLES.contains(role)) { /// string values result = QString::fromStdString(valueString); } else if (INT_ROLES.contains(role)) { /// int values /// GetColumn crashed (probably because of the empty values) /// so the strings will be processed later const QString intAsString = QString::fromStdString(valueString); result = intAsString.toInt(); } else if (DOUBLE_ROLES.contains(role)) { /// double values const QString doubleAsString = QString::fromStdString(valueString); double doubleValue; if (doubleAsString.contains(',')) { QLocale german(QLocale::German); doubleValue = german.toDouble(doubleAsString); } else { doubleValue = doubleAsString.toDouble(); } result = doubleValue; // } else if (typeColumns.contains(columnName)) { // // NEXT validate string is allowed // values[role] = QString::fromStdString(columnValueMap.value(columnName).at(row)); } else { /// no type recognized for column QString errorString = QString("Couldn't find value type for role '%1'").arg(role); qCritical() << errorString; } return result; }