/* * models.cpp * * classes for the equipment models of Subsurface * */ #include "models.h" #include #include 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; } struct 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. * */ TreeItemDT::~TreeItemDT() { qDeleteAll(childs); } int TreeItemDT::row() const { if (parent) return parent->childs.indexOf(const_cast(this)); return 0; } QVariant TreeItemDT::data(int column, int role) const { QVariant ret; switch (column) { case NR: ret = tr("#"); break; case DATE: ret = tr("Date"); break; case RATING: ret = UTF8_BLACKSTAR; break; case DEPTH: ret = (get_units()->length == units::METERS) ? tr("m") : tr("ft"); break; case DURATION: ret = tr("min"); break; case TEMPERATURE: ret = QString("%1%2").arg(UTF8_DEGREE).arg( (get_units()->temperature == units::CELSIUS) ? "C" : "F"); break; case TOTALWEIGHT: ret = (get_units()->weight == units::KG) ? tr("kg") : 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; } struct TripItem : public TreeItemDT { virtual QVariant data(int column, int role) const; dive_trip_t* trip; }; QVariant TripItem::data(int column, int role) const { QVariant ret; if (column != LOCATION) { return ret; } switch (role) { case Qt::DisplayRole: ret = QString(trip->location); } return ret; } struct DiveItem : public TreeItemDT { virtual QVariant data(int column, int role) const; struct dive* dive; QString displayDuration() const; QString displayDepth() const; QString displayTemperature() const; QString displayWeight() const; QString displaySac() const; int weight() const; }; QVariant DiveItem::data(int column, int role) const { QVariant retVal; if (role == Qt::TextAlignmentRole) { switch (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 (column) { case NR: retVal = dive->number; break; case DATE: retVal = QString(get_dive_date_string(dive->when)); break; case DEPTH: retVal = displayDepth(); break; case DURATION: retVal = displayDuration(); break; case TEMPERATURE: retVal = displayTemperature(); break; case TOTALWEIGHT: retVal = displayWeight(); break; case SUIT: retVal = QString(dive->suit); break; case SAC: retVal = displaySac(); break; case OTU: retVal = dive->otu; break; case MAXCNS: retVal = dive->maxcns; break; case LOCATION: retVal = QString(dive->location); break; case RATING: retVal = dive->rating; break; } } return retVal; } 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 = weight() % 1000; int kg = weight() / 1000; str = QString("%1.%2").arg(kg).arg((unsigned)(gr + 500) / 100); } else { str = QString("%1").arg((unsigned)(grams_to_lbs(weight()) + 0.5)); } return str; } int DiveItem::weight() const { weight_t tw = { total_weight(dive) }; return tw.grams; } DiveTripModel::DiveTripModel(QObject* parent) : QAbstractItemModel(parent) { rootItem = new TreeItemDT(); setupModelData(); } DiveTripModel::~DiveTripModel() { delete rootItem; } int DiveTripModel::columnCount(const QModelIndex& parent) const { if (parent.isValid()) return static_cast(parent.internalPointer())->columnCount(); else return rootItem->columnCount(); } QVariant DiveTripModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole) return QVariant(); TreeItemDT* item = static_cast(index.internalPointer()); return item->data(index.column(), role); } Qt::ItemFlags DiveTripModel::flags(const QModelIndex& index) const { if (!index.isValid()) return 0; return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QVariant DiveTripModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) return rootItem->data(section, role); return QVariant(); } QModelIndex DiveTripModel::index(int row, int column, const QModelIndex& parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); TreeItemDT* parentItem = (!parent.isValid()) ? rootItem : static_cast(parent.internalPointer()); TreeItemDT* childItem = parentItem->childs[row]; return (childItem) ? createIndex(row, column, childItem) : QModelIndex(); } QModelIndex DiveTripModel::parent(const QModelIndex& index) const { if (!index.isValid()) return QModelIndex(); TreeItemDT* childItem = static_cast(index.internalPointer()); TreeItemDT* parentItem = childItem->parent; if (parentItem == rootItem) return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem); } int DiveTripModel::rowCount(const QModelIndex& parent) const { TreeItemDT* parentItem; if (parent.column() > 0) { return 0; } if (!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); return parentItem->childs.count(); } void DiveTripModel::setupModelData() { int i = dive_table.nr; while (--i >= 0) { struct dive* dive = get_dive(i); dive_trip_t* trip = dive->divetrip; DiveItem* diveItem = new DiveItem(); diveItem->dive = dive; if (!trip) { diveItem->parent = rootItem; rootItem->childs.push_back(diveItem); continue; } if (!trips.keys().contains(trip)) { TripItem* tripItem = new TripItem(); tripItem->trip = trip; tripItem->parent = rootItem; tripItem->childs.push_back(diveItem); trips[trip] = tripItem; rootItem->childs.push_back(tripItem); continue; } TripItem* tripItem = trips[trip]; tripItem->childs.push_back(diveItem); } }