/* * Copyright (c) 2009 Ned Harding (ned@hardinggroup.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SplitRideDialog.h" #include "GcRideFile.h" #include "MainWindow.h" #include "RideFile.h" #include #include #include #include namespace { QString MakeTimeString(double secs) { QString strTime; double mins = ((int) secs) / 60; secs = secs - mins * 60.0; double hrs = ((int) mins) / 60; mins = mins - hrs * 60.0; strTime.sprintf("%02.0f:%02.0f:%02.0f", hrs, mins, secs); return strTime; } class ListItem_Split : public QListWidgetItem { public: int m_nRecNum; explicit ListItem_Split(int nRecNum, const QString &text, QListWidget *view) : QListWidgetItem(text, view) , m_nRecNum(nRecNum) { } }; } SplitRideDialog::SplitRideDialog(MainWindow *mainWindow) : mainWindow(mainWindow) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle("Split Ride"); listWidget = new QListWidget(this); listWidget->setSelectionMode(QAbstractItemView::SingleSelection); QLabel *splitLabel = new QLabel(tr("Split at the following positions:"), this); QLabel *labelSpacer = new QLabel(this); labelSpacer->setIndent(10); okButton = new QPushButton(tr("&OK"), this); cancelButton = new QPushButton(tr("&Cancel"), this); connect(okButton, SIGNAL(clicked()), this, SLOT(okClicked())); connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancelClicked())); connect(listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged())); QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addWidget(okButton); buttonLayout->addWidget(cancelButton); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->addWidget(splitLabel); mainLayout->addWidget(listWidget); mainLayout->addWidget(labelSpacer); mainLayout->addLayout(buttonLayout); const RideFile *ride = mainWindow->currentRide(); QMap splitPoints; QList intervals = ride->intervals(); if (!intervals.empty()) { intervals.removeFirst(); foreach (RideFileInterval interval, intervals) { int nDataPoint = ride->intervalBegin(interval); QString strDesc = QString("Interval %1").arg(interval.name); splitPoints.insert(nDataPoint, strDesc); } } for (int nDataPoint = 1; nDataPoint < ride->dataPoints().size(); ++nDataPoint) { const RideFilePoint *point = ride->dataPoints()[nDataPoint]; double dLastSeconds = ride->dataPoints()[nDataPoint - 1]->secs; if ((point->secs-dLastSeconds)>=30 && !splitPoints.contains(nDataPoint)) { QString strDesc = "Time Gap: " + MakeTimeString(point->secs-dLastSeconds); splitPoints.insert(nDataPoint, strDesc); } } QMapIterator i(splitPoints); while (i.hasNext()) { i.next(); int nDataPoint = i.key(); const RideFilePoint *point = ride->dataPoints()[nDataPoint]; QString strDesc = MakeTimeString(point->secs) + " - " + i.value(); ListItem_Split *pItem = new ListItem_Split(nDataPoint, strDesc, listWidget); if (nDataPoint > 0) { double dLastSeconds = ride->dataPoints()[nDataPoint - 1]->secs; if ((point->secs-dLastSeconds)>20*60) pItem->setCheckState(Qt::Checked); else pItem->setCheckState(Qt::Unchecked); } } } void SplitRideDialog::cancelClicked() { reject(); } void SplitRideDialog::CreateNewRideFile(const RideFile *ride, int nRecStart, int nRecEnd) { // set the start time, taking care to include the offset for the interval QDateTime newStart = ride->startTime(); RideFilePoint *pointStart = ride->dataPoints().at(nRecStart); newStart = newStart.addMSecs(static_cast(pointStart->secs*1000 + 0.5)); QString fileName; QString filePath; // adjust start time of file to avoid conflicts with existing files int offset = 0; QDateTime noConflicts; do { noConflicts = newStart.addSecs(offset); fileName.sprintf("%04d_%02d_%02d_%02d_%02d_%02d.gc", noConflicts.date().year(), noConflicts.date().month(), noConflicts.date().day(), noConflicts.time().hour(), noConflicts.time().minute(), noConflicts.time().second()); filePath = mainWindow->home.absolutePath() + "/" + fileName; offset++; } while (QFile(filePath).exists()); newStart = newStart.addSecs(offset); // create the ridefile in memory QScopedPointer newRideFile(new RideFile(newStart, ride->recIntSecs())); for (int nItem = nRecStart; nItemdataPoints().at(nItem); newRideFile->appendPoint(pPoint->secs-pointStart->secs, pPoint->cad, pPoint->hr, pPoint->km - pointStart->km, pPoint->kph, pPoint->nm, pPoint->watts, pPoint->alt, pPoint->lon, pPoint->lat, pPoint->headwind, pPoint->slope, pPoint->temp, pPoint->lrbalance, pPoint->interval-pointStart->interval); } newRideFile->setDeviceType(ride->deviceType()); newRideFile->setFileFormat(ride->fileFormat()); double endSecs = ride->dataPoints().at(nRecEnd - 1)->secs + ride->recIntSecs(); foreach (RideFileInterval interval, ride->intervals()) { if ((interval.start >= pointStart->secs) && (interval.stop <= endSecs)) { newRideFile->addInterval(interval.start - pointStart->secs, interval.stop - pointStart->secs, interval.name); } } // should never, ever complain.. could wipe out, but lets check anyway // it costs nothing and might save a file one day QFile file(filePath); if (file.exists()) { QMessageBox::critical(this, tr("Split Ride"), tr("The file %1 already exists and will not be overwritten").arg(filePath)); return; } // write to disk GcFileReader f; f.writeRideFile(mainWindow, newRideFile.data(), file); // add to the ride list mainWindow->addRide(fileName, false); } void SplitRideDialog::okClicked() { const RideFile *ride = mainWindow->currentRide(); int nStartPoint = 0; for (int nRow=0; nRowcount(); ++nRow) { const ListItem_Split *pItem = static_cast(listWidget->item(nRow)); if (pItem->checkState()==Qt::Checked) { CreateNewRideFile(ride, nStartPoint, pItem->m_nRecNum); nStartPoint = pItem->m_nRecNum; } } if (nStartPoint!=0) { CreateNewRideFile(ride, nStartPoint, mainWindow->currentRide()->dataPoints().count()); mainWindow->removeCurrentRide(); } done(0); } void SplitRideDialog::selectionChanged() { }