mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
Allow editing sensors through equipment tab
Add a column to the equipment table that shows if a sensor is attached to a tank, or which sensors would be available to attach to a tank that currently doesn't have a pressure sensor associated with it. Changing the sensor assignement can be undone. This column is hidden by default as this is a somewhat unusual activity. Signed-off-by: Michael Andreen <michael@andreen.dev> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
ec96cbaab5
commit
9b4263aa87
10 changed files with 130 additions and 3 deletions
|
@ -314,6 +314,11 @@ int editCylinder(int index, cylinder_t cyl, EditCylinderType type, bool currentD
|
|||
return execute_edit(new EditCylinder(index, cyl, type, currentDiveOnly));
|
||||
}
|
||||
|
||||
void editSensors(int toCylinder, const int fromCylinder)
|
||||
{
|
||||
execute(new EditSensors(toCylinder, fromCylinder));
|
||||
}
|
||||
|
||||
// Trip editing related commands
|
||||
void editTripLocation(dive_trip *trip, const QString &s)
|
||||
{
|
||||
|
|
|
@ -111,6 +111,7 @@ enum class EditCylinderType {
|
|||
GASMIX
|
||||
};
|
||||
int editCylinder(int index, cylinder_t cyl, EditCylinderType type, bool currentDiveOnly);
|
||||
void editSensors(int toCylinder, const int fromCylinder);
|
||||
#ifdef SUBSURFACE_MOBILE
|
||||
// Edits a dive and creates a divesite (if createDs != NULL) or edits a divesite (if changeDs != NULL).
|
||||
// Takes ownership of newDive and createDs!
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "core/divelist.h"
|
||||
#include "core/fulltext.h"
|
||||
#include "core/qthelper.h" // for copy_qstring
|
||||
#include "core/sample.h"
|
||||
#include "core/selection.h"
|
||||
#include "core/subsurface-string.h"
|
||||
#include "core/tag.h"
|
||||
|
@ -1360,6 +1361,43 @@ void EditCylinder::undo()
|
|||
redo();
|
||||
}
|
||||
|
||||
EditSensors::EditSensors(int toCylinderIn, int fromCylinderIn)
|
||||
: dc(current_dc), d(current_dive), toCylinder(toCylinderIn), fromCylinder(fromCylinderIn)
|
||||
{
|
||||
if (!d || !dc)
|
||||
return;
|
||||
|
||||
setText(Command::Base::tr("Edit sensors"));
|
||||
|
||||
}
|
||||
|
||||
void EditSensors::mapSensors(int toCyl, int fromCyl)
|
||||
{
|
||||
for (int i = 0; i < dc->samples; ++i) {
|
||||
for (int s = 0; s < MAX_SENSORS; ++s) {
|
||||
if (dc->sample[i].pressure[s].mbar && dc->sample[i].sensor[s] == fromCyl)
|
||||
dc->sample[i].sensor[s] = toCyl;
|
||||
}
|
||||
}
|
||||
emit diveListNotifier.diveComputerEdited(dc);
|
||||
invalidate_dive_cache(d); // Ensure that dive is written in git_save()
|
||||
}
|
||||
|
||||
void EditSensors::undo()
|
||||
{
|
||||
mapSensors(fromCylinder, toCylinder);
|
||||
}
|
||||
|
||||
void EditSensors::redo()
|
||||
{
|
||||
mapSensors(toCylinder, fromCylinder);
|
||||
}
|
||||
|
||||
bool EditSensors::workToBeDone()
|
||||
{
|
||||
return d && dc;
|
||||
}
|
||||
|
||||
#ifdef SUBSURFACE_MOBILE
|
||||
|
||||
EditDive::EditDive(dive *oldDiveIn, dive *newDiveIn, dive_site *createDs, dive_site *editDs, location_t dsLocationIn)
|
||||
|
|
|
@ -440,6 +440,22 @@ private:
|
|||
void redo() override;
|
||||
};
|
||||
|
||||
class EditSensors : public Base
|
||||
{
|
||||
public:
|
||||
EditSensors(int cylIndex, int fromCylinder);
|
||||
|
||||
private:
|
||||
struct divecomputer *dc;
|
||||
struct dive *d;
|
||||
int toCylinder;
|
||||
int fromCylinder;
|
||||
void mapSensors(int toCyl, int fromCyl);
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
bool workToBeDone() override;
|
||||
};
|
||||
|
||||
#ifdef SUBSURFACE_MOBILE
|
||||
// Edit a full dive. This is used on mobile where we don't have per-field granularity.
|
||||
// It may add or edit a dive site.
|
||||
|
|
|
@ -96,6 +96,8 @@ signals:
|
|||
void divesTimeChanged(timestamp_t delta, const QVector<dive *> &dives);
|
||||
void divesImported(); // A general signal when multiple dives have been imported.
|
||||
|
||||
void diveComputerEdited(divecomputer *dc);
|
||||
|
||||
void cylindersReset(const QVector<dive *> &dives);
|
||||
void cylinderAdded(dive *d, int pos);
|
||||
void cylinderRemoved(dive *d, int pos);
|
||||
|
|
|
@ -49,6 +49,7 @@ DivePlannerWidget::DivePlannerWidget(QWidget *parent) : QWidget(parent, QFlag(0)
|
|||
view->setColumnHidden(CylindersModel::DEPTH, false);
|
||||
view->setColumnHidden(CylindersModel::WORKINGPRESS_INT, true);
|
||||
view->setColumnHidden(CylindersModel::SIZE_INT, true);
|
||||
view->setColumnHidden(CylindersModel::SENSORS, true);
|
||||
view->setItemDelegateForColumn(CylindersModel::TYPE, new TankInfoDelegate(this));
|
||||
connect(ui.cylinderTableWidget, &TableView::addButtonClicked, plannerModel, &DivePlannerPointsModel::addCylinder_clicked);
|
||||
connect(ui.tableWidget, &TableView::addButtonClicked, plannerModel, &DivePlannerPointsModel::addDefaultStop);
|
||||
|
|
|
@ -20,6 +20,15 @@ static bool ignoreHiddenFlag(int i)
|
|||
i == CylindersModel::WORKINGPRESS_INT || i == CylindersModel::SIZE_INT;
|
||||
}
|
||||
|
||||
static bool hiddenByDefault(int i)
|
||||
{
|
||||
switch (i) {
|
||||
case CylindersModel::SENSORS:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TabDiveEquipment::TabDiveEquipment(QWidget *parent) : TabBase(parent),
|
||||
cylindersModel(new CylindersModel(false, true, this)),
|
||||
weightModel(new WeightModel(this))
|
||||
|
@ -81,7 +90,8 @@ TabDiveEquipment::TabDiveEquipment(QWidget *parent) : TabBase(parent),
|
|||
for (int i = 0; i < CylindersModel::COLUMNS; i++) {
|
||||
if (ignoreHiddenFlag(i))
|
||||
continue;
|
||||
bool checked = s.value(QString("column%1_hidden").arg(i)).toBool();
|
||||
auto setting = s.value(QString("column%1_hidden").arg(i));
|
||||
bool checked = setting.isValid() ? setting.toBool() : hiddenByDefault(i) ;
|
||||
QAction *action = new QAction(cylindersModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(), ui.cylinders->view());
|
||||
action->setCheckable(true);
|
||||
action->setData(i);
|
||||
|
|
|
@ -77,6 +77,7 @@ ProfileWidget2::ProfileWidget2(DivePlannerPointsModel *plannerModelIn, double dp
|
|||
connect(&diveListNotifier, &DiveListNotifier::pictureOffsetChanged, this, &ProfileWidget2::pictureOffsetChanged);
|
||||
connect(&diveListNotifier, &DiveListNotifier::divesChanged, this, &ProfileWidget2::divesChanged);
|
||||
connect(&diveListNotifier, &DiveListNotifier::deviceEdited, this, &ProfileWidget2::replot);
|
||||
connect(&diveListNotifier, &DiveListNotifier::diveComputerEdited, this, &ProfileWidget2::replot);
|
||||
#endif // SUBSURFACE_MOBILE
|
||||
|
||||
#if !defined(QT_NO_DEBUG) && defined(SHOW_PLOT_INFO_TABLE)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "core/color.h"
|
||||
#include "qt-models/diveplannermodel.h"
|
||||
#include "core/gettextfromc.h"
|
||||
#include "core/sample.h"
|
||||
#include "core/subsurface-qt/divelistnotifier.h"
|
||||
#include "core/subsurface-string.h"
|
||||
#include <string>
|
||||
|
@ -19,9 +20,10 @@ CylindersModel::CylindersModel(bool planner, bool hideUnused, QObject *parent) :
|
|||
tempRow(-1),
|
||||
tempCyl(empty_cylinder)
|
||||
{
|
||||
// enum {REMOVE, TYPE, SIZE, WORKINGPRESS, START, END, O2, HE, DEPTH, MOD, MND, USE, IS_USED, WORKINGPRESS_INT, SIZE_INT};
|
||||
// enum {REMOVE, TYPE, SIZE, WORKINGPRESS, START, END, O2, HE, DEPTH, MOD, MND, USE, WORKINGPRESS_INT, SIZE_INT, SENSORS};
|
||||
setHeaderDataStrings(QStringList() << "" << tr("Type") << tr("Size") << tr("Work press.") << tr("Start press.") << tr("End press.") << tr("O₂%") << tr("He%")
|
||||
<< tr("Deco switch at") <<tr("Bot. MOD") <<tr("MND") << tr("Use") << "" << "");
|
||||
<< tr("Deco switch at") << tr("Bot. MOD") << tr("MND") << tr("Use") << ""
|
||||
<< "" << tr("Sensors"));
|
||||
|
||||
connect(&diveListNotifier, &DiveListNotifier::cylindersReset, this, &CylindersModel::cylindersReset);
|
||||
connect(&diveListNotifier, &DiveListNotifier::cylinderAdded, this, &CylindersModel::cylinderAdded);
|
||||
|
@ -237,6 +239,24 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
|
|||
return static_cast<int>(cyl->type.workingpressure.mbar);
|
||||
case SIZE_INT:
|
||||
return static_cast<int>(cyl->type.size.mliter);
|
||||
case SENSORS: {
|
||||
std::vector<int16_t> sensors;
|
||||
for (int i = 0; i < current_dc->samples; ++i) {
|
||||
auto &sample = current_dc->sample[i];
|
||||
for (auto s = 0; s < MAX_SENSORS; ++s) {
|
||||
if (sample.pressure[s].mbar) {
|
||||
if (sample.sensor[s] == index.row())
|
||||
return tr("Sensor attached, can't move another sensor here.");
|
||||
else if (std::find(sensors.begin(), sensors.end(), sample.sensor[s]) == sensors.end())
|
||||
sensors.push_back(sample.sensor[s]);
|
||||
}
|
||||
}
|
||||
}
|
||||
QStringList sensorStrings;
|
||||
for (auto s : sensors)
|
||||
sensorStrings << QString::number(s);
|
||||
return tr("Select one of these cylinders: ") + sensorStrings.join(",");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Qt::DecorationRole:
|
||||
|
@ -272,6 +292,8 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
|
|||
return tr("Calculated using Bottom pO₂ preference. Setting MOD adjusts O₂%, set to '*' for best O₂% for max. depth.");
|
||||
case MND:
|
||||
return tr("Calculated using Best Mix END preference. Setting MND adjusts He%, set to '*' for best He% for max. depth.");
|
||||
case SENSORS:
|
||||
return tr("Index of cylinder that you want to move sensor data from.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -453,6 +475,24 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
|
|||
}
|
||||
type = Command::EditCylinderType::TYPE;
|
||||
break;
|
||||
case SENSORS: {
|
||||
std::vector<int> sensors;
|
||||
for (auto &sensor : vString.split(",")) {
|
||||
bool ok = false;
|
||||
int s = sensor.toInt(&ok);
|
||||
if (ok && s < MAX_SENSORS)
|
||||
sensors.push_back(s);
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
int s = vString.toInt(&ok);
|
||||
if (ok) {
|
||||
Command::editSensors(index.row(), s);
|
||||
// We don't use the edit cylinder command and editing sensors is not relevant for planner
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (inPlanner) {
|
||||
|
@ -512,6 +552,18 @@ Qt::ItemFlags CylindersModel::flags(const QModelIndex &index) const
|
|||
{
|
||||
if (index.column() == REMOVE || index.column() == USE)
|
||||
return Qt::ItemIsEnabled;
|
||||
if (index.column() == SENSORS) {
|
||||
for (int i = 0; i < current_dc->samples; ++i) {
|
||||
auto &sample = current_dc->sample[i];
|
||||
for (auto s = 0; s < MAX_SENSORS; ++s) {
|
||||
if (sample.pressure[s].mbar) {
|
||||
if (sample.sensor[s] == index.row())
|
||||
// Sensor attached, not editable.
|
||||
return QAbstractItemModel::flags(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ public:
|
|||
USE,
|
||||
WORKINGPRESS_INT,
|
||||
SIZE_INT,
|
||||
SENSORS,
|
||||
COLUMNS
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue