subsurface/qt-ui/models.cpp
Dirk Hohndel e156b00f05 Fix column headings for divelist
This looks better and is consistent with the Gtk version.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-04-24 16:02:41 -07:00

564 lines
11 KiB
C++

/*
* models.cpp
*
* classes for the equipment models of Subsurface
*
*/
#include "models.h"
#include "../dive.h"
#include "../divelist.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;
}
dive *d = get_dive(selected_dive);
cylinder_t& cyl = d->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[currentDive];
}
void CylindersModel::add(cylinder_t* cyl)
{
if (usedRows[currentDive] >= MAX_CYLINDERS) {
free(cyl);
}
int row = usedRows[currentDive];
cylinder_t& cylinder = currentDive->cylinder[row];
cylinder.end.mbar = cyl->end.mbar;
cylinder.start.mbar = cyl->start.mbar;
beginInsertRows(QModelIndex(), row, row);
usedRows[currentDive]++;
endInsertRows();
}
void CylindersModel::update()
{
if (usedRows[currentDive] > 0) {
beginRemoveRows(QModelIndex(), 0, usedRows[currentDive]-1);
endRemoveRows();
}
currentDive = get_dive(selected_dive);
if (usedRows[currentDive] > 0) {
beginInsertRows(QModelIndex(), 0, usedRows[currentDive]-1);
endInsertRows();
}
}
void CylindersModel::clear()
{
if (usedRows[currentDive] > 0) {
beginRemoveRows(QModelIndex(), 0, usedRows[currentDive]-1);
usedRows[currentDive] = 0;
endRemoveRows();
}
}
void WeightModel::clear()
{
}
int WeightModel::columnCount(const QModelIndex& parent) const
{
return 0;
}
QVariant WeightModel::data(const QModelIndex& index, int role) const
{
return QVariant();
}
int WeightModel::rowCount(const QModelIndex& parent) const
{
return rows;
}
QVariant WeightModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant ret;
if (orientation == Qt::Vertical) {
return ret;
}
switch(section) {
case TYPE:
ret = tr("Type");
break;
case WEIGHT:
ret = tr("Weight");
break;
}
return ret;
}
void WeightModel::add(weight_t* weight)
{
}
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:
explicit DiveItem(): number(0), dateTime(QString()), seconds(0), mm(0), location(QString()) { parentItem = 0; }
explicit DiveItem(int num, QString dt, int, int, QString loc, DiveItem *parent = 0);
~DiveItem() { qDeleteAll(childlist); }
int diveNumber() const { return number; }
const QString& diveDateTime() const { return dateTime; }
int diveDuration() const { return seconds; }
int diveDepth() const { return mm; }
QString displayDuration() const;
QString displayDepth() const;
const QString& diveLocation() const { return location; }
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:
int number;
QString dateTime;
int seconds;
int mm;
QString location;
DiveItem *parentItem;
QList <DiveItem*> childlist;
};
DiveItem::DiveItem(int num, QString dt, int dur, int dep, QString loc, DiveItem *p):
number(num), dateTime(dt), seconds(dur), mm(dep), location(loc), 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)(mm % scale) / 10);
str = QString("%1.%2").arg((unsigned)(mm / scale)).arg(fract);
}
if (get_units()->length == units::FEET) {
str = QString::number(mm_to_feet(mm),'f',2);
}
return str;
}
QString DiveItem::displayDuration() const
{
int hrs, mins, secs, val;
const int minutes_hour = 60;
const int seconds_minute= 60;
val = seconds;
secs = seconds % seconds_minute;
val /= seconds_minute;
mins = val % seconds_minute;
val /= minutes_hour;
hrs = val % minutes_hour;
QString displayTime;
if (hrs > 0)
displayTime = QString("%1:%2:%3").arg(hrs).arg(mins).arg(secs);
else
displayTime = QString("%1:%2").arg(mins).arg(secs);
return displayTime;
}
DiveTripModel::DiveTripModel(QObject *parent) : QAbstractItemModel(parent)
{
rootItem = new DiveItem;
int i;
struct dive *d;
for_each_dive(i, d) {
struct tm tm;
char *buffer;
utc_mkdate(d->when, &tm);
buffer = get_dive_date_string(&tm);
new DiveItem(d->number,
buffer,
d->duration.seconds,
d->maxdepth.mm,
d->location,
rootItem);
free(buffer);
}
}
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 DURATION: /* fall through */
case DEPTH:
retVal = Qt::AlignRight;
break;
default:
retVal = Qt::AlignLeft;
}
}
if (role == Qt::DisplayRole) {
switch (index.column()) {
case NR:
retVal = item->diveNumber();
break;
case DATE:
retVal = item->diveDateTime();
break;
case DURATION:
retVal = item->displayDuration();
//retVal = item->diveDuration();
break;
case DEPTH:
retVal = item->displayDepth();
//retVal = item->diveDepth();
break;
case LOCATION:
retVal = item->diveLocation();
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 = QString::fromUtf8(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(QString::fromUtf8(UTF8_DEGREE)).arg("C");
else
ret = QString("%1%2").arg(QString::fromUtf8(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(QString::fromUtf8(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;
}