mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-14 16:39:57 +00:00
Slowly migrating code and data from the MainWindow class to Athlete and Context classes. This update moves the ride and interval lists and data structures from MainWindow to Athlete.
918 lines
33 KiB
C++
918 lines
33 KiB
C++
/*
|
|
* Copyright (c) 2010 Mark Liversedge (liversedge@gmail.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 "TPDownloadDialog.h"
|
|
#include "TPDownload.h"
|
|
#include "MainWindow.h"
|
|
#include "Context.h"
|
|
#include "Athlete.h"
|
|
#include "PwxRideFile.h"
|
|
#include "JsonRideFile.h"
|
|
#include "RideFile.h"
|
|
#include "Settings.h"
|
|
#include "MetricAggregator.h"
|
|
#include "Units.h"
|
|
|
|
TPDownloadDialog::TPDownloadDialog(Context *context) : QDialog(context->mainWindow, Qt::Dialog), context(context), downloading(false), aborted(false)
|
|
{
|
|
setWindowTitle(tr("Download from TrainingPeaks.com"));
|
|
|
|
athleter = new TPAthlete(this);
|
|
|
|
connect (athleter, SIGNAL(completed(QList<QMap<QString,QString> >)), this, SLOT(completedAthlete(QList<QMap<QString,QString> >)));
|
|
athleter->list(appsettings->cvalue(context->athlete->cyclist, GC_TPTYPE, "0").toInt(),
|
|
appsettings->cvalue(context->athlete->cyclist, GC_TPUSER, "null").toString(),
|
|
appsettings->cvalue(context->athlete->cyclist, GC_TPPASS, "null").toString());
|
|
|
|
QWidget::hide(); // don't show just yet...
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::completedAthlete(QList<QMap<QString, QString> >athletes)
|
|
{
|
|
// did we get any athletes?
|
|
if (athletes.count() == 0) {
|
|
QWidget::hide(); // meh
|
|
|
|
QMessageBox msgBox;
|
|
msgBox.setWindowTitle(tr("Download from TrainingPeaks.com"));
|
|
msgBox.setText(tr("You must be a premium member to download from TrainingPeaks. Please check your cyclist configurations are correct on the Passwords tab."));
|
|
msgBox.setIcon(QMessageBox::Critical);
|
|
msgBox.exec();
|
|
reject();
|
|
return;
|
|
}
|
|
|
|
// setup tabs
|
|
tabs = new QTabWidget(this);
|
|
QWidget * upload = new QWidget(this);
|
|
QWidget * download = new QWidget(this);
|
|
QWidget * sync = new QWidget(this);
|
|
tabs->addTab(download, tr("Download"));
|
|
tabs->addTab(upload, tr("Upload"));
|
|
tabs->addTab(sync, tr("Synchronize"));
|
|
QVBoxLayout *downloadLayout = new QVBoxLayout(download);
|
|
QVBoxLayout *uploadLayout = new QVBoxLayout(upload);
|
|
QVBoxLayout *syncLayout = new QVBoxLayout(sync);
|
|
|
|
workouter = new TPWorkout(this);
|
|
connect (workouter, SIGNAL(completed(QList<QMap<QString,QString> >)), this,
|
|
SLOT(completedWorkout(QList<QMap<QString,QString> >)));
|
|
|
|
downloader = new TPDownload(this);
|
|
connect (downloader, SIGNAL(completed(QDomDocument)), this,
|
|
SLOT(completedDownload(QDomDocument)));
|
|
|
|
uploader = new TPUpload(this);
|
|
connect (uploader, SIGNAL(completed(QString)), this,
|
|
SLOT(completedUpload(QString)));
|
|
|
|
// OK! Lets build up that dialog box
|
|
athlete = athletes[0];
|
|
|
|
// combo box
|
|
athleteCombo = new QComboBox(this);
|
|
for (int i=0; i< athletes.count(); i++) {
|
|
|
|
QString name = QString("%1 %2").arg(athletes[i].value("FirstName"))
|
|
.arg(athletes[i].value("LastName"));
|
|
int id = athletes[i].value("PersonId").toInt();
|
|
athleteCombo->addItem(name, id);
|
|
}
|
|
athleteCombo->setCurrentIndex(0);
|
|
|
|
QLabel *fromLabel = new QLabel(tr("From:"), this);
|
|
QLabel *toLabel = new QLabel(tr("To:"), this);
|
|
|
|
from = new QDateEdit(this);
|
|
from->setDate(QDate::currentDate().addMonths(-1));
|
|
from->setCalendarPopup(true);
|
|
to = new QDateEdit(this);
|
|
to->setDate(QDate::currentDate());
|
|
to->setCalendarPopup(true);
|
|
|
|
// Buttons
|
|
refreshButton = new QPushButton(tr("Refresh Ride List"), this);
|
|
cancelButton = new QPushButton(tr("Close"),this);
|
|
downloadButton = new QPushButton(tr("Download"),this);
|
|
|
|
selectAll = new QCheckBox(tr("Select all"), this);
|
|
selectAll->setChecked(Qt::Unchecked);
|
|
|
|
// ride list
|
|
rideList = new QTreeWidget(this);
|
|
rideList->headerItem()->setText(0, " ");
|
|
rideList->headerItem()->setText(1, "Workout Id");
|
|
rideList->headerItem()->setText(2, "Date");
|
|
rideList->headerItem()->setText(3, "Time");
|
|
rideList->headerItem()->setText(4, "Duration");
|
|
rideList->headerItem()->setText(5, "Distance");
|
|
rideList->headerItem()->setText(6, "Exists");
|
|
rideList->headerItem()->setText(7, "Status");
|
|
rideList->setColumnCount(8);
|
|
rideList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
rideList->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
rideList->setUniformRowHeights(true);
|
|
rideList->setIndentation(0);
|
|
rideList->header()->resizeSection(0,20);
|
|
rideList->header()->resizeSection(1,90);
|
|
rideList->header()->resizeSection(2,100);
|
|
rideList->header()->resizeSection(3,100);
|
|
rideList->header()->resizeSection(4,100);
|
|
rideList->header()->resizeSection(5,70);
|
|
rideList->header()->resizeSection(6,50);
|
|
rideList->setSortingEnabled(true);
|
|
|
|
downloadLayout->addWidget(selectAll);
|
|
downloadLayout->addWidget(rideList);
|
|
|
|
selectAllUp = new QCheckBox(tr("Select all"), this);
|
|
selectAllUp->setChecked(Qt::Unchecked);
|
|
|
|
// ride list
|
|
rideListUp = new QTreeWidget(this);
|
|
rideListUp->headerItem()->setText(0, " ");
|
|
rideListUp->headerItem()->setText(1, "File");
|
|
rideListUp->headerItem()->setText(2, "Date");
|
|
rideListUp->headerItem()->setText(3, "Time");
|
|
rideListUp->headerItem()->setText(4, "Duration");
|
|
rideListUp->headerItem()->setText(5, "Distance");
|
|
rideListUp->headerItem()->setText(6, "Exists");
|
|
rideListUp->headerItem()->setText(7, "Status");
|
|
rideListUp->setColumnCount(8);
|
|
rideListUp->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
rideListUp->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
rideListUp->setUniformRowHeights(true);
|
|
rideListUp->setIndentation(0);
|
|
rideListUp->header()->resizeSection(0,20);
|
|
rideListUp->header()->resizeSection(1,200);
|
|
rideListUp->header()->resizeSection(2,100);
|
|
rideListUp->header()->resizeSection(3,100);
|
|
rideListUp->header()->resizeSection(4,100);
|
|
rideListUp->header()->resizeSection(5,70);
|
|
rideListUp->header()->resizeSection(6,50);
|
|
rideListUp->setSortingEnabled(true);
|
|
|
|
uploadLayout->addWidget(selectAllUp);
|
|
uploadLayout->addWidget(rideListUp);
|
|
|
|
selectAllSync = new QCheckBox(tr("Select all"), this);
|
|
selectAllSync->setChecked(Qt::Unchecked);
|
|
syncMode = new QComboBox(this);
|
|
syncMode->addItem(tr("Keep all do not delete any rides"));
|
|
syncMode->addItem(tr("Keep TP.com but delete Local"));
|
|
syncMode->addItem(tr("Keep Local but delete TP.com"));
|
|
QHBoxLayout *syncList = new QHBoxLayout;
|
|
syncList->addWidget(selectAllSync);
|
|
syncList->addStretch();
|
|
syncList->addWidget(syncMode);
|
|
|
|
|
|
// ride list
|
|
rideListSync = new QTreeWidget(this);
|
|
rideListSync->headerItem()->setText(0, " ");
|
|
rideListSync->headerItem()->setText(1, "Source");
|
|
rideListSync->headerItem()->setText(2, "Date");
|
|
rideListSync->headerItem()->setText(3, "Time");
|
|
rideListSync->headerItem()->setText(4, "Duration");
|
|
rideListSync->headerItem()->setText(5, "Distance");
|
|
rideListSync->headerItem()->setText(6, "Action");
|
|
rideListSync->headerItem()->setText(7, "Status");
|
|
rideListSync->setColumnCount(8);
|
|
rideListSync->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
rideListSync->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
rideListSync->setUniformRowHeights(true);
|
|
rideListSync->setIndentation(0);
|
|
rideListSync->header()->resizeSection(0,20);
|
|
rideListSync->header()->resizeSection(1,200);
|
|
rideListSync->header()->resizeSection(2,100);
|
|
rideListSync->header()->resizeSection(3,100);
|
|
rideListSync->header()->resizeSection(4,100);
|
|
rideListSync->header()->resizeSection(5,70);
|
|
rideListSync->header()->resizeSection(6,100);
|
|
rideListSync->setSortingEnabled(true);
|
|
|
|
syncLayout->addLayout(syncList);
|
|
syncLayout->addWidget(rideListSync);
|
|
|
|
// show progress
|
|
progressBar = new QProgressBar(this);
|
|
progressLabel = new QLabel("Initial", this);
|
|
|
|
overwrite = new QCheckBox(tr("Overwrite existing files"), this);
|
|
|
|
// layout the widget now...
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|
|
|
QHBoxLayout *topline = new QHBoxLayout;
|
|
topline->addWidget(athleteCombo);
|
|
topline->addStretch();
|
|
topline->addWidget(fromLabel);
|
|
topline->addWidget(from);
|
|
topline->addWidget(toLabel);
|
|
topline->addWidget(to);
|
|
topline->addStretch();
|
|
topline->addWidget(refreshButton);
|
|
|
|
|
|
QHBoxLayout *botline = new QHBoxLayout;
|
|
botline->addWidget(progressLabel);
|
|
botline->addStretch();
|
|
botline->addWidget(overwrite);
|
|
botline->addWidget(cancelButton);
|
|
botline->addWidget(downloadButton);
|
|
|
|
mainLayout->addLayout(topline);
|
|
mainLayout->addWidget(tabs);
|
|
mainLayout->addWidget(progressBar);
|
|
mainLayout->addLayout(botline);
|
|
|
|
|
|
connect (cancelButton, SIGNAL(clicked()), this, SLOT(cancelClicked()));
|
|
connect (refreshButton, SIGNAL(clicked()), this, SLOT(refreshClicked()));
|
|
connect (selectAll, SIGNAL(stateChanged(int)), this, SLOT(selectAllChanged(int)));
|
|
connect (selectAllUp, SIGNAL(stateChanged(int)), this, SLOT(selectAllUpChanged(int)));
|
|
connect (selectAllSync, SIGNAL(stateChanged(int)), this, SLOT(selectAllSyncChanged(int)));
|
|
connect (downloadButton, SIGNAL(clicked()), this, SLOT(downloadClicked()));
|
|
connect (tabs, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
|
|
QWidget::show();
|
|
|
|
// refresh anyway
|
|
refreshClicked();
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::cancelClicked()
|
|
{
|
|
reject();
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::refreshClicked()
|
|
{
|
|
progressLabel->setText(tr("Downloading ride list..."));
|
|
progressBar->setMinimum(0);
|
|
progressBar->setMaximum(1);
|
|
progressBar->setValue(0);
|
|
|
|
// wipe out current
|
|
foreach (QTreeWidgetItem *curr, rideList->invisibleRootItem()->takeChildren()) {
|
|
QCheckBox *check = (QCheckBox*)rideList->itemWidget(curr, 0);
|
|
QCheckBox *exists = (QCheckBox*)rideList->itemWidget(curr, 6);
|
|
delete check;
|
|
delete exists;
|
|
delete curr;
|
|
}
|
|
foreach (QTreeWidgetItem *curr, rideListUp->invisibleRootItem()->takeChildren()) {
|
|
QCheckBox *check = (QCheckBox*)rideListUp->itemWidget(curr, 0);
|
|
QCheckBox *exists = (QCheckBox*)rideListUp->itemWidget(curr, 6);
|
|
delete check;
|
|
delete exists;
|
|
delete curr;
|
|
}
|
|
foreach (QTreeWidgetItem *curr, rideListSync->invisibleRootItem()->takeChildren()) {
|
|
QCheckBox *check = (QCheckBox*)rideListSync->itemWidget(curr, 0);
|
|
delete check;
|
|
delete curr;
|
|
}
|
|
|
|
// First lets get the ride metrics - if they refresh it takes a while...
|
|
rideMetrics = context->athlete->metricDB->getAllMetricsFor(QDateTime(from->date()), QDateTime(to->date()));
|
|
|
|
// First lets kick off a download of ridefile lookups
|
|
// since that can take a while
|
|
workouter->list(
|
|
athleteCombo->itemData(athleteCombo->currentIndex()).toInt(),
|
|
from->date(),
|
|
to->date(),
|
|
appsettings->cvalue(context->athlete->cyclist, GC_TPUSER, "null").toString(),
|
|
appsettings->cvalue(context->athlete->cyclist, GC_TPPASS, "null").toString());
|
|
|
|
// Whilst we wait for the results lets fill the map of existing rideFiles
|
|
// (but ignore seconds since they aren't reliable)
|
|
rideFiles.clear();
|
|
QStringListIterator i(RideFileFactory::instance().listRideFiles(context->athlete->home));
|
|
for (i.toFront(); i.hasNext();) rideFiles << QFileInfo(i.next()).baseName().mid(0,14);
|
|
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::tabChanged(int idx)
|
|
{
|
|
if (downloadButton->text() == "Abort") return;
|
|
|
|
switch (idx) {
|
|
|
|
case 0 : // download
|
|
downloadButton->setText(tr("Download"));
|
|
refreshCount();
|
|
break;
|
|
case 1 : // upload
|
|
downloadButton->setText(tr("Upload"));
|
|
refreshUpCount();
|
|
break;
|
|
case 2 : // synchronise
|
|
downloadButton->setText(tr("Synchronize"));
|
|
refreshSyncCount();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::completedWorkout(QList<QMap<QString, QString> >workouts)
|
|
{
|
|
useMetricUnits = context->athlete->useMetricUnits;
|
|
|
|
//
|
|
// Setup the upload list
|
|
//
|
|
uploadFiles.clear();
|
|
for(int i=0; i<workouts.count(); i++) {
|
|
QTreeWidgetItem *add;
|
|
|
|
add = new QTreeWidgetItem(rideList->invisibleRootItem());
|
|
add->setFlags(add->flags() & ~Qt::ItemIsEditable);
|
|
|
|
QCheckBox *check = new QCheckBox("", this);
|
|
connect (check, SIGNAL(stateChanged(int)), this, SLOT(refreshCount()));
|
|
rideList->setItemWidget(add, 0, check);
|
|
|
|
add->setText(1, workouts[i].value("WorkoutId"));
|
|
add->setTextAlignment(1, Qt::AlignCenter);
|
|
|
|
QDateTime ridedatetime(QDateTime::fromString(workouts[i].value("WorkoutDay"), Qt::ISODate).date(),
|
|
QDateTime::fromString(workouts[i].value("StartTime"), Qt::ISODate).time());
|
|
|
|
add->setText(2, ridedatetime.toString("MMM d, yyyy"));
|
|
add->setTextAlignment(2, Qt::AlignLeft);
|
|
add->setText(3, ridedatetime.toString("hh:mm:ss ap"));
|
|
add->setTextAlignment(3, Qt::AlignCenter);
|
|
|
|
long secs = workouts[i].value("TimeTotalInSeconds").toInt();
|
|
QChar zero = QLatin1Char ( '0' );
|
|
QString duration = QString("%1:%2:%3").arg(secs/3600,2,10,zero)
|
|
.arg(secs%3600/60,2,10,zero)
|
|
.arg(secs%60,2,10,zero);
|
|
add->setText(4, duration);
|
|
add->setTextAlignment(4, Qt::AlignCenter);
|
|
|
|
double distance = workouts[i].value("DistanceInMeters").toDouble() / 1000.00;
|
|
if (useMetricUnits) {
|
|
add->setText(5, QString("%1 km").arg(distance, 0, 'f', 1));
|
|
} else {
|
|
add->setText(5, QString("%1 mi").arg(distance*MILES_PER_KM, 0, 'f', 1));
|
|
}
|
|
add->setTextAlignment(5, Qt::AlignRight);
|
|
|
|
QString targetnosuffix = QString ( "%1_%2_%3_%4_%5_%6" )
|
|
.arg ( ridedatetime.date().year(), 4, 10, zero )
|
|
.arg ( ridedatetime.date().month(), 2, 10, zero )
|
|
.arg ( ridedatetime.date().day(), 2, 10, zero )
|
|
.arg ( ridedatetime.time().hour(), 2, 10, zero )
|
|
.arg ( ridedatetime.time().minute(), 2, 10, zero )
|
|
.arg ( ridedatetime.time().second(), 2, 10, zero );
|
|
|
|
uploadFiles << targetnosuffix.mid(0,14);
|
|
|
|
// exists? - we ignore seconds, since TP seems to do odd
|
|
// things to date times and loses seconds (?)
|
|
QCheckBox *exists = new QCheckBox("", this);
|
|
exists->setEnabled(false);
|
|
rideList->setItemWidget(add, 6, exists);
|
|
add->setTextAlignment(6, Qt::AlignCenter);
|
|
if (rideFiles.contains(targetnosuffix.mid(0,14))) exists->setChecked(Qt::Checked);
|
|
else {
|
|
exists->setChecked(Qt::Unchecked);
|
|
|
|
// doesn't exist -- add it to the sync list too then
|
|
QTreeWidgetItem *sync = new QTreeWidgetItem(rideListSync->invisibleRootItem());
|
|
|
|
QCheckBox *check = new QCheckBox("", this);
|
|
connect (check, SIGNAL(stateChanged(int)), this, SLOT(refreshSyncCount()));
|
|
rideListSync->setItemWidget(sync, 0, check);
|
|
|
|
sync->setText(1, workouts[i].value("WorkoutId"));
|
|
sync->setTextAlignment(1, Qt::AlignCenter);
|
|
sync->setText(2, ridedatetime.toString("MMM d, yyyy"));
|
|
sync->setTextAlignment(2, Qt::AlignLeft);
|
|
sync->setText(3, ridedatetime.toString("hh:mm:ss ap"));
|
|
sync->setTextAlignment(3, Qt::AlignCenter);
|
|
sync->setText(4, duration);
|
|
sync->setTextAlignment(4, Qt::AlignCenter);
|
|
sync->setText(5, QString("%1 km").arg(distance, 0, 'f', 1));
|
|
sync->setTextAlignment(5, Qt::AlignRight);
|
|
sync->setText(6, tr("Download"));
|
|
sync->setTextAlignment(6, Qt::AlignLeft);
|
|
sync->setText(7, "");
|
|
}
|
|
|
|
add->setText(7, "");
|
|
}
|
|
|
|
//
|
|
// Now setup the upload list
|
|
//
|
|
for(int i=0; i<rideMetrics.count(); i++) {
|
|
QTreeWidgetItem *add;
|
|
|
|
add = new QTreeWidgetItem(rideListUp->invisibleRootItem());
|
|
add->setFlags(add->flags() & ~Qt::ItemIsEditable);
|
|
|
|
QCheckBox *check = new QCheckBox("", this);
|
|
connect (check, SIGNAL(stateChanged(int)), this, SLOT(refreshUpCount()));
|
|
rideListUp->setItemWidget(add, 0, check);
|
|
|
|
add->setText(1, rideMetrics[i].getFileName());
|
|
add->setTextAlignment(1, Qt::AlignLeft);
|
|
|
|
QDateTime ridedatetime = rideMetrics[i].getRideDate();
|
|
|
|
add->setText(2, ridedatetime.toString("MMM d, yyyy"));
|
|
add->setTextAlignment(2, Qt::AlignLeft);
|
|
add->setText(3, ridedatetime.toString("hh:mm:ss ap"));
|
|
add->setTextAlignment(3, Qt::AlignCenter);
|
|
|
|
long secs = rideMetrics[i].getForSymbol("workout_time");
|
|
QChar zero = QLatin1Char ( '0' );
|
|
QString duration = QString("%1:%2:%3").arg(secs/3600,2,10,zero)
|
|
.arg(secs%3600/60,2,10,zero)
|
|
.arg(secs%60,2,10,zero);
|
|
add->setText(4, duration);
|
|
add->setTextAlignment(4, Qt::AlignCenter);
|
|
|
|
double distance = rideMetrics[i].getForSymbol("total_distance");
|
|
add->setText(5, QString("%1 km").arg(distance, 0, 'f', 1));
|
|
add->setTextAlignment(5, Qt::AlignRight);
|
|
|
|
// exists? - we ignore seconds, since TP seems to do odd
|
|
// things to date times and loses seconds (?)
|
|
QCheckBox *exists = new QCheckBox("", this);
|
|
exists->setEnabled(false);
|
|
rideListUp->setItemWidget(add, 6, exists);
|
|
add->setTextAlignment(6, Qt::AlignCenter);
|
|
|
|
QString targetnosuffix = QString ( "%1_%2_%3_%4_%5_%6" )
|
|
.arg ( ridedatetime.date().year(), 4, 10, zero )
|
|
.arg ( ridedatetime.date().month(), 2, 10, zero )
|
|
.arg ( ridedatetime.date().day(), 2, 10, zero )
|
|
.arg ( ridedatetime.time().hour(), 2, 10, zero )
|
|
.arg ( ridedatetime.time().minute(), 2, 10, zero )
|
|
.arg ( ridedatetime.time().second(), 2, 10, zero );
|
|
|
|
// check if on TP.com already
|
|
if (uploadFiles.contains(targetnosuffix.mid(0,14))) exists->setChecked(Qt::Checked);
|
|
else {
|
|
exists->setChecked(Qt::Unchecked);
|
|
|
|
// doesn't exist -- add it to the sync list too then
|
|
QTreeWidgetItem *sync = new QTreeWidgetItem(rideListSync->invisibleRootItem());
|
|
|
|
QCheckBox *check = new QCheckBox("", this);
|
|
connect (check, SIGNAL(stateChanged(int)), this, SLOT(refreshSyncCount()));
|
|
rideListSync->setItemWidget(sync, 0, check);
|
|
|
|
sync->setText(1, rideMetrics[i].getFileName());
|
|
sync->setTextAlignment(1, Qt::AlignCenter);
|
|
sync->setText(2, ridedatetime.toString("MMM d, yyyy"));
|
|
sync->setTextAlignment(2, Qt::AlignLeft);
|
|
sync->setText(3, ridedatetime.toString("hh:mm:ss ap"));
|
|
sync->setTextAlignment(3, Qt::AlignCenter);
|
|
sync->setText(4, duration);
|
|
sync->setTextAlignment(4, Qt::AlignCenter);
|
|
sync->setText(5, QString("%1 km").arg(distance, 0, 'f', 1));
|
|
sync->setTextAlignment(5, Qt::AlignRight);
|
|
sync->setText(6, tr("Upload"));
|
|
sync->setTextAlignment(6, Qt::AlignLeft);
|
|
sync->setText(7, "");
|
|
}
|
|
add->setText(7, "");
|
|
}
|
|
|
|
// refresh the progress label
|
|
tabChanged(tabs->currentIndex());
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::selectAllChanged(int state)
|
|
{
|
|
for (int i=0; i<rideList->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideList->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideList->itemWidget(curr, 0);
|
|
check->setChecked(state);
|
|
}
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::selectAllUpChanged(int state)
|
|
{
|
|
for (int i=0; i<rideListUp->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideListUp->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideListUp->itemWidget(curr, 0);
|
|
check->setChecked(state);
|
|
}
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::selectAllSyncChanged(int state)
|
|
{
|
|
for (int i=0; i<rideListSync->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideListSync->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideListSync->itemWidget(curr, 0);
|
|
check->setChecked(state);
|
|
}
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::refreshUpCount()
|
|
{
|
|
int selected = 0;
|
|
|
|
for (int i=0; i<rideListUp->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideListUp->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideListUp->itemWidget(curr, 0);
|
|
if (check->isChecked()) selected++;
|
|
}
|
|
progressLabel->setText(QString("%1 of %2 selected").arg(selected)
|
|
.arg(rideListUp->invisibleRootItem()->childCount()));
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::refreshSyncCount()
|
|
{
|
|
int selected = 0;
|
|
|
|
for (int i=0; i<rideListSync->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideListSync->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideListSync->itemWidget(curr, 0);
|
|
if (check->isChecked()) selected++;
|
|
}
|
|
progressLabel->setText(QString("%1 of %2 selected").arg(selected)
|
|
.arg(rideListSync->invisibleRootItem()->childCount()));
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::refreshCount()
|
|
{
|
|
int selected = 0;
|
|
|
|
for (int i=0; i<rideList->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideList->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideList->itemWidget(curr, 0);
|
|
if (check->isChecked()) selected++;
|
|
}
|
|
progressLabel->setText(QString("%1 of %2 selected").arg(selected)
|
|
.arg(rideList->invisibleRootItem()->childCount()));
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::downloadClicked()
|
|
{
|
|
if (downloading == true) {
|
|
rideList->setSortingEnabled(true);
|
|
rideListUp->setSortingEnabled(true);
|
|
progressLabel->setText("");
|
|
downloadButton->setText("Download");
|
|
downloading=false;
|
|
aborted=true;
|
|
cancelButton->show();
|
|
return;
|
|
} else {
|
|
rideList->setSortingEnabled(false);
|
|
rideListUp->setSortingEnabled(true);
|
|
downloading=true;
|
|
aborted=false;
|
|
downloadButton->setText("Abort");
|
|
cancelButton->hide();
|
|
}
|
|
|
|
// keeping track of progress...
|
|
downloadcounter = 0;
|
|
successful = 0;
|
|
downloadtotal = 0;
|
|
listindex = 0;
|
|
|
|
QTreeWidget *which = NULL;
|
|
switch(tabs->currentIndex()) {
|
|
case 0 : which = rideList; break;
|
|
case 1 : which = rideListUp; break;
|
|
default:
|
|
case 2 : which = rideListSync; break;
|
|
}
|
|
|
|
for (int i=0; i<which->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = which->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)which->itemWidget(curr, 0);
|
|
if (check->isChecked()) {
|
|
downloadtotal++;
|
|
}
|
|
}
|
|
|
|
if (downloadtotal) {
|
|
progressBar->setMaximum(downloadtotal);
|
|
progressBar->setMinimum(0);
|
|
progressBar->setValue(0);
|
|
}
|
|
|
|
// even if nothing to download this
|
|
// cleans up variables et al
|
|
sync = false;
|
|
switch(tabs->currentIndex()) {
|
|
case 0 : downloadNext(); break;
|
|
case 1 : uploadNext(); break;
|
|
case 2 : sync = true; syncNext(); break;
|
|
}
|
|
}
|
|
|
|
bool
|
|
TPDownloadDialog::syncNext()
|
|
{
|
|
// the actual download/upload is kicked off using the uploader / downloader
|
|
// if in sync mode the completedDownload / completedUpload functions
|
|
// just call completedSync to get the next Sync done
|
|
for (int i=listindex; i<rideListSync->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideListSync->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideListSync->itemWidget(curr, 0);
|
|
|
|
if (check->isChecked()) {
|
|
|
|
listindex = i+1; // start from the next one
|
|
|
|
progressLabel->setText(QString(tr("Processed %1 of %2")).arg(downloadcounter).arg(downloadtotal));
|
|
if (curr->text(6) == "Download") {
|
|
curr->setText(7, tr("Downloading"));
|
|
rideListSync->setCurrentItem(curr);
|
|
downloader->download(
|
|
context->athlete->cyclist,
|
|
athleteCombo->itemData(athleteCombo->currentIndex()).toInt(),
|
|
curr->text(1).toInt()
|
|
);
|
|
QApplication::processEvents();
|
|
} else {
|
|
curr->setText(7, tr("Uploading"));
|
|
rideListSync->setCurrentItem(curr);
|
|
|
|
// read in the file
|
|
QStringList errors;
|
|
QFile file(context->athlete->home.absolutePath() + "/" + curr->text(1));
|
|
RideFile *ride = RideFileFactory::instance().openRideFile(context, file, errors);
|
|
|
|
if (ride) {
|
|
uploader->upload(context, ride);
|
|
delete ride; // clean up!
|
|
QApplication::processEvents();
|
|
return true;
|
|
} else {
|
|
curr->setText(7, "Parse failure");
|
|
QApplication::processEvents();
|
|
}
|
|
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Our work is done!
|
|
//
|
|
rideList->setSortingEnabled(true);
|
|
rideListUp->setSortingEnabled(true);
|
|
rideListSync->setSortingEnabled(true);
|
|
progressLabel->setText(tr("Sync complete"));
|
|
downloadButton->setText("Synchronize");
|
|
downloading=false;
|
|
aborted=false;
|
|
sync=false;
|
|
cancelButton->show();
|
|
selectAllSync->setChecked(Qt::Unchecked);
|
|
for (int i=0; i<rideListSync->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideListSync->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideListSync->itemWidget(curr, 0);
|
|
check->setChecked(false);
|
|
}
|
|
progressLabel->setText(QString(tr("Processed %1 of %2 successfully")).arg(successful).arg(downloadtotal));
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
TPDownloadDialog::downloadNext()
|
|
{
|
|
for (int i=listindex; i<rideList->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideList->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideList->itemWidget(curr, 0);
|
|
QCheckBox *exists = (QCheckBox*)rideList->itemWidget(curr, 6);
|
|
|
|
// skip existing if overwrite not set
|
|
if (check->isChecked() && exists->isChecked() && !overwrite->isChecked()) {
|
|
curr->setText(7, tr("File exists"));
|
|
progressBar->setValue(++downloadcounter);
|
|
continue;
|
|
}
|
|
|
|
if (check->isChecked()) {
|
|
|
|
listindex = i+1; // start from the next one
|
|
curr->setText(7, tr("Downloading"));
|
|
rideList->setCurrentItem(curr);
|
|
progressLabel->setText(QString(tr("Downloaded %1 of %2")).arg(downloadcounter).arg(downloadtotal));
|
|
downloader->download(
|
|
context->athlete->cyclist,
|
|
athleteCombo->itemData(athleteCombo->currentIndex()).toInt(),
|
|
curr->text(1).toInt()
|
|
);
|
|
QApplication::processEvents();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Our work is done!
|
|
//
|
|
rideList->setSortingEnabled(true);
|
|
rideListUp->setSortingEnabled(true);
|
|
progressLabel->setText(tr("Downloads complete"));
|
|
downloadButton->setText("Download");
|
|
downloading=false;
|
|
aborted=false;
|
|
cancelButton->show();
|
|
selectAll->setChecked(Qt::Unchecked);
|
|
for (int i=0; i<rideList->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideList->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideList->itemWidget(curr, 0);
|
|
check->setChecked(false);
|
|
}
|
|
progressLabel->setText(QString(tr("Downloaded %1 of %2 successfully")).arg(successful).arg(downloadtotal));
|
|
return false;
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::completedDownload(QDomDocument pwx)
|
|
{
|
|
QTreeWidget *which = sync ? rideListSync : rideList;
|
|
|
|
// was abort pressed?
|
|
if (aborted == true) {
|
|
QTreeWidgetItem *curr = which->invisibleRootItem()->child(listindex-1);
|
|
curr->setText(7, tr("Aborted"));
|
|
return;
|
|
}
|
|
|
|
// update status...
|
|
// validate (parse)
|
|
QStringList errors;
|
|
PwxFileReader reader;
|
|
RideFile *ride = reader.PwxFromDomDoc(pwx, errors);
|
|
|
|
progressBar->setValue(++downloadcounter);
|
|
|
|
QTreeWidgetItem *curr = which->invisibleRootItem()->child(listindex-1);
|
|
if (ride) {
|
|
if (saveRide(ride, pwx, errors) == true) {
|
|
curr->setText(7, tr("Saved"));
|
|
successful++;
|
|
} else {
|
|
curr->setText(7, errors.join(","));
|
|
}
|
|
} else {
|
|
QString err = "Failed:" + errors.join(",");
|
|
curr->setText(7, err);
|
|
}
|
|
QApplication::processEvents();
|
|
|
|
if (sync)
|
|
syncNext();
|
|
else
|
|
downloadNext();
|
|
}
|
|
|
|
bool
|
|
TPDownloadDialog::uploadNext()
|
|
{
|
|
for (int i=listindex; i<rideListUp->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideListUp->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideListUp->itemWidget(curr, 0);
|
|
QCheckBox *exists = (QCheckBox*)rideListUp->itemWidget(curr, 6);
|
|
|
|
// skip existing if overwrite not set
|
|
if (check->isChecked() && exists->isChecked() && !overwrite->isChecked()) {
|
|
curr->setText(7, tr("File exists"));
|
|
progressBar->setValue(++downloadcounter);
|
|
continue;
|
|
}
|
|
|
|
if (check->isChecked()) {
|
|
|
|
listindex = i+1; // start from the next one
|
|
curr->setText(7, tr("Uploading"));
|
|
rideListUp->setCurrentItem(curr);
|
|
progressLabel->setText(QString(tr("Uploaded %1 of %2")).arg(downloadcounter).arg(downloadtotal));
|
|
|
|
// read in the file
|
|
QStringList errors;
|
|
QFile file(context->athlete->home.absolutePath() + "/" + curr->text(1));
|
|
RideFile *ride = RideFileFactory::instance().openRideFile(context, file, errors);
|
|
|
|
if (ride) {
|
|
uploader->upload(context, ride);
|
|
delete ride; // clean up!
|
|
QApplication::processEvents();
|
|
return true;
|
|
} else {
|
|
curr->setText(7, "Parse failure");
|
|
QApplication::processEvents();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Our work is done!
|
|
//
|
|
rideList->setSortingEnabled(true);
|
|
rideListUp->setSortingEnabled(true);
|
|
progressLabel->setText(tr("Uploads complete"));
|
|
downloadButton->setText("Upload");
|
|
downloading=false;
|
|
aborted=false;
|
|
cancelButton->show();
|
|
selectAllUp->setChecked(Qt::Unchecked);
|
|
for (int i=0; i<rideListUp->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *curr = rideListUp->invisibleRootItem()->child(i);
|
|
QCheckBox *check = (QCheckBox*)rideListUp->itemWidget(curr, 0);
|
|
check->setChecked(false);
|
|
}
|
|
progressLabel->setText(QString(tr("Uploaded %1 of %2 successfully")).arg(successful).arg(downloadtotal));
|
|
return false;
|
|
}
|
|
|
|
void
|
|
TPDownloadDialog::completedUpload(QString result)
|
|
{
|
|
QTreeWidget *which = sync ? rideListSync : rideListUp;
|
|
|
|
// was abort pressed?
|
|
if (aborted == true) {
|
|
QTreeWidgetItem *curr = which->invisibleRootItem()->child(listindex-1);
|
|
curr->setText(7, tr("Aborted"));
|
|
return;
|
|
}
|
|
|
|
progressBar->setValue(++downloadcounter);
|
|
|
|
QTreeWidgetItem *curr = which->invisibleRootItem()->child(listindex-1);
|
|
curr->setText(7, result);
|
|
if (result == tr("Upload successful")) successful++;
|
|
QApplication::processEvents();
|
|
|
|
if (sync)
|
|
syncNext();
|
|
else
|
|
uploadNext();
|
|
}
|
|
|
|
bool
|
|
TPDownloadDialog::saveRide(RideFile *ride, QDomDocument &, QStringList &errors)
|
|
{
|
|
QDateTime ridedatetime = ride->startTime();
|
|
|
|
QChar zero = QLatin1Char ( '0' );
|
|
QString targetnosuffix = QString ( "%1_%2_%3_%4_%5_%6" )
|
|
.arg ( ridedatetime.date().year(), 4, 10, zero )
|
|
.arg ( ridedatetime.date().month(), 2, 10, zero )
|
|
.arg ( ridedatetime.date().day(), 2, 10, zero )
|
|
.arg ( ridedatetime.time().hour(), 2, 10, zero )
|
|
.arg ( ridedatetime.time().minute(), 2, 10, zero )
|
|
.arg ( ridedatetime.time().second(), 2, 10, zero );
|
|
|
|
QString filename = context->athlete->home.absolutePath() + "/" + targetnosuffix + ".json";
|
|
|
|
// exists?
|
|
QFileInfo fileinfo(filename);
|
|
if (fileinfo.exists() && overwrite->isChecked() == false) {
|
|
errors << "File exists";
|
|
return false;
|
|
}
|
|
|
|
JsonFileReader reader;
|
|
QFile file(filename);
|
|
reader.writeRideFile(context, ride, file);
|
|
|
|
// add to the ride list
|
|
rideFiles<<targetnosuffix;
|
|
context->athlete->addRide(fileinfo.fileName(), true);
|
|
|
|
return true;
|
|
}
|