mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-15 17:09:56 +00:00
Porting the codebase to QT 5 (5.2) to get the latest bug fixes, performance and improved platform support. This first part is to fixup the codebase to compile on Qt 5, but some aspects have been broken (video). The second part is to migrate from Qwt 6.0.1 to the latest Qwt for multiaxis support. The third part will be to fixup any platform specific issues or issues identified at runtime.
4096 lines
138 KiB
C++
4096 lines
138 KiB
C++
/*
|
|
* Copyright (c) 2012 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 "Athlete.h"
|
|
#include <QtGui>
|
|
#include <QIntValidator>
|
|
|
|
#include <assert.h>
|
|
|
|
#include "Pages.h"
|
|
#include "Units.h"
|
|
#include "Settings.h"
|
|
#include "Units.h"
|
|
#include "Colors.h"
|
|
#include "AddDeviceWizard.h"
|
|
#include "DeviceTypes.h"
|
|
#include "DeviceConfiguration.h"
|
|
#include "ColorButton.h"
|
|
#include "SpecialFields.h"
|
|
#include "DataProcessor.h"
|
|
#include "OAuthDialog.h"
|
|
|
|
//
|
|
// Main Config Page - tabs for each sub-page
|
|
//
|
|
GeneralPage::GeneralPage(Context *context) : context(context)
|
|
{
|
|
// layout without too wide margins
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|
QGridLayout *configLayout = new QGridLayout;
|
|
mainLayout->addLayout(configLayout);
|
|
mainLayout->addStretch();
|
|
setContentsMargins(0,0,0,0);
|
|
mainLayout->setSpacing(0);
|
|
mainLayout->setContentsMargins(0,0,0,0);
|
|
configLayout->setSpacing(10);
|
|
|
|
//
|
|
// Language Selection
|
|
//
|
|
langLabel = new QLabel(tr("Language:"));
|
|
langCombo = new QComboBox();
|
|
langCombo->addItem(tr("English"));
|
|
langCombo->addItem(tr("French"));
|
|
langCombo->addItem(tr("Japanese"));
|
|
langCombo->addItem(tr("Portugese (Brazil)"));
|
|
langCombo->addItem(tr("Italian"));
|
|
langCombo->addItem(tr("German"));
|
|
langCombo->addItem(tr("Russian"));
|
|
langCombo->addItem(tr("Czech"));
|
|
langCombo->addItem(tr("Spanish"));
|
|
langCombo->addItem(tr("Portugese"));
|
|
|
|
// Default to system locale
|
|
QVariant lang = appsettings->value(this, GC_LANG, QLocale::system().name());
|
|
|
|
if(lang.toString().startsWith("en")) langCombo->setCurrentIndex(0);
|
|
else if(lang.toString().startsWith("fr")) langCombo->setCurrentIndex(1);
|
|
else if(lang.toString().startsWith("ja")) langCombo->setCurrentIndex(2);
|
|
else if(lang.toString().startsWith("pt-br")) langCombo->setCurrentIndex(3);
|
|
else if(lang.toString().startsWith("it")) langCombo->setCurrentIndex(4);
|
|
else if(lang.toString().startsWith("de")) langCombo->setCurrentIndex(5);
|
|
else if(lang.toString().startsWith("ru")) langCombo->setCurrentIndex(6);
|
|
else if(lang.toString().startsWith("cs")) langCombo->setCurrentIndex(7);
|
|
else if(lang.toString().startsWith("es")) langCombo->setCurrentIndex(8);
|
|
else if(lang.toString().startsWith("pt")) langCombo->setCurrentIndex(9);
|
|
else langCombo->setCurrentIndex(0);
|
|
|
|
configLayout->addWidget(langLabel, 0,0, Qt::AlignRight);
|
|
configLayout->addWidget(langCombo, 0,1, Qt::AlignLeft);
|
|
|
|
//
|
|
// Crank length - only used by PfPv chart (should move there!)
|
|
//
|
|
QLabel *crankLengthLabel = new QLabel(tr("Crank Length:"));
|
|
QVariant crankLength = appsettings->value(this, GC_CRANKLENGTH);
|
|
crankLengthCombo = new QComboBox();
|
|
crankLengthCombo->addItem("160");
|
|
crankLengthCombo->addItem("162.5");
|
|
crankLengthCombo->addItem("165");
|
|
crankLengthCombo->addItem("167.5");
|
|
crankLengthCombo->addItem("170");
|
|
crankLengthCombo->addItem("172.5");
|
|
crankLengthCombo->addItem("175");
|
|
crankLengthCombo->addItem("177.5");
|
|
crankLengthCombo->addItem("180");
|
|
crankLengthCombo->addItem("182.5");
|
|
crankLengthCombo->addItem("185");
|
|
if(crankLength.toString() == "160") crankLengthCombo->setCurrentIndex(0);
|
|
if(crankLength.toString() == "162.5") crankLengthCombo->setCurrentIndex(1);
|
|
if(crankLength.toString() == "165") crankLengthCombo->setCurrentIndex(2);
|
|
if(crankLength.toString() == "167.5") crankLengthCombo->setCurrentIndex(3);
|
|
if(crankLength.toString() == "170") crankLengthCombo->setCurrentIndex(4);
|
|
if(crankLength.toString() == "172.5") crankLengthCombo->setCurrentIndex(5);
|
|
if(crankLength.toString() == "175") crankLengthCombo->setCurrentIndex(6);
|
|
if(crankLength.toString() == "177.5") crankLengthCombo->setCurrentIndex(7);
|
|
if(crankLength.toString() == "180") crankLengthCombo->setCurrentIndex(8);
|
|
if(crankLength.toString() == "182.5") crankLengthCombo->setCurrentIndex(9);
|
|
if(crankLength.toString() == "185") crankLengthCombo->setCurrentIndex(10);
|
|
|
|
configLayout->addWidget(crankLengthLabel, 1,0, Qt::AlignRight);
|
|
configLayout->addWidget(crankLengthCombo, 1,1, Qt::AlignLeft);
|
|
|
|
//
|
|
// Wheel size
|
|
//
|
|
QLabel *wheelSizeLabel = new QLabel(tr("Wheelsize:"), this);
|
|
int wheelSize = appsettings->value(this, GC_WHEELSIZE, 2100).toInt();
|
|
|
|
wheelSizeCombo = new QComboBox();
|
|
wheelSizeCombo->addItem("Road/Cross (700C/622)"); // 2100mm
|
|
wheelSizeCombo->addItem("Tri/TT (650C)"); // 1960mm
|
|
wheelSizeCombo->addItem("Mountain (26\")"); // 1985mm
|
|
wheelSizeCombo->addItem("BMX (20\")"); // 1750mm
|
|
|
|
switch (wheelSize) {
|
|
default:
|
|
case 2100 : wheelSizeCombo->setCurrentIndex(0); break;
|
|
case 1960 : wheelSizeCombo->setCurrentIndex(1); break;
|
|
case 1985 : wheelSizeCombo->setCurrentIndex(2); break;
|
|
case 1750 : wheelSizeCombo->setCurrentIndex(3); break;
|
|
}
|
|
|
|
configLayout->addWidget(wheelSizeLabel, 2,0, Qt::AlignRight);
|
|
configLayout->addWidget(wheelSizeCombo, 2,1, Qt::AlignLeft);
|
|
|
|
//
|
|
// Garmin crap
|
|
//
|
|
// garmin Smart Recording options
|
|
QVariant garminHWMark = appsettings->value(this, GC_GARMIN_HWMARK);
|
|
garminSmartRecord = new QCheckBox(tr("Use Garmin Smart Recording"), this);
|
|
QVariant isGarminSmartRecording = appsettings->value(this, GC_GARMIN_SMARTRECORD, Qt::Checked);
|
|
garminSmartRecord->setCheckState(isGarminSmartRecording.toInt() > 0 ? Qt::Checked : Qt::Unchecked);
|
|
|
|
// by default, set the threshold to 25 seconds
|
|
if (garminHWMark.isNull() || garminHWMark.toInt() == 0) garminHWMark.setValue(25);
|
|
QLabel *garminHWLabel = new QLabel(tr("Threshold (secs):"));
|
|
garminHWMarkedit = new QLineEdit(garminHWMark.toString(),this);
|
|
garminHWMarkedit->setInputMask("009");
|
|
|
|
configLayout->addWidget(garminSmartRecord, 3,1, Qt::AlignLeft);
|
|
configLayout->addWidget(garminHWLabel, 4,0, Qt::AlignRight);
|
|
configLayout->addWidget(garminHWMarkedit, 4,1, Qt::AlignLeft);
|
|
|
|
// Elevation hysterisis GC_ELEVATION_HYSTERISIS
|
|
QVariant elevationHysteresis = appsettings->value(this, GC_ELEVATION_HYSTERESIS);
|
|
if (elevationHysteresis.isNull() || elevationHysteresis.toFloat() == 0.0)
|
|
elevationHysteresis.setValue(3.0); // default is 1 meter
|
|
|
|
QLabel *hystlabel = new QLabel(tr("Elevation hysteresis (meters):"));
|
|
hystedit = new QLineEdit(elevationHysteresis.toString(),this);
|
|
hystedit->setInputMask("9.00");
|
|
|
|
configLayout->addWidget(hystlabel, 7,0, Qt::AlignRight);
|
|
configLayout->addWidget(hystedit, 7,1, Qt::AlignLeft);
|
|
|
|
//
|
|
// Performance manager
|
|
//
|
|
|
|
perfManSTSLabel = new QLabel(tr("STS average (days):"));
|
|
perfManLTSLabel = new QLabel(tr("LTS average (days):"));
|
|
perfManSTSavgValidator = new QIntValidator(1,21,this);
|
|
perfManLTSavgValidator = new QIntValidator(7,56,this);
|
|
|
|
// get config or set to defaults
|
|
QVariant perfManSTSVal = appsettings->cvalue(context->athlete->cyclist, GC_STS_DAYS);
|
|
if (perfManSTSVal.isNull() || perfManSTSVal.toInt() == 0) perfManSTSVal = 7;
|
|
QVariant perfManLTSVal = appsettings->cvalue(context->athlete->cyclist, GC_LTS_DAYS);
|
|
if (perfManLTSVal.isNull() || perfManLTSVal.toInt() == 0) perfManLTSVal = 42;
|
|
|
|
perfManSTSavg = new QLineEdit(perfManSTSVal.toString(),this);
|
|
perfManSTSavg->setValidator(perfManSTSavgValidator);
|
|
perfManLTSavg = new QLineEdit(perfManLTSVal.toString(),this);
|
|
perfManLTSavg->setValidator(perfManLTSavgValidator);
|
|
|
|
showSBToday = new QCheckBox(tr("PMC Stress Balance Today"), this);
|
|
showSBToday->setChecked(appsettings->cvalue(context->athlete->cyclist, GC_SB_TODAY).toInt());
|
|
|
|
configLayout->addWidget(perfManSTSLabel, 9,0, Qt::AlignRight);
|
|
configLayout->addWidget(perfManSTSavg, 9,1, Qt::AlignLeft);
|
|
configLayout->addWidget(perfManLTSLabel, 10,0, Qt::AlignRight);
|
|
configLayout->addWidget(perfManLTSavg, 10,1, Qt::AlignLeft);
|
|
configLayout->addWidget(showSBToday, 11,1, Qt::AlignLeft);
|
|
|
|
//
|
|
// Athlete directory (home of athletes)
|
|
//
|
|
QVariant athleteDir = appsettings->value(this, GC_HOMEDIR);
|
|
athleteLabel = new QLabel(tr("Athlete Library:"));
|
|
athleteDirectory = new QLineEdit;
|
|
athleteDirectory->setText(athleteDir.toString() == "0" ? "" : athleteDir.toString());
|
|
athleteBrowseButton = new QPushButton(tr("Browse"));
|
|
athleteBrowseButton->setFixedWidth(70);
|
|
|
|
configLayout->addWidget(athleteLabel, 12,0, Qt::AlignRight);
|
|
configLayout->addWidget(athleteDirectory, 12,1);
|
|
configLayout->addWidget(athleteBrowseButton, 12,2);
|
|
|
|
connect(athleteBrowseButton, SIGNAL(clicked()), this, SLOT(browseAthleteDir()));
|
|
|
|
//
|
|
// Workout directory (train view)
|
|
//
|
|
QVariant workoutDir = appsettings->value(this, GC_WORKOUTDIR);
|
|
workoutLabel = new QLabel(tr("Workout Library:"));
|
|
workoutDirectory = new QLineEdit;
|
|
workoutDirectory->setText(workoutDir.toString());
|
|
workoutBrowseButton = new QPushButton(tr("Browse"));
|
|
workoutBrowseButton->setFixedWidth(70);
|
|
|
|
configLayout->addWidget(workoutLabel, 14,0, Qt::AlignRight);
|
|
configLayout->addWidget(workoutDirectory, 14,1);
|
|
configLayout->addWidget(workoutBrowseButton, 14,2);
|
|
|
|
connect(workoutBrowseButton, SIGNAL(clicked()), this, SLOT(browseWorkoutDir()));
|
|
|
|
}
|
|
|
|
void
|
|
GeneralPage::saveClicked()
|
|
{
|
|
// Language
|
|
static const QString langs[] = {
|
|
"en", "fr", "ja", "pt-br", "it", "de", "ru", "cs", "es", "pt"
|
|
};
|
|
appsettings->setValue(GC_LANG, langs[langCombo->currentIndex()]);
|
|
|
|
// Garmon and cranks
|
|
appsettings->setValue(GC_GARMIN_HWMARK, garminHWMarkedit->text().toInt());
|
|
appsettings->setValue(GC_GARMIN_SMARTRECORD, garminSmartRecord->checkState());
|
|
appsettings->setValue(GC_CRANKLENGTH, crankLengthCombo->currentText());
|
|
|
|
// save wheel size
|
|
static const int wheelSizes[] = {
|
|
2100, 1960, 1985, 1750
|
|
};
|
|
|
|
appsettings->setValue(GC_WHEELSIZE, wheelSizes[wheelSizeCombo->currentIndex()]);
|
|
|
|
// Bike score estimation
|
|
appsettings->setValue(GC_WORKOUTDIR, workoutDirectory->text());
|
|
appsettings->setValue(GC_HOMEDIR, athleteDirectory->text());
|
|
appsettings->setValue(GC_ELEVATION_HYSTERESIS, hystedit->text());
|
|
|
|
// Performance Manager
|
|
appsettings->setCValue(context->athlete->cyclist, GC_STS_DAYS, perfManSTSavg->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_LTS_DAYS, perfManLTSavg->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_SB_TODAY, (int) showSBToday->isChecked());
|
|
|
|
// set default stress names if not set:
|
|
appsettings->setValue(GC_STS_NAME, appsettings->value(this, GC_STS_NAME,tr("Short Term Stress")));
|
|
appsettings->setValue(GC_STS_ACRONYM, appsettings->value(this, GC_STS_ACRONYM,tr("STS")));
|
|
appsettings->setValue(GC_LTS_NAME, appsettings->value(this, GC_LTS_NAME,tr("Long Term Stress")));
|
|
appsettings->setValue(GC_LTS_ACRONYM, appsettings->value(this, GC_LTS_ACRONYM,tr("LTS")));
|
|
appsettings->setValue(GC_SB_NAME, appsettings->value(this, GC_SB_NAME,tr("Stress Balance")));
|
|
appsettings->setValue(GC_SB_ACRONYM, appsettings->value(this, GC_SB_ACRONYM,tr("SB")));
|
|
}
|
|
|
|
void
|
|
GeneralPage::browseWorkoutDir()
|
|
{
|
|
QString dir = QFileDialog::getExistingDirectory(this, tr("Select Workout Library"),
|
|
"", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
|
workoutDirectory->setText(dir);
|
|
}
|
|
|
|
void
|
|
GeneralPage::browseAthleteDir()
|
|
{
|
|
QString dir = QFileDialog::getExistingDirectory(this, tr("Select Athlete Library"),
|
|
"", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
|
athleteDirectory->setText(dir);
|
|
}
|
|
|
|
//
|
|
// Passwords page
|
|
//
|
|
CredentialsPage::CredentialsPage(QWidget *parent, Context *context) : QScrollArea(parent), context(context)
|
|
{
|
|
QWidget *main = new QWidget(this);
|
|
main->setContentsMargins(0,0,0,0);
|
|
|
|
QGridLayout *grid = new QGridLayout;
|
|
|
|
QLabel *gc = new QLabel(tr("Golden Cheetah Racing"));
|
|
QFont current;
|
|
current.setWeight(QFont::Black);
|
|
gc->setFont(current);
|
|
|
|
QLabel *gcurlLabel = new QLabel(tr("Website"));
|
|
QLabel *gcuserLabel = new QLabel(tr("Username"));
|
|
QLabel *gcpassLabel = new QLabel(tr("Password"));
|
|
|
|
QLabel *tp = new QLabel(tr("TrainingPeaks"));
|
|
tp->setFont(current);
|
|
|
|
QLabel *urlLabel = new QLabel(tr("Website"));
|
|
QLabel *userLabel = new QLabel(tr("Username"));
|
|
QLabel *passLabel = new QLabel(tr("Password"));
|
|
QLabel *typeLabel = new QLabel(tr("Account Type"));
|
|
|
|
QLabel *twp = new QLabel(tr("Twitter"));
|
|
twp->setFont(current);
|
|
|
|
QLabel *twurlLabel = new QLabel(tr("Website"));
|
|
QLabel *twauthLabel = new QLabel(tr("Authorise"));
|
|
QLabel *twpinLabel = new QLabel(tr("PIN"));
|
|
|
|
QLabel *str = new QLabel(tr("Strava"));
|
|
str->setFont(current);
|
|
|
|
//QLabel *struserLabel = new QLabel(tr("Username"));
|
|
//QLabel *strpassLabel = new QLabel(tr("Password"));
|
|
QLabel *strauthLabel = new QLabel(tr("Authorise"));
|
|
|
|
QLabel *can = new QLabel(tr("Cycling Analytics"));
|
|
can->setFont(current);
|
|
QLabel *canauthLabel = new QLabel(tr("Authorise"));
|
|
|
|
QLabel *rwgps = new QLabel(tr("RideWithGPS"));
|
|
rwgps->setFont(current);
|
|
|
|
QLabel *rwgpsuserLabel = new QLabel(tr("Username"));
|
|
QLabel *rwgpspassLabel = new QLabel(tr("Password"));
|
|
|
|
QLabel *ttb = new QLabel(tr("Trainingstagebuch"));
|
|
ttb->setFont(current);
|
|
|
|
QLabel *ttbuserLabel = new QLabel(tr("Username"));
|
|
QLabel *ttbpassLabel = new QLabel(tr("Password"));
|
|
|
|
QLabel *sel = new QLabel(tr("Selfloops"));
|
|
sel->setFont(current);
|
|
|
|
QLabel *seluserLabel = new QLabel(tr("Username"));
|
|
QLabel *selpassLabel = new QLabel(tr("Password"));
|
|
|
|
QLabel *wip = new QLabel(tr("Withings Wifi Scales"));
|
|
wip->setFont(current);
|
|
|
|
QLabel *wiurlLabel = new QLabel(tr("Website"));
|
|
QLabel *wiuserLabel = new QLabel(tr("User Id"));
|
|
QLabel *wipassLabel = new QLabel(tr("Public Key"));
|
|
|
|
QLabel *zeo = new QLabel(tr("Zeo Sleep Data"));
|
|
zeo->setFont(current);
|
|
|
|
QLabel *zeourlLabel = new QLabel(tr("Website"));
|
|
QLabel *zeouserLabel = new QLabel(tr("User"));
|
|
QLabel *zeopassLabel = new QLabel(tr("Password"));
|
|
|
|
|
|
QLabel *webcal = new QLabel(tr("Web Calendar"));
|
|
webcal->setFont(current);
|
|
QLabel *wcurlLabel = new QLabel(tr("Webcal URL"));
|
|
|
|
QLabel *dv = new QLabel(tr("CalDAV Calendar"));
|
|
dv->setFont(current);
|
|
QLabel *dvurlLabel = new QLabel(tr("CalDAV URL"));
|
|
QLabel *dvuserLabel = new QLabel(tr("CalDAV User Id"));
|
|
QLabel *dvpassLabel = new QLabel(tr("CalDAV Password"));
|
|
|
|
|
|
gcURL = new QLineEdit(this);
|
|
gcURL->setText(appsettings->cvalue(context->athlete->cyclist, GC_GCURL, "http://race.goldencheetah.org").toString());
|
|
|
|
gcUser = new QLineEdit(this);
|
|
gcUser->setText(appsettings->cvalue(context->athlete->cyclist, GC_GCUSER, "").toString());
|
|
|
|
gcPass = new QLineEdit(this);
|
|
gcPass->setEchoMode(QLineEdit::Password);
|
|
gcPass->setText(appsettings->cvalue(context->athlete->cyclist, GC_GCPASS, "").toString());
|
|
|
|
tpURL = new QLineEdit(this);
|
|
tpURL->setText(appsettings->cvalue(context->athlete->cyclist, GC_TPURL, "http://www.trainingpeaks.com").toString());
|
|
|
|
tpUser = new QLineEdit(this);
|
|
tpUser->setText(appsettings->cvalue(context->athlete->cyclist, GC_TPUSER, "").toString());
|
|
|
|
tpPass = new QLineEdit(this);
|
|
tpPass->setEchoMode(QLineEdit::Password);
|
|
tpPass->setText(appsettings->cvalue(context->athlete->cyclist, GC_TPPASS, "").toString());
|
|
|
|
tpType = new QComboBox(this);
|
|
tpType->addItem("Shared Free");
|
|
tpType->addItem("Coached Free");
|
|
tpType->addItem("Self Coached Premium");
|
|
tpType->addItem("Shared Self Coached Premium");
|
|
tpType->addItem("Coached Premium");
|
|
tpType->addItem("Shared Coached Premium");
|
|
|
|
tpType->setCurrentIndex(appsettings->cvalue(context->athlete->cyclist, GC_TPTYPE, "0").toInt());
|
|
|
|
twitterURL = new QLineEdit(this);
|
|
twitterURL->setText(appsettings->cvalue(context->athlete->cyclist, GC_TWURL, "http://www.twitter.com").toString());
|
|
twitterAuthorise = new QPushButton("Authorise", this);
|
|
twitterPIN = new QLineEdit(this);
|
|
twitterPIN->setText("");
|
|
|
|
stravaAuthorise = new QPushButton("Authorise", this);
|
|
#ifndef GC_STRAVA_CLIENT_SECRET
|
|
stravaAuthorise->setEnabled(false);
|
|
#endif
|
|
|
|
QPixmap passwords = QPixmap(":/images/toolbar/passwords.png");
|
|
|
|
stravaAuthorised = new QPushButton(this);
|
|
stravaAuthorised->setContentsMargins(0,0,0,0);
|
|
stravaAuthorised->setIcon(passwords.scaled(16,16));
|
|
stravaAuthorised->setIconSize(QSize(16,16));
|
|
stravaAuthorised->setFixedHeight(16);
|
|
stravaAuthorised->setFixedWidth(16);
|
|
|
|
cyclingAnalyticsAuthorise = new QPushButton("Authorise", this);
|
|
#ifndef GC_CYCLINGANALYTICS_CLIENT_SECRET
|
|
cyclingAnalyticsAuthorise->setEnabled(false);
|
|
#endif
|
|
|
|
cyclingAnalyticsAuthorised = new QPushButton(this);
|
|
cyclingAnalyticsAuthorised->setContentsMargins(0,0,0,0);
|
|
cyclingAnalyticsAuthorised->setIcon(passwords.scaled(16,16));
|
|
cyclingAnalyticsAuthorised->setIconSize(QSize(16,16));
|
|
cyclingAnalyticsAuthorised->setFixedHeight(16);
|
|
cyclingAnalyticsAuthorised->setFixedWidth(16);
|
|
|
|
rideWithGPSUser = new QLineEdit(this);
|
|
rideWithGPSUser->setText(appsettings->cvalue(context->athlete->cyclist, GC_RWGPSUSER, "").toString());
|
|
|
|
rideWithGPSPass = new QLineEdit(this);
|
|
rideWithGPSPass->setEchoMode(QLineEdit::Password);
|
|
rideWithGPSPass->setText(appsettings->cvalue(context->athlete->cyclist, GC_RWGPSPASS, "").toString());
|
|
|
|
ttbUser = new QLineEdit(this);
|
|
ttbUser->setText(appsettings->cvalue(context->athlete->cyclist, GC_TTBUSER, "").toString());
|
|
|
|
ttbPass = new QLineEdit(this);
|
|
ttbPass->setEchoMode(QLineEdit::Password);
|
|
ttbPass->setText(appsettings->cvalue(context->athlete->cyclist, GC_TTBPASS, "").toString());
|
|
|
|
|
|
selUser = new QLineEdit(this);
|
|
selUser->setText(appsettings->cvalue(context->athlete->cyclist, GC_SELUSER, "").toString());
|
|
|
|
selPass = new QLineEdit(this);
|
|
selPass->setEchoMode(QLineEdit::Password);
|
|
selPass->setText(appsettings->cvalue(context->athlete->cyclist, GC_SELPASS, "").toString());
|
|
|
|
wiURL = new QLineEdit(this);
|
|
wiURL->setText(appsettings->cvalue(context->athlete->cyclist, GC_WIURL, "http://wbsapi.withings.net/").toString());
|
|
|
|
wiUser = new QLineEdit(this);
|
|
wiUser->setText(appsettings->cvalue(context->athlete->cyclist, GC_WIUSER, "").toString());
|
|
|
|
wiPass = new QLineEdit(this);
|
|
wiPass->setText(appsettings->cvalue(context->athlete->cyclist, GC_WIKEY, "").toString());
|
|
|
|
zeoURL = new QLineEdit(this);
|
|
zeoURL->setText(appsettings->cvalue(context->athlete->cyclist, GC_ZEOURL, "http://app-pro.myzeo.com:8080/").toString());
|
|
|
|
zeoUser = new QLineEdit(this);
|
|
zeoUser->setText(appsettings->cvalue(context->athlete->cyclist, GC_ZEOUSER, "").toString());
|
|
|
|
zeoPass = new QLineEdit(this);
|
|
zeoPass->setEchoMode(QLineEdit::Password);
|
|
zeoPass->setText(appsettings->cvalue(context->athlete->cyclist, GC_ZEOPASS, "").toString());
|
|
|
|
webcalURL = new QLineEdit(this);
|
|
webcalURL->setText(appsettings->cvalue(context->athlete->cyclist, GC_WEBCAL_URL, "").toString());
|
|
|
|
dvURL = new QLineEdit(this);
|
|
QString url = appsettings->cvalue(context->athlete->cyclist, GC_DVURL, "").toString();
|
|
url.replace("%40", "@"); // remove escape of @ character
|
|
dvURL->setText(url);
|
|
|
|
dvUser = new QLineEdit(this);
|
|
dvUser->setText(appsettings->cvalue(context->athlete->cyclist, GC_DVUSER, "").toString());
|
|
|
|
dvPass = new QLineEdit(this);
|
|
dvPass->setEchoMode(QLineEdit::Password);
|
|
dvPass->setText(appsettings->cvalue(context->athlete->cyclist, GC_DVPASS, "").toString());
|
|
|
|
grid->addWidget(tp, 0,0);
|
|
grid->addWidget(urlLabel, 1,0);
|
|
grid->addWidget(userLabel, 2,0);
|
|
grid->addWidget(passLabel, 3,0);
|
|
grid->addWidget(typeLabel, 4,0);
|
|
grid->addWidget(gc, 5,0);
|
|
grid->addWidget(gcurlLabel, 6,0);
|
|
grid->addWidget(gcuserLabel, 7,0);
|
|
grid->addWidget(gcpassLabel, 8,0);
|
|
grid->addWidget(twp, 9,0);
|
|
grid->addWidget(twurlLabel, 10,0);
|
|
grid->addWidget(twauthLabel, 11,0);
|
|
grid->addWidget(twpinLabel, 12,0);
|
|
grid->addWidget(str, 13,0);
|
|
grid->addWidget(strauthLabel, 14,0);
|
|
grid->addWidget(can, 15,0);
|
|
grid->addWidget(canauthLabel, 16,0);
|
|
grid->addWidget(rwgps, 18,0);
|
|
grid->addWidget(rwgpsuserLabel, 19,0);
|
|
grid->addWidget(rwgpspassLabel, 20,0);
|
|
grid->addWidget(wip, 21,0);
|
|
grid->addWidget(wiurlLabel, 22,0);
|
|
grid->addWidget(wiuserLabel, 23,0);
|
|
grid->addWidget(wipassLabel, 24,0);
|
|
grid->addWidget(zeo, 25,0);
|
|
grid->addWidget(zeourlLabel, 26,0);
|
|
grid->addWidget(zeouserLabel, 27,0);
|
|
grid->addWidget(zeopassLabel, 28,0);
|
|
grid->addWidget(webcal, 29, 0);
|
|
grid->addWidget(wcurlLabel, 30, 0);
|
|
grid->addWidget(dv, 31,0);
|
|
grid->addWidget(dvurlLabel, 32,0);
|
|
grid->addWidget(dvuserLabel, 33,0);
|
|
grid->addWidget(dvpassLabel, 34,0);
|
|
grid->addWidget(ttb, 35,0);
|
|
grid->addWidget(ttbuserLabel, 36,0);
|
|
grid->addWidget(ttbpassLabel, 37,0);
|
|
grid->addWidget(sel, 38,0);
|
|
grid->addWidget(seluserLabel, 39,0);
|
|
grid->addWidget(selpassLabel, 40,0);
|
|
|
|
grid->addWidget(tpURL, 1, 1, 0);
|
|
grid->addWidget(tpUser, 2, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
grid->addWidget(tpPass, 3, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
grid->addWidget(tpType, 4, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
grid->addWidget(gcURL, 6, 1, 0);
|
|
grid->addWidget(gcUser, 7, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
grid->addWidget(gcPass, 8, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
grid->addWidget(twitterURL, 10, 1, 0);
|
|
grid->addWidget(twitterAuthorise, 11, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
grid->addWidget(twitterPIN, 12, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
grid->addWidget(stravaAuthorise, 14, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
if (appsettings->cvalue(context->athlete->cyclist, GC_STRAVA_TOKEN, "")!="")
|
|
grid->addWidget(stravaAuthorised, 14, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
else
|
|
stravaAuthorised->hide(); // if no token no show
|
|
|
|
grid->addWidget(cyclingAnalyticsAuthorise, 16, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
if (appsettings->cvalue(context->athlete->cyclist, GC_CYCLINGANALYTICS_TOKEN, "")!="")
|
|
grid->addWidget(cyclingAnalyticsAuthorised, 16, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
else
|
|
cyclingAnalyticsAuthorised->hide();
|
|
|
|
grid->addWidget(rideWithGPSUser, 19, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
grid->addWidget(rideWithGPSPass, 20, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
grid->addWidget(wiURL, 22, 1, 0);
|
|
grid->addWidget(wiUser, 23, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
grid->addWidget(wiPass, 24, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
grid->addWidget(zeoURL, 26, 1, 0);
|
|
grid->addWidget(zeoUser, 27, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
grid->addWidget(zeoPass, 28, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
grid->addWidget(webcalURL, 30, 1, 0);
|
|
|
|
grid->addWidget(dvURL, 32, 1, 0);
|
|
grid->addWidget(dvUser, 33, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
grid->addWidget(dvPass, 34, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
grid->addWidget(ttbUser, 36, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
grid->addWidget(ttbPass, 37, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
grid->addWidget(selUser, 39, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
grid->addWidget(selPass, 40, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
grid->setColumnStretch(0,0);
|
|
grid->setColumnStretch(1,3);
|
|
|
|
main->setLayout(grid);
|
|
|
|
setFrameStyle(QFrame::NoFrame);
|
|
setWidgetResizable(true);
|
|
setWidget(main);
|
|
|
|
connect(twitterAuthorise, SIGNAL(clicked()), this, SLOT(authoriseTwitter()));
|
|
connect(stravaAuthorise, SIGNAL(clicked()), this, SLOT(authoriseStrava()));
|
|
connect(cyclingAnalyticsAuthorise, SIGNAL(clicked()), this, SLOT(authoriseCyclingAnalytics()));
|
|
}
|
|
|
|
|
|
void CredentialsPage::authoriseTwitter()
|
|
{
|
|
#ifdef GC_HAVE_LIBOAUTH
|
|
int rc;
|
|
char **rv = NULL;
|
|
QString token;
|
|
QString url = QString();
|
|
t_key = NULL;
|
|
t_secret = NULL;
|
|
|
|
const char *request_token_uri = "http://api.twitter.com/oauth/request_token";
|
|
|
|
char *req_url = NULL;
|
|
char *postarg = NULL;
|
|
char *reply = NULL;
|
|
req_url = oauth_sign_url2(request_token_uri, NULL, OA_HMAC, NULL, GC_TWITTER_CONSUMER_KEY, GC_TWITTER_CONSUMER_SECRET, NULL, NULL);
|
|
reply = oauth_http_get(req_url,postarg);
|
|
|
|
rc = oauth_split_url_parameters(reply, &rv);
|
|
qsort(rv, rc, sizeof(char *), oauth_cmpstringp);
|
|
token = QString(rv[1]);
|
|
t_key =strdup(&(rv[1][12]));
|
|
t_secret =strdup(&(rv[2][19]));
|
|
url = QString("http://api.twitter.com/oauth/authorize?");
|
|
url.append(token);
|
|
QDesktopServices::openUrl(QUrl(url));
|
|
if(rv) free(rv);
|
|
#endif
|
|
}
|
|
|
|
void CredentialsPage::saveTwitter()
|
|
{
|
|
#ifdef GC_HAVE_LIBOAUTH
|
|
char *reply;
|
|
char *req_url;
|
|
char **rv = NULL;
|
|
char *postarg = NULL;
|
|
QString url = QString("http://api.twitter.com/oauth/access_token?a=b&oauth_verifier=");
|
|
|
|
QString strPin = twitterPIN->text();
|
|
if(strPin.size() == 0)
|
|
return;
|
|
|
|
url.append(strPin);
|
|
|
|
req_url = oauth_sign_url2(url.toLatin1(), NULL, OA_HMAC, NULL, GC_TWITTER_CONSUMER_KEY, GC_TWITTER_CONSUMER_SECRET, t_key, t_secret);
|
|
reply = oauth_http_get(req_url,postarg);
|
|
|
|
int rc = oauth_split_url_parameters(reply, &rv);
|
|
|
|
if(rc ==4)
|
|
{
|
|
qsort(rv, rc, sizeof(char *), oauth_cmpstringp);
|
|
|
|
const char *oauth_token = strdup(&(rv[0][12]));
|
|
const char *oauth_secret = strdup(&(rv[1][19]));
|
|
|
|
//Save Twitter oauth_token and oauth_secret;
|
|
appsettings->setValue(GC_TWITTER_TOKEN, oauth_token);
|
|
appsettings->setValue(GC_TWITTER_SECRET, oauth_secret);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CredentialsPage::authoriseStrava()
|
|
{
|
|
#ifdef GC_HAVE_LIBOAUTH
|
|
OAuthDialog *oauthDialog = new OAuthDialog(context, OAuthDialog::STRAVA);
|
|
oauthDialog->setWindowModality(Qt::ApplicationModal);
|
|
oauthDialog->exec();
|
|
#endif
|
|
}
|
|
|
|
void CredentialsPage::authoriseCyclingAnalytics()
|
|
{
|
|
#ifdef GC_HAVE_LIBOAUTH
|
|
OAuthDialog *oauthDialog = new OAuthDialog(context, OAuthDialog::CYCLING_ANALYTICS);
|
|
oauthDialog->setWindowModality(Qt::ApplicationModal);
|
|
oauthDialog->exec();
|
|
#endif
|
|
}
|
|
|
|
void
|
|
CredentialsPage::saveClicked()
|
|
{
|
|
appsettings->setCValue(context->athlete->cyclist, GC_GCURL, gcURL->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_GCUSER, gcUser->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_GCPASS, gcPass->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_TPURL, tpURL->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_TPUSER, tpUser->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_TPPASS, tpPass->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_RWGPSUSER, rideWithGPSUser->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_RWGPSPASS, rideWithGPSPass->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_TTBUSER, ttbUser->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_TTBPASS, ttbPass->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_SELUSER, selUser->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_SELPASS, selPass->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_TPTYPE, tpType->currentIndex());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_WIURL, wiURL->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_WIUSER, wiUser->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_WIKEY, wiPass->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_ZEOURL, zeoURL->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_ZEOUSER, zeoUser->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_ZEOPASS, zeoPass->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_WEBCAL_URL, webcalURL->text());
|
|
|
|
// escape the at character
|
|
QString url = dvURL->text();
|
|
url.replace("@", "%40");
|
|
appsettings->setCValue(context->athlete->cyclist, GC_DVURL, url);
|
|
appsettings->setCValue(context->athlete->cyclist, GC_DVUSER, dvUser->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_DVPASS, dvPass->text());
|
|
}
|
|
|
|
//
|
|
// About me
|
|
//
|
|
RiderPage::RiderPage(QWidget *parent, Context *context) : QWidget(parent), context(context)
|
|
{
|
|
QVBoxLayout *all = new QVBoxLayout(this);
|
|
QGridLayout *grid = new QGridLayout;
|
|
|
|
QLabel *nicklabel = new QLabel(tr("Nickname"));
|
|
QLabel *doblabel = new QLabel(tr("Date of Birth"));
|
|
QLabel *sexlabel = new QLabel(tr("Sex"));
|
|
QLabel *unitlabel = new QLabel(tr("Unit"));
|
|
QLabel *biolabel = new QLabel(tr("Bio"));
|
|
|
|
QString weighttext = QString(tr("Weight (%1)")).arg(context->athlete->useMetricUnits ? tr("kg") : tr("lb"));
|
|
weightlabel = new QLabel(weighttext);
|
|
|
|
nickname = new QLineEdit(this);
|
|
nickname->setText(appsettings->cvalue(context->athlete->cyclist, GC_NICKNAME).toString());
|
|
|
|
dob = new QDateEdit(this);
|
|
dob->setDate(appsettings->cvalue(context->athlete->cyclist, GC_DOB).toDate());
|
|
|
|
sex = new QComboBox(this);
|
|
sex->addItem(tr("Male"));
|
|
sex->addItem(tr("Female"));
|
|
|
|
|
|
// we set to 0 or 1 for male or female since this
|
|
// is language independent (and for once the code is easier!)
|
|
sex->setCurrentIndex(appsettings->cvalue(context->athlete->cyclist, GC_SEX).toInt());
|
|
|
|
unitCombo = new QComboBox();
|
|
unitCombo->addItem(tr("Metric"));
|
|
unitCombo->addItem(tr("Imperial"));
|
|
|
|
if (context->athlete->useMetricUnits)
|
|
unitCombo->setCurrentIndex(0);
|
|
else
|
|
unitCombo->setCurrentIndex(1);
|
|
|
|
weight = new QDoubleSpinBox(this);
|
|
weight->setMaximum(999.9);
|
|
weight->setMinimum(0.0);
|
|
weight->setDecimals(1);
|
|
weight->setValue(appsettings->cvalue(context->athlete->cyclist, GC_WEIGHT).toDouble() * (context->athlete->useMetricUnits ? 1.0 : LB_PER_KG));
|
|
|
|
bio = new QTextEdit(this);
|
|
bio->setText(appsettings->cvalue(context->athlete->cyclist, GC_BIO).toString());
|
|
|
|
if (QFileInfo(context->athlete->home.absolutePath() + "/" + "avatar.png").exists())
|
|
avatar = QPixmap(context->athlete->home.absolutePath() + "/" + "avatar.png");
|
|
else
|
|
avatar = QPixmap(":/images/noavatar.png");
|
|
|
|
avatarButton = new QPushButton(this);
|
|
avatarButton->setContentsMargins(0,0,0,0);
|
|
avatarButton->setFlat(true);
|
|
avatarButton->setIcon(avatar.scaled(140,140));
|
|
avatarButton->setIconSize(QSize(140,140));
|
|
avatarButton->setFixedHeight(140);
|
|
avatarButton->setFixedWidth(140);
|
|
|
|
Qt::Alignment alignment = Qt::AlignLeft|Qt::AlignVCenter;
|
|
|
|
grid->addWidget(nicklabel, 0, 0, alignment);
|
|
grid->addWidget(doblabel, 1, 0, alignment);
|
|
grid->addWidget(sexlabel, 2, 0, alignment);
|
|
grid->addWidget(unitlabel, 3, 0, alignment);
|
|
grid->addWidget(weightlabel, 4, 0, alignment);
|
|
grid->addWidget(biolabel, 5, 0, alignment);
|
|
|
|
grid->addWidget(nickname, 0, 1, alignment);
|
|
grid->addWidget(dob, 1, 1, alignment);
|
|
grid->addWidget(sex, 2, 1, alignment);
|
|
grid->addWidget(unitCombo, 3, 1, alignment);
|
|
grid->addWidget(weight, 4, 1, alignment);
|
|
grid->addWidget(bio, 6, 0, 1, 4);
|
|
|
|
grid->addWidget(avatarButton, 0, 2, 4, 2, Qt::AlignRight|Qt::AlignVCenter);
|
|
all->addLayout(grid);
|
|
all->addStretch();
|
|
|
|
connect (avatarButton, SIGNAL(clicked()), this, SLOT(chooseAvatar()));
|
|
connect (unitCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));
|
|
}
|
|
|
|
void
|
|
RiderPage::chooseAvatar()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Choose Picture"),
|
|
"", tr("Images (*.png *.jpg *.bmp"));
|
|
if (filename != "") {
|
|
|
|
avatar = QPixmap(filename);
|
|
avatarButton->setIcon(avatar.scaled(140,140));
|
|
avatarButton->setIconSize(QSize(140,140));
|
|
}
|
|
}
|
|
|
|
void
|
|
RiderPage::unitChanged(int currentIndex)
|
|
{
|
|
if (currentIndex == 0) {
|
|
QString weighttext = QString(tr("Weight (%1)")).arg(tr("kg"));
|
|
weightlabel->setText(weighttext);
|
|
weight->setValue(weight->value() / LB_PER_KG);
|
|
}
|
|
else {
|
|
QString weighttext = QString(tr("Weight (%1)")).arg(tr("lb"));
|
|
weightlabel->setText(weighttext);
|
|
weight->setValue(weight->value() * LB_PER_KG);
|
|
}
|
|
}
|
|
|
|
void
|
|
RiderPage::saveClicked()
|
|
{
|
|
appsettings->setCValue(context->athlete->cyclist, GC_NICKNAME, nickname->text());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_DOB, dob->date());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_WEIGHT, weight->value() * (unitCombo->currentIndex() ? KG_PER_LB : 1.0));
|
|
|
|
if (unitCombo->currentIndex()==0)
|
|
appsettings->setCValue(context->athlete->cyclist, GC_UNIT, GC_UNIT_METRIC);
|
|
else if (unitCombo->currentIndex()==1)
|
|
appsettings->setCValue(context->athlete->cyclist, GC_UNIT, GC_UNIT_IMPERIAL);
|
|
|
|
appsettings->setCValue(context->athlete->cyclist, GC_SEX, sex->currentIndex());
|
|
appsettings->setCValue(context->athlete->cyclist, GC_BIO, bio->toPlainText());
|
|
avatar.save(context->athlete->home.absolutePath() + "/" + "avatar.png", "PNG");
|
|
}
|
|
|
|
//
|
|
// Realtime devices page
|
|
//
|
|
DevicePage::DevicePage(QWidget *parent, Context *context) : QWidget(parent), context(context)
|
|
{
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|
|
|
DeviceTypes all;
|
|
devices = all.getList();
|
|
|
|
addButton = new QPushButton(tr("+"),this);
|
|
delButton = new QPushButton(tr("-"),this);
|
|
|
|
deviceList = new QTableView(this);
|
|
#ifdef Q_OS_MAC
|
|
deviceList->setAttribute(Qt::WA_MacShowFocusRect, 0);
|
|
#else
|
|
addButton->setFixedSize(20,20);
|
|
delButton->setFixedSize(20,20);
|
|
#endif
|
|
deviceListModel = new deviceModel(this);
|
|
|
|
// replace standard model with ours
|
|
QItemSelectionModel *stdmodel = deviceList->selectionModel();
|
|
deviceList->setModel(deviceListModel);
|
|
delete stdmodel;
|
|
|
|
deviceList->setSortingEnabled(false);
|
|
deviceList->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
deviceList->horizontalHeader()->setStretchLastSection(true);
|
|
deviceList->verticalHeader()->hide();
|
|
deviceList->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|
deviceList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
|
|
multiCheck = new QCheckBox("Allow multiple devices in Train View", this);
|
|
multiCheck->setChecked(appsettings->value(this, TRAIN_MULTI, false).toBool());
|
|
|
|
mainLayout->addWidget(deviceList);
|
|
QHBoxLayout *bottom = new QHBoxLayout;
|
|
bottom->setSpacing(2);
|
|
bottom->addWidget(multiCheck);
|
|
bottom->addStretch();
|
|
bottom->addWidget(addButton);
|
|
bottom->addWidget(delButton);
|
|
mainLayout->addLayout(bottom);
|
|
|
|
connect(addButton, SIGNAL(clicked()), this, SLOT(devaddClicked()));
|
|
connect(delButton, SIGNAL(clicked()), this, SLOT(devdelClicked()));
|
|
}
|
|
|
|
void
|
|
DevicePage::saveClicked()
|
|
{
|
|
// Save the device configuration...
|
|
DeviceConfigurations all;
|
|
all.writeConfig(deviceListModel->Configuration);
|
|
appsettings->setValue(TRAIN_MULTI, multiCheck->isChecked());
|
|
}
|
|
|
|
void
|
|
DevicePage::devaddClicked()
|
|
{
|
|
DeviceConfiguration add;
|
|
AddDeviceWizard *p = new AddDeviceWizard(context);
|
|
p->show();
|
|
}
|
|
|
|
void
|
|
DevicePage::devdelClicked()
|
|
{
|
|
deviceListModel->del();
|
|
}
|
|
|
|
// add a new configuration
|
|
void
|
|
deviceModel::add(DeviceConfiguration &newone)
|
|
{
|
|
insertRows(0,1, QModelIndex());
|
|
|
|
// insert name
|
|
QModelIndex index = deviceModel::index(0,0, QModelIndex());
|
|
setData(index, newone.name, Qt::EditRole);
|
|
|
|
// insert type
|
|
index = deviceModel::index(0,1, QModelIndex());
|
|
setData(index, newone.type, Qt::EditRole);
|
|
|
|
// insert portSpec
|
|
index = deviceModel::index(0,2, QModelIndex());
|
|
setData(index, newone.portSpec, Qt::EditRole);
|
|
|
|
// insert Profile
|
|
index = deviceModel::index(0,3, QModelIndex());
|
|
setData(index, newone.deviceProfile, Qt::EditRole);
|
|
|
|
// insert postProcess
|
|
index = deviceModel::index(0,4, QModelIndex());
|
|
setData(index, newone.postProcess, Qt::EditRole);
|
|
}
|
|
|
|
// delete an existing configuration
|
|
void
|
|
deviceModel::del()
|
|
{
|
|
// which row is selected in the table?
|
|
DevicePage *temp = static_cast<DevicePage*>(parent);
|
|
QItemSelectionModel *selectionModel = temp->deviceList->selectionModel();
|
|
|
|
QModelIndexList indexes = selectionModel->selectedRows();
|
|
QModelIndex index;
|
|
|
|
foreach (index, indexes) {
|
|
//int row = this->mapToSource(index).row();
|
|
removeRows(index.row(), 1, QModelIndex());
|
|
}
|
|
}
|
|
|
|
deviceModel::deviceModel(QObject *parent) : QAbstractTableModel(parent)
|
|
{
|
|
this->parent = parent;
|
|
|
|
// get current configuration
|
|
DeviceConfigurations all;
|
|
Configuration = all.getList();
|
|
}
|
|
|
|
int
|
|
deviceModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
Q_UNUSED(parent);
|
|
return Configuration.size();
|
|
}
|
|
|
|
int
|
|
deviceModel::columnCount(const QModelIndex &) const
|
|
{
|
|
return 5;
|
|
}
|
|
|
|
|
|
// setup the headings!
|
|
QVariant deviceModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (role != Qt::DisplayRole) return QVariant(); // no display, no game!
|
|
|
|
if (orientation == Qt::Horizontal) {
|
|
switch (section) {
|
|
case 0:
|
|
return tr("Device Name");
|
|
case 1:
|
|
return tr("Device Type");
|
|
case 2:
|
|
return tr("Port Spec");
|
|
case 3:
|
|
return tr("Profile");
|
|
case 4:
|
|
return tr("Virtual");
|
|
default:
|
|
return QVariant();
|
|
}
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
// return data item for row/col specified in index
|
|
QVariant deviceModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid()) return QVariant();
|
|
if (index.row() >= Configuration.size() || index.row() < 0) return QVariant();
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
DeviceConfiguration Entry = Configuration.at(index.row());
|
|
|
|
switch(index.column()) {
|
|
case 0 : return Entry.name;
|
|
break;
|
|
case 1 :
|
|
{
|
|
DeviceTypes all;
|
|
DeviceType lookupType = all.getType (Entry.type);
|
|
return lookupType.name;
|
|
}
|
|
break;
|
|
case 2 :
|
|
return Entry.portSpec;
|
|
break;
|
|
case 3 :
|
|
return Entry.deviceProfile;
|
|
case 4 :
|
|
return Entry.postProcess;
|
|
}
|
|
}
|
|
|
|
// how did we get here!?
|
|
return QVariant();
|
|
}
|
|
|
|
// update the model with new data
|
|
bool deviceModel::insertRows(int position, int rows, const QModelIndex &index)
|
|
{
|
|
Q_UNUSED(index);
|
|
beginInsertRows(QModelIndex(), position, position+rows-1);
|
|
|
|
for (int row=0; row < rows; row++) {
|
|
DeviceConfiguration emptyEntry;
|
|
Configuration.insert(position, emptyEntry);
|
|
}
|
|
endInsertRows();
|
|
return true;
|
|
}
|
|
|
|
// delete a row!
|
|
bool deviceModel::removeRows(int position, int rows, const QModelIndex &index)
|
|
{
|
|
Q_UNUSED(index);
|
|
beginRemoveRows(QModelIndex(), position, position+rows-1);
|
|
|
|
for (int row=0; row < rows; ++row) {
|
|
Configuration.removeAt(position);
|
|
}
|
|
|
|
endRemoveRows();
|
|
return true;
|
|
}
|
|
|
|
bool deviceModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
{
|
|
if (index.isValid() && role == Qt::EditRole) {
|
|
int row = index.row();
|
|
|
|
DeviceConfiguration p = Configuration.value(row);
|
|
|
|
switch (index.column()) {
|
|
case 0 : //name
|
|
p.name = value.toString();
|
|
break;
|
|
case 1 : //type
|
|
p.type = value.toInt();
|
|
break;
|
|
case 2 : // spec
|
|
p.portSpec = value.toString();
|
|
break;
|
|
case 3 : // Profile
|
|
p.deviceProfile = value.toString();
|
|
break;
|
|
case 4 : // Profile
|
|
p.postProcess = value.toInt();
|
|
break;
|
|
}
|
|
Configuration.replace(row,p);
|
|
emit(dataChanged(index, index));
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void setSizes(QComboBox *p)
|
|
{
|
|
#ifdef Q_OS_MAC
|
|
p->addItem("7");
|
|
p->addItem("9");
|
|
p->addItem("11");
|
|
p->addItem("13");
|
|
p->addItem("15");
|
|
p->addItem("17");
|
|
p->addItem("19");
|
|
p->addItem("21");
|
|
#else
|
|
p->addItem("6");
|
|
p->addItem("8");
|
|
p->addItem("10");
|
|
p->addItem("12");
|
|
p->addItem("14");
|
|
p->addItem("16");
|
|
p->addItem("18");
|
|
p->addItem("20");
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Appearances page
|
|
//
|
|
ColorsPage::ColorsPage(QWidget *parent) : QWidget(parent)
|
|
{
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|
|
|
colors = new QTreeWidget;
|
|
colors->headerItem()->setText(0, tr("Color"));
|
|
colors->headerItem()->setText(1, tr("Select"));
|
|
colors->setColumnCount(2);
|
|
colors->setColumnWidth(0,310);
|
|
colors->setSelectionMode(QAbstractItemView::NoSelection);
|
|
//colors->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
colors->setUniformRowHeights(true);
|
|
colors->setIndentation(0);
|
|
//colors->header()->resizeSection(0,300);
|
|
|
|
shadeZones = new QCheckBox;
|
|
shadeZones->setChecked(appsettings->value(this, GC_SHADEZONES, true).toBool());
|
|
antiAliased = new QCheckBox;
|
|
antiAliased->setChecked(appsettings->value(this, GC_ANTIALIAS, false).toBool());
|
|
lineWidth = new QDoubleSpinBox;
|
|
lineWidth->setMaximum(5);
|
|
lineWidth->setMinimum(0.5);
|
|
lineWidth->setSingleStep(0.5);
|
|
reset = new QPushButton("Reset");
|
|
lineWidth->setValue(appsettings->value(this, GC_LINEWIDTH, 2.0).toDouble());
|
|
|
|
QLabel *lineWidthLabel = new QLabel(tr("Line Width"));
|
|
QLabel *antialiasLabel = new QLabel(tr("Antialias" ));
|
|
QLabel *shadeZonesLabel = new QLabel(tr("Shade Zones" ));
|
|
|
|
QLabel *defaultLabel = new QLabel(tr("Default"));
|
|
QLabel *titlesLabel = new QLabel(tr("Title" ));
|
|
QLabel *markerLabel = new QLabel(tr("Chart Markers" ));
|
|
QLabel *chartLabel = new QLabel(tr("Chart Labels" ));
|
|
QLabel *calendarLabel = new QLabel(tr("Calendar Text" ));
|
|
QLabel *popupLabel = new QLabel(tr("Popup Text" ));
|
|
|
|
def = new QFontComboBox(this);
|
|
titles = new QFontComboBox(this);
|
|
chartmarkers = new QFontComboBox(this);
|
|
chartlabels = new QFontComboBox(this);
|
|
calendar = new QFontComboBox(this);
|
|
popup = new QFontComboBox(this);
|
|
|
|
defaultSize = new QComboBox(this); setSizes(defaultSize);
|
|
titlesSize = new QComboBox(this); setSizes(titlesSize);
|
|
chartmarkersSize = new QComboBox(this); setSizes(chartmarkersSize);
|
|
chartlabelsSize = new QComboBox(this); setSizes(chartlabelsSize);
|
|
calendarSize = new QComboBox(this); setSizes(calendarSize);
|
|
popupSize = new QComboBox(this); setSizes(popupSize);
|
|
|
|
// get round QTBUG
|
|
def->setCurrentIndex(0);
|
|
def->setCurrentIndex(1);
|
|
def->setCurrentFont(QFont());
|
|
titles->setCurrentIndex(0);
|
|
titles->setCurrentIndex(1);
|
|
titles->setCurrentFont(QFont());
|
|
chartmarkers->setCurrentIndex(0);
|
|
chartmarkers->setCurrentIndex(1);
|
|
chartmarkers->setCurrentFont(QFont());
|
|
chartlabels->setCurrentIndex(0);
|
|
chartlabels->setCurrentIndex(1);
|
|
chartlabels->setCurrentFont(QFont());
|
|
calendar->setCurrentIndex(0);
|
|
calendar->setCurrentIndex(1);
|
|
calendar->setCurrentFont(QFont());
|
|
popup->setCurrentIndex(0);
|
|
popup->setCurrentIndex(1);
|
|
popup->setCurrentFont(QFont());
|
|
|
|
QFont font;
|
|
|
|
font.fromString(appsettings->value(this, GC_FONT_DEFAULT, QFont().toString()).toString());
|
|
def->setCurrentFont(font);
|
|
|
|
font.fromString(appsettings->value(this, GC_FONT_TITLES, QFont().toString()).toString());
|
|
titles->setCurrentFont(font);
|
|
|
|
font.fromString(appsettings->value(this, GC_FONT_CHARTMARKERS, QFont().toString()).toString());
|
|
chartmarkers->setCurrentFont(font);
|
|
|
|
font.fromString(appsettings->value(this, GC_FONT_CHARTLABELS, QFont().toString()).toString());
|
|
chartlabels->setCurrentFont(font);
|
|
|
|
font.fromString(appsettings->value(this, GC_FONT_CALENDAR, QFont().toString()).toString());
|
|
calendar->setCurrentFont(font);
|
|
|
|
font.fromString(appsettings->value(this, GC_FONT_POPUP, QFont().toString()).toString());
|
|
popup->setCurrentFont(font);
|
|
|
|
#ifdef Q_OS_MAC
|
|
defaultSize->setCurrentIndex((appsettings->value(this, GC_FONT_DEFAULT_SIZE, 12).toInt() -7) / 2);
|
|
titlesSize->setCurrentIndex((appsettings->value(this, GC_FONT_TITLES_SIZE, 12).toInt() -7) / 2);
|
|
chartmarkersSize->setCurrentIndex((appsettings->value(this, GC_FONT_CHARTMARKERS_SIZE, 12).toInt() -7) / 2);
|
|
chartlabelsSize->setCurrentIndex((appsettings->value(this, GC_FONT_CHARTLABELS_SIZE, 12).toInt() -7) / 2);
|
|
calendarSize->setCurrentIndex((appsettings->value(this, GC_FONT_CALENDAR_SIZE, 12).toInt() -7) / 2);
|
|
popupSize->setCurrentIndex((appsettings->value(this, GC_FONT_POPUP_SIZE, 10).toInt() -7) / 2);
|
|
#else
|
|
defaultSize->setCurrentIndex((appsettings->value(this, GC_FONT_DEFAULT_SIZE, 12).toInt() -6) / 2);
|
|
titlesSize->setCurrentIndex((appsettings->value(this, GC_FONT_TITLES_SIZE, 12).toInt() -6) / 2);
|
|
chartmarkersSize->setCurrentIndex((appsettings->value(this, GC_FONT_CHARTMARKERS_SIZE, 12).toInt() -6) / 2);
|
|
chartlabelsSize->setCurrentIndex((appsettings->value(this, GC_FONT_CHARTLABELS_SIZE, 12).toInt() -6) / 2);
|
|
calendarSize->setCurrentIndex((appsettings->value(this, GC_FONT_CALENDAR_SIZE, 12).toInt() -6) / 2);
|
|
popupSize->setCurrentIndex((appsettings->value(this, GC_FONT_POPUP_SIZE, 10).toInt() -6) / 2);
|
|
#endif
|
|
|
|
QGridLayout *grid = new QGridLayout;
|
|
grid->setSpacing(5);
|
|
|
|
QHBoxLayout *misc = new QHBoxLayout;
|
|
misc->addWidget(lineWidthLabel);
|
|
misc->addWidget(lineWidth);
|
|
misc->addStretch();
|
|
misc->addWidget(antialiasLabel);
|
|
misc->addWidget(antiAliased);
|
|
misc->addWidget(shadeZonesLabel);
|
|
misc->addWidget(shadeZones);
|
|
misc->addStretch();
|
|
misc->addWidget(reset);
|
|
|
|
grid->addWidget(defaultLabel, 0,0);
|
|
grid->addWidget(titlesLabel, 1,0);
|
|
grid->addWidget(markerLabel, 2,0);
|
|
grid->addWidget(chartLabel, 3,0);
|
|
grid->addWidget(calendarLabel, 4,0);
|
|
grid->addWidget(popupLabel, 5,0);
|
|
|
|
grid->addWidget(def, 0,1, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget(titles, 1,1, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget(chartmarkers, 2,1, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget(chartlabels, 3,1, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget(calendar, 4,1, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget(popup, 5,1, Qt::AlignVCenter|Qt::AlignLeft);
|
|
|
|
grid->addWidget(defaultSize, 0,2, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget(titlesSize, 1,2, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget(chartmarkersSize, 2,2, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget(chartlabelsSize, 3,2, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget(calendarSize, 4,2, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget(popupSize, 5,2, Qt::AlignVCenter|Qt::AlignLeft);
|
|
|
|
grid->setColumnStretch(0,1);
|
|
grid->setColumnStretch(1,5);
|
|
grid->setColumnStretch(2,1);
|
|
grid->setColumnStretch(3,1);
|
|
grid->setColumnStretch(4,3);
|
|
|
|
mainLayout->addLayout(grid);
|
|
mainLayout->addLayout(misc);
|
|
mainLayout->addWidget(colors);
|
|
|
|
colorSet = GCColor::colorSet();
|
|
for (int i=0; colorSet[i].name != ""; i++) {
|
|
|
|
QTreeWidgetItem *add;
|
|
ColorButton *colorButton = new ColorButton(this, colorSet[i].name, colorSet[i].color);
|
|
add = new QTreeWidgetItem(colors->invisibleRootItem());
|
|
add->setText(0, colorSet[i].name);
|
|
colors->setItemWidget(add, 1, colorButton);
|
|
|
|
}
|
|
connect(reset, SIGNAL(clicked()), this, SLOT(resetClicked()));
|
|
}
|
|
|
|
void
|
|
ColorsPage::resetClicked()
|
|
{
|
|
colorSet = GCColor::defaultColorSet();
|
|
colors->clear();
|
|
for (int i=0; colorSet[i].name != ""; i++) {
|
|
|
|
QTreeWidgetItem *add;
|
|
ColorButton *colorButton = new ColorButton(this, colorSet[i].name, colorSet[i].color);
|
|
add = new QTreeWidgetItem(colors->invisibleRootItem());
|
|
add->setText(0, colorSet[i].name);
|
|
colors->setItemWidget(add, 1, colorButton);
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
ColorsPage::saveClicked()
|
|
{
|
|
appsettings->setValue(GC_LINEWIDTH, lineWidth->value());
|
|
appsettings->setValue(GC_ANTIALIAS, antiAliased->isChecked());
|
|
appsettings->setValue(GC_SHADEZONES, shadeZones->isChecked());
|
|
|
|
// run down and get the current colors and save
|
|
for (int i=0; colorSet[i].name != ""; i++) {
|
|
QTreeWidgetItem *current = colors->invisibleRootItem()->child(i);
|
|
QColor newColor = ((ColorButton*)colors->itemWidget(current, 1))->getColor();
|
|
QString colorstring = QString("%1:%2:%3").arg(newColor.red())
|
|
.arg(newColor.green())
|
|
.arg(newColor.blue());
|
|
appsettings->setValue(colorSet[i].setting, colorstring);
|
|
}
|
|
// Font
|
|
appsettings->setValue(GC_FONT_DEFAULT, def->currentFont().toString());
|
|
appsettings->setValue(GC_FONT_TITLES, titles->currentFont().toString());
|
|
appsettings->setValue(GC_FONT_CHARTMARKERS, chartmarkers->currentFont().toString());
|
|
appsettings->setValue(GC_FONT_CHARTLABELS, chartlabels->currentFont().toString());
|
|
appsettings->setValue(GC_FONT_CALENDAR, calendar->currentFont().toString());
|
|
appsettings->setValue(GC_FONT_POPUP, popup->currentFont().toString());
|
|
#ifdef Q_OS_MAC
|
|
appsettings->setValue(GC_FONT_DEFAULT_SIZE, 7+(defaultSize->currentIndex()*2));
|
|
appsettings->setValue(GC_FONT_TITLES_SIZE, 7+(titlesSize->currentIndex()*2));
|
|
appsettings->setValue(GC_FONT_CHARTMARKERS_SIZE, 7+(chartmarkersSize->currentIndex()*2));
|
|
appsettings->setValue(GC_FONT_CHARTLABELS_SIZE, 7+(chartlabelsSize->currentIndex()*2));
|
|
appsettings->setValue(GC_FONT_CALENDAR_SIZE, 7+(calendarSize->currentIndex()*2));
|
|
appsettings->setValue(GC_FONT_POPUP_SIZE, 7+(popupSize->currentIndex()*2));
|
|
#else
|
|
appsettings->setValue(GC_FONT_DEFAULT_SIZE, 6+(defaultSize->currentIndex()*2));
|
|
appsettings->setValue(GC_FONT_TITLES_SIZE, 6+(titlesSize->currentIndex()*2));
|
|
appsettings->setValue(GC_FONT_CHARTMARKERS_SIZE, 6+(chartmarkersSize->currentIndex()*2));
|
|
appsettings->setValue(GC_FONT_CHARTLABELS_SIZE, 6+(chartlabelsSize->currentIndex()*2));
|
|
appsettings->setValue(GC_FONT_CALENDAR_SIZE, 6+(calendarSize->currentIndex()*2));
|
|
appsettings->setValue(GC_FONT_POPUP_SIZE, 6+(popupSize->currentIndex()*2));
|
|
#endif
|
|
|
|
QFont font;
|
|
font.fromString(appsettings->value(this, GC_FONT_DEFAULT, QFont().toString()).toString());
|
|
font.setPointSize(appsettings->value(this, GC_FONT_DEFAULT_SIZE, 13).toInt());
|
|
QApplication::setFont(font);
|
|
}
|
|
|
|
IntervalMetricsPage::IntervalMetricsPage(QWidget *parent) :
|
|
QWidget(parent), changed(false)
|
|
{
|
|
availList = new QListWidget;
|
|
availList->setSortingEnabled(true);
|
|
availList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
QVBoxLayout *availLayout = new QVBoxLayout;
|
|
availLayout->addWidget(new QLabel(tr("Available Metrics")));
|
|
availLayout->addWidget(availList);
|
|
selectedList = new QListWidget;
|
|
selectedList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
QVBoxLayout *selectedLayout = new QVBoxLayout;
|
|
selectedLayout->addWidget(new QLabel(tr("Selected Metrics")));
|
|
selectedLayout->addWidget(selectedList);
|
|
#ifndef Q_OS_MAC
|
|
upButton = new QToolButton(this);
|
|
downButton = new QToolButton(this);
|
|
leftButton = new QToolButton(this);
|
|
rightButton = new QToolButton(this);
|
|
upButton->setArrowType(Qt::UpArrow);
|
|
downButton->setArrowType(Qt::DownArrow);
|
|
leftButton->setArrowType(Qt::LeftArrow);
|
|
rightButton->setArrowType(Qt::RightArrow);
|
|
upButton->setFixedSize(20,20);
|
|
downButton->setFixedSize(20,20);
|
|
leftButton->setFixedSize(20,20);
|
|
rightButton->setFixedSize(20,20);
|
|
#else
|
|
upButton = new QPushButton(tr("Up"));
|
|
downButton = new QPushButton(tr("Down"));
|
|
leftButton = new QPushButton("<");
|
|
rightButton = new QPushButton(">");
|
|
#endif
|
|
QVBoxLayout *buttonGrid = new QVBoxLayout;
|
|
QHBoxLayout *upLayout = new QHBoxLayout;
|
|
QHBoxLayout *inexcLayout = new QHBoxLayout;
|
|
QHBoxLayout *downLayout = new QHBoxLayout;
|
|
|
|
upLayout->addStretch();
|
|
upLayout->addWidget(upButton);
|
|
upLayout->addStretch();
|
|
|
|
inexcLayout->addStretch();
|
|
inexcLayout->addWidget(leftButton);
|
|
inexcLayout->addWidget(rightButton);
|
|
inexcLayout->addStretch();
|
|
|
|
downLayout->addStretch();
|
|
downLayout->addWidget(downButton);
|
|
downLayout->addStretch();
|
|
|
|
buttonGrid->addStretch();
|
|
buttonGrid->addLayout(upLayout);
|
|
buttonGrid->addLayout(inexcLayout);
|
|
buttonGrid->addLayout(downLayout);
|
|
buttonGrid->addStretch();
|
|
|
|
QHBoxLayout *hlayout = new QHBoxLayout;
|
|
hlayout->addLayout(availLayout);
|
|
hlayout->addLayout(buttonGrid);
|
|
hlayout->addLayout(selectedLayout);
|
|
setLayout(hlayout);
|
|
|
|
QString s;
|
|
if (appsettings->contains(GC_SETTINGS_INTERVAL_METRICS))
|
|
s = appsettings->value(this, GC_SETTINGS_INTERVAL_METRICS).toString();
|
|
else
|
|
s = GC_SETTINGS_INTERVAL_METRICS_DEFAULT;
|
|
QStringList selectedMetrics = s.split(",");
|
|
|
|
const RideMetricFactory &factory = RideMetricFactory::instance();
|
|
for (int i = 0; i < factory.metricCount(); ++i) {
|
|
QString symbol = factory.metricName(i);
|
|
if (selectedMetrics.contains(symbol))
|
|
continue;
|
|
QSharedPointer<RideMetric> m(factory.newMetric(symbol));
|
|
QString name = m->name();
|
|
name.replace(tr("™"), tr(" (TM)"));
|
|
QListWidgetItem *item = new QListWidgetItem(name);
|
|
item->setData(Qt::UserRole, symbol);
|
|
availList->addItem(item);
|
|
}
|
|
foreach (QString symbol, selectedMetrics) {
|
|
if (!factory.haveMetric(symbol))
|
|
continue;
|
|
QSharedPointer<RideMetric> m(factory.newMetric(symbol));
|
|
QString name = m->name();
|
|
name.replace(tr("™"), tr(" (TM)"));
|
|
QListWidgetItem *item = new QListWidgetItem(name);
|
|
item->setData(Qt::UserRole, symbol);
|
|
selectedList->addItem(item);
|
|
}
|
|
|
|
upButton->setEnabled(false);
|
|
downButton->setEnabled(false);
|
|
leftButton->setEnabled(false);
|
|
rightButton->setEnabled(false);
|
|
|
|
connect(upButton, SIGNAL(clicked()), this, SLOT(upClicked()));
|
|
connect(downButton, SIGNAL(clicked()), this, SLOT(downClicked()));
|
|
connect(leftButton, SIGNAL(clicked()), this, SLOT(leftClicked()));
|
|
connect(rightButton, SIGNAL(clicked()), this, SLOT(rightClicked()));
|
|
connect(availList, SIGNAL(itemSelectionChanged()),
|
|
this, SLOT(availChanged()));
|
|
connect(selectedList, SIGNAL(itemSelectionChanged()),
|
|
this, SLOT(selectedChanged()));
|
|
}
|
|
|
|
void
|
|
IntervalMetricsPage::upClicked()
|
|
{
|
|
assert(!selectedList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
int row = selectedList->row(item);
|
|
assert(row > 0);
|
|
selectedList->takeItem(row);
|
|
selectedList->insertItem(row - 1, item);
|
|
selectedList->setCurrentItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
IntervalMetricsPage::downClicked()
|
|
{
|
|
assert(!selectedList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
int row = selectedList->row(item);
|
|
assert(row < selectedList->count() - 1);
|
|
selectedList->takeItem(row);
|
|
selectedList->insertItem(row + 1, item);
|
|
selectedList->setCurrentItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
IntervalMetricsPage::leftClicked()
|
|
{
|
|
assert(!selectedList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
selectedList->takeItem(selectedList->row(item));
|
|
availList->addItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
IntervalMetricsPage::rightClicked()
|
|
{
|
|
assert(!availList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = availList->selectedItems().first();
|
|
availList->takeItem(availList->row(item));
|
|
selectedList->addItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
IntervalMetricsPage::availChanged()
|
|
{
|
|
rightButton->setEnabled(!availList->selectedItems().isEmpty());
|
|
}
|
|
|
|
void
|
|
IntervalMetricsPage::selectedChanged()
|
|
{
|
|
if (selectedList->selectedItems().isEmpty()) {
|
|
upButton->setEnabled(false);
|
|
downButton->setEnabled(false);
|
|
leftButton->setEnabled(false);
|
|
return;
|
|
}
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
int row = selectedList->row(item);
|
|
if (row == 0)
|
|
upButton->setEnabled(false);
|
|
else
|
|
upButton->setEnabled(true);
|
|
if (row == selectedList->count() - 1)
|
|
downButton->setEnabled(false);
|
|
else
|
|
downButton->setEnabled(true);
|
|
leftButton->setEnabled(true);
|
|
}
|
|
|
|
void
|
|
IntervalMetricsPage::saveClicked()
|
|
{
|
|
if (!changed)
|
|
return;
|
|
QStringList metrics;
|
|
for (int i = 0; i < selectedList->count(); ++i)
|
|
metrics << selectedList->item(i)->data(Qt::UserRole).toString();
|
|
appsettings->setValue(GC_SETTINGS_INTERVAL_METRICS, metrics.join(","));
|
|
}
|
|
|
|
BestsMetricsPage::BestsMetricsPage(QWidget *parent) :
|
|
QWidget(parent), changed(false)
|
|
{
|
|
availList = new QListWidget;
|
|
availList->setSortingEnabled(true);
|
|
availList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
QVBoxLayout *availLayout = new QVBoxLayout;
|
|
availLayout->addWidget(new QLabel(tr("Available Metrics")));
|
|
availLayout->addWidget(availList);
|
|
selectedList = new QListWidget;
|
|
selectedList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
QVBoxLayout *selectedLayout = new QVBoxLayout;
|
|
selectedLayout->addWidget(new QLabel(tr("Selected Metrics")));
|
|
selectedLayout->addWidget(selectedList);
|
|
#ifndef Q_OS_MAC
|
|
upButton = new QToolButton(this);
|
|
downButton = new QToolButton(this);
|
|
leftButton = new QToolButton(this);
|
|
rightButton = new QToolButton(this);
|
|
upButton->setArrowType(Qt::UpArrow);
|
|
downButton->setArrowType(Qt::DownArrow);
|
|
leftButton->setArrowType(Qt::LeftArrow);
|
|
rightButton->setArrowType(Qt::RightArrow);
|
|
upButton->setFixedSize(20,20);
|
|
downButton->setFixedSize(20,20);
|
|
leftButton->setFixedSize(20,20);
|
|
rightButton->setFixedSize(20,20);
|
|
#else
|
|
upButton = new QPushButton(tr("Up"));
|
|
downButton = new QPushButton(tr("Down"));
|
|
leftButton = new QPushButton("<");
|
|
rightButton = new QPushButton(">");
|
|
#endif
|
|
QVBoxLayout *buttonGrid = new QVBoxLayout;
|
|
QHBoxLayout *upLayout = new QHBoxLayout;
|
|
QHBoxLayout *inexcLayout = new QHBoxLayout;
|
|
QHBoxLayout *downLayout = new QHBoxLayout;
|
|
|
|
upLayout->addStretch();
|
|
upLayout->addWidget(upButton);
|
|
upLayout->addStretch();
|
|
|
|
inexcLayout->addStretch();
|
|
inexcLayout->addWidget(leftButton);
|
|
inexcLayout->addWidget(rightButton);
|
|
inexcLayout->addStretch();
|
|
|
|
downLayout->addStretch();
|
|
downLayout->addWidget(downButton);
|
|
downLayout->addStretch();
|
|
|
|
buttonGrid->addStretch();
|
|
buttonGrid->addLayout(upLayout);
|
|
buttonGrid->addLayout(inexcLayout);
|
|
buttonGrid->addLayout(downLayout);
|
|
buttonGrid->addStretch();
|
|
|
|
QHBoxLayout *hlayout = new QHBoxLayout;
|
|
hlayout->addLayout(availLayout);
|
|
hlayout->addLayout(buttonGrid);
|
|
hlayout->addLayout(selectedLayout);
|
|
setLayout(hlayout);
|
|
|
|
QString s;
|
|
if (appsettings->contains(GC_SETTINGS_BESTS_METRICS))
|
|
s = appsettings->value(this, GC_SETTINGS_BESTS_METRICS).toString();
|
|
else
|
|
s = GC_SETTINGS_BESTS_METRICS_DEFAULT;
|
|
QStringList selectedMetrics = s.split(",");
|
|
|
|
const RideMetricFactory &factory = RideMetricFactory::instance();
|
|
for (int i = 0; i < factory.metricCount(); ++i) {
|
|
QString symbol = factory.metricName(i);
|
|
if (selectedMetrics.contains(symbol))
|
|
continue;
|
|
QSharedPointer<RideMetric> m(factory.newMetric(symbol));
|
|
QString name = m->name();
|
|
name.replace(tr("™"), tr(" (TM)"));
|
|
QListWidgetItem *item = new QListWidgetItem(name);
|
|
item->setData(Qt::UserRole, symbol);
|
|
availList->addItem(item);
|
|
}
|
|
foreach (QString symbol, selectedMetrics) {
|
|
if (!factory.haveMetric(symbol))
|
|
continue;
|
|
QSharedPointer<RideMetric> m(factory.newMetric(symbol));
|
|
QString name = m->name();
|
|
name.replace(tr("™"), tr(" (TM)"));
|
|
QListWidgetItem *item = new QListWidgetItem(name);
|
|
item->setData(Qt::UserRole, symbol);
|
|
selectedList->addItem(item);
|
|
}
|
|
|
|
upButton->setEnabled(false);
|
|
downButton->setEnabled(false);
|
|
leftButton->setEnabled(false);
|
|
rightButton->setEnabled(false);
|
|
|
|
connect(upButton, SIGNAL(clicked()), this, SLOT(upClicked()));
|
|
connect(downButton, SIGNAL(clicked()), this, SLOT(downClicked()));
|
|
connect(leftButton, SIGNAL(clicked()), this, SLOT(leftClicked()));
|
|
connect(rightButton, SIGNAL(clicked()), this, SLOT(rightClicked()));
|
|
connect(availList, SIGNAL(itemSelectionChanged()),
|
|
this, SLOT(availChanged()));
|
|
connect(selectedList, SIGNAL(itemSelectionChanged()),
|
|
this, SLOT(selectedChanged()));
|
|
}
|
|
|
|
void
|
|
BestsMetricsPage::upClicked()
|
|
{
|
|
assert(!selectedList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
int row = selectedList->row(item);
|
|
assert(row > 0);
|
|
selectedList->takeItem(row);
|
|
selectedList->insertItem(row - 1, item);
|
|
selectedList->setCurrentItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
BestsMetricsPage::downClicked()
|
|
{
|
|
assert(!selectedList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
int row = selectedList->row(item);
|
|
assert(row < selectedList->count() - 1);
|
|
selectedList->takeItem(row);
|
|
selectedList->insertItem(row + 1, item);
|
|
selectedList->setCurrentItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
BestsMetricsPage::leftClicked()
|
|
{
|
|
assert(!selectedList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
selectedList->takeItem(selectedList->row(item));
|
|
availList->addItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
BestsMetricsPage::rightClicked()
|
|
{
|
|
assert(!availList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = availList->selectedItems().first();
|
|
availList->takeItem(availList->row(item));
|
|
selectedList->addItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
BestsMetricsPage::availChanged()
|
|
{
|
|
rightButton->setEnabled(!availList->selectedItems().isEmpty());
|
|
}
|
|
|
|
void
|
|
BestsMetricsPage::selectedChanged()
|
|
{
|
|
if (selectedList->selectedItems().isEmpty()) {
|
|
upButton->setEnabled(false);
|
|
downButton->setEnabled(false);
|
|
leftButton->setEnabled(false);
|
|
return;
|
|
}
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
int row = selectedList->row(item);
|
|
if (row == 0)
|
|
upButton->setEnabled(false);
|
|
else
|
|
upButton->setEnabled(true);
|
|
if (row == selectedList->count() - 1)
|
|
downButton->setEnabled(false);
|
|
else
|
|
downButton->setEnabled(true);
|
|
leftButton->setEnabled(true);
|
|
}
|
|
|
|
void
|
|
BestsMetricsPage::saveClicked()
|
|
{
|
|
if (!changed)
|
|
return;
|
|
QStringList metrics;
|
|
for (int i = 0; i < selectedList->count(); ++i)
|
|
metrics << selectedList->item(i)->data(Qt::UserRole).toString();
|
|
appsettings->setValue(GC_SETTINGS_BESTS_METRICS, metrics.join(","));
|
|
}
|
|
|
|
SummaryMetricsPage::SummaryMetricsPage(QWidget *parent) :
|
|
QWidget(parent), changed(false)
|
|
{
|
|
availList = new QListWidget;
|
|
availList->setSortingEnabled(true);
|
|
availList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
QVBoxLayout *availLayout = new QVBoxLayout;
|
|
availLayout->addWidget(new QLabel(tr("Available Metrics")));
|
|
availLayout->addWidget(availList);
|
|
selectedList = new QListWidget;
|
|
selectedList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
QVBoxLayout *selectedLayout = new QVBoxLayout;
|
|
selectedLayout->addWidget(new QLabel(tr("Selected Metrics")));
|
|
selectedLayout->addWidget(selectedList);
|
|
#ifndef Q_OS_MAC
|
|
upButton = new QToolButton(this);
|
|
downButton = new QToolButton(this);
|
|
leftButton = new QToolButton(this);
|
|
rightButton = new QToolButton(this);
|
|
upButton->setArrowType(Qt::UpArrow);
|
|
downButton->setArrowType(Qt::DownArrow);
|
|
leftButton->setArrowType(Qt::LeftArrow);
|
|
rightButton->setArrowType(Qt::RightArrow);
|
|
upButton->setFixedSize(20,20);
|
|
downButton->setFixedSize(20,20);
|
|
leftButton->setFixedSize(20,20);
|
|
rightButton->setFixedSize(20,20);
|
|
#else
|
|
upButton = new QPushButton(tr("Up"));
|
|
downButton = new QPushButton(tr("Down"));
|
|
leftButton = new QPushButton("<");
|
|
rightButton = new QPushButton(">");
|
|
#endif
|
|
QVBoxLayout *buttonGrid = new QVBoxLayout;
|
|
QHBoxLayout *upLayout = new QHBoxLayout;
|
|
QHBoxLayout *inexcLayout = new QHBoxLayout;
|
|
QHBoxLayout *downLayout = new QHBoxLayout;
|
|
|
|
upLayout->addStretch();
|
|
upLayout->addWidget(upButton);
|
|
upLayout->addStretch();
|
|
|
|
inexcLayout->addStretch();
|
|
inexcLayout->addWidget(leftButton);
|
|
inexcLayout->addWidget(rightButton);
|
|
inexcLayout->addStretch();
|
|
|
|
downLayout->addStretch();
|
|
downLayout->addWidget(downButton);
|
|
downLayout->addStretch();
|
|
|
|
buttonGrid->addStretch();
|
|
buttonGrid->addLayout(upLayout);
|
|
buttonGrid->addLayout(inexcLayout);
|
|
buttonGrid->addLayout(downLayout);
|
|
buttonGrid->addStretch();
|
|
|
|
QHBoxLayout *hlayout = new QHBoxLayout;
|
|
hlayout->addLayout(availLayout);
|
|
hlayout->addLayout(buttonGrid);
|
|
hlayout->addLayout(selectedLayout);
|
|
setLayout(hlayout);
|
|
|
|
QString s = appsettings->value(this, GC_SETTINGS_SUMMARY_METRICS, GC_SETTINGS_SUMMARY_METRICS_DEFAULT).toString();
|
|
QStringList selectedMetrics = s.split(",");
|
|
|
|
const RideMetricFactory &factory = RideMetricFactory::instance();
|
|
for (int i = 0; i < factory.metricCount(); ++i) {
|
|
QString symbol = factory.metricName(i);
|
|
if (selectedMetrics.contains(symbol))
|
|
continue;
|
|
QSharedPointer<RideMetric> m(factory.newMetric(symbol));
|
|
QString name = m->name();
|
|
name.replace(tr("™"), tr(" (TM)"));
|
|
QListWidgetItem *item = new QListWidgetItem(name);
|
|
item->setData(Qt::UserRole, symbol);
|
|
availList->addItem(item);
|
|
}
|
|
foreach (QString symbol, selectedMetrics) {
|
|
if (!factory.haveMetric(symbol))
|
|
continue;
|
|
QSharedPointer<RideMetric> m(factory.newMetric(symbol));
|
|
QString name = m->name();
|
|
name.replace(tr("™"), tr(" (TM)"));
|
|
QListWidgetItem *item = new QListWidgetItem(name);
|
|
item->setData(Qt::UserRole, symbol);
|
|
selectedList->addItem(item);
|
|
}
|
|
|
|
upButton->setEnabled(false);
|
|
downButton->setEnabled(false);
|
|
leftButton->setEnabled(false);
|
|
rightButton->setEnabled(false);
|
|
|
|
connect(upButton, SIGNAL(clicked()), this, SLOT(upClicked()));
|
|
connect(downButton, SIGNAL(clicked()), this, SLOT(downClicked()));
|
|
connect(leftButton, SIGNAL(clicked()), this, SLOT(leftClicked()));
|
|
connect(rightButton, SIGNAL(clicked()), this, SLOT(rightClicked()));
|
|
connect(availList, SIGNAL(itemSelectionChanged()),
|
|
this, SLOT(availChanged()));
|
|
connect(selectedList, SIGNAL(itemSelectionChanged()),
|
|
this, SLOT(selectedChanged()));
|
|
}
|
|
|
|
void
|
|
SummaryMetricsPage::upClicked()
|
|
{
|
|
assert(!selectedList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
int row = selectedList->row(item);
|
|
assert(row > 0);
|
|
selectedList->takeItem(row);
|
|
selectedList->insertItem(row - 1, item);
|
|
selectedList->setCurrentItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
SummaryMetricsPage::downClicked()
|
|
{
|
|
assert(!selectedList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
int row = selectedList->row(item);
|
|
assert(row < selectedList->count() - 1);
|
|
selectedList->takeItem(row);
|
|
selectedList->insertItem(row + 1, item);
|
|
selectedList->setCurrentItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
SummaryMetricsPage::leftClicked()
|
|
{
|
|
assert(!selectedList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
selectedList->takeItem(selectedList->row(item));
|
|
availList->addItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
SummaryMetricsPage::rightClicked()
|
|
{
|
|
assert(!availList->selectedItems().isEmpty());
|
|
QListWidgetItem *item = availList->selectedItems().first();
|
|
availList->takeItem(availList->row(item));
|
|
selectedList->addItem(item);
|
|
changed = true;
|
|
}
|
|
|
|
void
|
|
SummaryMetricsPage::availChanged()
|
|
{
|
|
rightButton->setEnabled(!availList->selectedItems().isEmpty());
|
|
}
|
|
|
|
void
|
|
SummaryMetricsPage::selectedChanged()
|
|
{
|
|
if (selectedList->selectedItems().isEmpty()) {
|
|
upButton->setEnabled(false);
|
|
downButton->setEnabled(false);
|
|
leftButton->setEnabled(false);
|
|
return;
|
|
}
|
|
QListWidgetItem *item = selectedList->selectedItems().first();
|
|
int row = selectedList->row(item);
|
|
if (row == 0)
|
|
upButton->setEnabled(false);
|
|
else
|
|
upButton->setEnabled(true);
|
|
if (row == selectedList->count() - 1)
|
|
downButton->setEnabled(false);
|
|
else
|
|
downButton->setEnabled(true);
|
|
leftButton->setEnabled(true);
|
|
}
|
|
|
|
void
|
|
SummaryMetricsPage::saveClicked()
|
|
{
|
|
if (!changed)
|
|
return;
|
|
QStringList metrics;
|
|
for (int i = 0; i < selectedList->count(); ++i)
|
|
metrics << selectedList->item(i)->data(Qt::UserRole).toString();
|
|
appsettings->setValue(GC_SETTINGS_SUMMARY_METRICS, metrics.join(","));
|
|
}
|
|
|
|
MetadataPage::MetadataPage(Context *context) : context(context)
|
|
{
|
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
|
|
// get current config using default file
|
|
keywordDefinitions = context->athlete->rideMetadata()->getKeywords();
|
|
fieldDefinitions = context->athlete->rideMetadata()->getFields();
|
|
colorfield = context->athlete->rideMetadata()->getColorField();
|
|
|
|
// setup maintenance pages using current config
|
|
fieldsPage = new FieldsPage(this, fieldDefinitions);
|
|
keywordsPage = new KeywordsPage(this, keywordDefinitions);
|
|
processorPage = new ProcessorPage(context);
|
|
|
|
tabs = new QTabWidget(this);
|
|
tabs->addTab(fieldsPage, tr("Fields"));
|
|
tabs->addTab(keywordsPage, tr("Notes Keywords"));
|
|
tabs->addTab(processorPage, tr("Processing"));
|
|
|
|
// refresh the keywords combo when change tabs .. will do more often than
|
|
// needed but better that than less often than needed
|
|
connect (tabs, SIGNAL(currentChanged(int)), keywordsPage, SLOT(pageSelected()));
|
|
|
|
layout->addWidget(tabs);
|
|
}
|
|
|
|
void
|
|
MetadataPage::saveClicked()
|
|
{
|
|
// get current state
|
|
fieldsPage->getDefinitions(fieldDefinitions);
|
|
keywordsPage->getDefinitions(keywordDefinitions);
|
|
|
|
// write to metadata.xml
|
|
RideMetadata::serialize(context->athlete->home.absolutePath() + "/metadata.xml", keywordDefinitions, fieldDefinitions, colorfield);
|
|
|
|
// save processors config
|
|
processorPage->saveClicked();
|
|
}
|
|
|
|
// little helper since we create/recreate combos
|
|
// for field types all over the place (init, move up, move down)
|
|
void
|
|
FieldsPage::addFieldTypes(QComboBox *p)
|
|
{
|
|
p->addItem(tr("Text"));
|
|
p->addItem(tr("Textbox"));
|
|
p->addItem(tr("ShortText"));
|
|
p->addItem(tr("Integer"));
|
|
p->addItem(tr("Double"));
|
|
p->addItem(tr("Date"));
|
|
p->addItem(tr("Time"));
|
|
p->addItem(tr("Checkbox"));
|
|
}
|
|
|
|
//
|
|
// Calendar coloring page
|
|
//
|
|
KeywordsPage::KeywordsPage(MetadataPage *parent, QList<KeywordDefinition>keywordDefinitions) : QWidget(parent), parent(parent)
|
|
{
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|
|
|
QHBoxLayout *field = new QHBoxLayout();
|
|
fieldLabel = new QLabel(tr("Field"),this);
|
|
fieldChooser = new QComboBox(this);
|
|
field->addWidget(fieldLabel);
|
|
field->addWidget(fieldChooser);
|
|
field->addStretch();
|
|
mainLayout->addLayout(field);
|
|
|
|
addButton = new QPushButton(tr("+"));
|
|
deleteButton = new QPushButton(tr("-"));
|
|
#ifndef Q_OS_MAC
|
|
upButton = new QToolButton(this);
|
|
downButton = new QToolButton(this);
|
|
upButton->setArrowType(Qt::UpArrow);
|
|
downButton->setArrowType(Qt::DownArrow);
|
|
upButton->setFixedSize(20,20);
|
|
downButton->setFixedSize(20,20);
|
|
addButton->setFixedSize(20,20);
|
|
deleteButton->setFixedSize(20,20);
|
|
#else
|
|
upButton = new QPushButton(tr("Up"));
|
|
downButton = new QPushButton(tr("Down"));
|
|
#endif
|
|
|
|
QHBoxLayout *actionButtons = new QHBoxLayout;
|
|
actionButtons->setSpacing(2);
|
|
actionButtons->addWidget(upButton);
|
|
actionButtons->addWidget(downButton);
|
|
actionButtons->addStretch();
|
|
actionButtons->addWidget(addButton);
|
|
actionButtons->addWidget(deleteButton);
|
|
|
|
keywords = new QTreeWidget;
|
|
keywords->headerItem()->setText(0, tr("Keyword"));
|
|
keywords->headerItem()->setText(1, tr("Color"));
|
|
keywords->headerItem()->setText(2, tr("Related Notes Words"));
|
|
keywords->setColumnCount(3);
|
|
keywords->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
keywords->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
keywords->setUniformRowHeights(true);
|
|
keywords->setIndentation(0);
|
|
//keywords->header()->resizeSection(0,100);
|
|
//keywords->header()->resizeSection(1,45);
|
|
|
|
foreach(KeywordDefinition keyword, keywordDefinitions) {
|
|
QTreeWidgetItem *add;
|
|
ColorButton *colorButton = new ColorButton(this, keyword.name, keyword.color);
|
|
add = new QTreeWidgetItem(keywords->invisibleRootItem());
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// keyword
|
|
add->setText(0, keyword.name);
|
|
|
|
// color button
|
|
add->setTextAlignment(1, Qt::AlignHCenter);
|
|
keywords->setItemWidget(add, 1, colorButton);
|
|
|
|
QString text;
|
|
for (int i=0; i< keyword.tokens.count(); i++) {
|
|
if (i != keyword.tokens.count()-1)
|
|
text += keyword.tokens[i] + ",";
|
|
else
|
|
text += keyword.tokens[i];
|
|
}
|
|
|
|
// notes texts
|
|
add->setText(2, text);
|
|
}
|
|
keywords->setCurrentItem(keywords->invisibleRootItem()->child(0));
|
|
|
|
mainLayout->addWidget(keywords);
|
|
mainLayout->addLayout(actionButtons);
|
|
|
|
// connect up slots
|
|
connect(upButton, SIGNAL(clicked()), this, SLOT(upClicked()));
|
|
connect(downButton, SIGNAL(clicked()), this, SLOT(downClicked()));
|
|
connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked()));
|
|
connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
|
|
|
|
connect(fieldChooser, SIGNAL(currentIndexChanged(int)), this, SLOT(colorfieldChanged()));
|
|
}
|
|
|
|
void
|
|
KeywordsPage::pageSelected()
|
|
{
|
|
SpecialFields sp;
|
|
QString prev = "";
|
|
|
|
// remember what was selected, if anything?
|
|
if (fieldChooser->count()) {
|
|
prev = sp.internalName(fieldChooser->itemText(fieldChooser->currentIndex()));
|
|
parent->colorfield = prev;
|
|
} else prev = parent->colorfield;
|
|
// load in texts from metadata
|
|
fieldChooser->clear();
|
|
|
|
// get the current fields defiitions
|
|
QList<FieldDefinition> fromFieldsPage;
|
|
parent->fieldsPage->getDefinitions(fromFieldsPage);
|
|
foreach(FieldDefinition x, fromFieldsPage) {
|
|
if (x.type < 3) fieldChooser->addItem(sp.displayName(x.name));
|
|
}
|
|
fieldChooser->setCurrentIndex(fieldChooser->findText(sp.displayName(prev)));
|
|
}
|
|
|
|
void
|
|
KeywordsPage::colorfieldChanged()
|
|
{
|
|
SpecialFields sp;
|
|
int index = fieldChooser->currentIndex();
|
|
if (index >=0) parent->colorfield = sp.internalName(fieldChooser->itemText(fieldChooser->currentIndex()));
|
|
}
|
|
|
|
|
|
void
|
|
KeywordsPage::upClicked()
|
|
{
|
|
if (keywords->currentItem()) {
|
|
int index = keywords->invisibleRootItem()->indexOfChild(keywords->currentItem());
|
|
if (index == 0) return; // its at the top already
|
|
|
|
// movin on up!
|
|
QWidget *button = keywords->itemWidget(keywords->currentItem(),1);
|
|
ColorButton *colorButton = new ColorButton(this, ((ColorButton*)button)->getName(), ((ColorButton*)button)->getColor());
|
|
QTreeWidgetItem* moved = keywords->invisibleRootItem()->takeChild(index);
|
|
keywords->invisibleRootItem()->insertChild(index-1, moved);
|
|
keywords->setItemWidget(moved, 1, colorButton);
|
|
keywords->setCurrentItem(moved);
|
|
//LTMSettings save = (*presets)[index];
|
|
//presets->removeAt(index);
|
|
//presets->insert(index-1, save);
|
|
}
|
|
}
|
|
|
|
void
|
|
KeywordsPage::downClicked()
|
|
{
|
|
if (keywords->currentItem()) {
|
|
int index = keywords->invisibleRootItem()->indexOfChild(keywords->currentItem());
|
|
if (index == (keywords->invisibleRootItem()->childCount()-1)) return; // its at the bottom already
|
|
|
|
// movin on up!
|
|
QWidget *button = keywords->itemWidget(keywords->currentItem(),1);
|
|
ColorButton *colorButton = new ColorButton(this, ((ColorButton*)button)->getName(), ((ColorButton*)button)->getColor());
|
|
QTreeWidgetItem* moved = keywords->invisibleRootItem()->takeChild(index);
|
|
keywords->invisibleRootItem()->insertChild(index+1, moved);
|
|
keywords->setItemWidget(moved, 1, colorButton);
|
|
keywords->setCurrentItem(moved);
|
|
}
|
|
}
|
|
|
|
void
|
|
KeywordsPage::renameClicked()
|
|
{
|
|
// which one is selected?
|
|
if (keywords->currentItem()) keywords->editItem(keywords->currentItem(), 0);
|
|
}
|
|
|
|
void
|
|
KeywordsPage::addClicked()
|
|
{
|
|
int index = keywords->invisibleRootItem()->indexOfChild(keywords->currentItem());
|
|
if (index < 0) index = 0;
|
|
QTreeWidgetItem *add;
|
|
ColorButton *colorButton = new ColorButton(this, tr("New"), QColor(Qt::blue));
|
|
add = new QTreeWidgetItem;
|
|
keywords->invisibleRootItem()->insertChild(index, add);
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// keyword
|
|
QString text = tr("New");
|
|
for (int i=0; keywords->findItems(text, Qt::MatchExactly, 0).count() > 0; i++) {
|
|
text = QString(tr("New (%1)")).arg(i+1);
|
|
}
|
|
add->setText(0, text);
|
|
|
|
// color button
|
|
add->setTextAlignment(1, Qt::AlignHCenter);
|
|
keywords->setItemWidget(add, 1, colorButton);
|
|
|
|
// notes texts
|
|
add->setText(2, "");
|
|
}
|
|
|
|
void
|
|
KeywordsPage::deleteClicked()
|
|
{
|
|
if (keywords->currentItem()) {
|
|
int index = keywords->invisibleRootItem()->indexOfChild(keywords->currentItem());
|
|
|
|
// zap!
|
|
delete keywords->invisibleRootItem()->takeChild(index);
|
|
}
|
|
}
|
|
|
|
void
|
|
KeywordsPage::getDefinitions(QList<KeywordDefinition> &keywordList)
|
|
{
|
|
// clear current just in case
|
|
keywordList.clear();
|
|
|
|
for (int idx =0; idx < keywords->invisibleRootItem()->childCount(); idx++) {
|
|
KeywordDefinition add;
|
|
QTreeWidgetItem *item = keywords->invisibleRootItem()->child(idx);
|
|
|
|
add.name = item->text(0);
|
|
add.color = ((ColorButton*)keywords->itemWidget(item, 1))->getColor();
|
|
add.tokens = item->text(2).split(",", QString::SkipEmptyParts);
|
|
|
|
keywordList.append(add);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ride metadata page
|
|
//
|
|
FieldsPage::FieldsPage(QWidget *parent, QList<FieldDefinition>fieldDefinitions) : QWidget(parent)
|
|
{
|
|
QGridLayout *mainLayout = new QGridLayout(this);
|
|
|
|
addButton = new QPushButton(tr("+"));
|
|
deleteButton = new QPushButton(tr("-"));
|
|
#ifndef Q_OS_MAC
|
|
upButton = new QToolButton(this);
|
|
downButton = new QToolButton(this);
|
|
upButton->setArrowType(Qt::UpArrow);
|
|
downButton->setArrowType(Qt::DownArrow);
|
|
upButton->setFixedSize(20,20);
|
|
downButton->setFixedSize(20,20);
|
|
addButton->setFixedSize(20,20);
|
|
deleteButton->setFixedSize(20,20);
|
|
#else
|
|
upButton = new QPushButton(tr("Up"));
|
|
downButton = new QPushButton(tr("Down"));
|
|
#endif
|
|
QHBoxLayout *actionButtons = new QHBoxLayout;
|
|
actionButtons->setSpacing(2);
|
|
actionButtons->addWidget(upButton);
|
|
actionButtons->addWidget(downButton);
|
|
actionButtons->addStretch();
|
|
actionButtons->addWidget(addButton);
|
|
actionButtons->addWidget(deleteButton);
|
|
|
|
fields = new QTreeWidget;
|
|
fields->headerItem()->setText(0, tr("Screen Tab"));
|
|
fields->headerItem()->setText(1, tr("Field"));
|
|
fields->headerItem()->setText(2, tr("Type"));
|
|
fields->headerItem()->setText(3, tr("Values"));
|
|
fields->headerItem()->setText(4, tr("Diary"));
|
|
fields->setColumnWidth(0,80);
|
|
fields->setColumnWidth(1,100);
|
|
fields->setColumnWidth(2,100);
|
|
fields->setColumnWidth(3,80);
|
|
fields->setColumnWidth(4,20);
|
|
fields->setColumnCount(5);
|
|
fields->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
fields->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
fields->setUniformRowHeights(true);
|
|
fields->setIndentation(0);
|
|
|
|
SpecialFields specials;
|
|
SpecialTabs specialTabs;
|
|
foreach(FieldDefinition field, fieldDefinitions) {
|
|
QTreeWidgetItem *add;
|
|
QComboBox *comboButton = new QComboBox(this);
|
|
QCheckBox *checkBox = new QCheckBox("", this);
|
|
checkBox->setChecked(field.diary);
|
|
|
|
addFieldTypes(comboButton);
|
|
comboButton->setCurrentIndex(field.type);
|
|
|
|
add = new QTreeWidgetItem(fields->invisibleRootItem());
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// tab name
|
|
add->setText(0, specialTabs.displayName(field.tab));
|
|
// field name
|
|
add->setText(1, specials.displayName(field.name));
|
|
// values
|
|
add->setText(3, field.values.join(","));
|
|
|
|
// type button
|
|
add->setTextAlignment(2, Qt::AlignHCenter);
|
|
fields->setItemWidget(add, 2, comboButton);
|
|
fields->setItemWidget(add, 4, checkBox);
|
|
}
|
|
fields->setCurrentItem(fields->invisibleRootItem()->child(0));
|
|
|
|
mainLayout->addWidget(fields, 0,0);
|
|
mainLayout->addLayout(actionButtons, 1,0);
|
|
|
|
// connect up slots
|
|
connect(upButton, SIGNAL(clicked()), this, SLOT(upClicked()));
|
|
connect(downButton, SIGNAL(clicked()), this, SLOT(downClicked()));
|
|
connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked()));
|
|
connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
|
|
}
|
|
|
|
void
|
|
FieldsPage::upClicked()
|
|
{
|
|
if (fields->currentItem()) {
|
|
int index = fields->invisibleRootItem()->indexOfChild(fields->currentItem());
|
|
if (index == 0) return; // its at the top already
|
|
|
|
// movin on up!
|
|
QWidget *button = fields->itemWidget(fields->currentItem(),2);
|
|
QWidget *check = fields->itemWidget(fields->currentItem(),4);
|
|
QComboBox *comboButton = new QComboBox(this);
|
|
addFieldTypes(comboButton);
|
|
comboButton->setCurrentIndex(((QComboBox*)button)->currentIndex());
|
|
QCheckBox *checkBox = new QCheckBox("", this);
|
|
checkBox->setChecked(((QCheckBox*)check)->isChecked());
|
|
QTreeWidgetItem* moved = fields->invisibleRootItem()->takeChild(index);
|
|
fields->invisibleRootItem()->insertChild(index-1, moved);
|
|
fields->setItemWidget(moved, 2, comboButton);
|
|
fields->setItemWidget(moved, 4, checkBox);
|
|
fields->setCurrentItem(moved);
|
|
}
|
|
}
|
|
|
|
void
|
|
FieldsPage::downClicked()
|
|
{
|
|
if (fields->currentItem()) {
|
|
int index = fields->invisibleRootItem()->indexOfChild(fields->currentItem());
|
|
if (index == (fields->invisibleRootItem()->childCount()-1)) return; // its at the bottom already
|
|
|
|
QWidget *button = fields->itemWidget(fields->currentItem(),2);
|
|
QWidget *check = fields->itemWidget(fields->currentItem(),4);
|
|
QComboBox *comboButton = new QComboBox(this);
|
|
addFieldTypes(comboButton);
|
|
comboButton->setCurrentIndex(((QComboBox*)button)->currentIndex());
|
|
QCheckBox *checkBox = new QCheckBox("", this);
|
|
checkBox->setChecked(((QCheckBox*)check)->isChecked());
|
|
QTreeWidgetItem* moved = fields->invisibleRootItem()->takeChild(index);
|
|
fields->invisibleRootItem()->insertChild(index+1, moved);
|
|
fields->setItemWidget(moved, 2, comboButton);
|
|
fields->setItemWidget(moved, 4, checkBox);
|
|
fields->setCurrentItem(moved);
|
|
}
|
|
}
|
|
|
|
void
|
|
FieldsPage::renameClicked()
|
|
{
|
|
// which one is selected?
|
|
if (fields->currentItem()) fields->editItem(fields->currentItem(), 0);
|
|
}
|
|
|
|
void
|
|
FieldsPage::addClicked()
|
|
{
|
|
int index = fields->invisibleRootItem()->indexOfChild(fields->currentItem());
|
|
if (index < 0) index = 0;
|
|
QTreeWidgetItem *add;
|
|
QComboBox *comboButton = new QComboBox(this);
|
|
addFieldTypes(comboButton);
|
|
QCheckBox *checkBox = new QCheckBox("", this);
|
|
|
|
add = new QTreeWidgetItem;
|
|
fields->invisibleRootItem()->insertChild(index, add);
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// field
|
|
QString text = "New";
|
|
for (int i=0; fields->findItems(text, Qt::MatchExactly, 1).count() > 0; i++) {
|
|
text = QString("New (%1)").arg(i+1);
|
|
}
|
|
add->setText(1, text);
|
|
|
|
// type button
|
|
add->setTextAlignment(2, Qt::AlignHCenter);
|
|
fields->setItemWidget(add, 2, comboButton);
|
|
fields->setItemWidget(add, 4, checkBox);
|
|
}
|
|
|
|
void
|
|
FieldsPage::deleteClicked()
|
|
{
|
|
if (fields->currentItem()) {
|
|
int index = fields->invisibleRootItem()->indexOfChild(fields->currentItem());
|
|
|
|
// zap!
|
|
delete fields->invisibleRootItem()->takeChild(index);
|
|
}
|
|
}
|
|
|
|
void
|
|
FieldsPage::getDefinitions(QList<FieldDefinition> &fieldList)
|
|
{
|
|
SpecialFields sp;
|
|
SpecialTabs st;
|
|
QStringList checkdups;
|
|
|
|
// clear current just in case
|
|
fieldList.clear();
|
|
|
|
for (int idx =0; idx < fields->invisibleRootItem()->childCount(); idx++) {
|
|
|
|
FieldDefinition add;
|
|
QTreeWidgetItem *item = fields->invisibleRootItem()->child(idx);
|
|
|
|
// silently ignore duplicates
|
|
if (checkdups.contains(item->text(1))) continue;
|
|
else checkdups << item->text(1);
|
|
|
|
add.tab = st.internalName(item->text(0));
|
|
add.name = sp.internalName(item->text(1));
|
|
add.values = item->text(3).split(QRegExp("(, *|,)"), QString::KeepEmptyParts);
|
|
add.diary = ((QCheckBox*)fields->itemWidget(item, 4))->isChecked();
|
|
|
|
if (sp.isMetric(add.name))
|
|
add.type = 4;
|
|
else
|
|
add.type = ((QComboBox*)fields->itemWidget(item, 2))->currentIndex();
|
|
|
|
fieldList.append(add);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Data processors config page
|
|
//
|
|
ProcessorPage::ProcessorPage(Context *context) : context(context)
|
|
{
|
|
// get the available processors
|
|
const DataProcessorFactory &factory = DataProcessorFactory::instance();
|
|
processors = factory.getProcessors();
|
|
|
|
QGridLayout *mainLayout = new QGridLayout(this);
|
|
|
|
processorTree = new QTreeWidget;
|
|
processorTree->headerItem()->setText(0, tr("Processor"));
|
|
processorTree->headerItem()->setText(1, tr("Apply"));
|
|
processorTree->headerItem()->setText(2, tr("Settings"));
|
|
processorTree->setColumnCount(3);
|
|
processorTree->setSelectionMode(QAbstractItemView::NoSelection);
|
|
processorTree->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
processorTree->setUniformRowHeights(true);
|
|
processorTree->setIndentation(0);
|
|
//processorTree->header()->resizeSection(0,150);
|
|
|
|
// iterate over all the processors and add an entry to the
|
|
QMapIterator<QString, DataProcessor*> i(processors);
|
|
i.toFront();
|
|
while (i.hasNext()) {
|
|
i.next();
|
|
|
|
QTreeWidgetItem *add;
|
|
|
|
add = new QTreeWidgetItem(processorTree->invisibleRootItem());
|
|
add->setFlags(add->flags() & ~Qt::ItemIsEditable);
|
|
|
|
// Processor Name: it shows the localized name
|
|
add->setText(0, i.value()->name());
|
|
|
|
// Auto or Manual run?
|
|
QComboBox *comboButton = new QComboBox(this);
|
|
comboButton->addItem(tr("Manual"));
|
|
comboButton->addItem(tr("Auto"));
|
|
processorTree->setItemWidget(add, 1, comboButton);
|
|
|
|
QString configsetting = QString("dp/%1/apply").arg(i.key());
|
|
if (appsettings->value(this, configsetting, "Manual").toString() == "Manual")
|
|
comboButton->setCurrentIndex(0);
|
|
else
|
|
comboButton->setCurrentIndex(1);
|
|
|
|
// Get and Set the Config Widget
|
|
DataProcessorConfig *config = i.value()->processorConfig(this);
|
|
config->readConfig();
|
|
|
|
processorTree->setItemWidget(add, 2, config);
|
|
}
|
|
|
|
mainLayout->addWidget(processorTree, 0,0);
|
|
}
|
|
|
|
void
|
|
ProcessorPage::saveClicked()
|
|
{
|
|
// call each processor config widget's saveConfig() to
|
|
// write away separately
|
|
for (int i=0; i<processorTree->invisibleRootItem()->childCount(); i++) {
|
|
// auto or manual?
|
|
QString configsetting = QString("dp/%1/apply").arg(processorTree->invisibleRootItem()->child(i)->text(0));
|
|
QString apply = ((QComboBox*)(processorTree->itemWidget(processorTree->invisibleRootItem()->child(i), 1)))->currentIndex() ?
|
|
"Auto" : "Manual";
|
|
appsettings->setValue(configsetting, apply);
|
|
((DataProcessorConfig*)(processorTree->itemWidget(processorTree->invisibleRootItem()->child(i), 2)))->saveConfig();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Zone Config page
|
|
//
|
|
ZonePage::ZonePage(Context *context) : context(context)
|
|
{
|
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
|
|
// get current config by reading it in (leave mainwindow zones alone)
|
|
QFile zonesFile(context->athlete->home.absolutePath() + "/power.zones");
|
|
if (zonesFile.exists()) {
|
|
zones.read(zonesFile);
|
|
zonesFile.close();
|
|
}
|
|
|
|
// setup maintenance pages using current config
|
|
schemePage = new SchemePage(this);
|
|
cpPage = new CPPage(this);
|
|
|
|
tabs = new QTabWidget(this);
|
|
tabs->addTab(cpPage, tr("Critical Power"));
|
|
tabs->addTab(schemePage, tr("Default"));
|
|
|
|
layout->addWidget(tabs);
|
|
}
|
|
|
|
void
|
|
ZonePage::saveClicked()
|
|
{
|
|
zones.setScheme(schemePage->getScheme());
|
|
zones.write(context->athlete->home);
|
|
}
|
|
|
|
SchemePage::SchemePage(ZonePage* zonePage) : zonePage(zonePage)
|
|
{
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|
|
|
addButton = new QPushButton(tr("+"));
|
|
deleteButton = new QPushButton(tr("-"));
|
|
#ifndef Q_OS_MAC
|
|
addButton->setFixedSize(20,20);
|
|
deleteButton->setFixedSize(20,20);
|
|
#endif
|
|
QHBoxLayout *actionButtons = new QHBoxLayout;
|
|
actionButtons->setSpacing(2);
|
|
actionButtons->addStretch();
|
|
actionButtons->addWidget(addButton);
|
|
actionButtons->addWidget(deleteButton);
|
|
|
|
scheme = new QTreeWidget;
|
|
scheme->headerItem()->setText(0, tr("Short"));
|
|
scheme->headerItem()->setText(1, tr("Long"));
|
|
scheme->headerItem()->setText(2, tr("Percent of CP"));
|
|
scheme->setColumnCount(3);
|
|
scheme->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
scheme->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
scheme->setUniformRowHeights(true);
|
|
scheme->setIndentation(0);
|
|
//scheme->header()->resizeSection(0,90);
|
|
//scheme->header()->resizeSection(1,200);
|
|
//scheme->header()->resizeSection(2,80);
|
|
|
|
// setup list
|
|
for (int i=0; i< zonePage->zones.getScheme().nzones_default; i++) {
|
|
|
|
QTreeWidgetItem *add = new QTreeWidgetItem(scheme->invisibleRootItem());
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// tab name
|
|
add->setText(0, zonePage->zones.getScheme().zone_default_name[i]);
|
|
// field name
|
|
add->setText(1, zonePage->zones.getScheme().zone_default_desc[i]);
|
|
|
|
// low
|
|
QDoubleSpinBox *loedit = new QDoubleSpinBox(this);
|
|
loedit->setMinimum(0);
|
|
loedit->setMaximum(1000);
|
|
loedit->setSingleStep(1.0);
|
|
loedit->setDecimals(0);
|
|
loedit->setValue(zonePage->zones.getScheme().zone_default[i]);
|
|
scheme->setItemWidget(add, 2, loedit);
|
|
}
|
|
|
|
mainLayout->addWidget(scheme);
|
|
mainLayout->addLayout(actionButtons);
|
|
|
|
// button connect
|
|
connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked()));
|
|
connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
|
|
}
|
|
|
|
void
|
|
SchemePage::addClicked()
|
|
{
|
|
// are we at maximum already?
|
|
if (scheme->invisibleRootItem()->childCount() == 10) {
|
|
QMessageBox err;
|
|
err.setText("Maximum of 10 zones reached.");
|
|
err.setIcon(QMessageBox::Warning);
|
|
err.exec();
|
|
return;
|
|
}
|
|
|
|
int index = scheme->invisibleRootItem()->childCount();
|
|
|
|
// new item
|
|
QTreeWidgetItem *add = new QTreeWidgetItem;
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
QDoubleSpinBox *loedit = new QDoubleSpinBox(this);
|
|
loedit->setMinimum(0);
|
|
loedit->setMaximum(1000);
|
|
loedit->setSingleStep(1.0);
|
|
loedit->setDecimals(0);
|
|
loedit->setValue(100);
|
|
|
|
scheme->invisibleRootItem()->insertChild(index, add);
|
|
scheme->setItemWidget(add, 2, loedit);
|
|
|
|
// Short
|
|
QString text = "New";
|
|
for (int i=0; scheme->findItems(text, Qt::MatchExactly, 0).count() > 0; i++) {
|
|
text = QString("New (%1)").arg(i+1);
|
|
}
|
|
add->setText(0, text);
|
|
|
|
// long
|
|
text = "New";
|
|
for (int i=0; scheme->findItems(text, Qt::MatchExactly, 0).count() > 0; i++) {
|
|
text = QString("New (%1)").arg(i+1);
|
|
}
|
|
add->setText(1, text);
|
|
}
|
|
|
|
void
|
|
SchemePage::renameClicked()
|
|
{
|
|
// which one is selected?
|
|
if (scheme->currentItem()) scheme->editItem(scheme->currentItem(), 0);
|
|
}
|
|
|
|
void
|
|
SchemePage::deleteClicked()
|
|
{
|
|
if (scheme->currentItem()) {
|
|
int index = scheme->invisibleRootItem()->indexOfChild(scheme->currentItem());
|
|
delete scheme->invisibleRootItem()->takeChild(index);
|
|
}
|
|
}
|
|
|
|
// just for qSorting
|
|
struct schemeitem {
|
|
QString name, desc;
|
|
int lo;
|
|
double trimp;
|
|
bool operator<(schemeitem right) const { return lo < right.lo; }
|
|
};
|
|
|
|
ZoneScheme
|
|
SchemePage::getScheme()
|
|
{
|
|
// read the scheme widget and return a scheme object
|
|
QList<schemeitem> table;
|
|
ZoneScheme results;
|
|
|
|
// read back the details from the table
|
|
for (int i=0; i<scheme->invisibleRootItem()->childCount(); i++) {
|
|
|
|
schemeitem add;
|
|
add.name = scheme->invisibleRootItem()->child(i)->text(0);
|
|
add.desc = scheme->invisibleRootItem()->child(i)->text(1);
|
|
add.lo = ((QDoubleSpinBox *)(scheme->itemWidget(scheme->invisibleRootItem()->child(i), 2)))->value();
|
|
table.append(add);
|
|
}
|
|
|
|
// sort the list into ascending order
|
|
qSort(table);
|
|
|
|
// now update the results
|
|
results.nzones_default = 0;
|
|
foreach(schemeitem zone, table) {
|
|
results.nzones_default++;
|
|
results.zone_default.append(zone.lo);
|
|
results.zone_default_is_pct.append(true);
|
|
results.zone_default_name.append(zone.name);
|
|
results.zone_default_desc.append(zone.desc);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
|
|
CPPage::CPPage(ZonePage* zonePage) : zonePage(zonePage)
|
|
{
|
|
active = false;
|
|
|
|
QGridLayout *mainLayout = new QGridLayout(this);
|
|
mainLayout->setSpacing(10);
|
|
|
|
addButton = new QPushButton(tr("+"));
|
|
deleteButton = new QPushButton(tr("-"));
|
|
#ifndef Q_OS_MAC
|
|
addButton->setFixedSize(20,20);
|
|
deleteButton->setFixedSize(20,20);
|
|
#endif
|
|
defaultButton = new QPushButton(tr("Def"));
|
|
defaultButton->hide();
|
|
|
|
addZoneButton = new QPushButton(tr("+"));
|
|
deleteZoneButton = new QPushButton(tr("-"));
|
|
#ifndef Q_OS_MAC
|
|
addZoneButton->setFixedSize(20,20);
|
|
deleteZoneButton->setFixedSize(20,20);
|
|
#endif
|
|
|
|
QHBoxLayout *zoneButtons = new QHBoxLayout;
|
|
zoneButtons->addStretch();
|
|
zoneButtons->setSpacing(0);
|
|
zoneButtons->addWidget(addZoneButton);
|
|
zoneButtons->addWidget(deleteZoneButton);
|
|
|
|
QHBoxLayout *addLayout = new QHBoxLayout;
|
|
QLabel *dateLabel = new QLabel(tr("From Date"));
|
|
QLabel *cpLabel = new QLabel(tr("Critical Power"));
|
|
QLabel *wLabel = new QLabel(tr("W'"));
|
|
dateEdit = new QDateEdit;
|
|
dateEdit->setDate(QDate::currentDate());
|
|
|
|
cpEdit = new QDoubleSpinBox;
|
|
cpEdit->setMinimum(0);
|
|
cpEdit->setMaximum(1000);
|
|
cpEdit->setSingleStep(1.0);
|
|
cpEdit->setDecimals(0);
|
|
|
|
wEdit = new QDoubleSpinBox;
|
|
wEdit->setMinimum(0);
|
|
wEdit->setMaximum(40000);
|
|
wEdit->setSingleStep(100);
|
|
wEdit->setDecimals(0);
|
|
|
|
QHBoxLayout *actionButtons = new QHBoxLayout;
|
|
actionButtons->setSpacing(2);
|
|
actionButtons->addWidget(cpLabel);
|
|
actionButtons->addWidget(cpEdit);
|
|
actionButtons->addWidget(wLabel);
|
|
actionButtons->addWidget(wEdit);
|
|
actionButtons->addStretch();
|
|
actionButtons->addWidget(addButton);
|
|
actionButtons->addWidget(deleteButton);
|
|
actionButtons->addWidget(defaultButton);
|
|
|
|
addLayout->addWidget(dateLabel);
|
|
addLayout->addWidget(dateEdit);
|
|
addLayout->addStretch();
|
|
|
|
ranges = new QTreeWidget;
|
|
ranges->headerItem()->setText(0, tr("From Date"));
|
|
ranges->headerItem()->setText(1, tr("Critical Power"));
|
|
ranges->headerItem()->setText(2, tr("W'"));
|
|
ranges->setColumnCount(3);
|
|
ranges->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
//ranges->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
ranges->setUniformRowHeights(true);
|
|
ranges->setIndentation(0);
|
|
//ranges->header()->resizeSection(0,180);
|
|
|
|
// setup list of ranges
|
|
for (int i=0; i< zonePage->zones.getRangeSize(); i++) {
|
|
|
|
QTreeWidgetItem *add = new QTreeWidgetItem(ranges->invisibleRootItem());
|
|
add->setFlags(add->flags() & ~Qt::ItemIsEditable);
|
|
|
|
// Embolden ranges with manually configured zones
|
|
QFont font;
|
|
font.setWeight(zonePage->zones.getZoneRange(i).zonesSetFromCP ?
|
|
QFont::Normal : QFont::Black);
|
|
|
|
// date
|
|
add->setText(0, zonePage->zones.getStartDate(i).toString("MMM d, yyyy"));
|
|
add->setFont(0, font);
|
|
|
|
// CP
|
|
add->setText(1, QString("%1").arg(zonePage->zones.getCP(i)));
|
|
add->setFont(1, font);
|
|
|
|
// W'
|
|
add->setText(2, QString("%1").arg(zonePage->zones.getWprime(i)));
|
|
add->setFont(2, font);
|
|
|
|
}
|
|
|
|
zones = new QTreeWidget;
|
|
zones->headerItem()->setText(0, tr("Short"));
|
|
zones->headerItem()->setText(1, tr("Long"));
|
|
zones->headerItem()->setText(2, tr("From Watts"));
|
|
zones->setColumnCount(3);
|
|
zones->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
zones->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
zones->setUniformRowHeights(true);
|
|
zones->setIndentation(0);
|
|
//zones->header()->resizeSection(0,80);
|
|
//zones->header()->resizeSection(1,150);
|
|
|
|
mainLayout->addLayout(addLayout, 0,0);
|
|
mainLayout->addLayout(actionButtons, 1,0);
|
|
mainLayout->addWidget(ranges, 2,0);
|
|
mainLayout->addLayout(zoneButtons, 3,0);
|
|
mainLayout->addWidget(zones, 4,0);
|
|
|
|
// button connect
|
|
connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked()));
|
|
connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
|
|
connect(defaultButton, SIGNAL(clicked()), this, SLOT(defaultClicked()));
|
|
connect(addZoneButton, SIGNAL(clicked()), this, SLOT(addZoneClicked()));
|
|
connect(deleteZoneButton, SIGNAL(clicked()), this, SLOT(deleteZoneClicked()));
|
|
connect(ranges, SIGNAL(itemSelectionChanged()), this, SLOT(rangeSelectionChanged()));
|
|
connect(zones, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(zonesChanged()));
|
|
}
|
|
|
|
void
|
|
CPPage::addClicked()
|
|
{
|
|
// get current scheme
|
|
zonePage->zones.setScheme(zonePage->schemePage->getScheme());
|
|
|
|
int cp = cpEdit->value();
|
|
if( cp <= 0 ){
|
|
QMessageBox err;
|
|
err.setText("CP must be > 0");
|
|
err.setIcon(QMessageBox::Warning);
|
|
err.exec();
|
|
return;
|
|
}
|
|
|
|
//int index = ranges->invisibleRootItem()->childCount();
|
|
int index = zonePage->zones.addZoneRange(dateEdit->date(), cpEdit->value(), wEdit->value());
|
|
|
|
// new item
|
|
QTreeWidgetItem *add = new QTreeWidgetItem;
|
|
add->setFlags(add->flags() & ~Qt::ItemIsEditable);
|
|
ranges->invisibleRootItem()->insertChild(index, add);
|
|
|
|
// date
|
|
add->setText(0, dateEdit->date().toString("MMM d, yyyy"));
|
|
|
|
// CP
|
|
add->setText(1, QString("%1").arg(cpEdit->value()));
|
|
|
|
// W'
|
|
add->setText(2, QString("%1").arg(wEdit->value()));
|
|
|
|
}
|
|
|
|
void
|
|
CPPage::deleteClicked()
|
|
{
|
|
if (ranges->currentItem()) {
|
|
int index = ranges->invisibleRootItem()->indexOfChild(ranges->currentItem());
|
|
delete ranges->invisibleRootItem()->takeChild(index);
|
|
zonePage->zones.deleteRange(index);
|
|
}
|
|
}
|
|
|
|
void
|
|
CPPage::defaultClicked()
|
|
{
|
|
if (ranges->currentItem()) {
|
|
|
|
int index = ranges->invisibleRootItem()->indexOfChild(ranges->currentItem());
|
|
ZoneRange current = zonePage->zones.getZoneRange(index);
|
|
|
|
// unbold
|
|
QFont font;
|
|
font.setWeight(QFont::Normal);
|
|
ranges->currentItem()->setFont(0, font);
|
|
ranges->currentItem()->setFont(1, font);
|
|
|
|
// set the range to use defaults on the scheme page
|
|
zonePage->zones.setScheme(zonePage->schemePage->getScheme());
|
|
zonePage->zones.setZonesFromCP(index);
|
|
|
|
// hide the default button since we are now using defaults
|
|
defaultButton->hide();
|
|
|
|
// update the zones display
|
|
rangeSelectionChanged();
|
|
}
|
|
}
|
|
|
|
void
|
|
CPPage::rangeSelectionChanged()
|
|
{
|
|
active = true;
|
|
|
|
// wipe away current contents of zones
|
|
foreach (QTreeWidgetItem *item, zones->invisibleRootItem()->takeChildren()) {
|
|
delete zones->itemWidget(item, 2);
|
|
delete item;
|
|
}
|
|
|
|
// fill with current details
|
|
if (ranges->currentItem()) {
|
|
|
|
int index = ranges->invisibleRootItem()->indexOfChild(ranges->currentItem());
|
|
ZoneRange current = zonePage->zones.getZoneRange(index);
|
|
|
|
if (current.zonesSetFromCP) {
|
|
|
|
// reapply the scheme in case it has been changed
|
|
zonePage->zones.setScheme(zonePage->schemePage->getScheme());
|
|
zonePage->zones.setZonesFromCP(index);
|
|
current = zonePage->zones.getZoneRange(index);
|
|
|
|
defaultButton->hide();
|
|
|
|
} else defaultButton->show();
|
|
|
|
for (int i=0; i< current.zones.count(); i++) {
|
|
|
|
QTreeWidgetItem *add = new QTreeWidgetItem(zones->invisibleRootItem());
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// tab name
|
|
add->setText(0, current.zones[i].name);
|
|
// field name
|
|
add->setText(1, current.zones[i].desc);
|
|
|
|
// low
|
|
QDoubleSpinBox *loedit = new QDoubleSpinBox(this);
|
|
loedit->setMinimum(0);
|
|
loedit->setMaximum(1000);
|
|
loedit->setSingleStep(1.0);
|
|
loedit->setDecimals(0);
|
|
loedit->setValue(current.zones[i].lo);
|
|
zones->setItemWidget(add, 2, loedit);
|
|
connect(loedit, SIGNAL(valueChanged(double)), this, SLOT(zonesChanged()));
|
|
}
|
|
}
|
|
|
|
active = false;
|
|
}
|
|
|
|
void
|
|
CPPage::addZoneClicked()
|
|
{
|
|
// no range selected
|
|
if (!ranges->currentItem()) return;
|
|
|
|
// are we at maximum already?
|
|
if (zones->invisibleRootItem()->childCount() == 10) {
|
|
QMessageBox err;
|
|
err.setText("Maximum of 10 zones reached.");
|
|
err.setIcon(QMessageBox::Warning);
|
|
err.exec();
|
|
return;
|
|
}
|
|
|
|
active = true;
|
|
int index = zones->invisibleRootItem()->childCount();
|
|
|
|
// new item
|
|
QTreeWidgetItem *add = new QTreeWidgetItem;
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
QDoubleSpinBox *loedit = new QDoubleSpinBox(this);
|
|
loedit->setMinimum(0);
|
|
loedit->setMaximum(1000);
|
|
loedit->setSingleStep(1.0);
|
|
loedit->setDecimals(0);
|
|
loedit->setValue(100);
|
|
|
|
zones->invisibleRootItem()->insertChild(index, add);
|
|
zones->setItemWidget(add, 2, loedit);
|
|
connect(loedit, SIGNAL(editingFinished()), this, SLOT(zonesChanged()));
|
|
|
|
// Short
|
|
QString text = "New";
|
|
for (int i=0; zones->findItems(text, Qt::MatchExactly, 0).count() > 0; i++) {
|
|
text = QString("New (%1)").arg(i+1);
|
|
}
|
|
add->setText(0, text);
|
|
|
|
// long
|
|
text = "New";
|
|
for (int i=0; zones->findItems(text, Qt::MatchExactly, 0).count() > 0; i++) {
|
|
text = QString("New (%1)").arg(i+1);
|
|
}
|
|
add->setText(1, text);
|
|
active = false;
|
|
|
|
zonesChanged();
|
|
}
|
|
|
|
void
|
|
CPPage::deleteZoneClicked()
|
|
{
|
|
// no range selected
|
|
if (ranges->invisibleRootItem()->indexOfChild(ranges->currentItem()) == -1)
|
|
return;
|
|
|
|
active = true;
|
|
if (zones->currentItem()) {
|
|
int index = zones->invisibleRootItem()->indexOfChild(zones->currentItem());
|
|
delete zones->invisibleRootItem()->takeChild(index);
|
|
}
|
|
active = false;
|
|
|
|
zonesChanged();
|
|
}
|
|
|
|
void
|
|
CPPage::zonesChanged()
|
|
{
|
|
// only take changes when they are not done programmatically
|
|
// the active flag is set when the tree is being modified
|
|
// programmatically, but not when users interact with the widgets
|
|
if (active == false) {
|
|
// get the current zone range
|
|
if (ranges->currentItem()) {
|
|
|
|
int index = ranges->invisibleRootItem()->indexOfChild(ranges->currentItem());
|
|
ZoneRange current = zonePage->zones.getZoneRange(index);
|
|
|
|
// embolden that range on the list to show it has been edited
|
|
QFont font;
|
|
font.setWeight(QFont::Black);
|
|
ranges->currentItem()->setFont(0, font);
|
|
ranges->currentItem()->setFont(1, font);
|
|
|
|
// show the default button to undo
|
|
defaultButton->show();
|
|
|
|
// we manually edited so save in full
|
|
current.zonesSetFromCP = false;
|
|
|
|
// create the new zoneinfos for this range
|
|
QList<ZoneInfo> zoneinfos;
|
|
for (int i=0; i< zones->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *item = zones->invisibleRootItem()->child(i);
|
|
zoneinfos << ZoneInfo(item->text(0),
|
|
item->text(1),
|
|
((QDoubleSpinBox*)zones->itemWidget(item, 2))->value(),
|
|
0);
|
|
}
|
|
|
|
// now sort the list
|
|
qSort(zoneinfos);
|
|
|
|
// now fill the highs
|
|
for(int i=0; i<zoneinfos.count(); i++) {
|
|
if (i+1 <zoneinfos.count())
|
|
zoneinfos[i].hi = zoneinfos[i+1].lo;
|
|
else
|
|
zoneinfos[i].hi = INT_MAX;
|
|
}
|
|
current.zones = zoneinfos;
|
|
|
|
// now replace the current range struct
|
|
zonePage->zones.setZoneRange(index, current);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Zone Config page
|
|
//
|
|
HrZonePage::HrZonePage(Context *context) : context(context)
|
|
{
|
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
|
|
// get current config by reading it in (leave mainwindow zones alone)
|
|
QFile zonesFile(context->athlete->home.absolutePath() + "/hr.zones");
|
|
if (zonesFile.exists()) {
|
|
zones.read(zonesFile);
|
|
zonesFile.close();
|
|
}
|
|
|
|
// setup maintenance pages using current config
|
|
schemePage = new HrSchemePage(this);
|
|
ltPage = new LTPage(this);
|
|
|
|
tabs = new QTabWidget(this);
|
|
tabs->addTab(ltPage, tr("Lactic Threshold"));
|
|
tabs->addTab(schemePage, tr("Default"));
|
|
|
|
layout->addWidget(tabs);
|
|
}
|
|
|
|
void
|
|
HrZonePage::saveClicked()
|
|
{
|
|
zones.setScheme(schemePage->getScheme());
|
|
zones.write(context->athlete->home);
|
|
}
|
|
|
|
HrSchemePage::HrSchemePage(HrZonePage* zonePage) : zonePage(zonePage)
|
|
{
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|
|
|
addButton = new QPushButton(tr("+"));
|
|
deleteButton = new QPushButton(tr("-"));
|
|
#ifndef Q_OS_MAC
|
|
addButton->setFixedSize(20,20);
|
|
deleteButton->setFixedSize(20,20);
|
|
#endif
|
|
QHBoxLayout *actionButtons = new QHBoxLayout;
|
|
actionButtons->setSpacing(2);
|
|
actionButtons->addStretch();
|
|
actionButtons->addWidget(addButton);
|
|
actionButtons->addWidget(deleteButton);
|
|
|
|
scheme = new QTreeWidget;
|
|
scheme->headerItem()->setText(0, tr("Short"));
|
|
scheme->headerItem()->setText(1, tr("Long"));
|
|
scheme->headerItem()->setText(2, tr("Percent of LT"));
|
|
scheme->headerItem()->setText(3, tr("Trimp k"));
|
|
scheme->setColumnCount(4);
|
|
scheme->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
scheme->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
scheme->setUniformRowHeights(true);
|
|
scheme->setIndentation(0);
|
|
//scheme->header()->resizeSection(0,60);
|
|
//scheme->header()->resizeSection(1,180);
|
|
//scheme->header()->resizeSection(2,65);
|
|
//scheme->header()->resizeSection(3,65);
|
|
|
|
// setup list
|
|
for (int i=0; i< zonePage->zones.getScheme().nzones_default; i++) {
|
|
|
|
QTreeWidgetItem *add = new QTreeWidgetItem(scheme->invisibleRootItem());
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// tab name
|
|
add->setText(0, zonePage->zones.getScheme().zone_default_name[i]);
|
|
// field name
|
|
add->setText(1, zonePage->zones.getScheme().zone_default_desc[i]);
|
|
|
|
// low
|
|
QDoubleSpinBox *loedit = new QDoubleSpinBox(this);
|
|
loedit->setMinimum(0);
|
|
loedit->setMaximum(1000);
|
|
loedit->setSingleStep(1.0);
|
|
loedit->setDecimals(0);
|
|
loedit->setValue(zonePage->zones.getScheme().zone_default[i]);
|
|
scheme->setItemWidget(add, 2, loedit);
|
|
|
|
// trimp
|
|
QDoubleSpinBox *trimpedit = new QDoubleSpinBox(this);
|
|
trimpedit->setMinimum(0);
|
|
trimpedit->setMaximum(10);
|
|
trimpedit->setSingleStep(0.1);
|
|
trimpedit->setDecimals(2);
|
|
trimpedit->setValue(zonePage->zones.getScheme().zone_default_trimp[i]);
|
|
scheme->setItemWidget(add, 3, trimpedit);
|
|
}
|
|
|
|
mainLayout->addWidget(scheme);
|
|
mainLayout->addLayout(actionButtons);
|
|
|
|
// button connect
|
|
connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked()));
|
|
connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
|
|
}
|
|
|
|
void
|
|
HrSchemePage::addClicked()
|
|
{
|
|
// are we at maximum already?
|
|
if (scheme->invisibleRootItem()->childCount() == 10) {
|
|
QMessageBox err;
|
|
err.setText("Maximum of 10 zones reached.");
|
|
err.setIcon(QMessageBox::Warning);
|
|
err.exec();
|
|
return;
|
|
}
|
|
|
|
int index = scheme->invisibleRootItem()->childCount();
|
|
|
|
// new item
|
|
QTreeWidgetItem *add = new QTreeWidgetItem;
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
QDoubleSpinBox *loedit = new QDoubleSpinBox(this);
|
|
loedit->setMinimum(0);
|
|
loedit->setMaximum(1000);
|
|
loedit->setSingleStep(1.0);
|
|
loedit->setDecimals(0);
|
|
loedit->setValue(100);
|
|
|
|
scheme->invisibleRootItem()->insertChild(index, add);
|
|
scheme->setItemWidget(add, 2, loedit);
|
|
|
|
//trimp
|
|
QDoubleSpinBox *trimpedit = new QDoubleSpinBox(this);
|
|
trimpedit->setMinimum(0);
|
|
trimpedit->setMaximum(10);
|
|
trimpedit->setSingleStep(0.1);
|
|
trimpedit->setDecimals(2);
|
|
trimpedit->setValue(1);
|
|
|
|
scheme->setItemWidget(add, 3, trimpedit);
|
|
|
|
// Short
|
|
QString text = "New";
|
|
for (int i=0; scheme->findItems(text, Qt::MatchExactly, 0).count() > 0; i++) {
|
|
text = QString("New (%1)").arg(i+1);
|
|
}
|
|
add->setText(0, text);
|
|
|
|
// long
|
|
text = "New";
|
|
for (int i=0; scheme->findItems(text, Qt::MatchExactly, 0).count() > 0; i++) {
|
|
text = QString("New (%1)").arg(i+1);
|
|
}
|
|
add->setText(1, text);
|
|
}
|
|
|
|
void
|
|
HrSchemePage::renameClicked()
|
|
{
|
|
// which one is selected?
|
|
if (scheme->currentItem()) scheme->editItem(scheme->currentItem(), 0);
|
|
}
|
|
|
|
void
|
|
HrSchemePage::deleteClicked()
|
|
{
|
|
if (scheme->currentItem()) {
|
|
int index = scheme->invisibleRootItem()->indexOfChild(scheme->currentItem());
|
|
delete scheme->invisibleRootItem()->takeChild(index);
|
|
}
|
|
}
|
|
|
|
HrZoneScheme
|
|
HrSchemePage::getScheme()
|
|
{
|
|
// read the scheme widget and return a scheme object
|
|
QList<schemeitem> table;
|
|
HrZoneScheme results;
|
|
|
|
// read back the details from the table
|
|
for (int i=0; i<scheme->invisibleRootItem()->childCount(); i++) {
|
|
|
|
schemeitem add;
|
|
add.name = scheme->invisibleRootItem()->child(i)->text(0);
|
|
add.desc = scheme->invisibleRootItem()->child(i)->text(1);
|
|
add.lo = ((QDoubleSpinBox *)(scheme->itemWidget(scheme->invisibleRootItem()->child(i), 2)))->value();
|
|
add.trimp = ((QDoubleSpinBox *)(scheme->itemWidget(scheme->invisibleRootItem()->child(i), 3)))->value();
|
|
table.append(add);
|
|
}
|
|
|
|
// sort the list into ascending order
|
|
qSort(table);
|
|
|
|
// now update the results
|
|
results.nzones_default = 0;
|
|
foreach(schemeitem zone, table) {
|
|
results.nzones_default++;
|
|
results.zone_default.append(zone.lo);
|
|
results.zone_default_is_pct.append(true);
|
|
results.zone_default_name.append(zone.name);
|
|
results.zone_default_desc.append(zone.desc);
|
|
results.zone_default_trimp.append(zone.trimp);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
|
|
LTPage::LTPage(HrZonePage* zonePage) : zonePage(zonePage)
|
|
{
|
|
active = false;
|
|
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|
|
|
addButton = new QPushButton(tr("+"));
|
|
deleteButton = new QPushButton(tr("-"));
|
|
#ifndef Q_OS_MAC
|
|
addButton->setFixedSize(20,20);
|
|
deleteButton->setFixedSize(20,20);
|
|
#endif
|
|
defaultButton = new QPushButton(tr("Def"));
|
|
defaultButton->hide();
|
|
|
|
addZoneButton = new QPushButton(tr("+"));
|
|
deleteZoneButton = new QPushButton(tr("-"));
|
|
#ifndef Q_OS_MAC
|
|
addZoneButton->setFixedSize(20,20);
|
|
deleteZoneButton->setFixedSize(20,20);
|
|
#endif
|
|
|
|
QHBoxLayout *actionButtons = new QHBoxLayout;
|
|
actionButtons->setSpacing(2);
|
|
actionButtons->addStretch();
|
|
actionButtons->addWidget(addButton);
|
|
actionButtons->addWidget(deleteButton);
|
|
actionButtons->addWidget(defaultButton);
|
|
|
|
QHBoxLayout *zoneButtons = new QHBoxLayout;
|
|
zoneButtons->addStretch();
|
|
zoneButtons->addWidget(addZoneButton);
|
|
zoneButtons->addWidget(deleteZoneButton);
|
|
|
|
QHBoxLayout *addLayout = new QHBoxLayout;
|
|
QLabel *dateLabel = new QLabel(tr("From Date"));
|
|
QLabel *ltLabel = new QLabel(tr("Lactic Threshold"));
|
|
dateEdit = new QDateEdit;
|
|
dateEdit->setDate(QDate::currentDate());
|
|
|
|
ltEdit = new QDoubleSpinBox;
|
|
ltEdit->setMinimum(0);
|
|
ltEdit->setMaximum(240);
|
|
ltEdit->setSingleStep(1.0);
|
|
ltEdit->setDecimals(0);
|
|
|
|
addLayout->addWidget(dateLabel);
|
|
addLayout->addWidget(dateEdit);
|
|
addLayout->addWidget(ltLabel);
|
|
addLayout->addWidget(ltEdit);
|
|
addLayout->addStretch();
|
|
|
|
QHBoxLayout *addLayout2 = new QHBoxLayout;
|
|
QLabel *restHrLabel = new QLabel(tr("Rest HR"));
|
|
QLabel *maxHrLabel = new QLabel(tr("Max HR"));
|
|
|
|
restHrEdit = new QDoubleSpinBox;
|
|
restHrEdit->setMinimum(0);
|
|
restHrEdit->setMaximum(240);
|
|
restHrEdit->setSingleStep(1.0);
|
|
restHrEdit->setDecimals(0);
|
|
|
|
maxHrEdit = new QDoubleSpinBox;
|
|
maxHrEdit->setMinimum(0);
|
|
maxHrEdit->setMaximum(240);
|
|
maxHrEdit->setSingleStep(1.0);
|
|
maxHrEdit->setDecimals(0);
|
|
|
|
addLayout2->addWidget(restHrLabel);
|
|
addLayout2->addWidget(restHrEdit);
|
|
addLayout2->addWidget(maxHrLabel);
|
|
addLayout2->addWidget(maxHrEdit);
|
|
addLayout2->addStretch();
|
|
|
|
ranges = new QTreeWidget;
|
|
ranges->headerItem()->setText(0, tr("From Date"));
|
|
ranges->headerItem()->setText(1, tr("Lactic Threshold"));
|
|
ranges->headerItem()->setText(2, tr("Rest HR"));
|
|
ranges->headerItem()->setText(3, tr("Max HR"));
|
|
ranges->setColumnCount(4);
|
|
ranges->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
//ranges->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
ranges->setUniformRowHeights(true);
|
|
ranges->setIndentation(0);
|
|
//ranges->header()->resizeSection(0,180);
|
|
|
|
// setup list of ranges
|
|
for (int i=0; i< zonePage->zones.getRangeSize(); i++) {
|
|
|
|
QTreeWidgetItem *add = new QTreeWidgetItem(ranges->invisibleRootItem());
|
|
add->setFlags(add->flags() & ~Qt::ItemIsEditable);
|
|
|
|
// Embolden ranges with manually configured zones
|
|
QFont font;
|
|
font.setWeight(zonePage->zones.getHrZoneRange(i).hrZonesSetFromLT ?
|
|
QFont::Normal : QFont::Black);
|
|
|
|
// date
|
|
add->setText(0, zonePage->zones.getStartDate(i).toString("MMM d, yyyy"));
|
|
add->setFont(0, font);
|
|
|
|
// LT
|
|
add->setText(1, QString("%1").arg(zonePage->zones.getLT(i)));
|
|
add->setFont(1, font);
|
|
|
|
// Rest HR
|
|
add->setText(2, QString("%1").arg(zonePage->zones.getRestHr(i)));
|
|
add->setFont(2, font);
|
|
|
|
// Max HR
|
|
add->setText(3, QString("%1").arg(zonePage->zones.getMaxHr(i)));
|
|
add->setFont(3, font);
|
|
}
|
|
|
|
zones = new QTreeWidget;
|
|
zones->headerItem()->setText(0, tr("Short"));
|
|
zones->headerItem()->setText(1, tr("Long"));
|
|
zones->headerItem()->setText(2, tr("From BPM"));
|
|
zones->headerItem()->setText(3, tr("Trimp k"));
|
|
zones->setColumnCount(4);
|
|
zones->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
zones->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
zones->setUniformRowHeights(true);
|
|
zones->setIndentation(0);
|
|
//zones->header()->resizeSection(0,50);
|
|
//zones->header()->resizeSection(1,150);
|
|
//zones->header()->resizeSection(2,65);
|
|
//zones->header()->resizeSection(3,65);
|
|
|
|
mainLayout->addLayout(addLayout);
|
|
mainLayout->addLayout(addLayout2);
|
|
mainLayout->addLayout(actionButtons);
|
|
mainLayout->addWidget(ranges);
|
|
mainLayout->addLayout(zoneButtons);
|
|
mainLayout->addWidget(zones);
|
|
|
|
// button connect
|
|
connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked()));
|
|
connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
|
|
connect(defaultButton, SIGNAL(clicked()), this, SLOT(defaultClicked()));
|
|
connect(addZoneButton, SIGNAL(clicked()), this, SLOT(addZoneClicked()));
|
|
connect(deleteZoneButton, SIGNAL(clicked()), this, SLOT(deleteZoneClicked()));
|
|
connect(ranges, SIGNAL(itemSelectionChanged()), this, SLOT(rangeSelectionChanged()));
|
|
connect(zones, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(zonesChanged()));
|
|
}
|
|
|
|
void
|
|
LTPage::addClicked()
|
|
{
|
|
// get current scheme
|
|
zonePage->zones.setScheme(zonePage->schemePage->getScheme());
|
|
|
|
//int index = ranges->invisibleRootItem()->childCount();
|
|
int index = zonePage->zones.addHrZoneRange(dateEdit->date(), ltEdit->value(), restHrEdit->value(), maxHrEdit->value());
|
|
|
|
// new item
|
|
QTreeWidgetItem *add = new QTreeWidgetItem;
|
|
add->setFlags(add->flags() & ~Qt::ItemIsEditable);
|
|
ranges->invisibleRootItem()->insertChild(index, add);
|
|
|
|
// date
|
|
add->setText(0, dateEdit->date().toString("MMM d, yyyy"));
|
|
|
|
// LT
|
|
add->setText(1, QString("%1").arg(ltEdit->value()));
|
|
// Rest HR
|
|
add->setText(2, QString("%1").arg(restHrEdit->value()));
|
|
// Max HR
|
|
add->setText(3, QString("%1").arg(maxHrEdit->value()));
|
|
}
|
|
|
|
void
|
|
LTPage::deleteClicked()
|
|
{
|
|
if (ranges->currentItem()) {
|
|
int index = ranges->invisibleRootItem()->indexOfChild(ranges->currentItem());
|
|
delete ranges->invisibleRootItem()->takeChild(index);
|
|
zonePage->zones.deleteRange(index);
|
|
}
|
|
}
|
|
|
|
void
|
|
LTPage::defaultClicked()
|
|
{
|
|
if (ranges->currentItem()) {
|
|
|
|
int index = ranges->invisibleRootItem()->indexOfChild(ranges->currentItem());
|
|
HrZoneRange current = zonePage->zones.getHrZoneRange(index);
|
|
|
|
// unbold
|
|
QFont font;
|
|
font.setWeight(QFont::Normal);
|
|
ranges->currentItem()->setFont(0, font);
|
|
ranges->currentItem()->setFont(1, font);
|
|
|
|
// set the range to use defaults on the scheme page
|
|
zonePage->zones.setScheme(zonePage->schemePage->getScheme());
|
|
zonePage->zones.setHrZonesFromLT(index);
|
|
|
|
// hide the default button since we are now using defaults
|
|
defaultButton->hide();
|
|
|
|
// update the zones display
|
|
rangeSelectionChanged();
|
|
}
|
|
}
|
|
|
|
void
|
|
LTPage::rangeSelectionChanged()
|
|
{
|
|
active = true;
|
|
|
|
// wipe away current contents of zones
|
|
foreach (QTreeWidgetItem *item, zones->invisibleRootItem()->takeChildren()) {
|
|
delete zones->itemWidget(item, 2);
|
|
delete item;
|
|
}
|
|
|
|
// fill with current details
|
|
if (ranges->currentItem()) {
|
|
|
|
int index = ranges->invisibleRootItem()->indexOfChild(ranges->currentItem());
|
|
HrZoneRange current = zonePage->zones.getHrZoneRange(index);
|
|
|
|
if (current.hrZonesSetFromLT) {
|
|
|
|
// reapply the scheme in case it has been changed
|
|
zonePage->zones.setScheme(zonePage->schemePage->getScheme());
|
|
zonePage->zones.setHrZonesFromLT(index);
|
|
current = zonePage->zones.getHrZoneRange(index);
|
|
|
|
defaultButton->hide();
|
|
|
|
} else defaultButton->show();
|
|
|
|
for (int i=0; i< current.zones.count(); i++) {
|
|
|
|
QTreeWidgetItem *add = new QTreeWidgetItem(zones->invisibleRootItem());
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// tab name
|
|
add->setText(0, current.zones[i].name);
|
|
// field name
|
|
add->setText(1, current.zones[i].desc);
|
|
|
|
// low
|
|
QDoubleSpinBox *loedit = new QDoubleSpinBox(this);
|
|
loedit->setMinimum(0);
|
|
loedit->setMaximum(1000);
|
|
loedit->setSingleStep(1.0);
|
|
loedit->setDecimals(0);
|
|
loedit->setValue(current.zones[i].lo);
|
|
zones->setItemWidget(add, 2, loedit);
|
|
connect(loedit, SIGNAL(editingFinished()), this, SLOT(zonesChanged()));
|
|
|
|
//trimp
|
|
QDoubleSpinBox *trimpedit = new QDoubleSpinBox(this);
|
|
trimpedit->setMinimum(0);
|
|
trimpedit->setMaximum(10);
|
|
trimpedit->setSingleStep(0.1);
|
|
trimpedit->setDecimals(2);
|
|
trimpedit->setValue(current.zones[i].trimp);
|
|
zones->setItemWidget(add, 3, trimpedit);
|
|
connect(trimpedit, SIGNAL(editingFinished()), this, SLOT(zonesChanged()));
|
|
|
|
}
|
|
}
|
|
|
|
active = false;
|
|
}
|
|
|
|
void
|
|
LTPage::addZoneClicked()
|
|
{
|
|
// no range selected
|
|
if (!ranges->currentItem()) return;
|
|
|
|
// are we at maximum already?
|
|
if (zones->invisibleRootItem()->childCount() == 10) {
|
|
QMessageBox err;
|
|
err.setText("Maximum of 10 zones reached.");
|
|
err.setIcon(QMessageBox::Warning);
|
|
err.exec();
|
|
return;
|
|
}
|
|
|
|
active = true;
|
|
int index = zones->invisibleRootItem()->childCount();
|
|
|
|
// new item
|
|
QTreeWidgetItem *add = new QTreeWidgetItem;
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
QDoubleSpinBox *loedit = new QDoubleSpinBox(this);
|
|
loedit->setMinimum(0);
|
|
loedit->setMaximum(1000);
|
|
loedit->setSingleStep(1.0);
|
|
loedit->setDecimals(0);
|
|
loedit->setValue(100);
|
|
|
|
zones->invisibleRootItem()->insertChild(index, add);
|
|
zones->setItemWidget(add, 2, loedit);
|
|
connect(loedit, SIGNAL(editingFinished()), this, SLOT(zonesChanged()));
|
|
|
|
//trimp
|
|
QDoubleSpinBox *trimpedit = new QDoubleSpinBox(this);
|
|
trimpedit->setMinimum(0);
|
|
trimpedit->setMaximum(10);
|
|
trimpedit->setSingleStep(0.1);
|
|
trimpedit->setDecimals(2);
|
|
trimpedit->setValue(1);
|
|
zones->setItemWidget(add, 3, trimpedit);
|
|
connect(trimpedit, SIGNAL(editingFinished()), this, SLOT(zonesChanged()));
|
|
|
|
// Short
|
|
QString text = "New";
|
|
for (int i=0; zones->findItems(text, Qt::MatchExactly, 0).count() > 0; i++) {
|
|
text = QString("New (%1)").arg(i+1);
|
|
}
|
|
add->setText(0, text);
|
|
|
|
// long
|
|
text = "New";
|
|
for (int i=0; zones->findItems(text, Qt::MatchExactly, 0).count() > 0; i++) {
|
|
text = QString("New (%1)").arg(i+1);
|
|
}
|
|
add->setText(1, text);
|
|
active = false;
|
|
|
|
zonesChanged();
|
|
}
|
|
|
|
void
|
|
LTPage::deleteZoneClicked()
|
|
{
|
|
// no range selected
|
|
if (ranges->invisibleRootItem()->indexOfChild(ranges->currentItem()) == -1)
|
|
return;
|
|
|
|
active = true;
|
|
if (zones->currentItem()) {
|
|
int index = zones->invisibleRootItem()->indexOfChild(zones->currentItem());
|
|
delete zones->invisibleRootItem()->takeChild(index);
|
|
}
|
|
active = false;
|
|
|
|
zonesChanged();
|
|
}
|
|
|
|
void
|
|
LTPage::zonesChanged()
|
|
{
|
|
// only take changes when they are not done programmatically
|
|
// the active flag is set when the tree is being modified
|
|
// programmatically, but not when users interact with the widgets
|
|
if (active == false) {
|
|
// get the current zone range
|
|
if (ranges->currentItem()) {
|
|
|
|
int index = ranges->invisibleRootItem()->indexOfChild(ranges->currentItem());
|
|
HrZoneRange current = zonePage->zones.getHrZoneRange(index);
|
|
|
|
// embolden that range on the list to show it has been edited
|
|
QFont font;
|
|
font.setWeight(QFont::Black);
|
|
ranges->currentItem()->setFont(0, font);
|
|
ranges->currentItem()->setFont(1, font);
|
|
|
|
// show the default button to undo
|
|
defaultButton->show();
|
|
|
|
// we manually edited so save in full
|
|
current.hrZonesSetFromLT = false;
|
|
|
|
// create the new zoneinfos for this range
|
|
QList<HrZoneInfo> zoneinfos;
|
|
for (int i=0; i< zones->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *item = zones->invisibleRootItem()->child(i);
|
|
zoneinfos << HrZoneInfo(item->text(0),
|
|
item->text(1),
|
|
((QDoubleSpinBox*)zones->itemWidget(item, 2))->value(),
|
|
0, ((QDoubleSpinBox*)zones->itemWidget(item, 3))->value());
|
|
}
|
|
|
|
// now sort the list
|
|
qSort(zoneinfos);
|
|
|
|
// now fill the highs
|
|
for(int i=0; i<zoneinfos.count(); i++) {
|
|
if (i+1 <zoneinfos.count())
|
|
zoneinfos[i].hi = zoneinfos[i+1].lo;
|
|
else
|
|
zoneinfos[i].hi = INT_MAX;
|
|
}
|
|
current.zones = zoneinfos;
|
|
|
|
// now replace the current range struct
|
|
zonePage->zones.setHrZoneRange(index, current);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ride metadata page
|
|
//
|
|
MeasuresPage::MeasuresPage(Context *context) : context(context)
|
|
{
|
|
QGridLayout *mainLayout = new QGridLayout(this);
|
|
|
|
addButton = new QPushButton(tr("+"));
|
|
deleteButton = new QPushButton(tr("-"));
|
|
#ifndef Q_OS_MAC
|
|
upButton = new QToolButton(this);
|
|
downButton = new QToolButton(this);
|
|
upButton->setArrowType(Qt::UpArrow);
|
|
downButton->setArrowType(Qt::DownArrow);
|
|
upButton->setFixedSize(20,20);
|
|
downButton->setFixedSize(20,20);
|
|
addButton->setFixedSize(20,20);
|
|
deleteButton->setFixedSize(20,20);
|
|
#else
|
|
upButton = new QPushButton(tr("Up"));
|
|
downButton = new QPushButton(tr("Down"));
|
|
#endif
|
|
|
|
QHBoxLayout *actionButtons = new QHBoxLayout;
|
|
actionButtons->setSpacing(2);
|
|
actionButtons->addWidget(upButton);
|
|
actionButtons->addWidget(downButton);
|
|
actionButtons->addStretch();
|
|
actionButtons->addWidget(addButton);
|
|
actionButtons->addWidget(deleteButton);
|
|
|
|
fields = new QTreeWidget;
|
|
fields->headerItem()->setText(0, tr("Screen Tab"));
|
|
fields->headerItem()->setText(1, tr("Measure"));
|
|
fields->headerItem()->setText(2, tr("Type"));
|
|
fields->setColumnCount(3);
|
|
fields->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
fields->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
fields->setUniformRowHeights(true);
|
|
fields->setIndentation(0);
|
|
//fields->header()->resizeSection(0,130);
|
|
//fields->header()->resizeSection(1,140);
|
|
|
|
// temporary storage for measures config
|
|
QList<FieldDefinition> fieldDefinitions;
|
|
QList<KeywordDefinition> keywordDefinitions; //NOTE: not used in measures.xml
|
|
|
|
// check we have one and use built in if not there
|
|
QString filename = context->athlete->home.absolutePath()+"/measures.xml";
|
|
QString colorfield;
|
|
|
|
if (!QFile(filename).exists()) filename = ":/xml/measures.xml";
|
|
RideMetadata::readXML(filename, keywordDefinitions, fieldDefinitions, colorfield);
|
|
|
|
// iterate over the fields and setup the editable items
|
|
foreach(FieldDefinition field, fieldDefinitions) {
|
|
QTreeWidgetItem *add;
|
|
QComboBox *comboButton = new QComboBox(this);
|
|
|
|
FieldsPage::addFieldTypes(comboButton);
|
|
comboButton->setCurrentIndex(field.type);
|
|
|
|
add = new QTreeWidgetItem(fields->invisibleRootItem());
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// tab name
|
|
add->setText(0, field.tab);
|
|
// field name
|
|
add->setText(1, field.name);
|
|
|
|
// type button
|
|
add->setTextAlignment(2, Qt::AlignHCenter);
|
|
fields->setItemWidget(add, 2, comboButton);
|
|
}
|
|
fields->setCurrentItem(fields->invisibleRootItem()->child(0));
|
|
|
|
mainLayout->addWidget(fields, 0,0);
|
|
mainLayout->addLayout(actionButtons, 1,0);
|
|
|
|
// connect up slots
|
|
connect(upButton, SIGNAL(clicked()), this, SLOT(upClicked()));
|
|
connect(downButton, SIGNAL(clicked()), this, SLOT(downClicked()));
|
|
connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked()));
|
|
connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
|
|
}
|
|
|
|
void
|
|
MeasuresPage::upClicked()
|
|
{
|
|
if (fields->currentItem()) {
|
|
int index = fields->invisibleRootItem()->indexOfChild(fields->currentItem());
|
|
if (index == 0) return; // its at the top already
|
|
|
|
// movin on up!
|
|
QWidget *button = fields->itemWidget(fields->currentItem(),2);
|
|
QComboBox *comboButton = new QComboBox(this);
|
|
FieldsPage::addFieldTypes(comboButton);
|
|
comboButton->setCurrentIndex(((QComboBox*)button)->currentIndex());
|
|
QTreeWidgetItem* moved = fields->invisibleRootItem()->takeChild(index);
|
|
fields->invisibleRootItem()->insertChild(index-1, moved);
|
|
fields->setItemWidget(moved, 2, comboButton);
|
|
fields->setCurrentItem(moved);
|
|
}
|
|
}
|
|
|
|
void
|
|
MeasuresPage::downClicked()
|
|
{
|
|
if (fields->currentItem()) {
|
|
int index = fields->invisibleRootItem()->indexOfChild(fields->currentItem());
|
|
if (index == (fields->invisibleRootItem()->childCount()-1)) return; // its at the bottom already
|
|
|
|
QWidget *button = fields->itemWidget(fields->currentItem(),2);
|
|
QComboBox *comboButton = new QComboBox(this);
|
|
FieldsPage::addFieldTypes(comboButton);
|
|
comboButton->setCurrentIndex(((QComboBox*)button)->currentIndex());
|
|
QTreeWidgetItem* moved = fields->invisibleRootItem()->takeChild(index);
|
|
fields->invisibleRootItem()->insertChild(index+1, moved);
|
|
fields->setItemWidget(moved, 2, comboButton);
|
|
fields->setCurrentItem(moved);
|
|
}
|
|
}
|
|
|
|
void
|
|
MeasuresPage::renameClicked()
|
|
{
|
|
// which one is selected?
|
|
if (fields->currentItem()) fields->editItem(fields->currentItem(), 0);
|
|
}
|
|
|
|
void
|
|
MeasuresPage::addClicked()
|
|
{
|
|
int index = fields->invisibleRootItem()->indexOfChild(fields->currentItem());
|
|
if (index < 0) index = 0;
|
|
QTreeWidgetItem *add;
|
|
QComboBox *comboButton = new QComboBox(this);
|
|
FieldsPage::addFieldTypes(comboButton);
|
|
|
|
add = new QTreeWidgetItem;
|
|
fields->invisibleRootItem()->insertChild(index, add);
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// field
|
|
QString text = "New";
|
|
for (int i=0; fields->findItems(text, Qt::MatchExactly, 1).count() > 0; i++) {
|
|
text = QString("New (%1)").arg(i+1);
|
|
}
|
|
add->setText(1, text);
|
|
|
|
// type button
|
|
add->setTextAlignment(2, Qt::AlignHCenter);
|
|
fields->setItemWidget(add, 2, comboButton);
|
|
}
|
|
|
|
void
|
|
MeasuresPage::deleteClicked()
|
|
{
|
|
if (fields->currentItem()) {
|
|
int index = fields->invisibleRootItem()->indexOfChild(fields->currentItem());
|
|
|
|
// zap!
|
|
delete fields->invisibleRootItem()->takeChild(index);
|
|
}
|
|
}
|
|
|
|
void
|
|
MeasuresPage::getDefinitions(QList<FieldDefinition> &fieldList)
|
|
{
|
|
QStringList checkdups;
|
|
|
|
// clear current just in case
|
|
fieldList.clear();
|
|
|
|
for (int idx =0; idx < fields->invisibleRootItem()->childCount(); idx++) {
|
|
|
|
FieldDefinition add;
|
|
QTreeWidgetItem *item = fields->invisibleRootItem()->child(idx);
|
|
|
|
// silently ignore duplicates
|
|
if (checkdups.contains(item->text(1))) continue;
|
|
else checkdups << item->text(1);
|
|
|
|
add.tab = item->text(0);
|
|
add.name = item->text(1);
|
|
add.type = ((QComboBox*)fields->itemWidget(item, 2))->currentIndex();
|
|
|
|
fieldList.append(add);
|
|
}
|
|
}
|
|
|
|
void
|
|
MeasuresPage::saveClicked()
|
|
{
|
|
QList<FieldDefinition> current;
|
|
getDefinitions(current);
|
|
|
|
// write to measures.xml (uses same format as metadata.xml)
|
|
RideMetadata::serialize(context->athlete->home.absolutePath() + "/measures.xml", QList<KeywordDefinition>(), current, "");
|
|
}
|
|
|
|
//
|
|
// Season Editor
|
|
//
|
|
SeasonsPage::SeasonsPage(QWidget *parent, Context *context) : QWidget(parent), context(context)
|
|
{
|
|
QGridLayout *mainLayout = new QGridLayout(this);
|
|
QFormLayout *editLayout = new QFormLayout;
|
|
editLayout->setFieldGrowthPolicy(QFormLayout::FieldsStayAtSizeHint);
|
|
|
|
// get the list
|
|
array = context->athlete->seasons->seasons;
|
|
|
|
// Edit widgets
|
|
nameEdit = new QLineEdit(this);
|
|
typeEdit = new QComboBox(this);
|
|
foreach(QString t, Season::types) typeEdit->addItem(t);
|
|
typeEdit->setCurrentIndex(0);
|
|
fromEdit = new QDateEdit(this);
|
|
fromEdit->setCalendarPopup(true);
|
|
|
|
toEdit = new QDateEdit(this);
|
|
toEdit->setCalendarPopup(true);
|
|
|
|
// set form
|
|
editLayout->addRow(new QLabel("Name"), nameEdit);
|
|
editLayout->addRow(new QLabel("Type"), typeEdit);
|
|
editLayout->addRow(new QLabel("From"), fromEdit);
|
|
editLayout->addRow(new QLabel("To"), toEdit);
|
|
|
|
addButton = new QPushButton(tr("+"));
|
|
deleteButton = new QPushButton(tr("-"));
|
|
#ifndef Q_OS_MAC
|
|
upButton = new QToolButton(this);
|
|
downButton = new QToolButton(this);
|
|
upButton->setArrowType(Qt::UpArrow);
|
|
downButton->setArrowType(Qt::DownArrow);
|
|
upButton->setFixedSize(20,20);
|
|
downButton->setFixedSize(20,20);
|
|
addButton->setFixedSize(20,20);
|
|
deleteButton->setFixedSize(20,20);
|
|
#else
|
|
upButton = new QPushButton(tr("Up"));
|
|
downButton = new QPushButton(tr("Down"));
|
|
#endif
|
|
|
|
QVBoxLayout *actionButtons = new QVBoxLayout;
|
|
actionButtons->setSpacing(2);
|
|
actionButtons->addWidget(deleteButton);
|
|
actionButtons->addWidget(upButton);
|
|
actionButtons->addWidget(downButton);
|
|
actionButtons->addStretch();
|
|
|
|
seasons = new QTreeWidget;
|
|
seasons->headerItem()->setText(0, tr("Name"));
|
|
seasons->headerItem()->setText(1, tr("Type"));
|
|
seasons->headerItem()->setText(2, tr("From"));
|
|
seasons->headerItem()->setText(3, tr("To"));
|
|
seasons->setColumnCount(4);
|
|
seasons->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
//seasons->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
seasons->setUniformRowHeights(true);
|
|
seasons->setIndentation(0);
|
|
|
|
#ifdef Q_OS_MAC
|
|
//seasons->header()->resizeSection(0,160); // tab
|
|
//seasons->header()->resizeSection(1,80); // name
|
|
//seasons->header()->resizeSection(2,130); // type
|
|
//seasons->header()->resizeSection(3,130); // values
|
|
#else
|
|
//seasons->header()->resizeSection(0,160); // tab
|
|
//seasons->header()->resizeSection(1,80); // name
|
|
//seasons->header()->resizeSection(2,130); // type
|
|
//seasons->header()->resizeSection(3,130); // values
|
|
#endif
|
|
|
|
foreach(Season season, array) {
|
|
QTreeWidgetItem *add;
|
|
|
|
if (season.type == Season::temporary) continue;
|
|
|
|
add = new QTreeWidgetItem(seasons->invisibleRootItem());
|
|
add->setFlags(add->flags() & ~Qt::ItemIsEditable);
|
|
|
|
// tab name
|
|
add->setText(0, season.name);
|
|
// type
|
|
add->setText(1, Season::types[static_cast<int>(season.type)]);
|
|
// from
|
|
add->setText(2, season.start.toString("ddd MMM d, yyyy"));
|
|
// to
|
|
add->setText(3, season.end.toString("ddd MMM d, yyyy"));
|
|
// guid -- hidden
|
|
add->setText(4, season._id.toString());
|
|
|
|
}
|
|
seasons->setCurrentItem(seasons->invisibleRootItem()->child(0));
|
|
|
|
mainLayout->addLayout(editLayout, 0,0);
|
|
mainLayout->addWidget(addButton, 0,1, Qt::AlignTop);
|
|
mainLayout->addWidget(seasons, 1,0);
|
|
mainLayout->addLayout(actionButtons, 1,1);
|
|
|
|
// set all the edits to a default value
|
|
clearEdit();
|
|
|
|
// connect up slots
|
|
connect(upButton, SIGNAL(clicked()), this, SLOT(upClicked()));
|
|
connect(downButton, SIGNAL(clicked()), this, SLOT(downClicked()));
|
|
connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked()));
|
|
connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
|
|
}
|
|
|
|
void
|
|
SeasonsPage::clearEdit()
|
|
{
|
|
typeEdit->setCurrentIndex(0);
|
|
nameEdit->setText("");
|
|
fromEdit->setDate(QDate::currentDate());
|
|
toEdit->setDate(QDate::currentDate().addMonths(3));
|
|
}
|
|
|
|
void
|
|
SeasonsPage::upClicked()
|
|
{
|
|
if (seasons->currentItem()) {
|
|
int index = seasons->invisibleRootItem()->indexOfChild(seasons->currentItem());
|
|
if (index == 0) return; // its at the top already
|
|
|
|
// movin on up!
|
|
QTreeWidgetItem* moved = seasons->invisibleRootItem()->takeChild(index);
|
|
seasons->invisibleRootItem()->insertChild(index-1, moved);
|
|
seasons->setCurrentItem(moved);
|
|
|
|
// and move the array too
|
|
array.move(index, index-1);
|
|
}
|
|
}
|
|
|
|
void
|
|
SeasonsPage::downClicked()
|
|
{
|
|
if (seasons->currentItem()) {
|
|
int index = seasons->invisibleRootItem()->indexOfChild(seasons->currentItem());
|
|
if (index == (seasons->invisibleRootItem()->childCount()-1)) return; // its at the bottom already
|
|
|
|
QTreeWidgetItem* moved = seasons->invisibleRootItem()->takeChild(index);
|
|
seasons->invisibleRootItem()->insertChild(index+1, moved);
|
|
seasons->setCurrentItem(moved);
|
|
|
|
array.move(index, index+1);
|
|
}
|
|
}
|
|
|
|
void
|
|
SeasonsPage::renameClicked()
|
|
{
|
|
// which one is selected?
|
|
if (seasons->currentItem()) seasons->editItem(seasons->currentItem(), 0);
|
|
}
|
|
|
|
void
|
|
SeasonsPage::addClicked()
|
|
{
|
|
if (nameEdit->text() == "") return; // just ignore it
|
|
|
|
// swap if not right way around
|
|
if (fromEdit->date() > toEdit->date()) {
|
|
QDate temp = fromEdit->date();
|
|
fromEdit->setDate(toEdit->date());
|
|
toEdit->setDate(temp);
|
|
}
|
|
|
|
QTreeWidgetItem *add = new QTreeWidgetItem(seasons->invisibleRootItem());
|
|
add->setFlags(add->flags() & ~Qt::ItemIsEditable);
|
|
QString id;
|
|
|
|
// tab name
|
|
add->setText(0, nameEdit->text());
|
|
// type
|
|
add->setText(1, Season::types[typeEdit->currentIndex()]);
|
|
// from
|
|
add->setText(2, fromEdit->date().toString("ddd MMM d, yyyy"));
|
|
// to
|
|
add->setText(3, toEdit->date().toString("ddd MMM d, yyyy"));
|
|
// guid -- hidden
|
|
add->setText(4, (id=QUuid::createUuid().toString()));
|
|
|
|
// now clear the edits
|
|
clearEdit();
|
|
|
|
Season addSeason;
|
|
addSeason.setStart(fromEdit->date());
|
|
addSeason.setEnd(toEdit->date());
|
|
addSeason.setName(nameEdit->text());
|
|
addSeason.setType(typeEdit->currentIndex());
|
|
addSeason.setId(id);
|
|
array.append(Season());
|
|
}
|
|
|
|
void
|
|
SeasonsPage::deleteClicked()
|
|
{
|
|
if (seasons->currentItem()) {
|
|
int index = seasons->invisibleRootItem()->indexOfChild(seasons->currentItem());
|
|
|
|
// zap!
|
|
delete seasons->invisibleRootItem()->takeChild(index);
|
|
|
|
array.removeAt(index);
|
|
}
|
|
}
|
|
|
|
void
|
|
SeasonsPage::saveClicked()
|
|
{
|
|
// get any edits to the names and dates
|
|
// since we don't trap these as they are made
|
|
for(int i=0; i<seasons->invisibleRootItem()->childCount(); i++) {
|
|
|
|
QTreeWidgetItem *item = seasons->invisibleRootItem()->child(i);
|
|
|
|
array[i].setName(item->text(0));
|
|
array[i].setType(Season::types.indexOf(item->text(1)));
|
|
array[i].setStart(QDate::fromString(item->text(2), "ddd MMM d, yyyy"));
|
|
array[i].setEnd(QDate::fromString(item->text(3), "ddd MMM d, yyyy"));
|
|
array[i]._id = QUuid(item->text(4));
|
|
}
|
|
|
|
// write to disk
|
|
QString file = QString(context->athlete->home.absolutePath() + "/seasons.xml");
|
|
SeasonParser::serialize(file, array);
|
|
|
|
// re-read
|
|
context->athlete->seasons->readSeasons();
|
|
}
|