#include <fstream>
#include <boost/tokenizer.hpp>
#include <Wt/WAbstractItemModel.h>
#include <Wt/WStandardItemModel.h>
#include <Wt/WStandardItem.h>
#include <Wt/WString.h>
#include "CsvUtil.h"
/*
* A standard item which converts text edits to numbers
*/
class NumericItem : public WStandardItem {
public:
virtual std::unique_ptr<WStandardItem> clone() const {
return std::unique_ptr<NumericItem>(std::make_unique<NumericItem>());
}
virtual void setData(const cpp17::any &data, ItemDataRole role = ItemDataRole::User) {
cpp17::any dt;
if (role == ItemDataRole::Edit) {
std::string s = asString(data).toUTF8();
char *end;
double d = std::strtod(s.c_str(), &end);
if (*end == 0)
dt = cpp17::any(d);
else
dt = data;
} else
dt = data;
WStandardItem::setData(dt, role);
}
};
std::shared_ptr<WStandardItemModel> csvToModel(const std::string& csvFile,
bool firstLineIsHeaders)
{
std::ifstream f(csvFile.c_str());
if (f) {
std::shared_ptr<WStandardItemModel> result = std::make_shared<WStandardItemModel>(0, 0);
result->setItemPrototype(std::make_unique<NumericItem>());
readFromCsv(f, result, -1, firstLineIsHeaders);
return result;
} else
return nullptr;
}
void readFromCsv(std::istream& f, std::shared_ptr<WAbstractItemModel> model,
int numRows, bool firstLineIsHeaders)
{
int csvRow = 0;
while (f) {
std::string line;
getline(f, line);
if (f) {
typedef boost::tokenizer<boost::escaped_list_separator<char> >
CsvTokenizer;
CsvTokenizer tok(line);
int col = 0;
for (CsvTokenizer::iterator i = tok.begin();
i != tok.end(); ++i, ++col) {
if (col >= model->columnCount())
model->insertColumns(model->columnCount(),
col + 1 - model->columnCount());
if (firstLineIsHeaders && csvRow == 0)
model->setHeaderData(col, cpp17::any{WString{*i}});
else {
int dataRow = firstLineIsHeaders ? csvRow - 1 : csvRow;
if (numRows != -1 && dataRow >= numRows)
return;
if (dataRow >= model->rowCount())
model->insertRows(model->rowCount(),
dataRow + 1 - model->rowCount());
cpp17::any data{WString{*i}};
model->setData(dataRow, col, data);
}
}
}
++csvRow;
}
}