From 492a113eb331b45e502020cde657b47d5f99210f Mon Sep 17 00:00:00 2001 From: Mark Liversedge Date: Sat, 14 Jan 2012 11:52:01 +0000 Subject: [PATCH] Configure Seasons in ConfigDialog Allow the user to add,delete and reorder seasons in the config dialog. Although the user could create and manipulate seasons / date ranges in the LTM chart, this provides a more coherent place to do the same but also adds the ability to re-order seasons. Fixes #399. --- src/Pages.cpp | 220 +++++++++++++++++++++++++++++++++++++++++++++++++ src/Pages.h | 37 +++++++++ src/Season.cpp | 12 +++ src/Season.h | 3 +- 4 files changed, 270 insertions(+), 2 deletions(-) diff --git a/src/Pages.cpp b/src/Pages.cpp index 1a9e37805..0c04347c2 100644 --- a/src/Pages.cpp +++ b/src/Pages.cpp @@ -250,9 +250,11 @@ CyclistPage::CyclistPage(MainWindow *main) : QWidget *rdTab = new QWidget(this); QWidget *psTab = new QWidget(this); QWidget *pmTab = new QWidget(this); + QWidget *seTab = new QWidget(this); tabs->addTab(rdTab, tr("About Me")); tabs->addTab(cpTab, tr("Power Zones")); tabs->addTab(hrTab, tr("HR Zones")); + tabs->addTab(seTab, tr("Seasons")); tabs->addTab(pmTab, tr("Performance Manager")); tabs->addTab(psTab, tr("Passwords")); QVBoxLayout *cpLayout = new QVBoxLayout(cpTab); @@ -260,6 +262,7 @@ CyclistPage::CyclistPage(MainWindow *main) : QVBoxLayout *pmLayout = new QVBoxLayout(pmTab); QVBoxLayout *rdLayout = new QVBoxLayout(rdTab); QVBoxLayout *psLayout = new QVBoxLayout(psTab); + QVBoxLayout *seLayout = new QVBoxLayout(seTab); riderPage = new RiderPage(this, mainWindow); rdLayout->addWidget(riderPage); @@ -273,6 +276,9 @@ CyclistPage::CyclistPage(MainWindow *main) : passPage = new CredentialsPage(this, mainWindow); psLayout->addWidget(passPage); + seasonsPage = new SeasonsPage(this, mainWindow); + seLayout->addWidget(seasonsPage); + perfManLabel = new QLabel(tr("Performance Manager")); showSBToday = new QCheckBox(tr("Show Stress Balance Today"), this); showSBToday->setChecked(appsettings->cvalue(mainWindow->cyclist, GC_SB_TODAY).toInt()); @@ -330,6 +336,7 @@ CyclistPage::saveClicked() hrZonePage->saveClicked(); riderPage->saveClicked(); passPage->saveClicked(); + seasonsPage->saveClicked(); } // @@ -3632,3 +3639,216 @@ void CredentialsPage::saveTwitter() } #endif } + +// +// Season Editor +// +SeasonsPage::SeasonsPage(QWidget *parent, MainWindow *mainWindow) : QWidget(parent), mainWindow(mainWindow) +{ + QGridLayout *mainLayout = new QGridLayout(this); + QFormLayout *editLayout = new QFormLayout; + editLayout->setFieldGrowthPolicy(QFormLayout::FieldsStayAtSizeHint); + + // get the list + array = mainWindow->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); + + upButton = new QPushButton(tr("Move up")); + downButton = new QPushButton(tr("Move down")); + addButton = new QPushButton(tr("Add")); + deleteButton = new QPushButton(tr("Delete")); + + QVBoxLayout *actionButtons = new QVBoxLayout; + 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(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); + } +} + +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); + } +} + +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); + + // 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, QUuid::createUuid().toString()); + + // now clear the edits + clearEdit(); +} + +void +SeasonsPage::deleteClicked() +{ + if (seasons->currentItem()) { + int index = seasons->invisibleRootItem()->indexOfChild(seasons->currentItem()); + + // zap! + delete seasons->invisibleRootItem()->takeChild(index); + } +} + +void +SeasonsPage::saveClicked() +{ + // update the season array to reflect our edits + array.clear(); + for(int i=0; iinvisibleRootItem()->childCount(); i++) { + + QTreeWidgetItem *item = seasons->invisibleRootItem()->child(i); + + Season add; + add.name = item->text(0); + add.type = Season::types.indexOf(item->text(1)); + add.start = QDate::fromString(item->text(2), "ddd MMM d, yyyy"); + add.end = QDate::fromString(item->text(3), "ddd MMM d, yyyy"); + add._id = QUuid(item->text(4)); + array << add; + } + + // write to disk + QString file = QString(mainWindow->home.absolutePath() + "/seasons.xml"); + SeasonParser::serialize(file, array); + + // wipe existing mainwindow config + delete mainWindow->seasons; + + // re-read + mainWindow->seasons = new Seasons(mainWindow->home); +} diff --git a/src/Pages.h b/src/Pages.h index ac90a2f1a..781b80d4a 100644 --- a/src/Pages.h +++ b/src/Pages.h @@ -24,6 +24,8 @@ #include "DeviceConfiguration.h" #include "RideMetadata.h" #include "DataProcessor.h" +#include "Season.h" +#include "SeasonParser.h" #ifdef GC_HAVE_LIBOAUTH extern "C" { @@ -46,6 +48,7 @@ class FieldsPage; class MeasuresPage; class Colors; class RiderPage; +class SeasonsPage; class ConfigurationPage : public QWidget { @@ -211,6 +214,7 @@ class CyclistPage : public QWidget CredentialsPage *passPage; ZonePage *zonePage; HrZonePage *hrZonePage; + SeasonsPage *seasonsPage; private: QVBoxLayout *perfManLayout; @@ -684,6 +688,39 @@ protected: // local versions for modification }; +class SeasonsPage : public QWidget +{ + Q_OBJECT + G_OBJECT + + + public: + SeasonsPage(QWidget *parent, MainWindow *main); + void getDefinitions(QList&); + + public slots: + void addClicked(); + void upClicked(); + void downClicked(); + void renameClicked(); + void deleteClicked(); + void clearEdit(); + void saveClicked(); + + private: + + QTreeWidget *seasons; + MainWindow *mainWindow; + + QLineEdit *nameEdit; + QComboBox *typeEdit; + QDateEdit *fromEdit, *toEdit; + + QPushButton *upButton, *downButton, *addButton, *renameButton, *deleteButton; + + QList array; +}; + class MeasuresPage : public QWidget { Q_OBJECT diff --git a/src/Season.cpp b/src/Season.cpp index 4a5c140b0..1257c96f8 100644 --- a/src/Season.cpp +++ b/src/Season.cpp @@ -25,6 +25,18 @@ #define tr(s) QObject::tr(s) +static QList _setSeasonTypes() +{ + QList returning; + returning << "Season" + << "Cycle" + << "Adhoc" + << "System"; + return returning; +} + +QList Season::types = _setSeasonTypes(); + Season::Season() { type = season; // by default seasons are of type season diff --git a/src/Season.h b/src/Season.h index 46ea7e164..6757535a9 100644 --- a/src/Season.h +++ b/src/Season.h @@ -29,6 +29,7 @@ class Season { public: + static QList types; enum SeasonType { season=0, cycle=1, adhoc=2, temporary=3 }; //typedef enum seasontype SeasonType; @@ -48,8 +49,6 @@ class Season void setId(QUuid x) { _id = x; } QVector &load() { return _load; } - - private: QDate start; // first day of the season QDate end; // last day of the season int _days; // how many days in this season?