438 lines
13 KiB
C++
438 lines
13 KiB
C++
#include "xlsxhandler.h"
|
|
#include "logger.h"
|
|
#include "analysisoperationrecorder.h"
|
|
#include "global.h"
|
|
|
|
namespace AnaOpRecorder = AnalysisOperationRecorder;
|
|
using AnaOpRecorderOperation = AnalysisOperationRecorder::AnalysisOperation;
|
|
|
|
using AnalysisMode = Global::AnalysisMode;
|
|
|
|
|
|
QString XlsxHandler::_currentFilePath;
|
|
|
|
void XlsxHandler::test()
|
|
{
|
|
#if 0
|
|
QString sourceFilePath = QDir::currentPath() + "/sample.xlsx";
|
|
qDebug() << "fileName:" << sourceFilePath;
|
|
readFile(sourceFilePath);
|
|
#endif
|
|
|
|
QString sourceFilePath = QDir::currentPath() + "/sample-save.xlsx";
|
|
writeFile(sourceFilePath);
|
|
}
|
|
|
|
int XlsxHandler::readFile(const QString sourceFilePath, Global::CurveFileData &cfd)
|
|
{
|
|
if(!QFile::exists(sourceFilePath))
|
|
{
|
|
qDebug() << "xlsx file not existed:" << sourceFilePath;
|
|
return 1;
|
|
}
|
|
QFileInfo fileInfo(sourceFilePath);
|
|
|
|
// 获取文件的后缀名并转换为小写,方便比较
|
|
QString fileSuffix = fileInfo.suffix().toLower();
|
|
|
|
// 判断后缀名是否为 "xlsx"
|
|
if (fileSuffix != "xlsx") {
|
|
std::cout << "该文件的后缀不是 xlsx" << std::endl;
|
|
return 2;
|
|
}
|
|
|
|
_currentFilePath = sourceFilePath;
|
|
|
|
QXlsx::Document xlsx(sourceFilePath);
|
|
|
|
QXlsx::Worksheet *workSheet = xlsx.currentWorksheet();
|
|
if(!workSheet)
|
|
{
|
|
logde << "current sheet is empty.";
|
|
return 3;
|
|
}
|
|
|
|
//
|
|
int index = 2;
|
|
Global::ExperimentInfo& ei = cfd.ei;
|
|
ei.sampleName = workSheet->cellAt(index++, 2)->value().toString();
|
|
ei.sampleWeight = workSheet->cellAt(index++, 2)->value().toString();
|
|
logde<<"xlsx sample weight:"<<ei.sampleWeight.toStdString();
|
|
|
|
index++; // skip crucible weight.
|
|
ei.date = workSheet->cellAt(index++, 2)->value().toString();
|
|
ei.experimentor = workSheet->cellAt(index++, 2)->value().toString();
|
|
index++; // skip measure type.
|
|
ei.phaseSize = workSheet->cellAt(index++, 2)->value().toInt();
|
|
|
|
QVector<Global::PhaseTotalInfo>& phaseTotalVtr = cfd.phaseTotalVtr;
|
|
int dataIndex = 9;
|
|
for(int i = 0; i < ei.phaseSize; i++)
|
|
{
|
|
Global::PhaseTotalInfo phaseTotal;
|
|
phaseTotal.phaseIndex = i + 1;
|
|
|
|
readPhaseData(workSheet, dataIndex, phaseTotal);
|
|
phaseTotalVtr.push_back(phaseTotal);
|
|
}
|
|
|
|
logde<<"dataIndex:"<<dataIndex;
|
|
|
|
readAnalysisOperation(workSheet,dataIndex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void XlsxHandler::readPhaseData(QXlsx::Worksheet *workSheet, int &startLineIndex,
|
|
Global::PhaseTotalInfo &phaseTotal)
|
|
{
|
|
// skip.# Time/min Temp/℃ Voltage/mW
|
|
startLineIndex++;
|
|
// skip.第一段
|
|
startLineIndex++;
|
|
|
|
logde<<"startLineIndex:"<<startLineIndex;
|
|
|
|
phaseTotal.phase.cutoff_temp = workSheet->cellAt(startLineIndex++, 2)->value().toDouble();
|
|
phaseTotal.phase.temp_flow = workSheet->cellAt(startLineIndex++, 2)->value().toDouble();
|
|
phaseTotal.phase.constant_temp_time_min = (uint16_t)(workSheet->cellAt(startLineIndex++, 2)->value().toInt());
|
|
phaseTotal.phase.gas = static_cast<GasType>(workSheet->cellAt(startLineIndex++, 2)->value().toInt());
|
|
|
|
int dataSize = workSheet->cellAt(startLineIndex++, 2)->value().toInt();
|
|
logde<<"data size:"<<dataSize;
|
|
|
|
for(int i = 0; i < dataSize; i++)
|
|
{
|
|
Global::ExperimentData data;
|
|
data.runTime = workSheet->cellAt(startLineIndex, 2)->value().toDouble();
|
|
data.sampleTemp = workSheet->cellAt(startLineIndex, 3)->value().toDouble();
|
|
data.dsc = workSheet->cellAt(startLineIndex, 4)->value().toDouble();
|
|
|
|
phaseTotal.dataVtr.push_back(data);
|
|
|
|
startLineIndex++;
|
|
}
|
|
}
|
|
|
|
void XlsxHandler::writeFile(const QString filePath)
|
|
{
|
|
if(Global::_curveExperimentDataVtr.empty()){
|
|
logde<<"_curveExperimentDataVtr empty...";
|
|
return;
|
|
}
|
|
|
|
Global::ExperimentInfo& ei = Global::_experimentInfo;
|
|
|
|
QXlsx::Document xlsx;
|
|
xlsx.addSheet("Sheet1"); // 添加一个新的工作表
|
|
|
|
// Write experiment info.
|
|
int row = 1;
|
|
xlsx.write(row++ , 1, ConFileDataInfo);
|
|
|
|
xlsx.write(row , 1, ConSampleName);
|
|
QString sampleName = ei.sampleName;
|
|
if(sampleName.isEmpty()){
|
|
sampleName = "sample";
|
|
}
|
|
xlsx.write(row , 2, sampleName);
|
|
row++;
|
|
|
|
xlsx.write(row , 1, ConSampleWeight);
|
|
QString sampleWeight = ei.sampleWeight;
|
|
if(sampleWeight.isEmpty()){
|
|
sampleWeight = "1";
|
|
}
|
|
xlsx.write(row , 2, sampleWeight);
|
|
|
|
xlsx.write(row , 3, ConUnitMg);
|
|
row++;
|
|
|
|
xlsx.write(row , 1, ConCrucibleWeight);
|
|
xlsx.write(row , 2, 0);
|
|
xlsx.write(row , 3, ConUnitMg);
|
|
row++;
|
|
|
|
xlsx.write(row , 1, Conexperimenter);
|
|
QString experimentor = ei.experimentor;
|
|
if(experimentor.isEmpty()){
|
|
experimentor = "experimentor";
|
|
}
|
|
xlsx.write(row , 2, experimentor);
|
|
row++;
|
|
|
|
xlsx.write(row , 1, ConDate);
|
|
QString date = ei.date;
|
|
if(date.isEmpty()){
|
|
date = "20250101";
|
|
}
|
|
xlsx.write(row , 2, date);
|
|
row++;
|
|
|
|
xlsx.write(row , 1, ConMeasureType);
|
|
xlsx.write(row , 2, "样品");
|
|
row++;
|
|
|
|
int phaseSizeRow = row;
|
|
int phaseCount = 0;
|
|
xlsx.write(row , 1, ConPhaseSize);
|
|
xlsx.write(row , 2, ei.phaseVtr.size());
|
|
row++;
|
|
|
|
// Write phase data.
|
|
int dataSizeRow = 0;
|
|
logde<<"phase vtr size:"<<ei.phaseVtr.size();
|
|
for(int i = 0; i < ei.phaseVtr.size();i++){
|
|
logde<<"phase index:"<<i;
|
|
const Phase& phase = ei.phaseVtr.at(i);
|
|
|
|
if(phase.onoff == 0){
|
|
logde<<"onoff == 0.";
|
|
continue;
|
|
}
|
|
|
|
phaseCount++;
|
|
|
|
xlsx.write(row , 1, ConPhaseProfix);
|
|
xlsx.write(row , 2, ConPhaseHeaderTime);
|
|
xlsx.write(row , 3, ConPhaseHeaderTemp);
|
|
xlsx.write(row , 4, ConPhaseHeaderVoltage);
|
|
xlsx.write(row , 5, ConPhaseHeaderTime);
|
|
row++;
|
|
|
|
xlsx.write(row , 1, ConPhaseIndex);
|
|
xlsx.write(row , 2, i + 1);
|
|
row++;
|
|
// phase info
|
|
xlsx.write(row , 1, ConPhaseCutoffTemp);
|
|
xlsx.write(row , 2, phase.cutoff_temp);
|
|
xlsx.write(row , 3, ConUnitDegreeCentigrade);
|
|
row++;
|
|
|
|
xlsx.write(row , 1, ConPhaseHeatingRate);
|
|
xlsx.write(row , 2, phase.temp_flow);
|
|
xlsx.write(row , 3, ConUnitDegreeCentigradePerMin);
|
|
row++;
|
|
|
|
xlsx.write(row , 1, ConPhaseConstantTempTime);
|
|
xlsx.write(row , 2, phase.constant_temp_time_min);
|
|
xlsx.write(row , 3, ConUnitMin);
|
|
row++;
|
|
|
|
xlsx.write(row , 1, ConPhaseAtmosphere);
|
|
switch(phase.gas){
|
|
case GasType::NC:
|
|
xlsx.write(row , 2, "NC");
|
|
break;
|
|
case GasType::N2:
|
|
xlsx.write(row , 2, "N2");
|
|
break;
|
|
case GasType::O2:
|
|
xlsx.write(row , 2, "O2");
|
|
break;
|
|
default:break;
|
|
}
|
|
row++;
|
|
|
|
// phase data.
|
|
logde<<"Global::_curveExperimentDataVtr size:"
|
|
<<Global::_curveExperimentDataVtr.size();
|
|
|
|
const QVector<Global::ExperimentData>& edVtr =
|
|
Global::_curveExperimentDataVtr.at(i).dataVtr;
|
|
// phase data size.
|
|
dataSizeRow = row;
|
|
xlsx.write(row , 1, ConPhaseDataSize);
|
|
xlsx.write(row , 2, edVtr.size());
|
|
row++;
|
|
|
|
logde<<"edVtr size:"<<edVtr.size();
|
|
|
|
for(int index = 0;index < edVtr.size();index++){
|
|
logde<<"index :"<<index;
|
|
const Global::ExperimentData & ed = edVtr.at(index);
|
|
|
|
xlsx.write(row , 1, index);
|
|
xlsx.write(row , 2, ed.runTime);
|
|
xlsx.write(row , 3, ed.sampleTemp);
|
|
xlsx.write(row , 4, ed.dsc);
|
|
xlsx.write(row , 5, ed.constantTempTime);
|
|
row++;
|
|
}
|
|
}
|
|
//
|
|
xlsx.write(phaseSizeRow , 1, ConPhaseSize);
|
|
xlsx.write(phaseSizeRow , 2, phaseCount);
|
|
|
|
// Clear data.
|
|
Global::clearExperimentData();
|
|
|
|
//
|
|
logde<<"before xlsx save as...";
|
|
if (!xlsx.saveAs(filePath)) {
|
|
logde<<"Save xlsx failed.";
|
|
return ;
|
|
}
|
|
|
|
}
|
|
|
|
void XlsxHandler::writeAnalysisOperation(const QString filePath)
|
|
{
|
|
QXlsx::Document* xlsx = openXlsxFile(_currentFilePath);
|
|
if(!xlsx){
|
|
logde<<"xlsx is nullptr." ;
|
|
return;
|
|
}
|
|
|
|
QXlsx::Worksheet *sheet = xlsx->currentWorksheet();
|
|
if(!sheet)
|
|
{
|
|
logde << "current sheet is empty.";
|
|
return;
|
|
}
|
|
int index = sheet->dimension().lastRow();
|
|
logde<<"lastRow:"<<index;
|
|
|
|
int row = index + 1;
|
|
QVector<AnalysisOperationRecorder::AnalysisOperation>& aoVtr =
|
|
AnalysisOperationRecorder::_ananlysisOperationVtr;
|
|
|
|
xlsx->write(row , 1, ConAnalysisOperationCount);
|
|
xlsx->write(row , 2, aoVtr.size());
|
|
row++;
|
|
|
|
for (AnaOpRecorderOperation& ao:aoVtr){
|
|
QString analysisOpName;
|
|
|
|
switch(ao.mode){
|
|
case AnalysisMode::NumericalLabel:
|
|
{
|
|
analysisOpName = AnalysisOperationRecorder::NumericalLabelStr;
|
|
break;
|
|
}
|
|
case Global::StartPoint:
|
|
{
|
|
analysisOpName = AnalysisOperationRecorder::StartPointStr;
|
|
break;
|
|
}
|
|
case Global::StopPoint:
|
|
{
|
|
analysisOpName = AnalysisOperationRecorder::StopPointStr;
|
|
break;
|
|
}
|
|
case Global::PeakSynthesisAnalysis:
|
|
{
|
|
analysisOpName = AnalysisOperationRecorder::PeakSynthesisAnalysisStr;
|
|
break;
|
|
}
|
|
case Global::GlassTransition:
|
|
{
|
|
analysisOpName = AnalysisOperationRecorder::GlassTransitionStr;
|
|
break;
|
|
}
|
|
case Global::OnsetTemperaturePoint:
|
|
{
|
|
analysisOpName = AnalysisOperationRecorder::OnsetTemperaturePointStr;
|
|
break;
|
|
}
|
|
case Global::EndsetTemperaturePoint:
|
|
{
|
|
analysisOpName = AnalysisOperationRecorder::EndsetTemperaturePointStr;
|
|
break;
|
|
}
|
|
default:break;
|
|
}
|
|
|
|
xlsx->write(row , 1, analysisOpName);
|
|
xlsx->write(row , 2, ao.x1);
|
|
xlsx->write(row , 3, ao.x2);
|
|
row++;
|
|
}
|
|
|
|
// save
|
|
#if 1
|
|
if (!xlsx->saveAs(filePath)) {
|
|
logde<<"Save xlsx failed.";
|
|
delete xlsx;
|
|
return ;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
delete xlsx;
|
|
logde<<"Save xlsx succ.";
|
|
}
|
|
|
|
QXlsx::Document* XlsxHandler::openXlsxFile(const QString& sourceFilePath) {
|
|
// 检查文件是否存在
|
|
if (!QFile::exists(sourceFilePath)) {
|
|
qDebug() << "xlsx file not existed:" << sourceFilePath;
|
|
return nullptr;
|
|
}
|
|
QFileInfo fileInfo(sourceFilePath);
|
|
|
|
// 获取文件的后缀名并转换为小写,方便比较
|
|
QString fileSuffix = fileInfo.suffix().toLower();
|
|
|
|
// 判断后缀名是否为 "xlsx"
|
|
if (fileSuffix != "xlsx") {
|
|
std::cout << "该文件的后缀不是 xlsx" << std::endl;
|
|
return nullptr;
|
|
}
|
|
|
|
QXlsx::Document* xlsx = new QXlsx::Document(sourceFilePath);
|
|
|
|
QXlsx::Worksheet* workSheet = xlsx->currentWorksheet();
|
|
if (!workSheet) {
|
|
qDebug() << "current sheet is empty.";
|
|
delete xlsx;
|
|
return nullptr;
|
|
}
|
|
|
|
return xlsx;
|
|
}
|
|
|
|
void XlsxHandler::readAnalysisOperation(QXlsx::Worksheet *sheet, int &startLineIndex)
|
|
{
|
|
QXlsx::Cell *cell = sheet->cellAt(startLineIndex, 2);
|
|
if (!cell) {
|
|
logde << "Cell does not exist.";
|
|
return;
|
|
}
|
|
|
|
int size = sheet->cellAt(startLineIndex++, 2)->value().toInt();
|
|
|
|
logde<<"ana op size:"<<size;
|
|
|
|
for(int i = 0;i < size; i++){
|
|
AnaOpRecorderOperation ao;
|
|
QString modeStr = sheet->cellAt(startLineIndex, 1)->value().toString();
|
|
|
|
if(modeStr == AnaOpRecorder::NumericalLabelStr){
|
|
ao.mode = Global::AnalysisMode::NumericalLabel;
|
|
}else if(modeStr == AnaOpRecorder::StartPointStr){
|
|
ao.mode = Global::AnalysisMode::StartPoint;
|
|
}else if(modeStr == AnaOpRecorder::StopPointStr){
|
|
ao.mode = Global::AnalysisMode::StopPoint;
|
|
}else if(modeStr == AnaOpRecorder::PeakSynthesisAnalysisStr){
|
|
ao.mode = Global::AnalysisMode::PeakSynthesisAnalysis;
|
|
}else if(modeStr == AnaOpRecorder::GlassTransitionStr){
|
|
ao.mode = Global::AnalysisMode::GlassTransition;
|
|
}else if(modeStr == AnaOpRecorder::OnsetTemperaturePointStr){
|
|
ao.mode = Global::AnalysisMode::OnsetTemperaturePoint;
|
|
}else if(modeStr == AnaOpRecorder::EndsetTemperaturePointStr){
|
|
ao.mode = Global::AnalysisMode::EndsetTemperaturePoint;
|
|
}
|
|
|
|
ao.x1 = sheet->cellAt(startLineIndex, 2)->value().toDouble();
|
|
ao.x2 = sheet->cellAt(startLineIndex, 3)->value().toDouble();
|
|
|
|
AnaOpRecorder::_ananlysisOperationVtr.push_back(ao);
|
|
|
|
startLineIndex++;
|
|
|
|
logde<<" ao mode:"<<modeStr.toStdString();
|
|
logde<<"x1:"<<ao.x1<<",x2:"<<ao.x2;
|
|
}
|
|
}
|