2013-04-14 03:44:02 +00:00
|
|
|
/*
|
|
|
|
* models.cpp
|
|
|
|
*
|
|
|
|
* classes for the equipment models of Subsurface
|
|
|
|
*
|
|
|
|
*/
|
2013-04-13 13:17:59 +00:00
|
|
|
#include "models.h"
|
2013-11-13 12:45:54 +00:00
|
|
|
#include "diveplanner.h"
|
|
|
|
#include "mainwindow.h"
|
2013-05-21 19:03:05 +00:00
|
|
|
#include "../helpers.h"
|
2013-05-22 17:02:28 +00:00
|
|
|
#include "../dive.h"
|
2013-06-07 14:43:45 +00:00
|
|
|
#include "../device.h"
|
2013-06-18 07:33:03 +00:00
|
|
|
#include "../statistics.h"
|
2013-06-17 22:58:26 +00:00
|
|
|
#include "../qthelper.h"
|
2013-06-07 18:25:29 +00:00
|
|
|
|
2013-05-02 02:51:34 +00:00
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QDebug>
|
2013-05-02 21:19:15 +00:00
|
|
|
#include <QColor>
|
|
|
|
#include <QBrush>
|
2013-05-19 13:46:49 +00:00
|
|
|
#include <QFont>
|
2013-05-22 14:00:20 +00:00
|
|
|
#include <QIcon>
|
2013-11-13 12:45:54 +00:00
|
|
|
#include <QMessageBox>
|
2013-04-24 15:57:30 +00:00
|
|
|
|
2013-06-16 14:13:32 +00:00
|
|
|
QFont defaultModelFont()
|
|
|
|
{
|
|
|
|
QFont font;
|
|
|
|
font.setPointSizeF( font.pointSizeF() * 0.8);
|
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
2013-10-11 13:50:40 +00:00
|
|
|
CleanerTableModel::CleanerTableModel(): QAbstractTableModel()
|
2013-04-13 13:17:59 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-10-11 13:50:40 +00:00
|
|
|
int CleanerTableModel::columnCount(const QModelIndex& parent) const
|
|
|
|
{
|
|
|
|
return headers.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant CleanerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
2013-04-13 13:17:59 +00:00
|
|
|
{
|
|
|
|
QVariant ret;
|
2013-05-26 03:04:31 +00:00
|
|
|
|
2013-05-02 05:00:08 +00:00
|
|
|
if (orientation == Qt::Vertical)
|
2013-04-13 13:17:59 +00:00
|
|
|
return ret;
|
|
|
|
|
2013-05-26 03:04:31 +00:00
|
|
|
switch (role) {
|
|
|
|
case Qt::FontRole:
|
2013-06-16 14:13:32 +00:00
|
|
|
ret = defaultModelFont();
|
|
|
|
break;
|
2013-05-26 03:04:31 +00:00
|
|
|
case Qt::DisplayRole:
|
2013-10-11 14:04:27 +00:00
|
|
|
ret = headers.at(section);
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
2013-10-11 14:04:27 +00:00
|
|
|
return ret;
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
|
|
|
|
2013-10-11 13:50:40 +00:00
|
|
|
void CleanerTableModel::setHeaderDataStrings(const QStringList& newHeaders)
|
|
|
|
{
|
|
|
|
headers = newHeaders;
|
|
|
|
}
|
|
|
|
|
|
|
|
CylindersModel::CylindersModel(QObject* parent): current(0), rows(0)
|
2013-04-13 13:17:59 +00:00
|
|
|
{
|
2013-11-12 02:12:43 +00:00
|
|
|
// enum{REMOVE, TYPE, SIZE, WORKINGPRESS, START, END, O2, HE, DEPTH};
|
|
|
|
setHeaderDataStrings( QStringList() << "" << tr("Type") << tr("Size") << tr("WorkPress") << tr("StartPress") << tr("EndPress") << tr("O2%") << tr("HE") << tr("Switch at"));
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
|
|
|
|
2013-11-09 22:06:26 +00:00
|
|
|
CylindersModel *CylindersModel::instance()
|
|
|
|
{
|
|
|
|
static CylindersModel *self = new CylindersModel();
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2013-06-20 04:22:09 +00:00
|
|
|
static QVariant percent_string(fraction_t fraction)
|
|
|
|
{
|
|
|
|
int permille = fraction.permille;
|
|
|
|
|
|
|
|
if (!permille)
|
|
|
|
return QVariant();
|
|
|
|
return QString("%1%").arg(permille / 10.0, 0, 'f', 1);
|
|
|
|
}
|
|
|
|
|
2013-04-13 13:17:59 +00:00
|
|
|
QVariant CylindersModel::data(const QModelIndex& index, int role) const
|
|
|
|
{
|
|
|
|
QVariant ret;
|
2013-05-26 03:04:31 +00:00
|
|
|
|
2013-05-02 05:00:08 +00:00
|
|
|
if (!index.isValid() || index.row() >= MAX_CYLINDERS)
|
2013-04-13 13:17:59 +00:00
|
|
|
return ret;
|
2013-05-02 05:00:08 +00:00
|
|
|
|
2013-05-21 19:03:05 +00:00
|
|
|
cylinder_t *cyl = ¤t->cylinder[index.row()];
|
2013-05-26 03:04:31 +00:00
|
|
|
switch (role) {
|
2013-06-20 04:42:48 +00:00
|
|
|
case Qt::FontRole: {
|
|
|
|
QFont font = defaultModelFont();
|
|
|
|
switch (index.column()) {
|
2013-11-22 01:38:28 +00:00
|
|
|
case START: font.setItalic(!cyl->start.mbar); break;
|
|
|
|
case END: font.setItalic(!cyl->end.mbar); break;
|
2013-06-20 04:42:48 +00:00
|
|
|
}
|
|
|
|
ret = font;
|
2013-05-26 03:04:31 +00:00
|
|
|
break;
|
2013-06-20 04:42:48 +00:00
|
|
|
}
|
2013-05-26 03:04:31 +00:00
|
|
|
case Qt::TextAlignmentRole:
|
2013-11-22 01:24:58 +00:00
|
|
|
ret = Qt::AlignCenter;
|
2013-11-22 01:36:39 +00:00
|
|
|
break;
|
2013-05-26 03:04:31 +00:00
|
|
|
case Qt::DisplayRole:
|
|
|
|
case Qt::EditRole:
|
2013-04-13 13:17:59 +00:00
|
|
|
switch(index.column()) {
|
|
|
|
case TYPE:
|
2013-05-21 19:03:05 +00:00
|
|
|
ret = QString(cyl->type.description);
|
2013-04-13 13:17:59 +00:00
|
|
|
break;
|
|
|
|
case SIZE:
|
2013-05-21 19:03:05 +00:00
|
|
|
// we can't use get_volume_string because the idiotic imperial tank
|
|
|
|
// sizes take working pressure into account...
|
|
|
|
if (cyl->type.size.mliter) {
|
Fix the imperial cylinder size calculations in equipment handling
This makes us use the same linear calculations as we did in the Gtk
branch. We don't take compressibility into account, since tank
manufacturers don't seem to either. A Luxfer AL80 is 11.1 liters, and
with the standard (non-compressibility) calculations, 80 cuft of air at
3000 psi is 11.094 liter, so that is the right model to use.
Also, stop with the horrible "units in edited numbers" stuff. It uses
up precious space, and doesn't look any better. If the user asked for
cuft, give him cuft without making a big deal about it.
Oh, and if the working pressure doesn't exist, sizes are always in
liters. That's what we did in the Gtk branch, that's what we do here.
Again, no reason to even bother stating units, it's not helping.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-06-20 02:33:49 +00:00
|
|
|
double volume;
|
|
|
|
int mbar = cyl->type.workingpressure.mbar;
|
|
|
|
|
|
|
|
if (mbar && prefs.units.volume == prefs.units.CUFT) {
|
|
|
|
volume = ml_to_cuft(cyl->type.size.mliter);
|
|
|
|
volume *= bar_to_atm(mbar / 1000.0);
|
2013-05-21 19:03:05 +00:00
|
|
|
} else {
|
Fix the imperial cylinder size calculations in equipment handling
This makes us use the same linear calculations as we did in the Gtk
branch. We don't take compressibility into account, since tank
manufacturers don't seem to either. A Luxfer AL80 is 11.1 liters, and
with the standard (non-compressibility) calculations, 80 cuft of air at
3000 psi is 11.094 liter, so that is the right model to use.
Also, stop with the horrible "units in edited numbers" stuff. It uses
up precious space, and doesn't look any better. If the user asked for
cuft, give him cuft without making a big deal about it.
Oh, and if the working pressure doesn't exist, sizes are always in
liters. That's what we did in the Gtk branch, that's what we do here.
Again, no reason to even bother stating units, it's not helping.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-06-20 02:33:49 +00:00
|
|
|
volume = cyl->type.size.mliter / 1000.0;
|
2013-05-21 19:03:05 +00:00
|
|
|
}
|
Fix the imperial cylinder size calculations in equipment handling
This makes us use the same linear calculations as we did in the Gtk
branch. We don't take compressibility into account, since tank
manufacturers don't seem to either. A Luxfer AL80 is 11.1 liters, and
with the standard (non-compressibility) calculations, 80 cuft of air at
3000 psi is 11.094 liter, so that is the right model to use.
Also, stop with the horrible "units in edited numbers" stuff. It uses
up precious space, and doesn't look any better. If the user asked for
cuft, give him cuft without making a big deal about it.
Oh, and if the working pressure doesn't exist, sizes are always in
liters. That's what we did in the Gtk branch, that's what we do here.
Again, no reason to even bother stating units, it's not helping.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-06-20 02:33:49 +00:00
|
|
|
ret = QString("%1").arg(volume, 0, 'f', 1);
|
2013-05-21 19:03:05 +00:00
|
|
|
}
|
2013-04-13 13:17:59 +00:00
|
|
|
break;
|
2013-05-22 20:29:17 +00:00
|
|
|
case WORKINGPRESS:
|
2013-05-21 19:03:05 +00:00
|
|
|
if (cyl->type.workingpressure.mbar)
|
|
|
|
ret = get_pressure_string(cyl->type.workingpressure, TRUE);
|
2013-04-13 13:17:59 +00:00
|
|
|
break;
|
|
|
|
case START:
|
2013-05-21 19:03:05 +00:00
|
|
|
if (cyl->start.mbar)
|
2013-06-20 04:42:48 +00:00
|
|
|
ret = get_pressure_string(cyl->start, FALSE);
|
|
|
|
else if (cyl->sample_start.mbar)
|
|
|
|
ret = get_pressure_string(cyl->sample_start, FALSE);
|
2013-04-13 13:17:59 +00:00
|
|
|
break;
|
|
|
|
case END:
|
2013-05-21 19:03:05 +00:00
|
|
|
if (cyl->end.mbar)
|
2013-06-20 04:42:48 +00:00
|
|
|
ret = get_pressure_string(cyl->end, FALSE);
|
|
|
|
else if (cyl->sample_end.mbar)
|
|
|
|
ret = get_pressure_string(cyl->sample_end, FALSE);
|
2013-04-13 13:17:59 +00:00
|
|
|
break;
|
|
|
|
case O2:
|
2013-06-20 04:22:09 +00:00
|
|
|
ret = percent_string(cyl->gasmix.o2);
|
2013-04-13 13:17:59 +00:00
|
|
|
break;
|
|
|
|
case HE:
|
2013-06-20 04:22:09 +00:00
|
|
|
ret = percent_string(cyl->gasmix.he);
|
2013-04-13 13:17:59 +00:00
|
|
|
break;
|
2013-11-12 02:12:43 +00:00
|
|
|
case DEPTH:
|
|
|
|
if (prefs.units.length == prefs.units.FEET)
|
|
|
|
ret = mm_to_feet(cyl->depth.mm);
|
|
|
|
else
|
|
|
|
ret = cyl->depth.mm / 1000;
|
|
|
|
break;
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
2013-05-26 03:04:31 +00:00
|
|
|
break;
|
|
|
|
case Qt::DecorationRole:
|
2013-05-23 04:25:05 +00:00
|
|
|
if (index.column() == REMOVE)
|
2013-05-22 14:00:20 +00:00
|
|
|
ret = QIcon(":trash");
|
2013-05-26 03:04:31 +00:00
|
|
|
break;
|
2013-11-22 01:32:11 +00:00
|
|
|
|
|
|
|
case Qt::ToolTipRole:
|
|
|
|
if (index.column() == REMOVE)
|
|
|
|
ret = tr("Clicking here will remove this cylinder.");
|
|
|
|
break;
|
2013-05-22 14:00:20 +00:00
|
|
|
}
|
2013-07-18 13:24:02 +00:00
|
|
|
|
2013-04-13 13:17:59 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-07-18 13:24:02 +00:00
|
|
|
cylinder_t* CylindersModel::cylinderAt(const QModelIndex& index)
|
|
|
|
{
|
|
|
|
return ¤t->cylinder[index.row()];
|
|
|
|
}
|
|
|
|
|
2013-05-23 20:31:46 +00:00
|
|
|
// this is our magic 'pass data in' function that allows the delegate to get
|
|
|
|
// the data here without silly unit conversions;
|
|
|
|
// so we only implement the two columns we care about
|
|
|
|
void CylindersModel::passInData(const QModelIndex& index, const QVariant& value)
|
|
|
|
{
|
2013-11-12 07:33:01 +00:00
|
|
|
cylinder_t *cyl = cylinderAt(index);
|
2013-05-23 20:31:46 +00:00
|
|
|
switch(index.column()) {
|
|
|
|
case SIZE:
|
|
|
|
if (cyl->type.size.mliter != value.toInt()) {
|
|
|
|
cyl->type.size.mliter = value.toInt();
|
2013-07-16 22:13:58 +00:00
|
|
|
dataChanged(index, index);
|
2013-05-23 20:31:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WORKINGPRESS:
|
|
|
|
if (cyl->type.workingpressure.mbar != value.toInt()) {
|
|
|
|
cyl->type.workingpressure.mbar = value.toInt();
|
2013-07-16 22:13:58 +00:00
|
|
|
dataChanged(index, index);
|
2013-05-23 20:31:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-13 17:49:26 +00:00
|
|
|
#define CHANGED(_t,_u1,_u2) \
|
|
|
|
value.toString().remove(_u1).remove(_u2)._t() != \
|
|
|
|
data(index, role).toString().remove(_u1).remove(_u2)._t()
|
2013-05-22 20:29:17 +00:00
|
|
|
|
2013-05-22 15:20:00 +00:00
|
|
|
bool CylindersModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
|
|
|
{
|
2013-11-13 12:45:54 +00:00
|
|
|
bool addDiveMode = DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING;
|
|
|
|
if (addDiveMode)
|
|
|
|
DivePlannerPointsModel::instance()->rememberTanks();
|
|
|
|
|
2013-11-12 07:33:01 +00:00
|
|
|
cylinder_t *cyl = cylinderAt(index);
|
2013-05-22 20:29:17 +00:00
|
|
|
switch(index.column()) {
|
|
|
|
case TYPE:
|
|
|
|
if (!value.isNull()) {
|
Fix usage of temporary QByteArrays
This commit fixes three different things:
- a memory leak in WeightModel::setData()
- getSetting() calling strdup() on a QByteArray
- a possible usage of memory after deallocation
Here's an explanation of the last issue (taken from the mailing list, slightly
adapted):
toByteArray(), as well as others "toSomething()" methods, returns
a new object which the compiler allocates on the stack. The compiler
will consider it a temporary data, and destroy it on the next line. So,
when one does
char *text= value.toByteArray().data(); // line 1
if (strcmp(description, text)) { // line 2
the compiler creates a QByteArray on line 1, calls ::data() on it, which
returns a valid char *, and assigns its value to "text". So far, so
good. But before jumping to line 2, the compiler destroys the temporary
QByteArray, and this will in turn invoke the QByteArray destructor,
which will destroy the internal data. The result is that on line 2,
"text" will point to some memory which has already been freed.
One solution is to store a copy of the temporary QByteArray into a local
variable: the compiler will still destroy the temporary QByteArray it created,
but (thanks to the reference-counted data sharing built in QByteArray) now the
destructor will see that the data is referenced by another instance of
QByteArray (the local variable "ba") and will not free the internal data.
In this way, the internal data will be available until the local variable is
destroyed, which will happen at the end of the {} block where it is defined.
Please note that when one uses the data in the same line, one doesn't need to
worry about this issue. In fact,
text = strdup(value.toString().toUtf8().data());
works just fine.
Signed-off-by: Alberto Mardegan <mardy@users.sourceforge.net>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-05-24 11:39:37 +00:00
|
|
|
QByteArray ba = value.toByteArray();
|
|
|
|
const char *text = ba.constData();
|
2013-05-22 23:22:21 +00:00
|
|
|
if (!cyl->type.description || strcmp(cyl->type.description, text)) {
|
2013-05-22 20:29:17 +00:00
|
|
|
cyl->type.description = strdup(text);
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-05-22 20:29:17 +00:00
|
|
|
}
|
2013-05-22 15:20:00 +00:00
|
|
|
}
|
2013-05-22 20:29:17 +00:00
|
|
|
break;
|
|
|
|
case SIZE:
|
|
|
|
if (CHANGED(toDouble, "cuft", "l")) {
|
|
|
|
// if units are CUFT then this value is meaningless until we have working pressure
|
|
|
|
if (value.toDouble() != 0.0) {
|
2013-05-24 05:56:12 +00:00
|
|
|
TankInfoModel *tanks = TankInfoModel::instance();
|
|
|
|
QModelIndexList matches = tanks->match(tanks->index(0,0), Qt::DisplayRole, cyl->type.description);
|
Fix the imperial cylinder size calculations in equipment handling
This makes us use the same linear calculations as we did in the Gtk
branch. We don't take compressibility into account, since tank
manufacturers don't seem to either. A Luxfer AL80 is 11.1 liters, and
with the standard (non-compressibility) calculations, 80 cuft of air at
3000 psi is 11.094 liter, so that is the right model to use.
Also, stop with the horrible "units in edited numbers" stuff. It uses
up precious space, and doesn't look any better. If the user asked for
cuft, give him cuft without making a big deal about it.
Oh, and if the working pressure doesn't exist, sizes are always in
liters. That's what we did in the Gtk branch, that's what we do here.
Again, no reason to even bother stating units, it's not helping.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-06-20 02:33:49 +00:00
|
|
|
int mbar = cyl->type.workingpressure.mbar;
|
|
|
|
int mliter;
|
|
|
|
|
|
|
|
if (mbar && prefs.units.volume == prefs.units.CUFT) {
|
|
|
|
double liters = cuft_to_l(value.toDouble());
|
|
|
|
liters /= bar_to_atm(mbar / 1000.0);
|
|
|
|
mliter = rint(liters * 1000);
|
2013-05-22 15:20:00 +00:00
|
|
|
} else {
|
Fix the imperial cylinder size calculations in equipment handling
This makes us use the same linear calculations as we did in the Gtk
branch. We don't take compressibility into account, since tank
manufacturers don't seem to either. A Luxfer AL80 is 11.1 liters, and
with the standard (non-compressibility) calculations, 80 cuft of air at
3000 psi is 11.094 liter, so that is the right model to use.
Also, stop with the horrible "units in edited numbers" stuff. It uses
up precious space, and doesn't look any better. If the user asked for
cuft, give him cuft without making a big deal about it.
Oh, and if the working pressure doesn't exist, sizes are always in
liters. That's what we did in the Gtk branch, that's what we do here.
Again, no reason to even bother stating units, it's not helping.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-06-20 02:33:49 +00:00
|
|
|
mliter = rint(value.toDouble() * 1000);
|
|
|
|
}
|
|
|
|
if (cyl->type.size.mliter != mliter) {
|
|
|
|
mark_divelist_changed(TRUE);
|
|
|
|
cyl->type.size.mliter = mliter;
|
|
|
|
if (!matches.isEmpty())
|
|
|
|
tanks->setData(tanks->index(matches.first().row(), TankInfoModel::ML), cyl->type.size.mliter);
|
2013-05-22 15:20:00 +00:00
|
|
|
}
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-05-22 15:20:00 +00:00
|
|
|
}
|
2013-05-22 20:29:17 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WORKINGPRESS:
|
|
|
|
if (CHANGED(toDouble, "psi", "bar")) {
|
2013-07-18 15:28:28 +00:00
|
|
|
QString vString = value.toString();
|
|
|
|
vString.remove("psi").remove("bar");
|
|
|
|
if (vString.toDouble() != 0.0) {
|
2013-05-24 05:56:12 +00:00
|
|
|
TankInfoModel *tanks = TankInfoModel::instance();
|
|
|
|
QModelIndexList matches = tanks->match(tanks->index(0,0), Qt::DisplayRole, cyl->type.description);
|
2013-05-22 20:29:17 +00:00
|
|
|
if (prefs.units.pressure == prefs.units.PSI)
|
2013-07-18 15:28:28 +00:00
|
|
|
cyl->type.workingpressure.mbar = psi_to_mbar(vString.toDouble());
|
2013-05-22 20:29:17 +00:00
|
|
|
else
|
2013-07-18 15:28:28 +00:00
|
|
|
cyl->type.workingpressure.mbar = vString.toDouble() * 1000;
|
2013-05-24 05:56:12 +00:00
|
|
|
if (!matches.isEmpty())
|
|
|
|
tanks->setData(tanks->index(matches.first().row(), TankInfoModel::BAR), cyl->type.workingpressure.mbar / 1000.0);
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-05-22 20:29:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case START:
|
|
|
|
if (CHANGED(toDouble, "psi", "bar")) {
|
|
|
|
if (value.toDouble() != 0.0) {
|
|
|
|
if (prefs.units.pressure == prefs.units.PSI)
|
|
|
|
cyl->start.mbar = psi_to_mbar(value.toDouble());
|
|
|
|
else
|
|
|
|
cyl->start.mbar = value.toDouble() * 1000;
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-05-22 20:29:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case END:
|
|
|
|
if (CHANGED(toDouble, "psi", "bar")) {
|
|
|
|
if (value.toDouble() != 0.0) {
|
|
|
|
if (prefs.units.pressure == prefs.units.PSI)
|
|
|
|
cyl->end.mbar = psi_to_mbar(value.toDouble());
|
|
|
|
else
|
|
|
|
cyl->end.mbar = value.toDouble() * 1000;
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-05-22 20:29:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case O2:
|
2013-06-20 01:40:15 +00:00
|
|
|
if (CHANGED(toDouble, "%", "%")) {
|
2013-11-19 13:00:09 +00:00
|
|
|
int o2 = value.toString().remove('%').toDouble() * 10 + 0.5;
|
|
|
|
if (cyl->gasmix.he.permille + o2 <= 1000) {
|
|
|
|
cyl->gasmix.o2.permille = o2;
|
|
|
|
changed = true;
|
|
|
|
}
|
2013-05-22 20:29:17 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case HE:
|
2013-06-20 01:40:15 +00:00
|
|
|
if (CHANGED(toDouble, "%", "%")) {
|
2013-11-19 13:00:09 +00:00
|
|
|
int he = value.toString().remove('%').toDouble() * 10 + 0.5;
|
|
|
|
if (cyl->gasmix.o2.permille + he <= 1000) {
|
|
|
|
cyl->gasmix.he.permille = he;
|
|
|
|
changed = true;
|
|
|
|
}
|
2013-05-22 20:29:17 +00:00
|
|
|
}
|
|
|
|
break;
|
2013-11-12 02:12:43 +00:00
|
|
|
case DEPTH:
|
|
|
|
if (CHANGED(toDouble, "ft", "m")) {
|
|
|
|
if (value.toInt() != 0) {
|
|
|
|
if (prefs.units.length == prefs.units.FEET)
|
|
|
|
cyl->depth.mm = feet_to_mm(value.toString().remove("ft").remove("m").toInt());
|
|
|
|
else
|
|
|
|
cyl->depth.mm = value.toString().remove("ft").remove("m").toInt() * 1000;
|
|
|
|
}
|
|
|
|
}
|
2013-05-22 15:20:00 +00:00
|
|
|
}
|
2013-07-16 22:13:58 +00:00
|
|
|
dataChanged(index, index);
|
2013-11-13 12:45:54 +00:00
|
|
|
if (addDiveMode)
|
|
|
|
DivePlannerPointsModel::instance()->tanksUpdated();
|
2013-07-16 22:13:58 +00:00
|
|
|
return true;
|
2013-05-22 15:20:00 +00:00
|
|
|
}
|
|
|
|
|
2013-04-13 13:17:59 +00:00
|
|
|
int CylindersModel::rowCount(const QModelIndex& parent) const
|
|
|
|
{
|
2013-05-21 12:33:55 +00:00
|
|
|
return rows;
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
|
|
|
|
2013-05-22 17:52:38 +00:00
|
|
|
void CylindersModel::add()
|
2013-04-13 13:17:59 +00:00
|
|
|
{
|
2013-05-21 12:33:55 +00:00
|
|
|
if (rows >= MAX_CYLINDERS) {
|
2013-05-01 21:49:17 +00:00
|
|
|
return;
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
|
|
|
|
2013-05-21 12:33:55 +00:00
|
|
|
int row = rows;
|
2013-11-13 12:45:54 +00:00
|
|
|
fill_default_cylinder(¤t->cylinder[row]);
|
2013-04-13 13:17:59 +00:00
|
|
|
beginInsertRows(QModelIndex(), row, row);
|
2013-05-21 12:33:55 +00:00
|
|
|
rows++;
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-04-13 13:17:59 +00:00
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CylindersModel::update()
|
|
|
|
{
|
2013-05-21 12:33:55 +00:00
|
|
|
setDive(current);
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CylindersModel::clear()
|
|
|
|
{
|
2013-05-21 12:33:55 +00:00
|
|
|
if (rows > 0) {
|
|
|
|
beginRemoveRows(QModelIndex(), 0, rows-1);
|
2013-04-13 13:17:59 +00:00
|
|
|
endRemoveRows();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-21 12:33:55 +00:00
|
|
|
void CylindersModel::setDive(dive* d)
|
|
|
|
{
|
|
|
|
if (current)
|
|
|
|
clear();
|
2013-11-10 20:54:04 +00:00
|
|
|
if (!d)
|
|
|
|
return;
|
2013-11-27 21:59:16 +00:00
|
|
|
rows = 0;
|
2013-05-23 04:25:05 +00:00
|
|
|
for(int i = 0; i < MAX_CYLINDERS; i++) {
|
2013-11-27 21:59:16 +00:00
|
|
|
if (!cylinder_none(&d->cylinder[i])) {
|
|
|
|
rows = i+1;
|
2013-05-21 12:33:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
current = d;
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = false;
|
2013-11-27 21:59:16 +00:00
|
|
|
if (rows > 0) {
|
|
|
|
beginInsertRows(QModelIndex(), 0, rows-1);
|
2013-10-13 13:20:32 +00:00
|
|
|
endInsertRows();
|
|
|
|
}
|
2013-05-21 12:33:55 +00:00
|
|
|
}
|
|
|
|
|
2013-05-22 14:00:20 +00:00
|
|
|
Qt::ItemFlags CylindersModel::flags(const QModelIndex& index) const
|
|
|
|
{
|
|
|
|
if (index.column() == REMOVE)
|
|
|
|
return Qt::ItemIsEnabled;
|
2013-05-22 15:20:00 +00:00
|
|
|
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
|
2013-05-22 14:00:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CylindersModel::remove(const QModelIndex& index)
|
|
|
|
{
|
2013-05-23 04:25:05 +00:00
|
|
|
if (index.column() != REMOVE) {
|
2013-05-22 14:00:20 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-11-13 12:45:54 +00:00
|
|
|
cylinder_t *cyl = ¤t->cylinder[index.row()];
|
|
|
|
if (DivePlannerPointsModel::instance()->tankInUse(cyl->gasmix.o2.permille, cyl->gasmix.he.permille)) {
|
2013-11-21 12:23:10 +00:00
|
|
|
QMessageBox::warning(mainWindow(), TITLE_OR_TEXT(
|
|
|
|
tr("Cylinder cannot be removed"),
|
|
|
|
tr("This gas in use. Only cylinders that are not used in the dive can be removed.")),
|
|
|
|
QMessageBox::Ok);
|
2013-11-13 12:45:54 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-05-22 14:40:57 +00:00
|
|
|
beginRemoveRows(QModelIndex(), index.row(), index.row()); // yah, know, ugly.
|
2013-05-22 17:02:28 +00:00
|
|
|
rows--;
|
|
|
|
remove_cylinder(current, index.row());
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-05-22 14:40:57 +00:00
|
|
|
endRemoveRows();
|
2013-05-22 14:00:20 +00:00
|
|
|
}
|
|
|
|
|
2013-10-11 14:04:27 +00:00
|
|
|
WeightModel::WeightModel(QObject* parent): current(0), rows(0)
|
2013-05-24 01:40:16 +00:00
|
|
|
{
|
2013-10-11 14:04:27 +00:00
|
|
|
//enum Column {REMOVE, TYPE, WEIGHT};
|
|
|
|
setHeaderDataStrings(QStringList() << tr("") << tr("Type") << tr("Weight"));
|
2013-05-24 01:40:16 +00:00
|
|
|
}
|
|
|
|
|
2013-07-18 14:53:47 +00:00
|
|
|
weightsystem_t* WeightModel::weightSystemAt(const QModelIndex& index)
|
|
|
|
{
|
|
|
|
return ¤t->weightsystem[index.row()];
|
|
|
|
}
|
|
|
|
|
2013-05-22 14:00:20 +00:00
|
|
|
void WeightModel::remove(const QModelIndex& index)
|
|
|
|
{
|
2013-05-23 04:25:05 +00:00
|
|
|
if (index.column() != REMOVE) {
|
2013-05-22 14:00:20 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-05-22 14:40:57 +00:00
|
|
|
beginRemoveRows(QModelIndex(), index.row(), index.row()); // yah, know, ugly.
|
2013-05-22 17:02:28 +00:00
|
|
|
rows--;
|
|
|
|
remove_weightsystem(current, index.row());
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-05-22 14:40:57 +00:00
|
|
|
endRemoveRows();
|
2013-05-22 14:00:20 +00:00
|
|
|
}
|
|
|
|
|
2013-04-13 13:17:59 +00:00
|
|
|
void WeightModel::clear()
|
|
|
|
{
|
2013-05-21 12:59:41 +00:00
|
|
|
if (rows > 0) {
|
|
|
|
beginRemoveRows(QModelIndex(), 0, rows-1);
|
2013-05-01 16:04:14 +00:00
|
|
|
endRemoveRows();
|
|
|
|
}
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QVariant WeightModel::data(const QModelIndex& index, int role) const
|
|
|
|
{
|
2013-05-01 17:11:46 +00:00
|
|
|
QVariant ret;
|
2013-05-02 05:00:08 +00:00
|
|
|
if (!index.isValid() || index.row() >= MAX_WEIGHTSYSTEMS)
|
2013-05-01 17:11:46 +00:00
|
|
|
return ret;
|
2013-05-02 05:00:08 +00:00
|
|
|
|
2013-05-24 01:40:16 +00:00
|
|
|
weightsystem_t *ws = ¤t->weightsystem[index.row()];
|
2013-05-01 17:11:46 +00:00
|
|
|
|
2013-05-26 03:04:31 +00:00
|
|
|
switch (role) {
|
|
|
|
case Qt::FontRole:
|
2013-06-16 14:13:32 +00:00
|
|
|
ret = defaultModelFont();
|
2013-05-26 03:04:31 +00:00
|
|
|
break;
|
|
|
|
case Qt::TextAlignmentRole:
|
2013-11-22 01:36:39 +00:00
|
|
|
ret = Qt::AlignCenter;
|
|
|
|
break;
|
2013-05-26 03:04:31 +00:00
|
|
|
case Qt::DisplayRole:
|
|
|
|
case Qt::EditRole:
|
2013-05-01 17:11:46 +00:00
|
|
|
switch(index.column()) {
|
|
|
|
case TYPE:
|
|
|
|
ret = QString(ws->description);
|
|
|
|
break;
|
|
|
|
case WEIGHT:
|
2013-05-21 19:03:05 +00:00
|
|
|
ret = get_weight_string(ws->weight, TRUE);
|
2013-05-01 17:11:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-05-26 03:04:31 +00:00
|
|
|
break;
|
|
|
|
case Qt::DecorationRole:
|
2013-05-23 04:25:05 +00:00
|
|
|
if (index.column() == REMOVE)
|
2013-05-22 14:00:20 +00:00
|
|
|
ret = QIcon(":trash");
|
2013-05-26 03:04:31 +00:00
|
|
|
break;
|
2013-11-22 01:32:11 +00:00
|
|
|
case Qt::ToolTipRole:
|
|
|
|
if (index.column() == REMOVE)
|
|
|
|
ret = tr("Clicking here will remove this weigthsystem.");
|
|
|
|
break;
|
2013-05-22 14:00:20 +00:00
|
|
|
}
|
2013-05-01 17:11:46 +00:00
|
|
|
return ret;
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
|
|
|
|
2013-05-24 01:40:16 +00:00
|
|
|
// this is our magic 'pass data in' function that allows the delegate to get
|
|
|
|
// the data here without silly unit conversions;
|
|
|
|
// so we only implement the two columns we care about
|
|
|
|
void WeightModel::passInData(const QModelIndex& index, const QVariant& value)
|
|
|
|
{
|
|
|
|
weightsystem_t *ws = ¤t->weightsystem[index.row()];
|
|
|
|
if (index.column() == WEIGHT) {
|
|
|
|
if (ws->weight.grams != value.toInt()) {
|
|
|
|
ws->weight.grams = value.toInt();
|
2013-07-16 22:13:58 +00:00
|
|
|
dataChanged(index, index);
|
2013-05-24 01:40:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-22 15:20:00 +00:00
|
|
|
bool WeightModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
|
|
|
{
|
2013-05-24 01:40:16 +00:00
|
|
|
weightsystem_t *ws = ¤t->weightsystem[index.row()];
|
2013-05-22 15:20:00 +00:00
|
|
|
switch(index.column()) {
|
2013-05-24 01:40:16 +00:00
|
|
|
case TYPE:
|
|
|
|
if (!value.isNull()) {
|
Fix usage of temporary QByteArrays
This commit fixes three different things:
- a memory leak in WeightModel::setData()
- getSetting() calling strdup() on a QByteArray
- a possible usage of memory after deallocation
Here's an explanation of the last issue (taken from the mailing list, slightly
adapted):
toByteArray(), as well as others "toSomething()" methods, returns
a new object which the compiler allocates on the stack. The compiler
will consider it a temporary data, and destroy it on the next line. So,
when one does
char *text= value.toByteArray().data(); // line 1
if (strcmp(description, text)) { // line 2
the compiler creates a QByteArray on line 1, calls ::data() on it, which
returns a valid char *, and assigns its value to "text". So far, so
good. But before jumping to line 2, the compiler destroys the temporary
QByteArray, and this will in turn invoke the QByteArray destructor,
which will destroy the internal data. The result is that on line 2,
"text" will point to some memory which has already been freed.
One solution is to store a copy of the temporary QByteArray into a local
variable: the compiler will still destroy the temporary QByteArray it created,
but (thanks to the reference-counted data sharing built in QByteArray) now the
destructor will see that the data is referenced by another instance of
QByteArray (the local variable "ba") and will not free the internal data.
In this way, the internal data will be available until the local variable is
destroyed, which will happen at the end of the {} block where it is defined.
Please note that when one uses the data in the same line, one doesn't need to
worry about this issue. In fact,
text = strdup(value.toString().toUtf8().data());
works just fine.
Signed-off-by: Alberto Mardegan <mardy@users.sourceforge.net>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-05-24 11:39:37 +00:00
|
|
|
QByteArray ba = value.toString().toUtf8();
|
|
|
|
const char *text = ba.constData();
|
2013-05-24 01:40:16 +00:00
|
|
|
if (!ws->description || strcmp(ws->description, text)) {
|
|
|
|
ws->description = strdup(text);
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-05-24 01:40:16 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-22 15:20:00 +00:00
|
|
|
break;
|
|
|
|
case WEIGHT:
|
2013-05-24 01:40:16 +00:00
|
|
|
if (CHANGED(toDouble, "kg", "lbs")) {
|
|
|
|
if (prefs.units.weight == prefs.units.LBS)
|
|
|
|
ws->weight.grams = lbs_to_grams(value.toDouble());
|
|
|
|
else
|
2013-06-20 01:40:15 +00:00
|
|
|
ws->weight.grams = value.toDouble() * 1000.0 + 0.5;
|
2013-05-24 05:56:12 +00:00
|
|
|
// now update the ws_info
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-05-24 05:56:12 +00:00
|
|
|
WSInfoModel *wsim = WSInfoModel::instance();
|
|
|
|
QModelIndexList matches = wsim->match(wsim->index(0,0), Qt::DisplayRole, ws->description);
|
|
|
|
if (!matches.isEmpty())
|
|
|
|
wsim->setData(wsim->index(matches.first().row(), WSInfoModel::GR), ws->weight.grams);
|
2013-05-24 01:40:16 +00:00
|
|
|
}
|
2013-05-22 15:20:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-07-16 22:13:58 +00:00
|
|
|
dataChanged(index, index);
|
|
|
|
return true;
|
2013-05-22 15:20:00 +00:00
|
|
|
}
|
|
|
|
|
2013-05-22 14:00:20 +00:00
|
|
|
Qt::ItemFlags WeightModel::flags(const QModelIndex& index) const
|
|
|
|
{
|
|
|
|
if (index.column() == REMOVE)
|
|
|
|
return Qt::ItemIsEnabled;
|
2013-05-22 15:20:00 +00:00
|
|
|
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
|
2013-05-22 14:00:20 +00:00
|
|
|
}
|
|
|
|
|
2013-04-13 13:17:59 +00:00
|
|
|
int WeightModel::rowCount(const QModelIndex& parent) const
|
|
|
|
{
|
2013-05-21 12:59:41 +00:00
|
|
|
return rows;
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
|
|
|
|
2013-05-22 17:52:38 +00:00
|
|
|
void WeightModel::add()
|
2013-04-13 13:17:59 +00:00
|
|
|
{
|
2013-05-21 18:29:21 +00:00
|
|
|
if (rows >= MAX_WEIGHTSYSTEMS)
|
2013-05-01 21:49:17 +00:00
|
|
|
return;
|
2013-05-01 17:11:46 +00:00
|
|
|
|
2013-05-21 12:59:41 +00:00
|
|
|
int row = rows;
|
2013-05-01 17:11:46 +00:00
|
|
|
beginInsertRows(QModelIndex(), row, row);
|
2013-05-21 12:59:41 +00:00
|
|
|
rows++;
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = true;
|
2013-05-01 17:11:46 +00:00
|
|
|
endInsertRows();
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void WeightModel::update()
|
|
|
|
{
|
2013-05-21 12:59:41 +00:00
|
|
|
setDive(current);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WeightModel::setDive(dive* d)
|
|
|
|
{
|
|
|
|
if (current)
|
|
|
|
clear();
|
2013-11-27 21:59:17 +00:00
|
|
|
rows = 0;
|
2013-05-21 18:29:21 +00:00
|
|
|
for(int i = 0; i < MAX_WEIGHTSYSTEMS; i++) {
|
2013-11-27 21:59:17 +00:00
|
|
|
if (!weightsystem_none(&d->weightsystem[i])) {
|
|
|
|
rows = i+1;
|
2013-05-21 12:59:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
current = d;
|
2013-09-25 17:23:51 +00:00
|
|
|
changed = false;
|
2013-11-27 21:59:17 +00:00
|
|
|
if (rows > 0) {
|
|
|
|
beginInsertRows(QModelIndex(), 0, rows-1);
|
2013-10-13 13:20:32 +00:00
|
|
|
endInsertRows();
|
|
|
|
}
|
2013-04-13 13:17:59 +00:00
|
|
|
}
|
2013-04-15 18:04:35 +00:00
|
|
|
|
2013-05-24 01:40:16 +00:00
|
|
|
WSInfoModel* WSInfoModel::instance()
|
|
|
|
{
|
|
|
|
static WSInfoModel *self = new WSInfoModel();
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WSInfoModel::insertRows(int row, int count, const QModelIndex& parent)
|
|
|
|
{
|
|
|
|
beginInsertRows(parent, rowCount(), rowCount());
|
|
|
|
rows += count;
|
|
|
|
endInsertRows();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WSInfoModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
|
|
|
{
|
2013-09-10 18:44:49 +00:00
|
|
|
struct ws_info_t *info = &ws_info[index.row()];
|
2013-05-24 05:56:12 +00:00
|
|
|
switch(index.column()) {
|
|
|
|
case DESCRIPTION:
|
|
|
|
info->name = strdup(value.toByteArray().data());
|
|
|
|
break;
|
|
|
|
case GR:
|
|
|
|
info->grams = value.toInt();
|
|
|
|
break;
|
|
|
|
}
|
2013-07-16 22:13:58 +00:00
|
|
|
emit dataChanged(index, index);
|
2013-05-24 01:40:16 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WSInfoModel::clear()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant WSInfoModel::data(const QModelIndex& index, int role) const
|
|
|
|
{
|
|
|
|
QVariant ret;
|
|
|
|
if (!index.isValid()) {
|
|
|
|
return ret;
|
|
|
|
}
|
2013-09-10 18:44:49 +00:00
|
|
|
struct ws_info_t *info = &ws_info[index.row()];
|
2013-05-24 01:40:16 +00:00
|
|
|
|
|
|
|
int gr = info->grams;
|
2013-06-16 14:13:32 +00:00
|
|
|
switch(role){
|
|
|
|
case Qt::FontRole :
|
|
|
|
ret = defaultModelFont();
|
|
|
|
break;
|
|
|
|
case Qt::DisplayRole :
|
|
|
|
case Qt::EditRole :
|
|
|
|
switch(index.column()) {
|
|
|
|
case GR:
|
|
|
|
ret = gr;
|
|
|
|
break;
|
|
|
|
case DESCRIPTION:
|
|
|
|
ret = QString(info->name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2013-05-24 01:40:16 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int WSInfoModel::rowCount(const QModelIndex& parent) const
|
|
|
|
{
|
|
|
|
return rows+1;
|
|
|
|
}
|
|
|
|
|
2013-06-16 16:28:59 +00:00
|
|
|
const QString& WSInfoModel::biggerString() const
|
|
|
|
{
|
|
|
|
return biggerEntry;
|
|
|
|
}
|
|
|
|
|
2013-10-11 14:13:16 +00:00
|
|
|
WSInfoModel::WSInfoModel() : rows(-1)
|
2013-05-24 01:40:16 +00:00
|
|
|
{
|
2013-10-11 14:13:16 +00:00
|
|
|
setHeaderDataStrings( QStringList() << tr("Description") << tr("kg"));
|
2013-09-10 18:44:49 +00:00
|
|
|
struct ws_info_t *info = ws_info;
|
2013-06-16 16:28:59 +00:00
|
|
|
for (info = ws_info; info->name; info++, rows++){
|
|
|
|
QString wsInfoName(info->name);
|
2013-10-11 13:21:04 +00:00
|
|
|
if( wsInfoName.count() > biggerEntry.count())
|
2013-06-16 16:28:59 +00:00
|
|
|
biggerEntry = wsInfoName;
|
|
|
|
}
|
2013-05-24 01:40:16 +00:00
|
|
|
|
|
|
|
if (rows > -1) {
|
|
|
|
beginInsertRows(QModelIndex(), 0, rows);
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-10 18:42:26 +00:00
|
|
|
void WSInfoModel::updateInfo()
|
|
|
|
{
|
2013-09-10 18:44:49 +00:00
|
|
|
struct ws_info_t *info = ws_info;
|
2013-09-10 18:42:26 +00:00
|
|
|
beginRemoveRows(QModelIndex(), 0, this->rows);
|
|
|
|
endRemoveRows();
|
2013-09-10 21:55:30 +00:00
|
|
|
rows = -1;
|
2013-09-10 18:42:26 +00:00
|
|
|
for (info = ws_info; info->name; info++, rows++){
|
|
|
|
QString wsInfoName(info->name);
|
2013-10-11 13:21:04 +00:00
|
|
|
if( wsInfoName.count() > biggerEntry.count())
|
2013-09-10 18:42:26 +00:00
|
|
|
biggerEntry = wsInfoName;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rows > -1) {
|
|
|
|
beginInsertRows(QModelIndex(), 0, rows);
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-24 01:40:16 +00:00
|
|
|
void WSInfoModel::update()
|
|
|
|
{
|
|
|
|
if (rows > -1) {
|
|
|
|
beginRemoveRows(QModelIndex(), 0, rows);
|
|
|
|
endRemoveRows();
|
2013-05-24 05:56:12 +00:00
|
|
|
rows = -1;
|
2013-05-24 01:40:16 +00:00
|
|
|
}
|
2013-09-10 18:44:49 +00:00
|
|
|
struct ws_info_t *info = ws_info;
|
2013-05-24 01:40:16 +00:00
|
|
|
for (info = ws_info; info->name; info++, rows++);
|
|
|
|
|
|
|
|
if (rows > -1) {
|
|
|
|
beginInsertRows(QModelIndex(), 0, rows);
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-23 18:33:20 +00:00
|
|
|
TankInfoModel* TankInfoModel::instance()
|
2013-04-15 18:04:35 +00:00
|
|
|
{
|
2013-05-23 18:33:20 +00:00
|
|
|
static TankInfoModel *self = new TankInfoModel();
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2013-06-16 16:28:59 +00:00
|
|
|
const QString& TankInfoModel::biggerString() const
|
|
|
|
{
|
|
|
|
return biggerEntry;
|
|
|
|
}
|
|
|
|
|
2013-05-23 18:33:20 +00:00
|
|
|
bool TankInfoModel::insertRows(int row, int count, const QModelIndex& parent)
|
|
|
|
{
|
|
|
|
beginInsertRows(parent, rowCount(), rowCount());
|
|
|
|
rows += count;
|
|
|
|
endInsertRows();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TankInfoModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
|
|
|
{
|
2013-09-10 18:44:49 +00:00
|
|
|
struct tank_info_t *info = &tank_info[index.row()];
|
2013-05-24 05:56:12 +00:00
|
|
|
switch(index.column()) {
|
|
|
|
case DESCRIPTION:
|
|
|
|
info->name = strdup(value.toByteArray().data());
|
|
|
|
break;
|
|
|
|
case ML:
|
|
|
|
info->ml = value.toInt();
|
|
|
|
break;
|
|
|
|
case BAR:
|
|
|
|
info->bar = value.toInt();
|
|
|
|
break;
|
|
|
|
}
|
2013-07-16 22:13:58 +00:00
|
|
|
emit dataChanged(index, index);
|
2013-05-24 01:40:16 +00:00
|
|
|
return TRUE;
|
2013-04-15 18:04:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TankInfoModel::clear()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant TankInfoModel::data(const QModelIndex& index, int role) const
|
|
|
|
{
|
|
|
|
QVariant ret;
|
|
|
|
if (!index.isValid()) {
|
|
|
|
return ret;
|
|
|
|
}
|
2013-06-16 15:33:27 +00:00
|
|
|
if (role == Qt::FontRole){
|
|
|
|
return defaultModelFont();
|
|
|
|
}
|
2013-06-19 21:36:48 +00:00
|
|
|
if (role == Qt::DisplayRole || role == Qt::EditRole) {
|
2013-09-10 18:44:49 +00:00
|
|
|
struct tank_info_t *info = &tank_info[index.row()];
|
2013-06-19 21:36:48 +00:00
|
|
|
int ml = info->ml;
|
|
|
|
double bar = (info->psi) ? psi_to_bar(info->psi) : info->bar;
|
2013-06-16 15:33:27 +00:00
|
|
|
|
2013-06-19 21:36:48 +00:00
|
|
|
if (info->cuft && info->psi)
|
|
|
|
ml = cuft_to_l(info->cuft) * 1000 / bar_to_atm(bar);
|
2013-04-15 18:04:35 +00:00
|
|
|
|
|
|
|
switch(index.column()) {
|
2013-05-02 05:00:08 +00:00
|
|
|
case BAR:
|
2013-06-19 21:36:48 +00:00
|
|
|
ret = bar * 1000;
|
2013-04-15 18:04:35 +00:00
|
|
|
break;
|
2013-05-02 05:00:08 +00:00
|
|
|
case ML:
|
|
|
|
ret = ml;
|
2013-04-15 18:04:35 +00:00
|
|
|
break;
|
|
|
|
case DESCRIPTION:
|
|
|
|
ret = QString(info->name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TankInfoModel::rowCount(const QModelIndex& parent) const
|
|
|
|
{
|
|
|
|
return rows+1;
|
|
|
|
}
|
|
|
|
|
2013-10-11 14:42:33 +00:00
|
|
|
TankInfoModel::TankInfoModel() : rows(-1)
|
2013-04-15 18:04:35 +00:00
|
|
|
{
|
2013-11-29 18:20:10 +00:00
|
|
|
setHeaderDataStrings( QStringList() << tr("Description") << tr("ml") << tr("bar"));
|
2013-09-10 18:44:49 +00:00
|
|
|
struct tank_info_t *info = tank_info;
|
2013-06-16 16:28:59 +00:00
|
|
|
for (info = tank_info; info->name; info++, rows++){
|
|
|
|
QString infoName(info->name);
|
2013-10-11 13:21:04 +00:00
|
|
|
if (infoName.count() > biggerEntry.count())
|
2013-06-16 16:28:59 +00:00
|
|
|
biggerEntry = infoName;
|
|
|
|
}
|
|
|
|
|
2013-04-15 18:04:35 +00:00
|
|
|
if (rows > -1) {
|
|
|
|
beginInsertRows(QModelIndex(), 0, rows);
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TankInfoModel::update()
|
|
|
|
{
|
2013-05-23 04:25:05 +00:00
|
|
|
if (rows > -1) {
|
2013-04-15 18:04:35 +00:00
|
|
|
beginRemoveRows(QModelIndex(), 0, rows);
|
|
|
|
endRemoveRows();
|
2013-05-24 05:56:12 +00:00
|
|
|
rows = -1;
|
2013-04-15 18:04:35 +00:00
|
|
|
}
|
2013-09-10 18:44:49 +00:00
|
|
|
struct tank_info_t *info = tank_info;
|
2013-05-02 05:00:08 +00:00
|
|
|
for (info = tank_info; info->name; info++, rows++);
|
2013-04-15 18:04:35 +00:00
|
|
|
|
|
|
|
if (rows > -1) {
|
|
|
|
beginInsertRows(QModelIndex(), 0, rows);
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
}
|
2013-04-22 01:12:36 +00:00
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
//#################################################################################################
|
|
|
|
//#
|
|
|
|
//# Tree Model - a Basic Tree Model so I don't need to kill myself repeating this for every model.
|
|
|
|
//#
|
|
|
|
//#################################################################################################
|
2013-04-27 15:27:27 +00:00
|
|
|
|
2013-04-22 01:12:36 +00:00
|
|
|
/*! 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.
|
|
|
|
*
|
|
|
|
*/
|
2013-05-02 02:51:34 +00:00
|
|
|
|
2013-06-18 20:29:37 +00:00
|
|
|
TreeItem::TreeItem()
|
|
|
|
{
|
|
|
|
parent = NULL;
|
|
|
|
}
|
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
TreeItem::~TreeItem()
|
2013-04-22 01:12:36 +00:00
|
|
|
{
|
2013-05-14 07:28:30 +00:00
|
|
|
qDeleteAll(children);
|
2013-05-02 02:51:34 +00:00
|
|
|
}
|
2013-04-25 07:50:01 +00:00
|
|
|
|
2013-11-19 00:33:01 +00:00
|
|
|
Qt::ItemFlags TreeItem::flags(const QModelIndex& index) const
|
|
|
|
{
|
|
|
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
|
|
|
}
|
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
int TreeItem::row() const
|
2013-05-02 02:51:34 +00:00
|
|
|
{
|
|
|
|
if (parent)
|
2013-06-17 21:59:50 +00:00
|
|
|
return parent->children.indexOf(const_cast<TreeItem*>(this));
|
2013-05-02 02:51:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-04-22 01:12:36 +00:00
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
QVariant TreeItem::data(int column, int role) const
|
2013-05-02 02:51:34 +00:00
|
|
|
{
|
2013-06-17 21:59:50 +00:00
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
TreeModel::TreeModel(QObject* parent): QAbstractItemModel(parent)
|
|
|
|
{
|
|
|
|
rootItem = new TreeItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
TreeModel::~TreeModel()
|
|
|
|
{
|
|
|
|
delete rootItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant TreeModel::data(const QModelIndex& index, int role) const
|
|
|
|
{
|
|
|
|
if (!index.isValid())
|
|
|
|
return QVariant();
|
|
|
|
|
|
|
|
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
|
2013-06-19 17:30:36 +00:00
|
|
|
QVariant val = item->data(index.column(), role);
|
2013-06-17 21:59:50 +00:00
|
|
|
|
2013-06-19 17:30:36 +00:00
|
|
|
if (role == Qt::FontRole && !val.isValid())
|
|
|
|
return defaultModelFont();
|
|
|
|
else
|
|
|
|
return val;
|
2013-05-02 02:51:34 +00:00
|
|
|
}
|
|
|
|
|
2013-11-19 00:33:01 +00:00
|
|
|
bool TreeItem::setData(const QModelIndex& index, const QVariant& value, int role)
|
|
|
|
{
|
2013-11-20 23:32:13 +00:00
|
|
|
return false;
|
2013-11-19 00:33:01 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
QModelIndex TreeModel::index(int row, int column, const QModelIndex& parent)
|
|
|
|
const
|
|
|
|
{
|
|
|
|
if (!hasIndex(row, column, parent))
|
|
|
|
return QModelIndex();
|
|
|
|
|
|
|
|
TreeItem* parentItem = (!parent.isValid()) ? rootItem : static_cast<TreeItem*>(parent.internalPointer());
|
|
|
|
|
|
|
|
TreeItem* childItem = parentItem->children[row];
|
|
|
|
|
|
|
|
return (childItem) ? createIndex(row, column, childItem) : QModelIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
QModelIndex TreeModel::parent(const QModelIndex& index) const
|
|
|
|
{
|
|
|
|
if (!index.isValid())
|
|
|
|
return QModelIndex();
|
|
|
|
|
|
|
|
TreeItem* childItem = static_cast<TreeItem*>(index.internalPointer());
|
|
|
|
TreeItem* parentItem = childItem->parent;
|
|
|
|
|
|
|
|
if (parentItem == rootItem || !parentItem)
|
|
|
|
return QModelIndex();
|
|
|
|
|
|
|
|
return createIndex(parentItem->row(), 0, parentItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
int TreeModel::rowCount(const QModelIndex& parent) const
|
|
|
|
{
|
|
|
|
TreeItem* parentItem;
|
|
|
|
|
|
|
|
if (!parent.isValid())
|
|
|
|
parentItem = rootItem;
|
|
|
|
else
|
|
|
|
parentItem = static_cast<TreeItem*>(parent.internalPointer());
|
|
|
|
|
|
|
|
int amount = parentItem->children.count();
|
|
|
|
return amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TreeModel::columnCount(const QModelIndex& parent) const
|
|
|
|
{
|
|
|
|
return columns;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*################################################################
|
|
|
|
*
|
|
|
|
* Implementation of the Dive List.
|
|
|
|
*
|
|
|
|
* ############################################################### */
|
|
|
|
struct TripItem : public TreeItem {
|
2013-05-02 02:51:34 +00:00
|
|
|
virtual QVariant data(int column, int role) const;
|
|
|
|
dive_trip_t* trip;
|
|
|
|
};
|
|
|
|
|
|
|
|
QVariant TripItem::data(int column, int role) const
|
|
|
|
{
|
|
|
|
QVariant ret;
|
2013-04-25 14:04:41 +00:00
|
|
|
|
2013-06-27 05:16:40 +00:00
|
|
|
if (role == DiveTripModel::TRIP_ROLE)
|
|
|
|
return QVariant::fromValue<void*>(trip);
|
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
if (role == DiveTripModel::SORT_ROLE)
|
2013-05-29 05:54:39 +00:00
|
|
|
return (qulonglong)trip->when;
|
|
|
|
|
2013-05-02 16:33:51 +00:00
|
|
|
if (role == Qt::DisplayRole) {
|
|
|
|
switch (column) {
|
2013-06-17 21:59:50 +00:00
|
|
|
case DiveTripModel::NR:
|
2013-11-19 22:16:33 +00:00
|
|
|
if (trip->location && *trip->location)
|
|
|
|
ret = QString(trip->location) + ", " + get_trip_date_string(trip->when, trip->nrdives);
|
|
|
|
else
|
|
|
|
ret = get_trip_date_string(trip->when, trip->nrdives);
|
2013-05-02 16:33:51 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-05-02 02:51:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-05-29 05:54:39 +00:00
|
|
|
static int nitrox_sort_value(struct dive *dive)
|
|
|
|
{
|
|
|
|
int o2, he, o2low;
|
|
|
|
get_dive_gas(dive, &o2, &he, &o2low);
|
|
|
|
return he*1000 + o2;
|
|
|
|
}
|
|
|
|
|
2013-05-02 02:51:34 +00:00
|
|
|
QVariant DiveItem::data(int column, int role) const
|
2013-04-22 01:12:36 +00:00
|
|
|
{
|
2013-05-02 02:51:34 +00:00
|
|
|
QVariant retVal;
|
|
|
|
|
2013-05-02 21:05:53 +00:00
|
|
|
switch (role) {
|
|
|
|
case Qt::TextAlignmentRole:
|
2013-05-02 02:51:34 +00:00
|
|
|
switch (column) {
|
|
|
|
case DATE: /* fall through */
|
|
|
|
case SUIT: /* fall through */
|
|
|
|
case LOCATION:
|
|
|
|
retVal = Qt::AlignLeft;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
retVal = Qt::AlignRight;
|
|
|
|
break;
|
|
|
|
}
|
2013-05-02 21:05:53 +00:00
|
|
|
break;
|
2013-06-17 21:59:50 +00:00
|
|
|
case DiveTripModel::SORT_ROLE:
|
2013-05-29 05:54:39 +00:00
|
|
|
switch (column) {
|
Sort 'dive number' column by date, not number
Ok, so this sounds insane, but it fixes our currently broken sorting
of dive trips vs plain dives not in trips.
The reason for that is simple: the dive trips are sorted by date, but
that's column #0, and for plain dives is the dive number.
So currently the trip-vs-dive sorting looks at the date of the trip,
and compares that to the number of the dive. Since the date of the
trip is expressed as seconds-since-1970-in-UTC, unsurprisingly the
dive number is generally much smaller (even for some very avid divers
;), and so the plain dives end up sorting way at the bottom (or at the
top, if you do "oldest trips first"
Since the dive number *should* sort as the date, this stupid attached
patch just makes us return the dive date instead.
Now, there are other possible solutions to this:
- make the date of the dive be column 0, and make the dive number be column 1.
Quite frankly, while more logical for this particular problem, it
probably sucks as a solution. We do want to have a column we can sort
dives by that is date-based, but doesn't include trips. And while the
dive number *should* sort identically to the date one, the fact is
that you can have dives without any numbering, so it doesn't.
In contrast, all dives have dates, and sorting numbered dives by
date should still result in sane behavior (and if it doesn't, then the
insanity comes from the dive numbering, and odd sorting is the fault
of the user and indicative of a problem)
- We could possibly do something magical like sorting dives by number
when they are inside trips, or when no trips exist at all. But then
we'd sort by date when there are trips and the dive is outside the
trip. But quite frankly, that just sounds insane.
So on the whole, I don't love this patch, but it seems to be the least
confusing of the possibilities.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-06-09 00:58:16 +00:00
|
|
|
case NR: retVal = (qulonglong) dive->when; break;
|
2013-05-29 20:43:14 +00:00
|
|
|
case DATE: retVal = (qulonglong) dive->when; break;
|
2013-05-29 20:53:50 +00:00
|
|
|
case RATING: retVal = dive->rating; break;
|
2013-05-29 20:43:14 +00:00
|
|
|
case DEPTH: retVal = dive->maxdepth.mm; break;
|
|
|
|
case DURATION: retVal = dive->duration.seconds; break;
|
|
|
|
case TEMPERATURE: retVal = dive->watertemp.mkelvin; break;
|
|
|
|
case TOTALWEIGHT: retVal = total_weight(dive); break;
|
|
|
|
case SUIT: retVal = QString(dive->suit); break;
|
|
|
|
case CYLINDER: retVal = QString(dive->cylinder[0].type.description); break;
|
|
|
|
case NITROX: retVal = nitrox_sort_value(dive); break;
|
|
|
|
case SAC: retVal = dive->sac; break;
|
|
|
|
case OTU: retVal = dive->otu; break;
|
|
|
|
case MAXCNS: retVal = dive->maxcns; break;
|
|
|
|
case LOCATION: retVal = QString(dive->location); break;
|
2013-05-29 05:54:39 +00:00
|
|
|
}
|
|
|
|
break;
|
2013-05-02 21:05:53 +00:00
|
|
|
case Qt::DisplayRole:
|
2013-05-02 02:51:34 +00:00
|
|
|
switch (column) {
|
2013-05-29 20:43:14 +00:00
|
|
|
case NR: retVal = dive->number; break;
|
2013-07-11 09:41:50 +00:00
|
|
|
case DATE: retVal = displayDate(); break;
|
2013-05-29 20:43:14 +00:00
|
|
|
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 CYLINDER: retVal = QString(dive->cylinder[0].type.description); break;
|
|
|
|
case NITROX: retVal = QString(get_nitrox_string(dive)); 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;
|
2013-05-02 02:51:34 +00:00
|
|
|
}
|
2013-05-02 21:05:53 +00:00
|
|
|
break;
|
2013-05-02 02:51:34 +00:00
|
|
|
}
|
2013-05-02 23:32:57 +00:00
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
if (role == DiveTripModel::STAR_ROLE)
|
2013-05-02 23:32:57 +00:00
|
|
|
retVal = dive->rating;
|
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
if (role == DiveTripModel::DIVE_ROLE)
|
2013-05-02 23:32:57 +00:00
|
|
|
retVal = QVariant::fromValue<void*>(dive);
|
|
|
|
|
2013-11-16 20:41:47 +00:00
|
|
|
if(role == DiveTripModel::DIVE_IDX){
|
|
|
|
retVal = get_divenr(dive);
|
|
|
|
}
|
2013-05-02 02:51:34 +00:00
|
|
|
return retVal;
|
2013-04-22 01:12:36 +00:00
|
|
|
}
|
|
|
|
|
2013-11-19 00:33:01 +00:00
|
|
|
Qt::ItemFlags DiveItem::flags(const QModelIndex& index) const
|
|
|
|
{
|
|
|
|
if(index.column() == NR){
|
|
|
|
return TreeItem::flags(index) | Qt::ItemIsEditable;
|
|
|
|
}
|
|
|
|
return TreeItem::flags(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DiveItem::setData(const QModelIndex& index, const QVariant& value, int role)
|
|
|
|
{
|
|
|
|
if (role != Qt::EditRole)
|
|
|
|
return false;
|
|
|
|
if (index.column() != NR)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int v = value.toInt();
|
2013-11-19 00:34:22 +00:00
|
|
|
if (v == 0)
|
|
|
|
return false;
|
|
|
|
|
2013-11-19 00:33:01 +00:00
|
|
|
int i;
|
|
|
|
struct dive *d;
|
|
|
|
for_each_dive(i, d){
|
|
|
|
if (d->number == v)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
dive->number = value.toInt();
|
|
|
|
mark_divelist_changed(TRUE);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-11 09:41:50 +00:00
|
|
|
QString DiveItem::displayDate() const
|
|
|
|
{
|
2013-10-16 22:00:17 +00:00
|
|
|
return get_dive_date_string(dive->when);
|
2013-07-11 09:41:50 +00:00
|
|
|
}
|
|
|
|
|
2013-04-24 15:57:30 +00:00
|
|
|
QString DiveItem::displayDepth() const
|
|
|
|
{
|
|
|
|
const int scale = 1000;
|
|
|
|
QString fract, str;
|
|
|
|
if (get_units()->length == units::METERS) {
|
2013-10-15 13:09:46 +00:00
|
|
|
fract = QString::number((unsigned)(dive->maxdepth.mm % scale) / 100);
|
|
|
|
str = QString("%1.%2").arg((unsigned)(dive->maxdepth.mm / scale)).arg(fract, 1, QChar('0'));
|
2013-04-24 15:57:30 +00:00
|
|
|
}
|
|
|
|
if (get_units()->length == units::FEET) {
|
2013-04-25 14:04:41 +00:00
|
|
|
str = QString::number(mm_to_feet(dive->maxdepth.mm),'f',0);
|
2013-04-24 15:57:30 +00:00
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString DiveItem::displayDuration() const
|
|
|
|
{
|
2013-04-24 23:03:14 +00:00
|
|
|
int hrs, mins, secs;
|
2013-04-25 14:04:41 +00:00
|
|
|
secs = dive->duration.seconds % 60;
|
|
|
|
mins = dive->duration.seconds / 60;
|
2013-04-24 23:03:14 +00:00
|
|
|
hrs = mins / 60;
|
|
|
|
mins -= hrs * 60;
|
2013-04-24 15:57:30 +00:00
|
|
|
|
|
|
|
QString displayTime;
|
2013-04-24 23:03:14 +00:00
|
|
|
if (hrs)
|
|
|
|
displayTime = QString("%1:%2:").arg(hrs).arg(mins, 2, 10, QChar('0'));
|
2013-04-24 15:57:30 +00:00
|
|
|
else
|
2013-04-24 23:03:14 +00:00
|
|
|
displayTime = QString("%1:").arg(mins);
|
|
|
|
displayTime += QString("%1").arg(secs, 2, 10, QChar('0'));
|
2013-04-24 15:57:30 +00:00
|
|
|
return displayTime;
|
|
|
|
}
|
|
|
|
|
2013-04-25 06:21:57 +00:00
|
|
|
QString DiveItem::displayTemperature() const
|
|
|
|
{
|
|
|
|
QString str;
|
2013-05-14 07:45:01 +00:00
|
|
|
if (!dive->watertemp.mkelvin)
|
|
|
|
return str;
|
2013-05-02 05:00:08 +00:00
|
|
|
if (get_units()->temperature == units::CELSIUS)
|
2013-04-25 14:04:41 +00:00
|
|
|
str = QString::number(mkelvin_to_C(dive->watertemp.mkelvin), 'f', 1);
|
2013-05-02 05:00:08 +00:00
|
|
|
else
|
2013-04-25 14:04:41 +00:00
|
|
|
str = QString::number(mkelvin_to_F(dive->watertemp.mkelvin), 'f', 1);
|
2013-04-25 06:21:57 +00:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString DiveItem::displaySac() const
|
|
|
|
{
|
|
|
|
QString str;
|
2013-05-02 05:00:08 +00:00
|
|
|
if (get_units()->volume == units::LITER)
|
2013-10-15 13:09:46 +00:00
|
|
|
str = QString::number(dive->sac / 1000.0, 'f', 1).append(tr(" l/min"));
|
2013-05-02 05:00:08 +00:00
|
|
|
else
|
2013-10-15 13:09:46 +00:00
|
|
|
str = QString::number(ml_to_cuft(dive->sac), 'f', 2).append(tr(" cuft/min"));
|
2013-04-25 06:21:57 +00:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString DiveItem::displayWeight() const
|
|
|
|
{
|
2013-10-04 18:39:33 +00:00
|
|
|
QString str = weight_string(weight());
|
2013-04-25 06:21:57 +00:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2013-05-02 02:51:34 +00:00
|
|
|
int DiveItem::weight() const
|
2013-04-22 01:12:36 +00:00
|
|
|
{
|
2013-05-02 02:51:34 +00:00
|
|
|
weight_t tw = { total_weight(dive) };
|
|
|
|
return tw.grams;
|
2013-04-22 01:12:36 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
DiveTripModel::DiveTripModel(QObject* parent): TreeModel(parent)
|
2013-05-02 02:51:34 +00:00
|
|
|
{
|
2013-06-17 21:59:50 +00:00
|
|
|
columns = COLUMNS;
|
2013-04-22 01:12:36 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 02:51:34 +00:00
|
|
|
Qt::ItemFlags DiveTripModel::flags(const QModelIndex& index) const
|
2013-04-22 01:12:36 +00:00
|
|
|
{
|
2013-05-02 02:51:34 +00:00
|
|
|
if (!index.isValid())
|
2013-04-22 01:12:36 +00:00
|
|
|
return 0;
|
2013-05-02 02:51:34 +00:00
|
|
|
|
2013-11-19 00:33:01 +00:00
|
|
|
TripItem *item = static_cast<TripItem*>(index.internalPointer());
|
|
|
|
return item->flags(index);
|
2013-04-22 01:12:36 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
QVariant DiveTripModel::headerData(int section, Qt::Orientation orientation, int role) const
|
2013-04-22 01:12:36 +00:00
|
|
|
{
|
2013-06-17 21:59:50 +00:00
|
|
|
QVariant ret;
|
|
|
|
if (orientation == Qt::Vertical)
|
|
|
|
return ret;
|
2013-04-22 01:12:36 +00:00
|
|
|
|
2013-06-16 14:13:32 +00:00
|
|
|
switch(role){
|
|
|
|
case Qt::FontRole :
|
2013-06-17 21:59:50 +00:00
|
|
|
ret = defaultModelFont(); break;
|
|
|
|
case Qt::DisplayRole :
|
|
|
|
switch (section) {
|
|
|
|
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;
|
|
|
|
}break;
|
2013-06-16 14:13:32 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 21:59:50 +00:00
|
|
|
return ret;
|
2013-05-02 02:51:34 +00:00
|
|
|
}
|
2013-04-22 01:12:36 +00:00
|
|
|
|
2013-05-02 02:51:34 +00:00
|
|
|
void DiveTripModel::setupModelData()
|
2013-04-22 01:12:36 +00:00
|
|
|
{
|
2013-05-02 02:51:34 +00:00
|
|
|
int i = dive_table.nr;
|
|
|
|
|
2013-05-28 19:56:58 +00:00
|
|
|
if (rowCount()){
|
|
|
|
beginRemoveRows(QModelIndex(), 0, rowCount()-1);
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
|
|
|
|
2013-06-15 23:45:04 +00:00
|
|
|
if (autogroup)
|
|
|
|
autogroup_dives();
|
|
|
|
dive_table.preexisting = dive_table.nr;
|
2013-05-02 02:51:34 +00:00
|
|
|
while (--i >= 0) {
|
|
|
|
struct dive* dive = get_dive(i);
|
2013-05-07 03:36:37 +00:00
|
|
|
update_cylinder_related_info(dive);
|
2013-05-02 02:51:34 +00:00
|
|
|
dive_trip_t* trip = dive->divetrip;
|
|
|
|
|
|
|
|
DiveItem* diveItem = new DiveItem();
|
|
|
|
diveItem->dive = dive;
|
|
|
|
|
2013-05-28 19:56:58 +00:00
|
|
|
if (!trip || currentLayout == LIST) {
|
2013-05-02 02:51:34 +00:00
|
|
|
diveItem->parent = rootItem;
|
2013-05-14 07:28:30 +00:00
|
|
|
rootItem->children.push_back(diveItem);
|
2013-05-02 02:51:34 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-05-28 19:56:58 +00:00
|
|
|
if (currentLayout == LIST)
|
|
|
|
continue;
|
|
|
|
|
2013-05-02 02:51:34 +00:00
|
|
|
if (!trips.keys().contains(trip)) {
|
|
|
|
TripItem* tripItem = new TripItem();
|
|
|
|
tripItem->trip = trip;
|
|
|
|
tripItem->parent = rootItem;
|
2013-05-14 07:28:30 +00:00
|
|
|
tripItem->children.push_back(diveItem);
|
2013-05-02 02:51:34 +00:00
|
|
|
trips[trip] = tripItem;
|
2013-05-14 07:28:30 +00:00
|
|
|
rootItem->children.push_back(tripItem);
|
2013-05-02 02:51:34 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
TripItem* tripItem = trips[trip];
|
2013-05-14 07:28:30 +00:00
|
|
|
tripItem->children.push_back(diveItem);
|
2013-04-22 01:12:36 +00:00
|
|
|
}
|
2013-05-28 19:56:58 +00:00
|
|
|
|
|
|
|
if (rowCount()){
|
2013-05-29 20:43:14 +00:00
|
|
|
beginInsertRows(QModelIndex(), 0, rowCount() - 1);
|
2013-05-28 19:56:58 +00:00
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DiveTripModel::Layout DiveTripModel::layout() const
|
|
|
|
{
|
|
|
|
return currentLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiveTripModel::setLayout(DiveTripModel::Layout layout)
|
|
|
|
{
|
|
|
|
currentLayout = layout;
|
|
|
|
setupModelData();
|
2013-04-22 01:12:36 +00:00
|
|
|
}
|
2013-06-07 14:43:45 +00:00
|
|
|
|
2013-11-19 00:33:01 +00:00
|
|
|
bool DiveTripModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
|
|
|
{
|
|
|
|
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
|
|
|
|
DiveItem *diveItem = dynamic_cast<DiveItem*>(item);
|
|
|
|
if(!diveItem)
|
|
|
|
return false;
|
|
|
|
return diveItem->setData(index, value, role);}
|
|
|
|
|
|
|
|
|
2013-06-17 19:46:35 +00:00
|
|
|
/*####################################################################
|
2013-06-07 14:43:45 +00:00
|
|
|
*
|
2013-06-17 19:46:35 +00:00
|
|
|
* Dive Computer Model
|
2013-06-07 14:43:45 +00:00
|
|
|
*
|
|
|
|
*####################################################################
|
|
|
|
*/
|
|
|
|
|
2013-10-11 14:42:33 +00:00
|
|
|
DiveComputerModel::DiveComputerModel(QMultiMap<QString, DiveComputerNode> &dcMap, QObject* parent): CleanerTableModel()
|
2013-06-07 14:43:45 +00:00
|
|
|
{
|
2013-10-11 14:42:33 +00:00
|
|
|
setHeaderDataStrings(QStringList() << "" << tr("Model") << tr("Device ID") << tr("Nickname"));
|
2013-06-17 22:58:26 +00:00
|
|
|
dcWorkingMap = dcMap;
|
|
|
|
numRows = 0;
|
2013-06-07 14:43:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QVariant DiveComputerModel::data(const QModelIndex& index, int role) const
|
|
|
|
{
|
2013-06-17 22:58:26 +00:00
|
|
|
QList<DiveComputerNode> values = dcWorkingMap.values();
|
|
|
|
DiveComputerNode node = values.at(index.row());
|
2013-06-07 14:43:45 +00:00
|
|
|
|
|
|
|
QVariant ret;
|
|
|
|
if (role == Qt::DisplayRole || role == Qt::EditRole){
|
|
|
|
switch(index.column()){
|
2013-06-17 22:58:26 +00:00
|
|
|
case ID: ret = QString("0x").append(QString::number(node.deviceId, 16)); break;
|
|
|
|
case MODEL: ret = node.model; break;
|
|
|
|
case NICKNAME: ret = node.nickName; break;
|
2013-06-07 14:43:45 +00:00
|
|
|
}
|
|
|
|
}
|
2013-06-17 19:46:35 +00:00
|
|
|
|
2013-11-22 01:32:11 +00:00
|
|
|
if (index.column() == REMOVE){
|
|
|
|
switch(role){
|
|
|
|
case Qt::DecorationRole : ret = QIcon(":trash"); break;
|
|
|
|
case Qt::ToolTipRole : ret = tr("Clicking here will remove this divecomputer."); break;
|
|
|
|
}
|
2013-06-07 14:43:45 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int DiveComputerModel::rowCount(const QModelIndex& parent) const
|
|
|
|
{
|
|
|
|
return numRows;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiveComputerModel::update()
|
|
|
|
{
|
2013-06-17 22:58:26 +00:00
|
|
|
QList<DiveComputerNode> values = dcWorkingMap.values();
|
|
|
|
int count = values.count();
|
2013-06-07 15:57:35 +00:00
|
|
|
|
2013-06-07 14:43:45 +00:00
|
|
|
if(numRows){
|
|
|
|
beginRemoveRows(QModelIndex(), 0, numRows-1);
|
|
|
|
numRows = 0;
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
2013-06-07 15:57:35 +00:00
|
|
|
|
2013-06-07 14:43:45 +00:00
|
|
|
if (count){
|
|
|
|
beginInsertRows(QModelIndex(), 0, count-1);
|
|
|
|
numRows = count;
|
|
|
|
endInsertRows();
|
|
|
|
}
|
2013-06-07 15:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Qt::ItemFlags DiveComputerModel::flags(const QModelIndex& index) const
|
|
|
|
{
|
|
|
|
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
|
|
|
|
if (index.column() == NICKNAME)
|
|
|
|
flags |= Qt::ItemIsEditable;
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DiveComputerModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
|
|
|
{
|
2013-06-17 22:58:26 +00:00
|
|
|
QList<DiveComputerNode> values = dcWorkingMap.values();
|
|
|
|
DiveComputerNode node = values.at(index.row());
|
|
|
|
dcWorkingMap.remove(node.model, node);
|
|
|
|
node.nickName = value.toString();
|
|
|
|
dcWorkingMap.insert(node.model, node);
|
2013-07-16 22:13:58 +00:00
|
|
|
emit dataChanged(index, index);
|
2013-06-07 18:25:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-06-17 22:58:26 +00:00
|
|
|
void DiveComputerModel::remove(const QModelIndex& index)
|
2013-06-07 18:25:29 +00:00
|
|
|
{
|
2013-06-17 22:58:26 +00:00
|
|
|
QList<DiveComputerNode> values = dcWorkingMap.values();
|
|
|
|
DiveComputerNode node = values.at(index.row());
|
|
|
|
dcWorkingMap.remove(node.model, node);
|
2013-06-07 18:25:29 +00:00
|
|
|
update();
|
2013-06-07 14:43:45 +00:00
|
|
|
}
|
2013-06-17 22:41:05 +00:00
|
|
|
|
2013-06-18 16:25:24 +00:00
|
|
|
void DiveComputerModel::dropWorkingList()
|
|
|
|
{
|
|
|
|
// how do I prevent the memory leak ?
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiveComputerModel::keepWorkingList()
|
|
|
|
{
|
|
|
|
if (dcList.dcMap != dcWorkingMap)
|
|
|
|
mark_divelist_changed(TRUE);
|
|
|
|
dcList.dcMap = dcWorkingMap;
|
|
|
|
}
|
|
|
|
|
2013-06-17 22:41:05 +00:00
|
|
|
/*#################################################################
|
|
|
|
* #
|
|
|
|
* # Yearly Statistics Model
|
|
|
|
* #
|
|
|
|
* ################################################################
|
|
|
|
*/
|
|
|
|
|
2013-06-18 00:05:17 +00:00
|
|
|
class YearStatisticsItem : public TreeItem{
|
|
|
|
public:
|
2013-06-18 16:26:23 +00:00
|
|
|
enum {YEAR, DIVES, TOTAL_TIME, AVERAGE_TIME, SHORTEST_TIME, LONGEST_TIME, AVG_DEPTH, MIN_DEPTH,
|
|
|
|
MAX_DEPTH, AVG_SAC, MIN_SAC, MAX_SAC, AVG_TEMP, MIN_TEMP, MAX_TEMP, COLUMNS};
|
2013-06-18 00:05:17 +00:00
|
|
|
|
|
|
|
QVariant data(int column, int role) const;
|
|
|
|
YearStatisticsItem(stats_t interval);
|
|
|
|
private:
|
|
|
|
stats_t stats_interval;
|
|
|
|
};
|
|
|
|
|
2013-06-18 16:26:23 +00:00
|
|
|
YearStatisticsItem::YearStatisticsItem(stats_t interval) : stats_interval(interval)
|
2013-06-18 00:05:17 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant YearStatisticsItem::data(int column, int role) const
|
|
|
|
{
|
2013-06-18 16:26:23 +00:00
|
|
|
double value;
|
2013-06-18 00:05:17 +00:00
|
|
|
QVariant ret;
|
|
|
|
|
2013-06-19 17:30:36 +00:00
|
|
|
if (role == Qt::FontRole) {
|
|
|
|
QFont font = defaultModelFont();
|
|
|
|
font.setBold(stats_interval.is_year);
|
|
|
|
return font;
|
|
|
|
} else if (role != Qt::DisplayRole) {
|
|
|
|
return ret;
|
|
|
|
}
|
2013-06-18 16:26:23 +00:00
|
|
|
switch(column) {
|
2013-11-24 01:09:34 +00:00
|
|
|
case YEAR:
|
|
|
|
if (stats_interval.is_trip) {
|
|
|
|
ret = stats_interval.location;
|
|
|
|
} else {
|
|
|
|
ret = stats_interval.period;
|
|
|
|
}
|
|
|
|
break;
|
2013-06-18 16:26:23 +00:00
|
|
|
case DIVES: ret = stats_interval.selection_size; break;
|
|
|
|
case TOTAL_TIME: ret = get_time_string(stats_interval.total_time.seconds, 0); break;
|
|
|
|
case AVERAGE_TIME: ret = get_minutes(stats_interval.total_time.seconds / stats_interval.selection_size); break;
|
|
|
|
case SHORTEST_TIME: ret = get_minutes(stats_interval.shortest_time.seconds); break;
|
|
|
|
case LONGEST_TIME: ret = get_minutes(stats_interval.longest_time.seconds); break;
|
2013-06-18 17:48:46 +00:00
|
|
|
case AVG_DEPTH: ret = get_depth_string(stats_interval.avg_depth); break;
|
|
|
|
case MIN_DEPTH: ret = get_depth_string(stats_interval.min_depth); break;
|
|
|
|
case MAX_DEPTH: ret = get_depth_string(stats_interval.max_depth); break;
|
|
|
|
case AVG_SAC: ret = get_volume_string(stats_interval.avg_sac); break;
|
|
|
|
case MIN_SAC: ret = get_volume_string(stats_interval.min_sac); break;
|
|
|
|
case MAX_SAC: ret = get_volume_string(stats_interval.max_sac); break;
|
2013-06-18 16:26:23 +00:00
|
|
|
case AVG_TEMP:
|
|
|
|
if (stats_interval.combined_temp && stats_interval.combined_count) {
|
2013-06-18 17:48:46 +00:00
|
|
|
ret = QString::number(stats_interval.combined_temp / stats_interval.combined_count, 'f', 1);
|
2013-06-18 16:26:23 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MIN_TEMP:
|
2013-06-18 17:48:46 +00:00
|
|
|
value = get_temp_units(stats_interval.min_temp, NULL);
|
|
|
|
if (value > -100.0)
|
|
|
|
ret = QString::number(value, 'f', 1);
|
2013-06-18 16:26:23 +00:00
|
|
|
break;
|
|
|
|
case MAX_TEMP:
|
2013-06-18 17:48:46 +00:00
|
|
|
value = get_temp_units(stats_interval.max_temp, NULL);
|
|
|
|
if (value > -100.0)
|
|
|
|
ret = QString::number(value, 'f', 1);
|
2013-06-18 16:26:23 +00:00
|
|
|
break;
|
2013-06-18 00:05:17 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-06-17 22:41:05 +00:00
|
|
|
YearlyStatisticsModel::YearlyStatisticsModel(QObject* parent)
|
|
|
|
{
|
2013-06-17 23:02:30 +00:00
|
|
|
columns = COLUMNS;
|
2013-06-18 00:05:17 +00:00
|
|
|
update_yearly_stats();
|
2013-06-17 22:41:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QVariant YearlyStatisticsModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
|
|
{
|
|
|
|
QVariant val;
|
2013-06-18 16:26:23 +00:00
|
|
|
if (role == Qt::FontRole)
|
2013-06-17 23:02:30 +00:00
|
|
|
val = defaultModelFont();
|
2013-06-18 00:05:17 +00:00
|
|
|
|
2013-06-18 16:26:23 +00:00
|
|
|
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
|
|
|
switch(section) {
|
2013-11-24 01:09:34 +00:00
|
|
|
case YEAR: val = tr("Year \n > Month / Trip"); break;
|
2013-06-18 16:26:23 +00:00
|
|
|
case DIVES: val = tr("#"); break;
|
|
|
|
case TOTAL_TIME: val = tr("Duration \n Total"); break;
|
2013-06-18 17:48:46 +00:00
|
|
|
case AVERAGE_TIME: val = tr("\nAverage"); break;
|
|
|
|
case SHORTEST_TIME: val = tr("\nShortest"); break;
|
|
|
|
case LONGEST_TIME: val = tr("\nLongest"); break;
|
|
|
|
case AVG_DEPTH: val = QString(tr("Depth (%1)\n Average")).arg(get_depth_unit()); break;
|
|
|
|
case MIN_DEPTH: val = tr("\nMinimum"); break;
|
|
|
|
case MAX_DEPTH: val = tr("\nMaximum"); break;
|
|
|
|
case AVG_SAC: val = QString(tr("SAC (%1)\n Average")).arg(get_volume_unit()); break;
|
|
|
|
case MIN_SAC: val = tr("\nMinimum"); break;
|
|
|
|
case MAX_SAC: val = tr("\nMaximum"); break;
|
|
|
|
case AVG_TEMP: val = QString(tr("Temp. (%1)\n Average").arg(get_temp_unit())); break;
|
|
|
|
case MIN_TEMP: val = tr("\nMinimum"); break;
|
|
|
|
case MAX_TEMP: val = tr("\nMaximum"); break;
|
2013-06-17 23:02:30 +00:00
|
|
|
}
|
2013-06-17 22:41:05 +00:00
|
|
|
}
|
2013-06-17 23:02:30 +00:00
|
|
|
return val;
|
2013-06-17 22:41:05 +00:00
|
|
|
}
|
2013-06-18 00:05:17 +00:00
|
|
|
|
|
|
|
void YearlyStatisticsModel::update_yearly_stats()
|
|
|
|
{
|
|
|
|
int i, month = 0;
|
|
|
|
unsigned int j, combined_months;
|
|
|
|
|
2013-06-18 16:26:23 +00:00
|
|
|
for (i = 0; stats_yearly != NULL && stats_yearly[i].period; ++i) {
|
2013-06-18 00:05:17 +00:00
|
|
|
YearStatisticsItem *item = new YearStatisticsItem(stats_yearly[i]);
|
|
|
|
combined_months = 0;
|
|
|
|
for (j = 0; combined_months < stats_yearly[i].selection_size; ++j) {
|
|
|
|
combined_months += stats_monthly[month].selection_size;
|
|
|
|
YearStatisticsItem *iChild = new YearStatisticsItem(stats_monthly[month]);
|
|
|
|
item->children.append(iChild);
|
2013-06-18 20:29:37 +00:00
|
|
|
iChild->parent = item;
|
2013-06-18 00:05:17 +00:00
|
|
|
month++;
|
|
|
|
}
|
|
|
|
rootItem->children.append(item);
|
2013-06-18 20:29:37 +00:00
|
|
|
item->parent = rootItem;
|
2013-06-18 00:05:17 +00:00
|
|
|
}
|
2013-11-24 01:09:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (stats_by_trip != NULL ) {
|
|
|
|
YearStatisticsItem *item = new YearStatisticsItem(stats_by_trip[0]);
|
|
|
|
for (i = 1; stats_by_trip != NULL && stats_by_trip[i].is_trip; ++i) {
|
|
|
|
YearStatisticsItem *iChild = new YearStatisticsItem(stats_by_trip[i]);
|
|
|
|
item->children.append(iChild);
|
|
|
|
iChild->parent = item;
|
|
|
|
}
|
|
|
|
rootItem->children.append(item);
|
|
|
|
item->parent = rootItem;
|
|
|
|
}
|
2013-06-18 00:05:17 +00:00
|
|
|
}
|
2013-07-25 09:52:20 +00:00
|
|
|
|
|
|
|
/*#################################################################
|
|
|
|
* #
|
|
|
|
* # Table Print Model
|
|
|
|
* #
|
|
|
|
* ################################################################
|
|
|
|
*/
|
|
|
|
TablePrintModel::TablePrintModel()
|
|
|
|
{
|
|
|
|
columns = 7;
|
|
|
|
rows = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TablePrintModel::~TablePrintModel()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < list.size(); i++)
|
|
|
|
delete list.at(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TablePrintModel::insertRow(int index)
|
|
|
|
{
|
|
|
|
struct TablePrintItem *item = new struct TablePrintItem();
|
|
|
|
item->colorBackground = 0xffffffff;
|
|
|
|
if (index == -1) {
|
|
|
|
beginInsertRows(QModelIndex(), rows, rows);
|
|
|
|
list.append(item);
|
|
|
|
} else {
|
|
|
|
beginInsertRows(QModelIndex(), index, index);
|
|
|
|
list.insert(index, item);
|
|
|
|
}
|
|
|
|
endInsertRows();
|
|
|
|
rows++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TablePrintModel::callReset()
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant TablePrintModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
|
|
|
if (!index.isValid())
|
|
|
|
return QVariant();
|
|
|
|
if (role == Qt::BackgroundRole)
|
|
|
|
return QColor(list.at(index.row())->colorBackground);
|
|
|
|
if (role == Qt::DisplayRole)
|
|
|
|
switch (index.column()) {
|
2013-10-11 13:21:04 +00:00
|
|
|
case 0: return list.at(index.row())->number;
|
|
|
|
case 1: return list.at(index.row())->date;
|
|
|
|
case 2: return list.at(index.row())->depth;
|
|
|
|
case 3: return list.at(index.row())->duration;
|
|
|
|
case 4: return list.at(index.row())->divemaster;
|
|
|
|
case 5: return list.at(index.row())->buddy;
|
|
|
|
case 6: return list.at(index.row())->location;
|
2013-07-25 09:52:20 +00:00
|
|
|
}
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TablePrintModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
|
|
{
|
|
|
|
if (index.isValid()) {
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
|
|
switch (index.column()) {
|
2013-10-11 13:21:04 +00:00
|
|
|
case 0: list.at(index.row())->number = value.toString();
|
|
|
|
case 1: list.at(index.row())->date = value.toString();
|
|
|
|
case 2: list.at(index.row())->depth = value.toString();
|
|
|
|
case 3: list.at(index.row())->duration = value.toString();
|
|
|
|
case 4: list.at(index.row())->divemaster = value.toString();
|
|
|
|
case 5: list.at(index.row())->buddy = value.toString();
|
|
|
|
case 6: list.at(index.row())->location = value.toString();
|
2013-07-25 09:52:20 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (role == Qt::BackgroundRole) {
|
|
|
|
list.at(index.row())->colorBackground = value.value<unsigned int>();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TablePrintModel::rowCount(const QModelIndex &parent) const
|
|
|
|
{
|
|
|
|
Q_UNUSED(parent);
|
|
|
|
return rows;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TablePrintModel::columnCount(const QModelIndex &parent) const
|
|
|
|
{
|
|
|
|
Q_UNUSED(parent);
|
|
|
|
return columns;
|
|
|
|
}
|
2013-10-03 14:50:40 +00:00
|
|
|
|
|
|
|
/*#################################################################
|
|
|
|
* #
|
|
|
|
* # Profile Print Model
|
|
|
|
* #
|
|
|
|
* ################################################################
|
|
|
|
*/
|
|
|
|
|
|
|
|
ProfilePrintModel::ProfilePrintModel(QObject *parent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProfilePrintModel::setDive(struct dive *divePtr)
|
|
|
|
{
|
|
|
|
dive = divePtr;
|
|
|
|
// reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
int ProfilePrintModel::rowCount(const QModelIndex &parent) const
|
|
|
|
{
|
2013-11-30 12:38:54 +00:00
|
|
|
return 12;
|
2013-10-03 14:50:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int ProfilePrintModel::columnCount(const QModelIndex &parent) const
|
|
|
|
{
|
2013-11-30 12:38:54 +00:00
|
|
|
return 5;
|
2013-10-03 14:50:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QVariant ProfilePrintModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
|
|
|
const int row = index.row();
|
|
|
|
const int col = index.column();
|
|
|
|
|
|
|
|
switch (role) {
|
|
|
|
case Qt::DisplayRole: {
|
|
|
|
struct DiveItem di;
|
2013-11-12 07:33:01 +00:00
|
|
|
di.dive = dive;
|
2013-10-03 14:50:40 +00:00
|
|
|
char buf[80];
|
2013-10-11 13:21:04 +00:00
|
|
|
|
|
|
|
const QString unknown = tr("unknown");
|
2013-10-03 14:50:40 +00:00
|
|
|
|
|
|
|
// dive# + date, depth, location, duration
|
|
|
|
if (row == 0) {
|
|
|
|
if (col == 0)
|
2013-10-11 13:21:04 +00:00
|
|
|
return tr("Dive #%1 - %2").arg(dive->number).arg(di.displayDate());
|
2013-11-30 13:46:13 +00:00
|
|
|
if (col == 4) {
|
2013-10-11 13:21:04 +00:00
|
|
|
QString unit = (get_units()->length == units::METERS) ? "m" : "ft";
|
|
|
|
return tr("Max depth: %1 %2").arg(di.displayDepth()).arg(unit);
|
2013-10-03 14:50:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (row == 1) {
|
|
|
|
if (col == 0)
|
2013-11-30 13:46:13 +00:00
|
|
|
return QString(dive->location);
|
|
|
|
if (col == 4)
|
2013-10-03 14:50:40 +00:00
|
|
|
return QString(tr("Duration: %1 min")).arg(di.displayDuration());
|
|
|
|
}
|
2013-11-30 14:00:51 +00:00
|
|
|
// headings
|
2013-10-03 14:50:40 +00:00
|
|
|
if (row == 2) {
|
|
|
|
if (col == 0)
|
2013-11-30 14:00:51 +00:00
|
|
|
return tr("Gas Used:");
|
2013-10-03 14:50:40 +00:00
|
|
|
if (col == 2)
|
2013-11-30 14:00:51 +00:00
|
|
|
return tr("SAC:");
|
|
|
|
if (col == 3)
|
|
|
|
return tr("Max. CNS:");
|
|
|
|
if (col == 4)
|
|
|
|
return tr("Weights:");
|
2013-10-03 14:50:40 +00:00
|
|
|
}
|
2013-11-30 14:09:54 +00:00
|
|
|
// notes
|
|
|
|
if (col == 0) {
|
|
|
|
if (row == 6)
|
|
|
|
return tr("Notes:");
|
|
|
|
if (row == 7)
|
|
|
|
return QString(dive->notes);
|
|
|
|
}
|
|
|
|
/*
|
2013-10-03 14:50:40 +00:00
|
|
|
// cylinder data
|
|
|
|
if (row > 2 && row < 10 && row - 3 < MAX_CYLINDERS) {
|
|
|
|
cylinder_t *cyl = &dive->cylinder[row - 3];
|
|
|
|
if (cyl->type.description) { // how do we check if a cylinder is added?
|
|
|
|
if (col == 0) {
|
|
|
|
if (cyl->type.description[0] != '\0')
|
|
|
|
return QString(cyl->type.description);
|
|
|
|
return unknown;
|
|
|
|
}
|
|
|
|
if (col == 1) {
|
|
|
|
get_gas_string(cyl->gasmix.o2.permille, cyl->gasmix.he.permille, buf, sizeof(buf));
|
|
|
|
return QString(buf);
|
|
|
|
}
|
|
|
|
if (col == 2) {
|
|
|
|
return get_cylinder_used_gas_string(cyl, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// dive notes
|
|
|
|
if (row == 10 && col == 0)
|
2013-11-30 13:46:13 +00:00
|
|
|
return QString(dive->notes);
|
2013-10-03 14:50:40 +00:00
|
|
|
// sac, cns, otu - headings
|
|
|
|
if (col == 3) {
|
|
|
|
if (row == 2)
|
2013-10-11 13:21:04 +00:00
|
|
|
return tr("SAC");
|
2013-10-03 14:50:40 +00:00
|
|
|
if (row == 4)
|
2013-10-11 13:21:04 +00:00
|
|
|
return tr("Max. CNS");
|
2013-10-03 14:50:40 +00:00
|
|
|
if (row == 6)
|
2013-10-11 13:21:04 +00:00
|
|
|
return tr("OTU");
|
2013-10-03 14:50:40 +00:00
|
|
|
}
|
|
|
|
// sac, cns, otu - data
|
|
|
|
if (col == 4) {
|
|
|
|
if (row == 2)
|
|
|
|
return di.displaySac();
|
|
|
|
if (row == 4)
|
|
|
|
return QString::number(dive->maxcns);
|
|
|
|
if (row == 6)
|
|
|
|
return QString::number(dive->otu);
|
|
|
|
}
|
|
|
|
// weights heading
|
|
|
|
if (row == 2 && col == 5)
|
2013-10-11 13:21:04 +00:00
|
|
|
return tr("Weights");
|
2013-10-03 14:50:40 +00:00
|
|
|
// total weight
|
|
|
|
if (row == 9) {
|
|
|
|
weight_t tw = { total_weight(dive) };
|
|
|
|
if (tw.grams) {
|
|
|
|
if (col == 5)
|
2013-10-11 13:21:04 +00:00
|
|
|
return tr("Total weight");
|
2013-10-03 14:50:40 +00:00
|
|
|
if (col == 6)
|
|
|
|
return get_weight_string(tw, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// weight data
|
|
|
|
if (row > 2 && row < 10 && row - 3 < MAX_WEIGHTSYSTEMS) {
|
|
|
|
weightsystem_t *ws = &dive->weightsystem[row - 3];
|
|
|
|
if (ws->weight.grams) {
|
|
|
|
if (col == 5) {
|
|
|
|
if (ws->description && ws->description[0] != '\0')
|
|
|
|
return QString(ws->description);
|
|
|
|
return unknown;
|
|
|
|
}
|
|
|
|
if (col == 6) {
|
|
|
|
return get_weight_string(ws->weight, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-11-30 14:09:54 +00:00
|
|
|
*/
|
2013-10-11 13:21:04 +00:00
|
|
|
return QString();
|
2013-10-03 14:50:40 +00:00
|
|
|
}
|
|
|
|
case Qt::FontRole: {
|
|
|
|
QFont font;
|
2013-10-15 09:54:17 +00:00
|
|
|
const int baseSize = 9;
|
2013-10-03 14:50:40 +00:00
|
|
|
// dive #
|
|
|
|
if (row == 0 && col == 0) {
|
|
|
|
font.setBold(true);
|
|
|
|
font.setPixelSize(baseSize + 1);
|
|
|
|
return QVariant::fromValue(font);
|
|
|
|
}
|
|
|
|
// dive location
|
|
|
|
if (row == 1 && col == 0) {
|
|
|
|
font.setBold(true);
|
2013-11-30 13:41:18 +00:00
|
|
|
font.setPixelSize(baseSize);
|
2013-10-03 14:50:40 +00:00
|
|
|
return QVariant::fromValue(font);
|
|
|
|
}
|
|
|
|
// depth/duration
|
2013-11-30 13:41:18 +00:00
|
|
|
if ((row == 0 || row == 1) && col == 4) {
|
2013-10-03 14:50:40 +00:00
|
|
|
font.setPixelSize(baseSize);
|
|
|
|
return QVariant::fromValue(font);
|
|
|
|
}
|
|
|
|
// notes
|
2013-11-30 13:41:18 +00:00
|
|
|
if (row > 5 && col == 0) {
|
2013-10-03 14:50:40 +00:00
|
|
|
font.setPixelSize(baseSize + 1);
|
|
|
|
return QVariant::fromValue(font);
|
|
|
|
}
|
|
|
|
font.setPixelSize(baseSize);
|
|
|
|
return QVariant::fromValue(font);
|
|
|
|
}
|
|
|
|
case Qt::TextAlignmentRole: {
|
2013-11-30 13:41:18 +00:00
|
|
|
// everything is aligned to the left
|
|
|
|
unsigned int align = Qt::AlignLeft;
|
|
|
|
// align depth and duration right
|
|
|
|
if (row < 2 && col == 4)
|
2013-10-03 14:50:40 +00:00
|
|
|
align = Qt::AlignRight | Qt::AlignVCenter;
|
|
|
|
return QVariant::fromValue(align);
|
|
|
|
}
|
|
|
|
} // switch (role)
|
|
|
|
return QVariant();
|
|
|
|
}
|
2013-11-14 19:39:35 +00:00
|
|
|
|
|
|
|
Qt::ItemFlags GasSelectionModel::flags(const QModelIndex& index) const
|
|
|
|
{
|
2013-11-20 02:17:50 +00:00
|
|
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
2013-11-14 19:39:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GasSelectionModel* GasSelectionModel::instance()
|
|
|
|
{
|
2013-11-20 02:17:50 +00:00
|
|
|
static GasSelectionModel* self = new GasSelectionModel();
|
|
|
|
return self;
|
2013-11-14 19:39:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GasSelectionModel::repopulate()
|
|
|
|
{
|
2013-11-20 02:17:50 +00:00
|
|
|
setStringList(DivePlannerPointsModel::instance()->getGasList());
|
2013-11-14 19:39:35 +00:00
|
|
|
}
|
2013-11-14 19:43:28 +00:00
|
|
|
|
|
|
|
QVariant GasSelectionModel::data(const QModelIndex& index, int role) const
|
|
|
|
{
|
|
|
|
if(role == Qt::FontRole){
|
|
|
|
return defaultModelFont();
|
|
|
|
}
|
|
|
|
return QStringListModel::data(index, role);
|
|
|
|
}
|