aboutsummaryrefslogtreecommitdiffstats
path: root/qt-models
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2020-02-28 20:38:04 +0100
committerGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2020-04-07 00:13:35 +0200
commit1dcc885bb257d6c8c64074f8788b468397c34aaa (patch)
tree39c987e36b7f0f103dbdf412c582da1b1907a0e1 /qt-models
parent1aa06e680230351024c05152aeca9a189c5a8d4f (diff)
downloadsubsurface-1dcc885bb257d6c8c64074f8788b468397c34aaa.tar.gz
undo/cylinders: Implement editing of the type
This one is tricky, as when browsing through the types-combobox, the user is presented with presets without actually changing the dive. We do not want an undo-command for every change-event in the combo-box. Therefore, implement a scheme analoguous to the weight-editing: A temporary row can be set / committed or reset. Sadly, the code is more complex because we have to consider the planner, which is not included in the undo system. Firstly, the planner uses a different model, therefore all interactions are channeled through setData() with special roles. Secondly, in the planner we shouldn't place an undo command, but simply overwrite the dive. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'qt-models')
-rw-r--r--qt-models/cylindermodel.cpp95
-rw-r--r--qt-models/cylindermodel.h11
2 files changed, 95 insertions, 11 deletions
diff --git a/qt-models/cylindermodel.cpp b/qt-models/cylindermodel.cpp
index d76cdb344..f2ee0c12e 100644
--- a/qt-models/cylindermodel.cpp
+++ b/qt-models/cylindermodel.cpp
@@ -2,6 +2,7 @@
#include "cylindermodel.h"
#include "tankinfomodel.h"
#include "models.h"
+#include "commands/command.h"
#include "core/qthelper.h"
#include "core/color.h"
#include "qt-models/diveplannermodel.h"
@@ -10,7 +11,9 @@
#include "core/subsurface-string.h"
CylindersModel::CylindersModel(QObject *parent) : CleanerTableModel(parent),
- d(nullptr)
+ d(nullptr),
+ tempRow(-1),
+ tempCyl(empty_cylinder)
{
// enum {REMOVE, TYPE, SIZE, WORKINGPRESS, START, END, O2, HE, DEPTH, MOD, MND, USE, IS_USED};
setHeaderDataStrings(QStringList() << "" << tr("Type") << tr("Size") << tr("Work press.") << tr("Start press.") << tr("End press.") << tr("O₂%") << tr("He%")
@@ -155,7 +158,7 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
return QVariant();
}
- const cylinder_t *cyl = get_cylinder(d, index.row());
+ const cylinder_t *cyl = index.row() == tempRow ? &tempCyl : get_cylinder(d, index.row());
switch (role) {
case Qt::BackgroundRole: {
@@ -299,25 +302,49 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
if (!cyl)
return false;
- if (role == PASS_IN_ROLE) {
- // 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
+ // Here we handle a few cases that allow us to set / commit / revert
+ // a temporary row. This is a horribly misuse of the model/view system.
+ // The reason it is done this way is that the planner and the equipment
+ // tab use different model-classes which are not in a superclass / subclass
+ // relationship.
+ switch (role) {
+ case TEMP_ROLE:
+ // TEMP_ROLE means that we are not supposed to write through to the
+ // actual dive, but a temporary cylinder that is displayed while the
+ // user browses throught the cylinder types.
+ initTempCyl(index.row());
+
switch (index.column()) {
+ case TYPE: {
+ QString type = value.toString();
+ if (!same_string(qPrintable(type), tempCyl.type.description)) {
+ free((void *)tempCyl.type.description);
+ tempCyl.type.description = strdup(qPrintable(type));
+ dataChanged(index, index);
+ }
+ }
case SIZE:
- if (cyl->type.size.mliter != value.toInt()) {
- cyl->type.size.mliter = value.toInt();
+ if (tempCyl.type.size.mliter != value.toInt()) {
+ tempCyl.type.size.mliter = value.toInt();
dataChanged(index, index);
}
return true;
case WORKINGPRESS:
- if (cyl->type.workingpressure.mbar != value.toInt()) {
- cyl->type.workingpressure.mbar = value.toInt();
+ if (tempCyl.type.workingpressure.mbar != value.toInt()) {
+ tempCyl.type.workingpressure.mbar = value.toInt();
dataChanged(index, index);
}
return true;
}
return false;
+ case COMMIT_ROLE:
+ commitTempCyl(index.row());
+ return true;
+ case REVERT_ROLE:
+ clearTempCyl();
+ return true;
+ default:
+ break;
}
QString vString = value.toString();
@@ -621,6 +648,54 @@ void CylindersModel::cylindersReset(const QVector<dive *> &dives)
endResetModel();
}
+// Save the cylinder in the given row so that we can revert if the user cancels a type-editing action.
+void CylindersModel::initTempCyl(int row)
+{
+ if (!d || tempRow == row)
+ return;
+ clearTempCyl();
+ const cylinder_t *cyl = get_cylinder(d, row);
+ if (!cyl)
+ return;
+
+ tempRow = row;
+ tempCyl = clone_cylinder(*cyl);
+
+ dataChanged(index(row, TYPE), index(row, USE));
+}
+
+void CylindersModel::clearTempCyl()
+{
+ if (tempRow < 0)
+ return;
+ int oldRow = tempRow;
+ tempRow = -1;
+ free_cylinder(tempCyl);
+ dataChanged(index(oldRow, TYPE), index(oldRow, USE));
+}
+
+void CylindersModel::commitTempCyl(int row)
+{
+#ifndef SUBSURFACE_MOBILE
+ if (tempRow < 0)
+ return;
+ if (row != tempRow)
+ return clearTempCyl(); // Huh? We are supposed to commit a different row than the one we stored?
+ cylinder_t *cyl = get_cylinder(d, tempRow);
+ if (!cyl)
+ return;
+ // Only submit a command if the type changed
+ if (!same_string(cyl->type.description, tempCyl.type.description) || gettextFromC::tr(cyl->type.description) != QString(tempCyl.type.description)) {
+ if (in_planner())
+ std::swap(*cyl, tempCyl);
+ else
+ Command::editCylinder(tempRow, tempCyl, false);
+ }
+ free_cylinder(tempCyl);
+ tempRow = -1;
+#endif
+}
+
CylindersModelFiltered::CylindersModelFiltered(QObject *parent) : QSortFilterProxyModel(parent)
{
setSourceModel(&source);
diff --git a/qt-models/cylindermodel.h b/qt-models/cylindermodel.h
index d3d87b900..e4585b0ac 100644
--- a/qt-models/cylindermodel.h
+++ b/qt-models/cylindermodel.h
@@ -31,7 +31,9 @@ public:
};
enum Roles {
- PASS_IN_ROLE = Qt::UserRole + 1 // For setting data: don't do any conversions
+ TEMP_ROLE = Qt::UserRole + 1, // Temporarily set data, but don't store in dive
+ COMMIT_ROLE, // Save the temporary data to the dive. Must be set with Column == TYPE.
+ REVERT_ROLE // Revert to original data from dive. Must be set with Column == TYPE.
};
explicit CylindersModel(QObject *parent = 0);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
@@ -59,7 +61,14 @@ slots:
private:
dive *d;
+ // Used if we temporarily change a line because the user is selecting a weight type
+ int tempRow;
+ cylinder_t tempCyl;
+
cylinder_t *cylinderAt(const QModelIndex &index);
+ void initTempCyl(int row);
+ void clearTempCyl();
+ void commitTempCyl(int row);
};
// Cylinder model that hides unused cylinders if the pref.show_unused_cylinders flag is not set