diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2020-02-28 20:38:04 +0100 |
---|---|---|
committer | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2020-04-07 00:13:35 +0200 |
commit | 1dcc885bb257d6c8c64074f8788b468397c34aaa (patch) | |
tree | 39c987e36b7f0f103dbdf412c582da1b1907a0e1 /qt-models | |
parent | 1aa06e680230351024c05152aeca9a189c5a8d4f (diff) | |
download | subsurface-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.cpp | 95 | ||||
-rw-r--r-- | qt-models/cylindermodel.h | 11 |
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 |