mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
04e59a0e1c
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
658 lines
14 KiB
C++
658 lines
14 KiB
C++
/*
|
|
* models.cpp
|
|
*
|
|
* classes for the equipment models of Subsurface
|
|
*
|
|
*/
|
|
#include "models.h"
|
|
#include <QtDebug>
|
|
|
|
extern struct tank_info tank_info[100];
|
|
|
|
CylindersModel::CylindersModel(QObject* parent): QAbstractTableModel(parent)
|
|
{
|
|
}
|
|
|
|
QVariant CylindersModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
QVariant ret;
|
|
if (orientation == Qt::Vertical) {
|
|
return ret;
|
|
}
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
switch(section) {
|
|
case TYPE:
|
|
ret = tr("Type");
|
|
break;
|
|
case SIZE:
|
|
ret = tr("Size");
|
|
break;
|
|
case MAXPRESS:
|
|
ret = tr("MaxPress");
|
|
break;
|
|
case START:
|
|
ret = tr("Start");
|
|
break;
|
|
case END:
|
|
ret = tr("End");
|
|
break;
|
|
case O2:
|
|
ret = tr("O2%");
|
|
break;
|
|
case HE:
|
|
ret = tr("He%");
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int CylindersModel::columnCount(const QModelIndex& parent) const
|
|
{
|
|
return 7;
|
|
}
|
|
|
|
QVariant CylindersModel::data(const QModelIndex& index, int role) const
|
|
{
|
|
QVariant ret;
|
|
if (!index.isValid() || index.row() >= MAX_CYLINDERS) {
|
|
return ret;
|
|
}
|
|
cylinder_t& cyl = current_dive->cylinder[index.row()];
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
switch(index.column()) {
|
|
case TYPE:
|
|
ret = QString(cyl.type.description);
|
|
break;
|
|
case SIZE:
|
|
ret = cyl.type.size.mliter;
|
|
break;
|
|
case MAXPRESS:
|
|
ret = cyl.type.workingpressure.mbar;
|
|
break;
|
|
case START:
|
|
ret = cyl.start.mbar;
|
|
break;
|
|
case END:
|
|
ret = cyl.end.mbar;
|
|
break;
|
|
case O2:
|
|
ret = cyl.gasmix.o2.permille;
|
|
break;
|
|
case HE:
|
|
ret = cyl.gasmix.he.permille;
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int CylindersModel::rowCount(const QModelIndex& parent) const
|
|
{
|
|
return usedRows[current_dive];
|
|
}
|
|
|
|
void CylindersModel::add(cylinder_t* cyl)
|
|
{
|
|
if (usedRows[current_dive] >= MAX_CYLINDERS) {
|
|
free(cyl);
|
|
}
|
|
|
|
int row = usedRows[current_dive];
|
|
|
|
cylinder_t& cylinder = current_dive->cylinder[row];
|
|
|
|
cylinder.end.mbar = cyl->end.mbar;
|
|
cylinder.start.mbar = cyl->start.mbar;
|
|
|
|
beginInsertRows(QModelIndex(), row, row);
|
|
usedRows[current_dive]++;
|
|
endInsertRows();
|
|
}
|
|
|
|
void CylindersModel::update()
|
|
{
|
|
if (usedRows[current_dive] > 0) {
|
|
beginRemoveRows(QModelIndex(), 0, usedRows[current_dive]-1);
|
|
endRemoveRows();
|
|
}
|
|
if (usedRows[current_dive] > 0) {
|
|
beginInsertRows(QModelIndex(), 0, usedRows[current_dive]-1);
|
|
endInsertRows();
|
|
}
|
|
}
|
|
|
|
void CylindersModel::clear()
|
|
{
|
|
if (usedRows[current_dive] > 0) {
|
|
beginRemoveRows(QModelIndex(), 0, usedRows[current_dive]-1);
|
|
usedRows[current_dive] = 0;
|
|
endRemoveRows();
|
|
}
|
|
}
|
|
|
|
void WeightModel::clear()
|
|
{
|
|
if (usedRows[current_dive] > 0) {
|
|
beginRemoveRows(QModelIndex(), 0, usedRows[current_dive]-1);
|
|
usedRows[current_dive] = 0;
|
|
endRemoveRows();
|
|
}
|
|
}
|
|
|
|
int WeightModel::columnCount(const QModelIndex& parent) const
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
QVariant WeightModel::data(const QModelIndex& index, int role) const
|
|
{
|
|
QVariant ret;
|
|
if (!index.isValid() || index.row() >= MAX_WEIGHTSYSTEMS) {
|
|
return ret;
|
|
}
|
|
weightsystem_t *ws = ¤t_dive->weightsystem[index.row()];
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
switch(index.column()) {
|
|
case TYPE:
|
|
ret = QString(ws->description);
|
|
break;
|
|
case WEIGHT:
|
|
if (get_units()->weight == units::KG) {
|
|
int gr = ws->weight.grams % 1000;
|
|
int kg = ws->weight.grams / 1000;
|
|
ret = QString("%1.%2").arg(kg).arg((unsigned)(gr + 500) / 100);
|
|
} else {
|
|
ret = QString("%1").arg((unsigned)(grams_to_lbs(ws->weight.grams) + 0.5));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int WeightModel::rowCount(const QModelIndex& parent) const
|
|
{
|
|
return usedRows[current_dive];
|
|
}
|
|
|
|
QVariant WeightModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
QVariant ret;
|
|
if (orientation == Qt::Vertical) {
|
|
return ret;
|
|
}
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
switch(section) {
|
|
case TYPE:
|
|
ret = tr("Type");
|
|
break;
|
|
case WEIGHT:
|
|
ret = tr("Weight");
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void WeightModel::add(weightsystem_t* weight)
|
|
{
|
|
if (usedRows[current_dive] >= MAX_WEIGHTSYSTEMS) {
|
|
free(weight);
|
|
}
|
|
|
|
int row = usedRows[current_dive];
|
|
|
|
weightsystem_t *ws = ¤t_dive->weightsystem[row];
|
|
|
|
ws->description = weight->description;
|
|
ws->weight.grams = weight->weight.grams;
|
|
|
|
beginInsertRows(QModelIndex(), row, row);
|
|
usedRows[current_dive]++;
|
|
endInsertRows();
|
|
}
|
|
|
|
void WeightModel::update()
|
|
{
|
|
}
|
|
|
|
void TankInfoModel::add(const QString& description)
|
|
{
|
|
// When the user `creates` a new one on the combobox.
|
|
// for now, empty till dirk cleans the GTK code.
|
|
}
|
|
|
|
void TankInfoModel::clear()
|
|
{
|
|
}
|
|
|
|
int TankInfoModel::columnCount(const QModelIndex& parent) const
|
|
{
|
|
return 3;
|
|
}
|
|
|
|
QVariant TankInfoModel::data(const QModelIndex& index, int role) const
|
|
{
|
|
QVariant ret;
|
|
if (!index.isValid()) {
|
|
return ret;
|
|
}
|
|
struct tank_info *info = &tank_info[index.row()];
|
|
|
|
int ml = info->ml;
|
|
|
|
int bar = ((info->psi) ? psi_to_bar(info->psi) : info->bar) * 1000 + 0.5;
|
|
|
|
if (info->cuft) {
|
|
double airvolume = cuft_to_l(info->cuft) * 1000.0;
|
|
ml = airvolume / bar_to_atm(bar) + 0.5;
|
|
}
|
|
if (role == Qt::DisplayRole) {
|
|
switch(index.column()) {
|
|
case BAR: ret = bar;
|
|
break;
|
|
case ML: ret = ml;
|
|
break;
|
|
case DESCRIPTION:
|
|
ret = QString(info->name);
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
QVariant TankInfoModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
QVariant ret;
|
|
|
|
if (orientation != Qt::Horizontal)
|
|
return ret;
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
switch(section) {
|
|
case BAR:
|
|
ret = tr("Bar");
|
|
break;
|
|
case ML:
|
|
ret = tr("Ml");
|
|
break;
|
|
case DESCRIPTION:
|
|
ret = tr("Description");
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int TankInfoModel::rowCount(const QModelIndex& parent) const
|
|
{
|
|
return rows+1;
|
|
}
|
|
|
|
TankInfoModel::TankInfoModel() : QAbstractTableModel(), rows(-1)
|
|
{
|
|
struct tank_info *info = tank_info;
|
|
for (info = tank_info ; info->name; info++, rows++);
|
|
|
|
if (rows > -1) {
|
|
beginInsertRows(QModelIndex(), 0, rows);
|
|
endInsertRows();
|
|
}
|
|
}
|
|
|
|
void TankInfoModel::update()
|
|
{
|
|
if(rows > -1) {
|
|
beginRemoveRows(QModelIndex(), 0, rows);
|
|
endRemoveRows();
|
|
}
|
|
struct tank_info *info = tank_info;
|
|
for (info = tank_info ; info->name; info++, rows++);
|
|
|
|
if (rows > -1) {
|
|
beginInsertRows(QModelIndex(), 0, rows);
|
|
endInsertRows();
|
|
}
|
|
}
|
|
|
|
|
|
/*! A DiveItem for use with a DiveTripModel
|
|
*
|
|
* A simple class which wraps basic stats for a dive (e.g. duration, depth) and
|
|
* tidies up after it's children. This is done manually as we don't inherit from
|
|
* QObject.
|
|
*
|
|
*/
|
|
class DiveItem
|
|
{
|
|
public:
|
|
DiveItem(): dive(NULL), parentItem(NULL) {}
|
|
|
|
DiveItem(struct dive *d, DiveItem *parent = NULL);
|
|
|
|
~DiveItem() { qDeleteAll(childlist); }
|
|
|
|
int diveNumber() const { return dive->number; }
|
|
const QString diveDateTime() const { return get_dive_date_string(dive->when); }
|
|
int diveDuration() const { return dive->duration.seconds; }
|
|
int diveDepth() const { return dive->maxdepth.mm; }
|
|
int diveSac() const { return dive->sac; }
|
|
int diveOtu() const { return dive->otu; }
|
|
int diveMaxcns() const { return dive->maxcns; }
|
|
|
|
int diveWeight() const
|
|
{
|
|
weight_t tw = { total_weight(dive) };
|
|
return tw.grams;
|
|
}
|
|
|
|
int diveRating() const { return dive->rating; }
|
|
|
|
QString displayDuration() const;
|
|
QString displayDepth() const;
|
|
QString displayTemperature() const;
|
|
QString displayWeight() const;
|
|
QString displaySac() const;
|
|
const QString diveLocation() const { return dive->location; }
|
|
const QString diveSuit() const { return dive->suit; }
|
|
DiveItem *parent() const { return parentItem; }
|
|
const QList<DiveItem *>& children() const { return childlist; }
|
|
|
|
void addChild(DiveItem* item) {
|
|
item->parentItem = this;
|
|
childlist.push_back(item);
|
|
} /* parent = self */
|
|
|
|
private:
|
|
struct dive *dive;
|
|
DiveItem *parentItem;
|
|
QList <DiveItem*> childlist;
|
|
};
|
|
|
|
|
|
DiveItem::DiveItem(struct dive *d, DiveItem *p):
|
|
dive(d),
|
|
parentItem(p)
|
|
{
|
|
if (parentItem)
|
|
parentItem->addChild(this);
|
|
}
|
|
|
|
QString DiveItem::displayDepth() const
|
|
{
|
|
const int scale = 1000;
|
|
QString fract, str;
|
|
if (get_units()->length == units::METERS) {
|
|
fract = QString::number((unsigned)(dive->maxdepth.mm % scale) / 10);
|
|
str = QString("%1.%2").arg((unsigned)(dive->maxdepth.mm / scale)).arg(fract, 2, QChar('0'));
|
|
}
|
|
if (get_units()->length == units::FEET) {
|
|
str = QString::number(mm_to_feet(dive->maxdepth.mm),'f',0);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
QString DiveItem::displayDuration() const
|
|
{
|
|
int hrs, mins, secs;
|
|
|
|
secs = dive->duration.seconds % 60;
|
|
mins = dive->duration.seconds / 60;
|
|
hrs = mins / 60;
|
|
mins -= hrs * 60;
|
|
|
|
QString displayTime;
|
|
if (hrs)
|
|
displayTime = QString("%1:%2:").arg(hrs).arg(mins, 2, 10, QChar('0'));
|
|
else
|
|
displayTime = QString("%1:").arg(mins);
|
|
displayTime += QString("%1").arg(secs, 2, 10, QChar('0'));
|
|
return displayTime;
|
|
}
|
|
|
|
QString DiveItem::displayTemperature() const
|
|
{
|
|
QString str;
|
|
|
|
if (get_units()->temperature == units::CELSIUS) {
|
|
str = QString::number(mkelvin_to_C(dive->watertemp.mkelvin), 'f', 1);
|
|
} else {
|
|
str = QString::number(mkelvin_to_F(dive->watertemp.mkelvin), 'f', 1);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
QString DiveItem::displaySac() const
|
|
{
|
|
QString str;
|
|
|
|
if (get_units()->volume == units::LITER) {
|
|
str = QString::number(dive->sac / 1000, 'f', 1);
|
|
} else {
|
|
str = QString::number(ml_to_cuft(dive->sac), 'f', 2);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
QString DiveItem::displayWeight() const
|
|
{
|
|
QString str;
|
|
|
|
if (get_units()->weight == units::KG) {
|
|
int gr = diveWeight() % 1000;
|
|
int kg = diveWeight() / 1000;
|
|
str = QString("%1.%2").arg(kg).arg((unsigned)(gr + 500) / 100);
|
|
} else {
|
|
str = QString("%1").arg((unsigned)(grams_to_lbs(diveWeight()) + 0.5));
|
|
}
|
|
return str;
|
|
}
|
|
|
|
DiveTripModel::DiveTripModel(QObject *parent) : QAbstractItemModel(parent)
|
|
{
|
|
rootItem = new DiveItem;
|
|
int i;
|
|
struct dive *d;
|
|
|
|
for_each_dive(i, d) {
|
|
new DiveItem(d, rootItem);
|
|
}
|
|
}
|
|
|
|
|
|
Qt::ItemFlags DiveTripModel::flags(const QModelIndex &index) const
|
|
{
|
|
Qt::ItemFlags diveFlags = QAbstractItemModel::flags(index);
|
|
if (index.isValid()) {
|
|
diveFlags |= Qt::ItemIsSelectable|Qt::ItemIsEnabled;
|
|
}
|
|
return diveFlags;
|
|
}
|
|
|
|
|
|
QVariant DiveTripModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid())
|
|
return QVariant();
|
|
|
|
DiveItem *item = static_cast<DiveItem*>(index.internalPointer());
|
|
|
|
QVariant retVal;
|
|
if (role == Qt::TextAlignmentRole) {
|
|
switch (index.column()) {
|
|
case DATE: /* fall through */
|
|
case SUIT: /* fall through */
|
|
case LOCATION:
|
|
retVal = Qt::AlignLeft;
|
|
break;
|
|
default:
|
|
retVal = Qt::AlignRight;
|
|
break;
|
|
}
|
|
}
|
|
if (role == Qt::DisplayRole) {
|
|
switch (index.column()) {
|
|
case NR:
|
|
retVal = item->diveNumber();
|
|
break;
|
|
case DATE:
|
|
retVal = item->diveDateTime();
|
|
break;
|
|
case DEPTH:
|
|
retVal = item->displayDepth();
|
|
break;
|
|
case DURATION:
|
|
retVal = item->displayDuration();
|
|
break;
|
|
case TEMPERATURE:
|
|
retVal = item->displayTemperature();
|
|
break;
|
|
case TOTALWEIGHT:
|
|
retVal = item->displayWeight();
|
|
break;
|
|
case SUIT:
|
|
retVal = item->diveSuit();
|
|
break;
|
|
case SAC:
|
|
retVal = item->displaySac();
|
|
break;
|
|
case OTU:
|
|
retVal = item->diveOtu();
|
|
break;
|
|
case MAXCNS:
|
|
retVal = item->diveMaxcns();
|
|
break;
|
|
case LOCATION:
|
|
retVal = item->diveLocation();
|
|
break;
|
|
case RATING:
|
|
retVal = item->diveRating();
|
|
break;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
|
|
QVariant DiveTripModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
QVariant ret;
|
|
if (orientation != Qt::Horizontal)
|
|
return ret;
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
switch(section) {
|
|
case NR:
|
|
ret = tr("#");
|
|
break;
|
|
case DATE:
|
|
ret = tr("Date");
|
|
break;
|
|
case RATING:
|
|
ret = UTF8_BLACKSTAR;
|
|
break;
|
|
case DEPTH:
|
|
if (get_units()->length == units::METERS)
|
|
ret = tr("m");
|
|
else
|
|
ret = tr("ft");
|
|
break;
|
|
case DURATION:
|
|
ret = tr("min");
|
|
break;
|
|
case TEMPERATURE:
|
|
if (get_units()->temperature == units::CELSIUS)
|
|
ret = QString("%1%2").arg(UTF8_DEGREE).arg("C");
|
|
else
|
|
ret = QString("%1%2").arg(UTF8_DEGREE).arg("F");
|
|
break;
|
|
case TOTALWEIGHT:
|
|
if (get_units()->weight == units::KG)
|
|
ret = tr("kg");
|
|
else
|
|
ret = tr("lbs");
|
|
break;
|
|
case SUIT:
|
|
ret = tr("Suit");
|
|
break;
|
|
case CYLINDER:
|
|
ret = tr("Cyl");
|
|
break;
|
|
case NITROX:
|
|
ret = QString("O%1%").arg(UTF8_SUBSCRIPT_2);
|
|
break;
|
|
case SAC:
|
|
ret = tr("SAC");
|
|
break;
|
|
case OTU:
|
|
ret = tr("OTU");
|
|
break;
|
|
case MAXCNS:
|
|
ret = tr("maxCNS");
|
|
break;
|
|
case LOCATION:
|
|
ret = tr("Location");
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int DiveTripModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
/* only allow kids in column 0 */
|
|
if (parent.isValid() && parent.column() > 0)
|
|
return 0;
|
|
DiveItem *item = itemForIndex(parent);
|
|
return item ? item->children().count() : 0;
|
|
}
|
|
|
|
int DiveTripModel::columnCount(const QModelIndex &parent) const
|
|
{
|
|
return parent.isValid() && parent.column() != 0 ? 0 : COLUMNS;
|
|
}
|
|
|
|
|
|
QModelIndex DiveTripModel::index(int row, int column, const QModelIndex &parent) const
|
|
{
|
|
|
|
if (!rootItem || row < 0 || column < 0 || column >= COLUMNS ||
|
|
(parent.isValid() && parent.column() != 0))
|
|
return QModelIndex();
|
|
|
|
DiveItem *parentItem = itemForIndex(parent);
|
|
Q_ASSERT(parentItem);
|
|
if (DiveItem *item = parentItem->children().at(row))
|
|
return createIndex(row, column, item);
|
|
return QModelIndex();
|
|
}
|
|
|
|
|
|
QModelIndex DiveTripModel::parent(const QModelIndex &childIndex) const
|
|
{
|
|
if (!childIndex.isValid())
|
|
return QModelIndex();
|
|
|
|
DiveItem *child = static_cast<DiveItem*>(childIndex.internalPointer());
|
|
DiveItem *parent = child->parent();
|
|
|
|
if (parent == rootItem)
|
|
return QModelIndex();
|
|
|
|
return createIndex(parent->children().indexOf(child), 0, parent);
|
|
}
|
|
|
|
|
|
DiveItem* DiveTripModel::itemForIndex(const QModelIndex &index) const
|
|
{
|
|
if (index.isValid()) {
|
|
DiveItem *item = static_cast<DiveItem*>(index.internalPointer());
|
|
return item;
|
|
}
|
|
return rootItem;
|
|
}
|