mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-15 17:09:56 +00:00
383 lines
13 KiB
C++
383 lines
13 KiB
C++
#include <QtGui>
|
|
#include <QSettings>
|
|
#include <assert.h>
|
|
|
|
#include "MainWindow.h"
|
|
#include "ConfigDialog.h"
|
|
#include "RealtimeWindow.h"
|
|
#include "Pages.h"
|
|
#include "Settings.h"
|
|
#include "Zones.h"
|
|
|
|
|
|
/* cyclist dialog protocol redesign:
|
|
* no zones:
|
|
* calendar disabled
|
|
* automatically go into "new" mode
|
|
* zone(s) defined:
|
|
* click on calendar: sets current zone to that associated with date
|
|
* save clicked:
|
|
* if new mode, create a new zone starting at selected date, or for all dates
|
|
* if this is only zone.
|
|
* delete clicked:
|
|
* deletes currently selected zone
|
|
*/
|
|
|
|
ConfigDialog::ConfigDialog(QDir _home, Zones *_zones, MainWindow *mainWindow) :
|
|
mainWindow(mainWindow), zones(_zones)
|
|
{
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
home = _home;
|
|
|
|
cyclistPage = new CyclistPage(zones);
|
|
|
|
contentsWidget = new QListWidget;
|
|
contentsWidget->setViewMode(QListView::IconMode);
|
|
contentsWidget->setIconSize(QSize(96, 84));
|
|
contentsWidget->setMovement(QListView::Static);
|
|
contentsWidget->setMinimumWidth(128);
|
|
contentsWidget->setMaximumWidth(128);
|
|
contentsWidget->setMinimumHeight(128);
|
|
contentsWidget->setSpacing(12);
|
|
|
|
configPage = new ConfigurationPage();
|
|
|
|
devicePage = new DevicePage(this);
|
|
|
|
pagesWidget = new QStackedWidget;
|
|
pagesWidget->addWidget(configPage);
|
|
pagesWidget->addWidget(cyclistPage);
|
|
pagesWidget->addWidget(devicePage);
|
|
|
|
closeButton = new QPushButton(tr("Close"));
|
|
saveButton = new QPushButton(tr("Save"));
|
|
|
|
createIcons();
|
|
contentsWidget->setCurrentItem(contentsWidget->item(0));
|
|
|
|
// connect(closeButton, SIGNAL(clicked()), this, SLOT(reject()));
|
|
// connect(saveButton, SIGNAL(clicked()), this, SLOT(accept()));
|
|
connect(closeButton, SIGNAL(clicked()), this, SLOT(accept()));
|
|
connect(cyclistPage->btnBack, SIGNAL(clicked()), this, SLOT(back_Clicked()));
|
|
connect(cyclistPage->btnForward, SIGNAL(clicked()), this, SLOT(forward_Clicked()));
|
|
connect(cyclistPage->btnDelete, SIGNAL(clicked()), this, SLOT(delete_Clicked()));
|
|
connect(cyclistPage->calendar, SIGNAL(selectionChanged()), this, SLOT(calendarDateChanged()));
|
|
|
|
// connect the pieces...
|
|
connect(devicePage->typeSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(changedType(int)));
|
|
connect(devicePage->addButton, SIGNAL(clicked()), this, SLOT(devaddClicked()));
|
|
connect(devicePage->delButton, SIGNAL(clicked()), this, SLOT(devdelClicked()));
|
|
connect(devicePage->pairButton, SIGNAL(clicked()), this, SLOT(devpairClicked()));
|
|
|
|
horizontalLayout = new QHBoxLayout;
|
|
horizontalLayout->addWidget(contentsWidget);
|
|
horizontalLayout->addWidget(pagesWidget, 1);
|
|
|
|
buttonsLayout = new QHBoxLayout;
|
|
buttonsLayout->addStretch(1);
|
|
buttonsLayout->addWidget(closeButton);
|
|
buttonsLayout->addWidget(saveButton);
|
|
|
|
mainLayout = new QVBoxLayout;
|
|
mainLayout->addLayout(horizontalLayout);
|
|
mainLayout->addStretch(1);
|
|
mainLayout->addSpacing(12);
|
|
mainLayout->addLayout(buttonsLayout);
|
|
setLayout(mainLayout);
|
|
|
|
setWindowTitle(tr("Config Dialog"));
|
|
}
|
|
|
|
void ConfigDialog::createIcons()
|
|
{
|
|
QListWidgetItem *configButton = new QListWidgetItem(contentsWidget);
|
|
configButton->setIcon(QIcon(":/images/config.png"));
|
|
configButton->setText(tr("Configuration"));
|
|
configButton->setTextAlignment(Qt::AlignHCenter);
|
|
configButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
|
|
|
|
|
QListWidgetItem *cyclistButton = new QListWidgetItem(contentsWidget);
|
|
cyclistButton->setIcon(QIcon(":images/cyclist.png"));
|
|
cyclistButton->setText(tr("Cyclist Info"));
|
|
cyclistButton->setTextAlignment(Qt::AlignHCenter);
|
|
cyclistButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
|
|
|
QListWidgetItem *realtimeButton = new QListWidgetItem(contentsWidget);
|
|
realtimeButton->setIcon(QIcon(":images/arduino.png"));
|
|
realtimeButton->setText(tr("Devices"));
|
|
realtimeButton->setTextAlignment(Qt::AlignHCenter);
|
|
realtimeButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
|
|
|
connect(contentsWidget,
|
|
SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
|
|
this, SLOT(changePage(QListWidgetItem *, QListWidgetItem*)));
|
|
|
|
connect(saveButton, SIGNAL(clicked()), this, SLOT(save_Clicked()));
|
|
}
|
|
|
|
|
|
void ConfigDialog::createNewRange()
|
|
{
|
|
}
|
|
|
|
void ConfigDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
|
|
{
|
|
if (!current)
|
|
current = previous;
|
|
|
|
pagesWidget->setCurrentIndex(contentsWidget->row(current));
|
|
}
|
|
|
|
// if save is clicked, we want to:
|
|
// new mode: create a new zone starting at the selected date (which may be null, implying BEGIN
|
|
// ! new mode: change the CP associated with the present mode
|
|
void ConfigDialog::save_Clicked()
|
|
{
|
|
boost::shared_ptr<QSettings> settings = GetApplicationSettings();
|
|
|
|
if (configPage->langCombo->currentIndex()==0)
|
|
settings->setValue(GC_LANG, "en");
|
|
else if (configPage->langCombo->currentIndex()==1)
|
|
settings->setValue(GC_LANG, "fr");
|
|
else if (configPage->langCombo->currentIndex()==2)
|
|
settings->setValue(GC_LANG, "ja");
|
|
|
|
if (configPage->unitCombo->currentIndex()==0)
|
|
settings->setValue(GC_UNIT, "Metric");
|
|
else if (configPage->unitCombo->currentIndex()==1)
|
|
settings->setValue(GC_UNIT, "Imperial");
|
|
|
|
settings->setValue(GC_ALLRIDES_ASCENDING, configPage->allRidesAscending->checkState());
|
|
settings->setValue(GC_CRANKLENGTH, configPage->crankLengthCombo->currentText());
|
|
settings->setValue(GC_BIKESCOREDAYS, configPage->BSdaysEdit->text());
|
|
settings->setValue(GC_BIKESCOREMODE, configPage->bsModeCombo->currentText());
|
|
settings->setValue(GC_INITIAL_STS, cyclistPage->perfManStart->text());
|
|
settings->setValue(GC_INITIAL_LTS, cyclistPage->perfManStart->text());
|
|
settings->setValue(GC_STS_DAYS, cyclistPage->perfManSTSavg->text());
|
|
settings->setValue(GC_LTS_DAYS, cyclistPage->perfManLTSavg->text());
|
|
|
|
// set default stress names if not set:
|
|
settings->setValue(GC_STS_NAME, settings->value(GC_STS_NAME,tr("Short Term Stress")));
|
|
settings->setValue(GC_STS_ACRONYM, settings->value(GC_STS_ACRONYM,tr("STS")));
|
|
settings->setValue(GC_LTS_NAME, settings->value(GC_LTS_NAME,tr("Long Term Stress")));
|
|
settings->setValue(GC_LTS_ACRONYM, settings->value(GC_LTS_ACRONYM,tr("LTS")));
|
|
settings->setValue(GC_SB_NAME, settings->value(GC_SB_NAME,tr("Stress Balance")));
|
|
settings->setValue(GC_SB_ACRONYM, settings->value(GC_SB_ACRONYM,tr("SB")));
|
|
|
|
|
|
// if the CP text entry reads invalid, there's nothing we can do
|
|
int cp = cyclistPage->getCP();
|
|
if (cp == 0) {
|
|
QMessageBox::warning(this, tr("Invalid CP"), "Please enter valid CP and try again.");
|
|
cyclistPage->setCPFocus();
|
|
return;
|
|
}
|
|
|
|
// if for some reason we have no zones yet, then create them
|
|
int range = cyclistPage->getCurrentRange();
|
|
|
|
// if this is new mode, or if no zone ranges are yet defined, set up the new range
|
|
if ((range == -1) || (cyclistPage->isNewMode()))
|
|
cyclistPage->setCurrentRange(range = zones->insertRangeAtDate(cyclistPage->selectedDate(), cp));
|
|
else
|
|
zones->setCP(range, cyclistPage->getText().toInt());
|
|
|
|
zones->setZonesFromCP(range);
|
|
|
|
// update the "new zone" checkbox to visible and unchecked
|
|
cyclistPage->checkboxNew->setChecked(Qt::Unchecked);
|
|
cyclistPage->checkboxNew->setEnabled(true);
|
|
|
|
zones->write(home);
|
|
|
|
// Save the device configuration...
|
|
DeviceConfigurations all;
|
|
all.writeConfig(devicePage->deviceListModel->Configuration);
|
|
|
|
// update widgets to let them know config has changed
|
|
// only realtime sorted thus far;
|
|
mainWindow->realtimeWindow->configUpdate();
|
|
}
|
|
|
|
void ConfigDialog::moveCalendarToCurrentRange() {
|
|
int range = cyclistPage->getCurrentRange();
|
|
|
|
if (range < 0)
|
|
return;
|
|
|
|
QDate date;
|
|
|
|
// put the cursor at the beginning of the selected range if it's not the first
|
|
if (range > 0)
|
|
date = zones->getStartDate(cyclistPage->getCurrentRange());
|
|
// unless the range is the first range, in which case it goes at the end of that range
|
|
// use JulianDay to subtract one day from the end date, which is actually the first
|
|
// day of the following range
|
|
else
|
|
date = QDate::fromJulianDay(zones->getEndDate(cyclistPage->getCurrentRange()).toJulianDay() - 1);
|
|
|
|
cyclistPage->setSelectedDate(date);
|
|
}
|
|
|
|
void ConfigDialog::back_Clicked()
|
|
{
|
|
QDate date;
|
|
cyclistPage->setCurrentRange(cyclistPage->getCurrentRange() - 1);
|
|
moveCalendarToCurrentRange();
|
|
}
|
|
|
|
void ConfigDialog::forward_Clicked()
|
|
{
|
|
QDate date;
|
|
cyclistPage->setCurrentRange(cyclistPage->getCurrentRange() + 1);
|
|
moveCalendarToCurrentRange();
|
|
}
|
|
|
|
void ConfigDialog::delete_Clicked() {
|
|
int range = cyclistPage->getCurrentRange();
|
|
int num_ranges = zones->getRangeSize();
|
|
assert (num_ranges > 1);
|
|
QMessageBox msgBox;
|
|
msgBox.setText(
|
|
tr("Are you sure you want to delete the zone range\n"
|
|
"from %1 to %2?\n"
|
|
"(%3 range will extend to this date range):") .
|
|
arg(zones->getStartDateString(cyclistPage->getCurrentRange())) .
|
|
arg(zones->getEndDateString(cyclistPage->getCurrentRange())) .
|
|
arg((range > 0) ? "previous" : "next")
|
|
);
|
|
QPushButton *deleteButton = msgBox.addButton(tr("Delete"),QMessageBox::YesRole);
|
|
msgBox.setStandardButtons(QMessageBox::Cancel);
|
|
msgBox.setDefaultButton(QMessageBox::Cancel);
|
|
msgBox.setIcon(QMessageBox::Critical);
|
|
msgBox.exec();
|
|
if(msgBox.clickedButton() == deleteButton)
|
|
cyclistPage->setCurrentRange(zones->deleteRange(range));
|
|
|
|
zones->write(home);
|
|
}
|
|
|
|
void ConfigDialog::calendarDateChanged() {
|
|
int range = zones->whichRange(cyclistPage->selectedDate());
|
|
assert(range >= 0);
|
|
cyclistPage->setCurrentRange(range);
|
|
}
|
|
|
|
//
|
|
// DEVICE CONFIG STUFF
|
|
//
|
|
|
|
void
|
|
ConfigDialog::changedType(int)
|
|
{
|
|
// THIS CODE IS DISABLED FOR THIS RELEASE XXX
|
|
// // disable/enable default checkboxes
|
|
// if (devicePage->devices.at(index).download == false) {
|
|
// devicePage->isDefaultDownload->setEnabled(false);
|
|
// devicePage->isDefaultDownload->setCheckState(Qt::Unchecked);
|
|
// } else {
|
|
// devicePage->isDefaultDownload->setEnabled(true);
|
|
// }
|
|
// if (devicePage->devices.at(index).realtime == false) {
|
|
// devicePage->isDefaultRealtime->setEnabled(false);
|
|
// devicePage->isDefaultRealtime->setCheckState(Qt::Unchecked);
|
|
// } else {
|
|
// devicePage->isDefaultRealtime->setEnabled(true);
|
|
// }
|
|
devicePage->setConfigPane();
|
|
}
|
|
|
|
void
|
|
ConfigDialog::devaddClicked()
|
|
{
|
|
DeviceConfiguration add;
|
|
DeviceTypes Supported;
|
|
|
|
// get values from the gui elements
|
|
add.name = devicePage->deviceName->displayText();
|
|
add.type = devicePage->typeSelector->itemData(devicePage->typeSelector->currentIndex()).toInt();
|
|
add.portSpec = devicePage->deviceSpecifier->displayText();
|
|
add.deviceProfile = devicePage->deviceProfile->displayText();
|
|
|
|
// NOT IMPLEMENTED IN THIS RELEASE XXX
|
|
//add.isDefaultDownload = devicePage->isDefaultDownload->isChecked() ? true : false;
|
|
//add.isDefaultRealtime = devicePage->isDefaultDownload->isChecked() ? true : false;
|
|
|
|
// Validate the name
|
|
QRegExp nameSpec(".+");
|
|
if (nameSpec.exactMatch(add.name) == false) {
|
|
QMessageBox::critical(0, "Invalid Device Name",
|
|
QString("Device Name should be non-blank"));
|
|
return ;
|
|
}
|
|
|
|
// Validate the portSpec
|
|
QRegExp antSpec("[^:]*:[^:]*"); // ip:port same as TCP ... for now...
|
|
QRegExp tcpSpec("[^:]*:[^:]*"); // ip:port
|
|
#ifdef WIN32
|
|
QRegExp serialSpec("COM[0-9]*"); // COMx for WIN32, /dev/* for others
|
|
#else
|
|
QRegExp serialSpec("/dev/.*"); // COMx for WIN32, /dev/* for others
|
|
#endif
|
|
|
|
// check the portSpec is valid, based upon the connection type
|
|
switch (Supported.getType(add.type).connector) {
|
|
case DEV_ANT :
|
|
if (antSpec.exactMatch(add.portSpec) == false) {
|
|
QMessageBox::critical(0, "Invalid Port Specification",
|
|
QString("For ANT devices the specifier must be ") +
|
|
"hostname:portnumber");
|
|
return ;
|
|
}
|
|
break;
|
|
case DEV_SERIAL :
|
|
if (serialSpec.exactMatch(add.portSpec) == false) {
|
|
QMessageBox::critical(0, "Invalid Port Specification",
|
|
QString("For Serial devices the specifier must be ") +
|
|
#ifdef WIN32
|
|
"COMn"
|
|
#else
|
|
"/dev/xxxxx"
|
|
#endif
|
|
);
|
|
return ;
|
|
}
|
|
break;
|
|
case DEV_TCP :
|
|
if (tcpSpec.exactMatch(add.portSpec) == false) {
|
|
QMessageBox::critical(0, "Invalid Port Specification",
|
|
QString("For TCP streaming devices the specifier must be ") +
|
|
"hostname:portnumber");
|
|
return ;
|
|
}
|
|
break;
|
|
}
|
|
|
|
devicePage->deviceListModel->add(add);
|
|
}
|
|
|
|
void
|
|
ConfigDialog::devdelClicked()
|
|
{
|
|
devicePage->deviceListModel->del();
|
|
}
|
|
|
|
void
|
|
ConfigDialog::devpairClicked()
|
|
{
|
|
DeviceConfiguration add;
|
|
|
|
// get values from the gui elements
|
|
add.name = devicePage->deviceName->displayText();
|
|
add.type = devicePage->typeSelector->itemData(devicePage->typeSelector->currentIndex()).toInt();
|
|
add.portSpec = devicePage->deviceSpecifier->displayText();
|
|
add.deviceProfile = devicePage->deviceProfile->displayText();
|
|
|
|
QProgressDialog *progress = new QProgressDialog("Looking for Devices...", "Abort Scan", 0, 200, this);
|
|
progress->setWindowModality(Qt::WindowModal);
|
|
|
|
devicePage->pairClicked(&add, progress);
|
|
}
|