mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
Support Wattbike TXT data exports
Thanks to Peter Norberg for the sample data export files. This support has been written against the two files supplied. if the export has imperial/metric conversion options then this support will need to be adjusted to cater for different units. Fixes #322.
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
|
||||
static int txtFileReaderRegistered =
|
||||
RideFileFactory::instance().registerReader(
|
||||
"txt","Racermate/Ergvideo", new TxtFileReader());
|
||||
"txt","Racermate/Ergvideo/Wattbike", new TxtFileReader());
|
||||
|
||||
// Racermate Workout Data Export File Format (.TXT)
|
||||
// ------------------------------------------------
|
||||
@@ -70,183 +70,358 @@ RideFile *TxtFileReader::openRideFile(QFile &file, QStringList &errors, QList<Ri
|
||||
bool metric = true; // are the values in metric or imperial?
|
||||
QDateTime startTime; // parsed from filename
|
||||
|
||||
// lets get on with it then
|
||||
// Lets make sure we can open the file
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
errors << ("Could not open ride file: \""
|
||||
+ file.fileName() + "\"");
|
||||
errors << ("Could not open ride file: \"" + file.fileName() + "\"");
|
||||
return NULL;
|
||||
}
|
||||
QTextStream is(&file);
|
||||
QTextStream in(&file);
|
||||
|
||||
// Lets construct our rideFile
|
||||
RideFile *rideFile = new RideFile();
|
||||
rideFile->setDeviceType("Computrainer/Velotron");
|
||||
// Now we need to determine if this is a Wattbike export
|
||||
// or a Racermate export. We can do this by looking at
|
||||
// the first line of the file.
|
||||
//
|
||||
// For it to be a wattbike, the first line is made up
|
||||
// of multiple tokens, separated by a tab, which match
|
||||
// the pattern "name [units]"
|
||||
bool isWattBike = false;
|
||||
QStringList tokens = in.readLine().split(QRegExp("[\t\n\r]"), QString::SkipEmptyParts);
|
||||
|
||||
while (!is.atEnd()) {
|
||||
|
||||
// the readLine() method doesn't handle old Macintosh CR line endings
|
||||
// this workaround will load the the entire file if it has CR endings
|
||||
// then split and loop through each line
|
||||
// otherwise, there will be nothing to split and it will read each line as expected.
|
||||
QString linesIn = is.readLine();
|
||||
QStringList lines = linesIn.split('\r');
|
||||
if(lines.isEmpty()) continue;
|
||||
|
||||
// loop through the lines we got
|
||||
foreach (QString line, lines) {
|
||||
|
||||
QRegExp sectionPattern("^\\[.*\\]$");
|
||||
QRegExp unitsPattern("^UNITS += +\\(.*\\)$");
|
||||
QRegExp sepPattern("( +|,)");
|
||||
|
||||
// ignore blank lines
|
||||
if (line == "") continue;
|
||||
|
||||
// begin or end of section
|
||||
if (sectionPattern.exactMatch(line)) {
|
||||
deviceInfo += line;
|
||||
deviceInfo += "\n";
|
||||
|
||||
if (section == "") section = line;
|
||||
else section = "";
|
||||
continue;
|
||||
}
|
||||
|
||||
// section Data
|
||||
if (section != "") {
|
||||
// save it away
|
||||
deviceInfo += line;
|
||||
deviceInfo += "\n";
|
||||
|
||||
// look for UNITS line
|
||||
if (unitsPattern.exactMatch(line)) {
|
||||
if (unitsPattern.cap(1) != "METRIC") metric = false;
|
||||
else metric = true;
|
||||
if (tokens.count() > 1) {
|
||||
// ok, so we have a bunch of tokens, thats a good sign this
|
||||
// may be a wattbike export, now are all the tokens of the
|
||||
// form "name [units]", or just "Index" or "name []"
|
||||
isWattBike=true;
|
||||
QRegExp wattToken("^[^[]+ \\[[^]]+\\]$");
|
||||
foreach(QString token, tokens) {
|
||||
if (wattToken.exactMatch(token) != true) {
|
||||
QRegExp noUnits("^[^[]+ \\[\\]$");
|
||||
if (token != "Index" && !noUnits.exactMatch(token)) {
|
||||
isWattBike = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// number of records, jsut ignore it
|
||||
if (line.startsWith("number of")) continue;
|
||||
|
||||
// either a data line, or a headings line
|
||||
if (headings.count() == 0) {
|
||||
headings = line.split(sepPattern, QString::SkipEmptyParts);
|
||||
|
||||
// where are the values stored?
|
||||
timeIndex = headings.indexOf("ms");
|
||||
wattsIndex = headings.indexOf("watts");
|
||||
cadIndex = headings.indexOf("rpm");
|
||||
hrIndex = headings.indexOf("hr");
|
||||
kmIndex = headings.indexOf("KM");
|
||||
milesIndex = headings.indexOf("miles");
|
||||
kphIndex = headings.indexOf("speed");
|
||||
headwindIndex = headings.indexOf("wind");
|
||||
continue;
|
||||
}
|
||||
// right! we now have a record
|
||||
QStringList values = line.split(sepPattern, QString::SkipEmptyParts);
|
||||
|
||||
// mmm... didn't get much data
|
||||
if (values.count() < 2) continue;
|
||||
|
||||
// extract out each value
|
||||
double secs = timeIndex > -1 ? values[timeIndex].toDouble() / (double) 1000 : 0.0;
|
||||
double watts = wattsIndex > -1 ? values[wattsIndex].toDouble() : 0.0;
|
||||
double cad = cadIndex > -1 ? values[cadIndex].toDouble() : 0.0;
|
||||
double hr = hrIndex > -1 ? values[hrIndex].toDouble() : 0.0;
|
||||
double km = kmIndex > -1 ? values[kmIndex].toDouble() : 0.0;
|
||||
double kph = kphIndex > -1 ? values[kphIndex].toDouble() : 0.0;
|
||||
double miles = milesIndex > -1 ? values[milesIndex].toDouble() : 0.0;
|
||||
double headwind = headwindIndex > -1 ? values[headwindIndex].toDouble() : 0.0;
|
||||
|
||||
if (miles != 0) {
|
||||
// imperial!
|
||||
kph *= KM_PER_MILE;
|
||||
km = miles * KM_PER_MILE;
|
||||
}
|
||||
rideFile->appendPoint(secs, cad, hr, km, kph, 0.0, watts, 0.0, 0.0, 0.0, headwind, 0.0, RideFile::noTemp, 0);
|
||||
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
|
||||
rideFile->setTag("Device Info", deviceInfo);
|
||||
if (!isWattBike) {
|
||||
|
||||
//
|
||||
// To estimate the recording interval, take the median of the
|
||||
// first 1000 samples and round to nearest millisecond.
|
||||
//
|
||||
int n = rideFile->dataPoints().size();
|
||||
n = qMin(n, 1000);
|
||||
if (n >= 2) {
|
||||
// RACERMATE STYLE
|
||||
|
||||
QVector<double> secs(n-1);
|
||||
for (int i = 0; i < n-1; ++i) {
|
||||
double now = rideFile->dataPoints()[i]->secs;
|
||||
double then = rideFile->dataPoints()[i+1]->secs;
|
||||
secs[i] = then - now;
|
||||
file.close(); // start again (seek did weird things on Linux, bug (?)
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
errors << ("Could not open ride file: \"" + file.fileName() + "\"");
|
||||
return NULL;
|
||||
}
|
||||
std::sort(secs.begin(), secs.end());
|
||||
int mid = n / 2 - 1;
|
||||
double recint = round(secs[mid] * 1000.0) / 1000.0;
|
||||
rideFile->setRecIntSecs(recint);
|
||||
QTextStream is(&file);
|
||||
|
||||
// Lets construct our rideFile
|
||||
RideFile *rideFile = new RideFile();
|
||||
rideFile->setDeviceType("Computrainer/Velotron");
|
||||
|
||||
while (!is.atEnd()) {
|
||||
|
||||
// the readLine() method doesn't handle old Macintosh CR line endings
|
||||
// this workaround will load the the entire file if it has CR endings
|
||||
// then split and loop through each line
|
||||
// otherwise, there will be nothing to split and it will read each line as expected.
|
||||
QString linesIn = is.readLine();
|
||||
QStringList lines = linesIn.split('\r');
|
||||
if(lines.isEmpty()) continue;
|
||||
|
||||
// loop through the lines we got
|
||||
foreach (QString line, lines) {
|
||||
|
||||
QRegExp sectionPattern("^\\[.*\\]$");
|
||||
QRegExp unitsPattern("^UNITS += +\\(.*\\)$");
|
||||
QRegExp sepPattern("( +|,)");
|
||||
|
||||
// ignore blank lines
|
||||
if (line == "") continue;
|
||||
|
||||
// begin or end of section
|
||||
if (sectionPattern.exactMatch(line)) {
|
||||
deviceInfo += line;
|
||||
deviceInfo += "\n";
|
||||
|
||||
if (section == "") section = line;
|
||||
else section = "";
|
||||
continue;
|
||||
}
|
||||
|
||||
// section Data
|
||||
if (section != "") {
|
||||
// save it away
|
||||
deviceInfo += line;
|
||||
deviceInfo += "\n";
|
||||
|
||||
// look for UNITS line
|
||||
if (unitsPattern.exactMatch(line)) {
|
||||
if (unitsPattern.cap(1) != "METRIC") metric = false;
|
||||
else metric = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// number of records, jsut ignore it
|
||||
if (line.startsWith("number of")) continue;
|
||||
|
||||
// either a data line, or a headings line
|
||||
if (headings.count() == 0) {
|
||||
headings = line.split(sepPattern, QString::SkipEmptyParts);
|
||||
|
||||
// where are the values stored?
|
||||
timeIndex = headings.indexOf("ms");
|
||||
wattsIndex = headings.indexOf("watts");
|
||||
cadIndex = headings.indexOf("rpm");
|
||||
hrIndex = headings.indexOf("hr");
|
||||
kmIndex = headings.indexOf("KM");
|
||||
milesIndex = headings.indexOf("miles");
|
||||
kphIndex = headings.indexOf("speed");
|
||||
headwindIndex = headings.indexOf("wind");
|
||||
continue;
|
||||
}
|
||||
// right! we now have a record
|
||||
QStringList values = line.split(sepPattern, QString::SkipEmptyParts);
|
||||
|
||||
// mmm... didn't get much data
|
||||
if (values.count() < 2) continue;
|
||||
|
||||
// extract out each value
|
||||
double secs = timeIndex > -1 ? values[timeIndex].toDouble() / (double) 1000 : 0.0;
|
||||
double watts = wattsIndex > -1 ? values[wattsIndex].toDouble() : 0.0;
|
||||
double cad = cadIndex > -1 ? values[cadIndex].toDouble() : 0.0;
|
||||
double hr = hrIndex > -1 ? values[hrIndex].toDouble() : 0.0;
|
||||
double km = kmIndex > -1 ? values[kmIndex].toDouble() : 0.0;
|
||||
double kph = kphIndex > -1 ? values[kphIndex].toDouble() : 0.0;
|
||||
double miles = milesIndex > -1 ? values[milesIndex].toDouble() : 0.0;
|
||||
double headwind = headwindIndex > -1 ? values[headwindIndex].toDouble() : 0.0;
|
||||
|
||||
if (miles != 0) {
|
||||
// imperial!
|
||||
kph *= KM_PER_MILE;
|
||||
km = miles * KM_PER_MILE;
|
||||
}
|
||||
rideFile->appendPoint(secs, cad, hr, km, kph, 0.0, watts, 0.0, 0.0, 0.0, headwind, 0.0, RideFile::noTemp, 0);
|
||||
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
|
||||
rideFile->setTag("Device Info", deviceInfo);
|
||||
|
||||
//
|
||||
// To estimate the recording interval, take the median of the
|
||||
// first 1000 samples and round to nearest millisecond.
|
||||
//
|
||||
int n = rideFile->dataPoints().size();
|
||||
n = qMin(n, 1000);
|
||||
if (n >= 2) {
|
||||
|
||||
QVector<double> secs(n-1);
|
||||
for (int i = 0; i < n-1; ++i) {
|
||||
double now = rideFile->dataPoints()[i]->secs;
|
||||
double then = rideFile->dataPoints()[i+1]->secs;
|
||||
secs[i] = then - now;
|
||||
}
|
||||
std::sort(secs.begin(), secs.end());
|
||||
int mid = n / 2 - 1;
|
||||
double recint = round(secs[mid] * 1000.0) / 1000.0;
|
||||
rideFile->setRecIntSecs(recint);
|
||||
|
||||
} else {
|
||||
|
||||
// less than 2 data points is not a valid ride file
|
||||
errors << "Insufficient valid data in file \"" + file.fileName() + "\".";
|
||||
delete rideFile;
|
||||
file.close();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Get date time from standard GC name
|
||||
//
|
||||
QRegExp gcPattern("^.*/(\\d\\d\\d\\d)_(\\d\\d)_(\\d\\d)_(\\d\\d)_(\\d\\d)_(\\d\\d)\\.txt$");
|
||||
gcPattern.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
// Racemermate uses name-mode-yyyy-mm-dd-hh-mm-ss.CDF.txt
|
||||
QRegExp rmPattern("^.*/[^-]*-[^-]*-(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)-(\\d\\d)-(\\d\\d)-(\\d\\d)\\.cdf.txt$");
|
||||
rmPattern.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
// Ergvideo uses name_ergvideo_ridename_yyyy-mm-dd@hh-mm-ss.txt
|
||||
QRegExp evPattern("^.*/[^_]*_[^_]*_[^_]*_(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)@(\\d\\d)-(\\d\\d)-(\\d\\d)\\.txt$");
|
||||
evPattern.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
// It is a GC Filename
|
||||
if (gcPattern.exactMatch(file.fileName())) {
|
||||
QDateTime datetime(QDate(gcPattern.cap(1).toInt(),
|
||||
gcPattern.cap(2).toInt(),
|
||||
gcPattern.cap(3).toInt()),
|
||||
QTime(gcPattern.cap(4).toInt(),
|
||||
gcPattern.cap(5).toInt(),
|
||||
gcPattern.cap(6).toInt()));
|
||||
rideFile->setStartTime(datetime);
|
||||
}
|
||||
|
||||
// It is an Ergvideo Filename
|
||||
if (evPattern.exactMatch(file.fileName())) {
|
||||
QDateTime datetime(QDate(evPattern.cap(1).toInt(),
|
||||
evPattern.cap(2).toInt(),
|
||||
evPattern.cap(3).toInt()),
|
||||
QTime(evPattern.cap(4).toInt(),
|
||||
evPattern.cap(5).toInt(),
|
||||
evPattern.cap(6).toInt()));
|
||||
rideFile->setStartTime(datetime);
|
||||
}
|
||||
|
||||
// It is an Racermate Filename
|
||||
if (rmPattern.exactMatch(file.fileName())) {
|
||||
QDateTime datetime(QDate(rmPattern.cap(1).toInt(),
|
||||
rmPattern.cap(2).toInt(),
|
||||
rmPattern.cap(3).toInt()),
|
||||
QTime(rmPattern.cap(4).toInt(),
|
||||
rmPattern.cap(5).toInt(),
|
||||
rmPattern.cap(6).toInt()));
|
||||
rideFile->setStartTime(datetime);
|
||||
}
|
||||
|
||||
return rideFile;
|
||||
|
||||
} else {
|
||||
// WATTBIKE STYLE
|
||||
|
||||
// less than 2 data points is not a valid ride file
|
||||
errors << "Insufficient valid data in file \"" + file.fileName() + "\".";
|
||||
delete rideFile;
|
||||
file.close();
|
||||
return NULL;
|
||||
// Lets construct our rideFile
|
||||
RideFile *rideFile = new RideFile();
|
||||
rideFile->setDeviceType("Wattbike");
|
||||
rideFile->setRecIntSecs(1);
|
||||
|
||||
// We need to work out which column represents
|
||||
// which data series. The heading tokens specify
|
||||
// both the series and units, but for now we will
|
||||
// assume the units are standardised until we have
|
||||
// seen files with different values for units.
|
||||
|
||||
// Here are the known heading tokens:
|
||||
// "Elapsed time total [s]"
|
||||
// "Cadence [1/min]"
|
||||
// "Velocity [km/h]"
|
||||
// "Distance total [m]"
|
||||
// "Heart rate [1/min]"
|
||||
// "Torque per revolution [Nm]"
|
||||
// "Power per revolution [W]"
|
||||
//
|
||||
// Note: no "spinscan" type data is provided.
|
||||
|
||||
int timeIndex = -1;
|
||||
int kmIndex = -1;
|
||||
int rpmIndex = -1;
|
||||
int kphIndex = -1;
|
||||
int bpmIndex = -1;
|
||||
int torqIndex = -1;
|
||||
int wattsIndex = -1;
|
||||
|
||||
// lets initialise the indexes for all the values
|
||||
QRegExp wattToken("^([^[]+) \\[([^]]+)\\]$");
|
||||
int i=0;
|
||||
int columns = tokens.count();
|
||||
|
||||
foreach(QString token, tokens) {
|
||||
|
||||
if (wattToken.exactMatch(token)) {
|
||||
QString name = wattToken.cap(1);
|
||||
QString unit = wattToken.cap(2);
|
||||
|
||||
if (name == "Elapsed time total") timeIndex = i;
|
||||
if (name == "Distance total") kmIndex = i;
|
||||
if (name == "Cadence") rpmIndex = i;
|
||||
if (name == "Velocity") kphIndex = i;
|
||||
if (name == "Heart rate") bpmIndex = i;
|
||||
if (name == "Torque per revolution") torqIndex = i;
|
||||
if (name == "Power per revolution") wattsIndex = i;
|
||||
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// lets loop through each row of data adding a sample
|
||||
// using the indexes we set above
|
||||
double rsecs = 0;
|
||||
while (!in.atEnd()) {
|
||||
|
||||
QString line = in.readLine();
|
||||
QStringList tokens = line.split(QRegExp("[\r\n\t]"), QString::SkipEmptyParts);
|
||||
|
||||
// do we have as many columns as we expected?
|
||||
if (tokens.count() == columns) {
|
||||
|
||||
double secs = 0.00f;
|
||||
double km = 0.00f;
|
||||
double rpm = 0.00f;
|
||||
double kph = 0.00f;
|
||||
double bpm = 0.00f;
|
||||
double torq = 0.00f;
|
||||
double watts = 0.00f;
|
||||
|
||||
if (timeIndex >= 0) {
|
||||
QTime time = QTime::fromString(tokens.at(timeIndex), "mm:ss:00");
|
||||
secs = QTime::fromString("00:00:00", "mm:ss:00").secsTo(time);
|
||||
|
||||
// its a bit shit, but the format appears to wrap round
|
||||
// on the hour; 59:59:00 is followed by 00:00:00
|
||||
// so we have a problem, since if there are gaps in
|
||||
// recording then we don't know which hour this is for
|
||||
// and if we assume largely contiguous data we may as
|
||||
// well just use a counter instead.
|
||||
//
|
||||
// for expediency, we use a counter for now:
|
||||
secs = rsecs++;
|
||||
}
|
||||
if (kmIndex >= 0) km = tokens.at(kmIndex).toDouble() / 1000;
|
||||
if (rpmIndex >= 0) rpm = tokens.at(rpmIndex).toDouble();
|
||||
if (kphIndex >= 0) kph = tokens.at(kphIndex).toDouble();
|
||||
if (bpmIndex >= 0) bpm = tokens.at(bpmIndex).toDouble();
|
||||
if (torqIndex >= 0) torq = tokens.at(torqIndex).toDouble();
|
||||
if (wattsIndex >= 0) watts = tokens.at(wattsIndex).toDouble();
|
||||
|
||||
rideFile->appendPoint(secs, rpm, bpm, km, kph, torq, watts, 0.0, 0.0, 0.0, 0.0, 0.0, RideFile::noTemp, 0);
|
||||
}
|
||||
}
|
||||
|
||||
QRegExp gcPattern("^.*/(\\d\\d\\d\\d)_(\\d\\d)_(\\d\\d)_(\\d\\d)_(\\d\\d)_(\\d\\d)\\.txt$");
|
||||
gcPattern.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
// Only filename we have seen is name_yyymmdd or name_yyymmdd_all.txt
|
||||
QRegExp wb1Pattern("^.*/[^_]*_(\\d\\d\\d\\d)(\\d\\d)(\\d\\d).txt$");
|
||||
wb1Pattern.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
QRegExp wb2Pattern("^.*/[^_]*_(\\d\\d\\d\\d)(\\d\\d)(\\d\\d)_all.txt$");
|
||||
wb2Pattern.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
// It is a GC Filename
|
||||
if (gcPattern.exactMatch(file.fileName())) {
|
||||
QDateTime datetime(QDate(gcPattern.cap(1).toInt(),
|
||||
gcPattern.cap(2).toInt(),
|
||||
gcPattern.cap(3).toInt()),
|
||||
QTime(gcPattern.cap(4).toInt(),
|
||||
gcPattern.cap(5).toInt(),
|
||||
gcPattern.cap(6).toInt()));
|
||||
rideFile->setStartTime(datetime);
|
||||
}
|
||||
|
||||
// It is an Wattbike Filename
|
||||
if (wb1Pattern.exactMatch(file.fileName())) {
|
||||
QDateTime datetime(QDate(wb1Pattern.cap(1).toInt(),
|
||||
wb1Pattern.cap(2).toInt(),
|
||||
wb1Pattern.cap(3).toInt()),
|
||||
QTime(0, 0, 0));
|
||||
rideFile->setStartTime(datetime);
|
||||
}
|
||||
if (wb2Pattern.exactMatch(file.fileName())) {
|
||||
QDateTime datetime(QDate(wb2Pattern.cap(1).toInt(),
|
||||
wb2Pattern.cap(2).toInt(),
|
||||
wb2Pattern.cap(3).toInt()),
|
||||
QTime(0, 0, 0));
|
||||
rideFile->setStartTime(datetime);
|
||||
}
|
||||
|
||||
return rideFile;
|
||||
}
|
||||
|
||||
//
|
||||
// Get date time from standard GC name
|
||||
//
|
||||
QRegExp gcPattern("^.*/(\\d\\d\\d\\d)_(\\d\\d)_(\\d\\d)_(\\d\\d)_(\\d\\d)_(\\d\\d)\\.txt$");
|
||||
gcPattern.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
// Racemermate uses name-mode-yyyy-mm-dd-hh-mm-ss.CDF.txt
|
||||
QRegExp rmPattern("^.*/[^-]*-[^-]*-(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)-(\\d\\d)-(\\d\\d)-(\\d\\d)\\.cdf.txt$");
|
||||
rmPattern.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
// Ergvideo uses name_ergvideo_ridename_yyyy-mm-dd@hh-mm-ss.txt
|
||||
QRegExp evPattern("^.*/[^_]*_[^_]*_[^_]*_(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)@(\\d\\d)-(\\d\\d)-(\\d\\d)\\.txt$");
|
||||
evPattern.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
// It is a GC Filename
|
||||
if (gcPattern.exactMatch(file.fileName())) {
|
||||
QDateTime datetime(QDate(gcPattern.cap(1).toInt(),
|
||||
gcPattern.cap(2).toInt(),
|
||||
gcPattern.cap(3).toInt()),
|
||||
QTime(gcPattern.cap(4).toInt(),
|
||||
gcPattern.cap(5).toInt(),
|
||||
gcPattern.cap(6).toInt()));
|
||||
rideFile->setStartTime(datetime);
|
||||
}
|
||||
|
||||
// It is an Ergvideo Filename
|
||||
if (evPattern.exactMatch(file.fileName())) {
|
||||
QDateTime datetime(QDate(evPattern.cap(1).toInt(),
|
||||
evPattern.cap(2).toInt(),
|
||||
evPattern.cap(3).toInt()),
|
||||
QTime(evPattern.cap(4).toInt(),
|
||||
evPattern.cap(5).toInt(),
|
||||
evPattern.cap(6).toInt()));
|
||||
rideFile->setStartTime(datetime);
|
||||
}
|
||||
|
||||
// It is an Racermate Filename
|
||||
if (rmPattern.exactMatch(file.fileName())) {
|
||||
QDateTime datetime(QDate(rmPattern.cap(1).toInt(),
|
||||
rmPattern.cap(2).toInt(),
|
||||
rmPattern.cap(3).toInt()),
|
||||
QTime(rmPattern.cap(4).toInt(),
|
||||
rmPattern.cap(5).toInt(),
|
||||
rmPattern.cap(6).toInt()));
|
||||
rideFile->setStartTime(datetime);
|
||||
}
|
||||
|
||||
return rideFile;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user