Files
GoldenCheetah/src/LTMSettings.cpp
Mark Liversedge 7bb9cf5462 Long Term Metrics
A user configurable chart for showing ride metrics and
other calculated values over time.

* Uses SQLITE database to store metrics
* Supports any metric available from the metric factory
* Adds new MaxHr, VI, Peak Power and Time In Zone metric
* Also includes LTS/STS/SB for PM charting
* Aggregates in days, weeks, months or years
* Reads and Updates seasons.xml
* Adds cycles and adhoc date ranges in seasons.xml
* Date ranges can be selected on the plot with shift-left click
* Allows users to customise preferences for color, symbols et al
* Allows user to customise metric names and unit names
* Supports smooth curves and topN highlighting
* Has a linear regress trend line function
* Allows users to save charts to charts.xml
* A default charts.xml is built-in
* A chart manager to import/export/rename/delete charts etc
* Provides a tooltip to provide basic datapoint information
* Performance Manager adjusted to use the MetricDB
* User configurable setting for SB calculation (today/tomorrow)
2010-02-25 08:01:43 -08:00

331 lines
11 KiB
C++

/*
* Copyright (c) 2010 Mark Liversedge (liversedge@gmail.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "LTMSettings.h"
#include "LTMTool.h"
#include "MainWindow.h"
#include "LTMChartParser.h"
#include <QtGui>
#include <qwt_plot.h>
#include <qwt_symbol.h>
#include <qwt_plot_curve.h>
/*----------------------------------------------------------------------
* EDIT CHART DIALOG
*--------------------------------------------------------------------*/
EditChartDialog::EditChartDialog(MainWindow *mainWindow, LTMSettings *settings, QList<LTMSettings>presets) :
QDialog(mainWindow, Qt::Dialog), mainWindow(mainWindow), settings(settings), presets(presets)
{
setWindowTitle(tr("Enter Chart Name"));
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// Metric Name
mainLayout->addSpacing(5);
chartName = new QLineEdit;
mainLayout->addWidget(chartName);
mainLayout->addStretch();
// Buttons
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
okButton = new QPushButton(tr("&OK"), this);
cancelButton = new QPushButton(tr("&Cancel"), this);
buttonLayout->addWidget(cancelButton);
buttonLayout->addWidget(okButton);
mainLayout->addLayout(buttonLayout);
// make it wide enough
setMinimumWidth(250);
// connect up slots
connect(okButton, SIGNAL(clicked()), this, SLOT(okClicked()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancelClicked()));
}
void
EditChartDialog::okClicked()
{
// mustn't be blank
if (chartName->text() == "") {
QMessageBox::warning( 0, "Entry Error", "Name is blank");
return;
}
// does it already exist?
foreach (LTMSettings chart, presets) {
if (chart.name == chartName->text()) {
QMessageBox::warning( 0, "Entry Error", "Chart already exists");
return;
}
}
settings->name = chartName->text();
accept();
}
void
EditChartDialog::cancelClicked()
{
reject();
}
/*----------------------------------------------------------------------
* CHART MANAGER DIALOG
*--------------------------------------------------------------------*/
ChartManagerDialog::ChartManagerDialog(MainWindow *mainWindow, QList<LTMSettings>*presets) :
QDialog(mainWindow, Qt::Dialog), mainWindow(mainWindow), presets(presets)
{
setWindowTitle(tr("Manage Charts"));
QGridLayout *mainLayout = new QGridLayout(this);
importButton = new QPushButton(tr("Import..."));
exportButton = new QPushButton(tr("Export..."));
upButton = new QPushButton(tr("Move up"));
downButton = new QPushButton(tr("Move down"));
renameButton = new QPushButton(tr("Rename"));
deleteButton = new QPushButton(tr("Delete"));
QVBoxLayout *actionButtons = new QVBoxLayout;
actionButtons->addWidget(renameButton);
actionButtons->addWidget(deleteButton);
actionButtons->addWidget(upButton);
actionButtons->addWidget(downButton);
actionButtons->addStretch();
actionButtons->addWidget(importButton);
actionButtons->addWidget(exportButton);
charts = new QTreeWidget;
charts->headerItem()->setText(0, "Charts");
charts->setColumnCount(1);
charts->setSelectionMode(QAbstractItemView::SingleSelection);
charts->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
charts->setIndentation(0);
foreach(LTMSettings chart, *presets) {
QTreeWidgetItem *add;
add = new QTreeWidgetItem(charts->invisibleRootItem());
add->setFlags(add->flags() | Qt::ItemIsEditable);
add->setText(0, chart.name);
}
charts->setCurrentItem(charts->invisibleRootItem()->child(0));
// Cancel/ OK Buttons
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
okButton = new QPushButton(tr("&OK"), this);
cancelButton = new QPushButton(tr("&Cancel"), this);
buttonLayout->addWidget(cancelButton);
buttonLayout->addWidget(okButton);
mainLayout->addWidget(charts, 0,0);
mainLayout->addLayout(actionButtons, 0,1);
mainLayout->addLayout(buttonLayout,1,0);
// seems reasonable...
setMinimumHeight(350);
// connect up slots
connect(okButton, SIGNAL(clicked()), this, SLOT(okClicked()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancelClicked()));
connect(upButton, SIGNAL(clicked()), this, SLOT(upClicked()));
connect(downButton, SIGNAL(clicked()), this, SLOT(downClicked()));
connect(renameButton, SIGNAL(clicked()), this, SLOT(renameClicked()));
connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
connect(importButton, SIGNAL(clicked()), this, SLOT(importClicked()));
connect(exportButton, SIGNAL(clicked()), this, SLOT(exportClicked()));
}
void
ChartManagerDialog::okClicked()
{
// take the edited versions of the name first
for(int i=0; i<charts->invisibleRootItem()->childCount(); i++)
(*presets)[i].name = charts->invisibleRootItem()->child(i)->text(0);
accept();
}
void
ChartManagerDialog::cancelClicked()
{
reject();
}
void
ChartManagerDialog::importClicked()
{
QFileDialog existing(this);
existing.setFileMode(QFileDialog::ExistingFile);
existing.setNameFilter(tr("Chart File (*.xml)"));
if (existing.exec()){
// we will only get one (ExistingFile not ExistingFiles)
QStringList filenames = existing.selectedFiles();
if (QFileInfo(filenames[0]).exists()) {
QList<LTMSettings> imported;
QFile chartsFile(filenames[0]);
// setup XML processor
QXmlInputSource source( &chartsFile );
QXmlSimpleReader xmlReader;
LTMChartParser (handler);
xmlReader.setContentHandler(&handler);
xmlReader.setErrorHandler(&handler);
// parse and get return values
xmlReader.parse(source);
imported = handler.getSettings();
// now append to the QList and QTreeWidget
*presets += imported;
foreach (LTMSettings chart, imported) {
QTreeWidgetItem *add;
add = new QTreeWidgetItem(charts->invisibleRootItem());
add->setFlags(add->flags() | Qt::ItemIsEditable);
add->setText(0, chart.name);
}
} else {
// oops non existant - does this ever happen?
QMessageBox::warning( 0, "Entry Error", QString("Selected file (%1) does not exist").arg(filenames[0]));
}
}
}
void
ChartManagerDialog::exportClicked()
{
QFileDialog newone(this);
newone.setFileMode(QFileDialog::AnyFile);
newone.setNameFilter(tr("Chart File (*.xml)"));
if (newone.exec()){
// we will only get one (ExistingFile not ExistingFiles)
QStringList filenames = newone.selectedFiles();
// if exists confirm overwrite
if (QFileInfo(filenames[0]).exists()) {
QMessageBox msgBox;
msgBox.setText(QString("The selected file (%1) exists.").arg(filenames[0]));
msgBox.setInformativeText("Do you want to overwrite it?");
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
msgBox.setIcon(QMessageBox::Warning);
if (msgBox.exec() != QMessageBox::Ok)
return;
}
LTMChartParser::serialize(filenames[0], *presets);
}
}
void
ChartManagerDialog::upClicked()
{
if (charts->currentItem()) {
int index = charts->invisibleRootItem()->indexOfChild(charts->currentItem());
if (index == 0) return; // its at the top already
// movin on up!
QTreeWidgetItem *moved;
charts->invisibleRootItem()->insertChild(index-1, moved=charts->invisibleRootItem()->takeChild(index));
charts->setCurrentItem(moved);
LTMSettings save = (*presets)[index];
presets->removeAt(index);
presets->insert(index-1, save);
}
}
void
ChartManagerDialog::downClicked()
{
if (charts->currentItem()) {
int index = charts->invisibleRootItem()->indexOfChild(charts->currentItem());
if (index == (charts->invisibleRootItem()->childCount()-1)) return; // its at the bottom already
// movin on up!
QTreeWidgetItem *moved;
charts->invisibleRootItem()->insertChild(index+1, moved=charts->invisibleRootItem()->takeChild(index));
charts->setCurrentItem(moved);
LTMSettings save = (*presets)[index];
presets->removeAt(index);
presets->insert(index+1, save);
}
}
void
ChartManagerDialog::renameClicked()
{
// which one is selected?
if (charts->currentItem()) charts->editItem(charts->currentItem(), 0);
}
void
ChartManagerDialog::deleteClicked()
{
// must have at least 1 child
if (charts->invisibleRootItem()->childCount() == 1) {
QMessageBox::warning(0, "Error", "You must have at least one chart");
return;
} else if (charts->currentItem()) {
int index = charts->invisibleRootItem()->indexOfChild(charts->currentItem());
// zap!
presets->removeAt(index);
delete charts->invisibleRootItem()->takeChild(index);
}
}
/*----------------------------------------------------------------------
* Write to charts.xml
*--------------------------------------------------------------------*/
void
LTMSettings::writeChartXML(QDir home, QList<LTMSettings> charts)
{
LTMChartParser::serialize(QString(home.path() + "/charts.xml"), charts);
}
/*----------------------------------------------------------------------
* Read charts.xml
*--------------------------------------------------------------------*/
void
LTMSettings::readChartXML(QDir home, QList<LTMSettings> &charts)
{
QFileInfo chartFile(home.absolutePath() + "/charts.xml");
QFile chartsFile;
// if it doesn't exist use our built-in default version
if (chartFile.exists())
chartsFile.setFileName(chartFile.filePath());
else
chartsFile.setFileName(":/xml/charts.xml");
QXmlInputSource source( &chartsFile );
QXmlSimpleReader xmlReader;
LTMChartParser( handler );
xmlReader.setContentHandler(&handler);
xmlReader.setErrorHandler(&handler);
xmlReader.parse( source );
charts = handler.getSettings();
}