Files
GoldenCheetah/src/RideFileTableModel.cpp
Damien Grauser ac3112b286 Add Temperature and Slope Data Series
This patch adds support for temperature and slope
across the ridefile readers.

For the most part their is no functional change
although it is now possible to view and edit these
data series in the editor.

File formats that can provide temp or slope include;
.bin, .fit, .srm, .sync, .wko

Further updates will be required to display the data
in the ride plot and histograms.
2011-12-03 23:17:11 +00:00

402 lines
12 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 "RideFileTableModel.h"
RideFileTableModel::RideFileTableModel(RideFile *ride) : ride(ride)
{
setRide(ride);
}
void
RideFileTableModel::setRide(RideFile *newride)
{
// QPointer helps us check if the current ride has been deleted before trying to disconnect
static QPointer<RideFileCommand> connection = NULL;
if (connection) {
disconnect(connection, SIGNAL(beginCommand(bool,RideCommand*)), this, SLOT(beginCommand(bool,RideCommand*)));
disconnect(connection, SIGNAL(endCommand(bool,RideCommand*)), this, SLOT(endCommand(bool,RideCommand*)));
}
ride = newride;
tooltips.clear(); // remove the tooltips -- rideEditor will set them (this is fugly, but efficient)
if (ride) {
// set the headings to reflect the data that is present
setHeadings();
// Trap commands
connection = ride->command;
connect(ride->command, SIGNAL(beginCommand(bool,RideCommand*)), this, SLOT(beginCommand(bool,RideCommand*)));
connect(ride->command, SIGNAL(endCommand(bool,RideCommand*)), this, SLOT(endCommand(bool,RideCommand*)));
connect(ride, SIGNAL(deleted()), this, SLOT(deleted()));
// refresh
emit layoutChanged();
}
}
void
RideFileTableModel::deleted()
{
// we don't need to disconnect since they're free'd up by QT
ride = NULL;
beginResetModel();
endResetModel();
dataChanged(createIndex(0,0), createIndex(90,999999));
}
void
RideFileTableModel::setHeadings(RideFile::SeriesType series)
{
headings_.clear();
headingsType.clear();
// set the headings array
if (series == RideFile::secs || ride->areDataPresent()->secs) {
headings_ << tr("Time");
headingsType << RideFile::secs;
}
if (series == RideFile::km || ride->areDataPresent()->km) {
headings_ << tr("Distance");
headingsType << RideFile::km;
}
if (series == RideFile::watts || ride->areDataPresent()->watts) {
headings_ << tr("Power");
headingsType << RideFile::watts;
}
if (series == RideFile::nm || ride->areDataPresent()->nm) {
headings_ << tr("Torque");
headingsType << RideFile::nm;
}
if (series == RideFile::cad || ride->areDataPresent()->cad) {
headings_ << tr("Cadence");
headingsType << RideFile::cad;
}
if (series == RideFile::hr || ride->areDataPresent()->hr) {
headings_ << tr("Heartrate");
headingsType << RideFile::hr;
}
if (series == RideFile::kph || ride->areDataPresent()->kph) {
headings_ << tr("Speed");
headingsType << RideFile::kph;
}
if (series == RideFile::alt || ride->areDataPresent()->alt) {
headings_ << tr("Altitude");
headingsType << RideFile::alt;
}
if (series == RideFile::lat || ride->areDataPresent()->lat) {
headings_ << tr("Latitude");
headingsType << RideFile::lat;
}
if (series == RideFile::lon || ride->areDataPresent()->lon) {
headings_ << tr("Longitude");
headingsType << RideFile::lon;
}
if (series == RideFile::headwind || ride->areDataPresent()->headwind) {
headings_ << tr("Headwind");
headingsType << RideFile::headwind;
}
if (series == RideFile::slope || ride->areDataPresent()->slope) {
headings_ << tr("Slope");
headingsType << RideFile::slope;
}
if (series == RideFile::temp || ride->areDataPresent()->temp) {
headings_ << tr("Temperature");
headingsType << RideFile::temp;
}
if (series == RideFile::interval || ride->areDataPresent()->interval) {
headings_ << tr("Interval");
headingsType << RideFile::interval;
}
}
Qt::ItemFlags
RideFileTableModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::ItemIsEditable;
else
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable |
Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant
RideFileTableModel::data(const QModelIndex & index, int role) const
{
if (role == Qt::ToolTipRole) return toolTip(index.row(), columnType(index.column()));
if (index.row() >= ride->dataPoints().count() || index.column() >= headings_.count())
return QVariant();
else {
return ride->getPoint(index.row(), headingsType[index.column()]);
}
}
QVariant
RideFileTableModel::headerData(int section, Qt::Orientation orient, int role) const
{
if (role != Qt::DisplayRole) return QVariant();
if (orient == Qt::Horizontal) {
if (section >= headings_.count())
return QVariant();
else {
return headings_[section];
}
} else {
return QString("%1").arg(section+1);
}
}
int
RideFileTableModel::rowCount(const QModelIndex &) const
{
if (ride) return ride->dataPoints().count();
else return 0;
}
int
RideFileTableModel::columnCount(const QModelIndex &) const
{
if (ride) return headingsType.count();
else return 0;
}
bool
RideFileTableModel::setData(const QModelIndex & index, const QVariant &value, int role)
{
if (index.row() >= ride->dataPoints().count() || index.column() >= headings_.count())
return false;
else if (role == Qt::EditRole) {
ride->command->setPointValue(index.row(), headingsType[index.column()], value.toDouble());
return true;
} else return false;
}
bool
RideFileTableModel::setHeaderData(int section, Qt::Orientation , const QVariant & value, int)
{
if (section >= headings_.count()) return false;
else {
headings_[section] = value.toString();
return true;
}
}
bool
RideFileTableModel::insertRow(int row, const QModelIndex &parent)
{
return insertRows(row, 1, parent);
}
bool
RideFileTableModel::insertRows(int row, int count, const QModelIndex &)
{
if (row >= ride->dataPoints().count()) return false;
else {
while (count--) {
struct RideFilePoint *p = new RideFilePoint;
ride->command->insertPoint(row, p);
}
return true;
}
}
bool
RideFileTableModel::appendRows(QVector<RideFilePoint>newRows)
{
ride->command->appendPoints(newRows);
return true;
}
bool
RideFileTableModel::removeRows(int row, int count, const QModelIndex &)
{
if ((row + count) > ride->dataPoints().count()) return false;
ride->command->deletePoints(row, count);
return true;
}
bool
RideFileTableModel::insertColumn(RideFile::SeriesType series)
{
if (headingsType.contains(series)) return false; // already there
ride->command->setDataPresent(series, true);
return true;
}
bool
RideFileTableModel::insertColumns(int, int, const QModelIndex &)
{
// WE DON'T SUPPORT THIS
// use insertColumn(RideFile::SeriesType) instead.
return false;
}
bool
RideFileTableModel::removeColumn(RideFile::SeriesType series)
{
if (headingsType.contains(series)) {
ride->command->setDataPresent(series, false);
return true;
} else
return false; // its not there
}
bool
RideFileTableModel::removeColumns (int , int , const QModelIndex &)
{
// WE DON'T SUPPORT THIS
// use removeColumn(RideFile::SeriesType) instead.
return false;
}
void
RideFileTableModel::setValue(int row, int column, double value)
{
ride->command->setPointValue(row, headingsType[column], value);
}
double
RideFileTableModel::getValue(int row, int column)
{
return ride->getPointValue(row, headingsType[column]);
}
void
RideFileTableModel::forceRedraw()
{
// tell the view to redraw everything
if (ride)
dataChanged(createIndex(0,0), createIndex(headingsType.count(), ride->dataPoints().count()));
}
//
// RideCommand has made changes...
//
void
RideFileTableModel::beginCommand(bool undo, RideCommand *cmd)
{
switch (cmd->type) {
case RideCommand::SetPointValue:
break;
case RideCommand::InsertPoint:
{
InsertPointCommand *dp = (InsertPointCommand *)cmd;
if (!undo) beginInsertRows(QModelIndex(), dp->row, dp->row);
else beginRemoveRows(QModelIndex(), dp->row, dp->row);
break;
}
case RideCommand::DeletePoint:
{
DeletePointCommand *dp = (DeletePointCommand *)cmd;
if (undo) beginInsertRows(QModelIndex(), dp->row, dp->row);
else beginRemoveRows(QModelIndex(), dp->row, dp->row);
break;
}
case RideCommand::DeletePoints:
{
DeletePointsCommand *ds = (DeletePointsCommand *)cmd;
if (undo) beginInsertRows(QModelIndex(), ds->row, ds->row + ds->count - 1);
else beginRemoveRows(QModelIndex(), ds->row, ds->row + ds->count - 1);
break;
}
case RideCommand::AppendPoints:
{
AppendPointsCommand *ap = (AppendPointsCommand *)cmd;
if (!undo) beginInsertRows(QModelIndex(), ap->row, ap->row + ap->count - 1);
else beginRemoveRows(QModelIndex(), ap->row, ap->row + ap->count - 1);
break;
}
default:
break;
}
}
void
RideFileTableModel::endCommand(bool undo, RideCommand *cmd)
{
switch (cmd->type) {
case RideCommand::SetPointValue:
{
SetPointValueCommand *spv = (SetPointValueCommand*)cmd;
QModelIndex cell(index(spv->row,headingsType.indexOf(spv->series)));
dataChanged(cell, cell);
break;
}
case RideCommand::InsertPoint:
if (!undo) endInsertRows();
else endRemoveRows();
break;
case RideCommand::DeletePoint:
case RideCommand::DeletePoints:
if (undo) endInsertRows();
else endRemoveRows();
break;
case RideCommand::AppendPoints:
if (undo) endRemoveRows();
else endInsertRows();
break;
case RideCommand::SetDataPresent:
setHeadings();
emit layoutChanged();
break;
default:
break;
}
}
// Tooltips are kept in a QMap, since they SHOULD be sparse
static QString xsstring(int x, RideFile::SeriesType series)
{
return QString("%1:%2").arg((int)x).arg(static_cast<int>(series));
}
void
RideFileTableModel::setToolTip(int row, RideFile::SeriesType series, QString text)
{
QString key = xsstring(row, series);
// if text is blank we are removing it
if (text == "") tooltips.remove(key);
// if text is non-blank we are changing it
if (text != "") tooltips.insert(key, text);
}
QString
RideFileTableModel::toolTip(int row, RideFile::SeriesType series) const
{
QString key = xsstring(row, series);
return tooltips.value(key, "");
}