mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-04-13 12:42:20 +00:00
* Changed the UI of CPPage to inline-editing of all values in all tables * Added a sports-specific selector for the model (cp2, cp3, ext, manual) * Allowed to create new ranges either manually or based on the estimated values of the model * Added option to reset each ranges values to those of the selected model * Added message to create a new range if todays estimate differs from those of the currently active one * Refined semi automatic power zones * Added a dialog to inspect and accept only some values while adoption * Added info messages * when the model does not provide FTP or PMAX * that AeTP is only a very rough estimate * Added a tolerance in comparison before proposing new values * Using the following order for defaults when adding a new manual range * selected row * last row * predefined defaults * Zones-Tab: To prevent crashes, a message is shown instead of the real interface if a metric refresh is ongoing * Changed Pace- and HR-Tabs to use inline editing * Moved the unittests into the same structure as the sourcecode * Added a simple (incomplete) unittest for kphToPace * Improved setting the column width * En-/Disabling the action buttons (add, delete, ...) based on the contents state * Changed the layout to prevent jumping widgets when showing / hiding buttons * Fixed compiler warnings from Visual-C++ * Adopt dialog: Refined layout * Fixed the unit of "From BPM" on HR-Page * Set the default mode to manual Fixes #1381
661 lines
15 KiB
C++
661 lines
15 KiB
C++
/*
|
|
* Copyright (c) 2020 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
|
|
*/
|
|
|
|
#ifndef ATHLETEPAGES_H
|
|
#define ATHLETEPAGES_H
|
|
#include "GoldenCheetah.h"
|
|
|
|
#include <QtGui>
|
|
#include <QLineEdit>
|
|
#include <QComboBox>
|
|
#include <QGroupBox>
|
|
#include <QCalendarWidget>
|
|
#include <QPushButton>
|
|
#include <QTreeWidget>
|
|
#include <QTableView>
|
|
#include <QModelIndex>
|
|
#include <QCheckBox>
|
|
#include <QListWidget>
|
|
#include <QList>
|
|
#include <QFileDialog>
|
|
#include "Zones.h"
|
|
#include "HrZones.h"
|
|
#include "PaceZones.h"
|
|
#include <QLabel>
|
|
#include <QDateEdit>
|
|
#include <QCheckBox>
|
|
#include <QValidator>
|
|
#include <QGridLayout>
|
|
#include <QProgressDialog>
|
|
#include <QFontComboBox>
|
|
#include "DeviceTypes.h"
|
|
#include "DeviceConfiguration.h"
|
|
#include "RideMetadata.h"
|
|
#include "DataProcessor.h"
|
|
#include "Season.h"
|
|
#include "RideAutoImportConfig.h"
|
|
#include "RemoteControl.h"
|
|
#include "Measures.h"
|
|
#include "StyledItemDelegates.h"
|
|
|
|
class MeasuresPage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
G_OBJECT
|
|
|
|
|
|
public:
|
|
MeasuresPage(QWidget *parent, Context *context, MeasuresGroup *measuresGroup);
|
|
qint32 saveClicked();
|
|
|
|
public slots:
|
|
void unitChanged(int currentIndex);
|
|
void addOReditClicked();
|
|
void deleteClicked();
|
|
void rangeEdited();
|
|
void rangeSelectionChanged();
|
|
|
|
private:
|
|
Context *context;
|
|
MeasuresGroup *measuresGroup;
|
|
bool metricUnits;
|
|
QList<Measure> measures;
|
|
|
|
QLabel *dateLabel;
|
|
QDateTimeEdit *dateTimeEdit;
|
|
|
|
QVector<QLabel*> valuesLabel;
|
|
QVector<QDoubleSpinBox*> valuesEdit;
|
|
|
|
QLabel *commentlabel;
|
|
QLineEdit *comment;
|
|
|
|
QTreeWidget *measuresTree;
|
|
QPushButton *addButton, *updateButton, *deleteButton;
|
|
|
|
struct {
|
|
unsigned long fingerprint;
|
|
} b4;
|
|
|
|
private slots:
|
|
};
|
|
|
|
class AboutRiderPage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
G_OBJECT
|
|
|
|
|
|
public:
|
|
AboutRiderPage(QWidget *parent, Context *context);
|
|
qint32 saveClicked();
|
|
|
|
public slots:
|
|
void chooseAvatar();
|
|
void unitChanged(int currentIndex);
|
|
|
|
private:
|
|
Context *context;
|
|
bool metricUnits;
|
|
|
|
QLineEdit *nickname;
|
|
QDateEdit *dob;
|
|
QComboBox *sex;
|
|
QLabel *weightlabel;
|
|
QDoubleSpinBox *weight;
|
|
QLabel *heightlabel;
|
|
QDoubleSpinBox *height;
|
|
QPushButton *avatarButton;
|
|
QPixmap avatar;
|
|
QComboBox *crankLengthCombo;
|
|
QComboBox *rimSizeCombo;
|
|
QComboBox *tireSizeCombo;
|
|
QLineEdit *wheelSizeEdit;
|
|
|
|
|
|
struct {
|
|
double weight;
|
|
double height;
|
|
int wheel;
|
|
int crank;
|
|
} b4;
|
|
|
|
private slots:
|
|
void calcWheelSize();
|
|
void resetWheelSize();
|
|
};
|
|
|
|
class AboutModelPage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
G_OBJECT
|
|
|
|
|
|
public:
|
|
AboutModelPage(Context *context);
|
|
qint32 saveClicked();
|
|
|
|
private:
|
|
Context *context;
|
|
|
|
QLabel *wbaltaulabel;
|
|
QSpinBox *wbaltau;
|
|
QLabel *perfManSTSLabel;
|
|
QLabel *perfManLTSLabel;
|
|
QLineEdit *perfManSTSavg;
|
|
QLineEdit *perfManLTSavg;
|
|
QIntValidator *perfManSTSavgValidator;
|
|
QIntValidator *perfManLTSavgValidator;
|
|
QCheckBox *showSBToday;
|
|
|
|
struct {
|
|
int lts,sts;
|
|
} b4;
|
|
|
|
};
|
|
|
|
class BackupPage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
G_OBJECT
|
|
|
|
|
|
public:
|
|
BackupPage(Context *context);
|
|
qint32 saveClicked();
|
|
|
|
private:
|
|
Context *context;
|
|
|
|
QSpinBox *autoBackupPeriod;
|
|
QLineEdit *autoBackupFolder;
|
|
QPushButton *autoBackupFolderBrowse;
|
|
|
|
private slots:
|
|
|
|
void chooseAutoBackupFolder();
|
|
};
|
|
|
|
class CredentialsPage : public QScrollArea
|
|
{
|
|
Q_OBJECT
|
|
G_OBJECT
|
|
|
|
|
|
public:
|
|
CredentialsPage(Context *context);
|
|
|
|
qint32 saveClicked();
|
|
void resetList();
|
|
|
|
public slots:
|
|
void addClicked();
|
|
void deleteClicked();
|
|
void editClicked();
|
|
|
|
|
|
private:
|
|
|
|
Context *context;
|
|
QTreeWidget *accounts;
|
|
QPushButton *addButton, *editButton, *deleteButton;
|
|
|
|
};
|
|
|
|
//
|
|
// Power Zones
|
|
//
|
|
class SchemePage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
SchemePage(Zones *zones);
|
|
|
|
ZoneScheme getScheme();
|
|
qint32 saveClicked();
|
|
|
|
private slots:
|
|
void addClicked();
|
|
void deleteClicked();
|
|
void updateButtons();
|
|
|
|
private:
|
|
Zones *zones;
|
|
QTreeWidget *scheme;
|
|
QPushButton *addButton, *deleteButton;
|
|
SpinBoxEditDelegate zoneFromDelegate;
|
|
};
|
|
|
|
|
|
// Compatibility helper for Qt5
|
|
// exposes methods that turned public in Qt6 from protected in Qt5
|
|
#if QT_VERSION < 0x060000
|
|
class TreeWidget6 : public QTreeWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
TreeWidget6(QWidget *parent = nullptr): QTreeWidget(parent) {
|
|
}
|
|
|
|
QModelIndex indexFromItem(const QTreeWidgetItem *item, int column = 0) const {
|
|
return QTreeWidget::indexFromItem(item, column);
|
|
}
|
|
|
|
QTreeWidgetItem* itemFromIndex(const QModelIndex &index) const {
|
|
return QTreeWidget::itemFromIndex(index);
|
|
}
|
|
|
|
};
|
|
#else
|
|
typedef QTreeWidget TreeWidget6;
|
|
#endif
|
|
|
|
|
|
class CPPage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
CPPage(Context *context, Zones *zones, SchemePage *schemePage);
|
|
|
|
qint32 saveClicked();
|
|
|
|
QComboBox *useModel;
|
|
QComboBox *useCPForFTPCombo;
|
|
|
|
struct {
|
|
int modelIdx;
|
|
int cpforftp;
|
|
} b4;
|
|
|
|
public slots:
|
|
void addClicked();
|
|
void deleteClicked();
|
|
void defaultClicked();
|
|
void rangeSelectionChanged();
|
|
void addZoneClicked();
|
|
void deleteZoneClicked();
|
|
void zonesChanged();
|
|
void initializeRanges();
|
|
|
|
private slots:
|
|
#if QT_VERSION < 0x060000
|
|
void rangeChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
|
|
#else
|
|
void rangeChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles = QList<int>());
|
|
#endif
|
|
|
|
void adopt();
|
|
void updateButtons();
|
|
|
|
private:
|
|
bool active;
|
|
|
|
DateEditDelegate dateDelegate;
|
|
SpinBoxEditDelegate cpDelegate;
|
|
SpinBoxEditDelegate aetDelegate;
|
|
SpinBoxEditDelegate ftpDelegate;
|
|
SpinBoxEditDelegate wDelegate;
|
|
SpinBoxEditDelegate pmaxDelegate;
|
|
NoEditDelegate statusDelegate;
|
|
|
|
SpinBoxEditDelegate zoneFromDelegate;
|
|
|
|
Context *context;
|
|
Zones *zones_;
|
|
SchemePage *schemePage;
|
|
TreeWidget6 *ranges;
|
|
QTreeWidget *zones;
|
|
QPushButton *addButton, *deleteButton;
|
|
QPushButton *adoptButton;
|
|
QPushButton *addZoneButton, *deleteZoneButton, *defaultButton;
|
|
QPushButton *newZoneRequired;
|
|
|
|
bool getValuesFor(const QDate &date, bool allowDefaults, int &cp, int &aetp, int &ftp, int &wprime, int &pmax, int &estOffset, bool &defaults, QDate *startDate = nullptr) const;
|
|
void setEstimateStatus(QTreeWidgetItem *item);
|
|
void setRangeData(QModelIndex modelIndex, int column, QVariant data);
|
|
bool needsNewRange() const;
|
|
void mkAdoptionRow(QGridLayout *grid, int row, int labelId, const QString &unit, int cur, int est, QCheckBox *&accept, const QString &infoText = QString()) const;
|
|
void connectAdoptionDialogApplyButton(QVector<QCheckBox*> checkboxes, QPushButton *applyButton) const;
|
|
bool modelHasFtp() const;
|
|
bool modelHasPmax() const;
|
|
QWidget *mkInfoLabel(int labelId, const QString &infoText = QString()) const;
|
|
QString getText(int id, int value = 0) const;
|
|
bool addDialogManual(QDate &date, int &cp, int &aetp, int &wprime, int &ftp, int &pmax) const;
|
|
};
|
|
|
|
class ZonePage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
G_OBJECT
|
|
|
|
|
|
public:
|
|
|
|
ZonePage(Context *);
|
|
~ZonePage();
|
|
qint32 saveClicked();
|
|
|
|
public slots:
|
|
|
|
|
|
protected:
|
|
|
|
Context *context;
|
|
|
|
QTabWidget *tabs;
|
|
|
|
private:
|
|
|
|
QLabel *sportLabel;
|
|
QComboBox *sportCombo;
|
|
|
|
//ZoneScheme scheme;
|
|
QHash<QString, Zones*> zones;
|
|
QHash<QString, quint16> b4Fingerprint; // how did it start ?
|
|
QHash<QString, SchemePage*> schemePage;
|
|
QHash<QString, CPPage*> cpPage;
|
|
|
|
private slots:
|
|
void changeSport();
|
|
|
|
};
|
|
|
|
|
|
//
|
|
// Heartrate Zones
|
|
//
|
|
class HrSchemePage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
HrSchemePage(HrZones *hrZones);
|
|
|
|
HrZoneScheme getScheme();
|
|
qint32 saveClicked();
|
|
|
|
private slots:
|
|
void addClicked();
|
|
void deleteClicked();
|
|
void updateButtons();
|
|
|
|
private:
|
|
HrZones *hrZones;
|
|
QTreeWidget *scheme;
|
|
QPushButton *addButton, *deleteButton;
|
|
|
|
SpinBoxEditDelegate ltDelegate;
|
|
DoubleSpinBoxEditDelegate trimpkDelegate;
|
|
};
|
|
|
|
|
|
class LTPage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
LTPage(Context *context, HrZones *hrZones, HrSchemePage *schemePage);
|
|
|
|
private slots:
|
|
void addClicked();
|
|
void deleteClicked();
|
|
void defaultClicked();
|
|
void rangeChanged(const QModelIndex &modelIndex);
|
|
void rangeSelectionChanged();
|
|
void addZoneClicked();
|
|
void deleteZoneClicked();
|
|
void zonesChanged();
|
|
void updateButtons();
|
|
|
|
private:
|
|
bool active;
|
|
|
|
DateEditDelegate dateDelegate;
|
|
SpinBoxEditDelegate ltDelegate;
|
|
SpinBoxEditDelegate aetDelegate;
|
|
SpinBoxEditDelegate restHrDelegate;
|
|
SpinBoxEditDelegate maxHrDelegate;
|
|
|
|
SpinBoxEditDelegate zoneLoDelegate;
|
|
DoubleSpinBoxEditDelegate zoneTrimpDelegate;
|
|
|
|
Context *context;
|
|
HrZones *hrZones;
|
|
HrSchemePage *schemePage;
|
|
QTreeWidget *ranges;
|
|
QTreeWidget *zones;
|
|
QPushButton *addButton, *deleteButton;
|
|
QPushButton *addZoneButton, *deleteZoneButton, *defaultButton;
|
|
};
|
|
|
|
class HrZonePage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
HrZonePage(Context *);
|
|
~HrZonePage();
|
|
qint32 saveClicked();
|
|
|
|
protected:
|
|
Context *context;
|
|
|
|
QTabWidget *tabs;
|
|
|
|
private:
|
|
QLabel *sportLabel;
|
|
QComboBox *sportCombo;
|
|
|
|
QHash<QString, HrZones*> hrZones;
|
|
QHash<QString, quint16> b4Fingerprint; // how did it start ?
|
|
QHash<QString, HrSchemePage*> schemePage;
|
|
QHash<QString, LTPage*> ltPage;
|
|
|
|
private slots:
|
|
void changeSport();
|
|
|
|
};
|
|
|
|
//
|
|
// Pace Zones
|
|
//
|
|
class PaceSchemePage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
PaceSchemePage(PaceZones* paceZones);
|
|
|
|
PaceZoneScheme getScheme();
|
|
qint32 saveClicked();
|
|
|
|
private slots:
|
|
void addClicked();
|
|
void deleteClicked();
|
|
void updateButtons();
|
|
|
|
private:
|
|
PaceZones* paceZones;
|
|
QTreeWidget *scheme;
|
|
QPushButton *addButton, *deleteButton;
|
|
SpinBoxEditDelegate fromDelegate;
|
|
};
|
|
|
|
class CVPage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
CVPage(PaceZones* paceZones, PaceSchemePage *schemePage);
|
|
|
|
bool metricPace;
|
|
|
|
private slots:
|
|
void addClicked();
|
|
void deleteClicked();
|
|
void defaultClicked();
|
|
#if QT_VERSION < 0x060000
|
|
void rangeChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
|
|
#else
|
|
void rangeChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles = QList<int>());
|
|
#endif
|
|
void rangeSelectionChanged();
|
|
void addZoneClicked();
|
|
void deleteZoneClicked();
|
|
void zonesChanged();
|
|
void updateButtons();
|
|
|
|
private:
|
|
bool active;
|
|
|
|
DateEditDelegate dateDelegate;
|
|
TimeEditDelegate cvDelegate;
|
|
TimeEditDelegate aetDelegate;
|
|
|
|
TimeEditDelegate zoneFromDelegate;
|
|
|
|
PaceZones* paceZones;
|
|
PaceSchemePage *schemePage;
|
|
QTreeWidget *ranges;
|
|
QTreeWidget *zones;
|
|
QPushButton *addButton, *deleteButton;
|
|
QPushButton *addZoneButton, *deleteZoneButton, *defaultButton;
|
|
QLabel *per;
|
|
};
|
|
|
|
class PaceZonePage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
G_OBJECT
|
|
|
|
|
|
public:
|
|
|
|
PaceZonePage(Context *);
|
|
~PaceZonePage();
|
|
qint32 saveClicked();
|
|
|
|
public slots:
|
|
|
|
|
|
protected:
|
|
|
|
Context *context;
|
|
|
|
QTabWidget *tabs;
|
|
|
|
private:
|
|
|
|
static const int nSports = 2;
|
|
|
|
QLabel *sportLabel;
|
|
QComboBox *sportCombo;
|
|
|
|
PaceZones* paceZones[nSports];
|
|
quint16 b4Fingerprint[nSports]; // how did it start ?
|
|
PaceSchemePage* schemePages[nSports];
|
|
CVPage* cvPages[nSports];
|
|
|
|
private slots:
|
|
void changeSport(int i);
|
|
|
|
};
|
|
|
|
// Seasons
|
|
|
|
class SeasonsPage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
G_OBJECT
|
|
|
|
|
|
public:
|
|
SeasonsPage(QWidget *parent, Context *context);
|
|
void getDefinitions(QList<Season>&);
|
|
|
|
public slots:
|
|
void addClicked();
|
|
void upClicked();
|
|
void downClicked();
|
|
void renameClicked();
|
|
void deleteClicked();
|
|
void clearEdit();
|
|
qint32 saveClicked();
|
|
|
|
private:
|
|
|
|
QTreeWidget *seasons;
|
|
Context *context;
|
|
|
|
QLineEdit *nameEdit;
|
|
QComboBox *typeEdit;
|
|
QDateEdit *fromEdit, *toEdit;
|
|
#ifndef Q_OS_MAC
|
|
QToolButton *upButton, *downButton;
|
|
#else
|
|
QPushButton *upButton, *downButton;
|
|
#endif
|
|
QPushButton *addButton, *renameButton, *deleteButton;
|
|
|
|
QList<Season> array;
|
|
};
|
|
|
|
class AutoImportPage : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
G_OBJECT
|
|
|
|
|
|
public:
|
|
|
|
AutoImportPage(Context *);
|
|
qint32 saveClicked();
|
|
void addRuleTypes(QComboBox *p);
|
|
|
|
public slots:
|
|
|
|
void addClicked();
|
|
void upClicked();
|
|
void downClicked();
|
|
void deleteClicked();
|
|
void browseImportDir();
|
|
|
|
|
|
private:
|
|
|
|
Context *context;
|
|
QList<RideAutoImportRule> rules;
|
|
|
|
QTreeWidget *fields;
|
|
|
|
#ifndef Q_OS_MAC
|
|
QToolButton *upButton, *downButton;
|
|
#else
|
|
QPushButton *upButton, *downButton;
|
|
#endif
|
|
QPushButton *addButton, *renameButton, *deleteButton, *browseButton;
|
|
|
|
};
|
|
|
|
extern void basicTreeWidgetStyle(QTreeWidget *tree);
|
|
|
|
#endif
|