diff options
author | Tomaz Canabrava <tomaz.canabrava@intel.com> | 2015-05-28 16:23:49 -0300 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2015-05-29 14:09:13 -0700 |
commit | f432b764e78ac3d66f5ab1bfc7c18fbdb75624e5 (patch) | |
tree | c2ec5c81660d22bf986968808bd4ecb7256623ae /qt-ui | |
parent | 6e4aa7d044a344527e61f17c2254851ba799c4bd (diff) | |
download | subsurface-f432b764e78ac3d66f5ab1bfc7c18fbdb75624e5.tar.gz |
Move DivePlannerModel and CylinderModel to qt-models
Still trying to make it easier for the Mobile Port:
This patch is a bit bigger than I hopped, but it was the smallest that I
could get.
A lot of TODO items where added where I broke the code because the current
implementation would break the QML implementtion on the designer. I'll
most probably fix those myself when I finish the transition to the models
to the new folder.
I only moved both models at once because there's an interdependency
between them (seems inevitable, tough, but I'll take a better look at it
later).
Signed-off-by: Tomaz Canabrava <tomaz.canabrava@intel.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'qt-ui')
-rw-r--r-- | qt-ui/diveplanner.cpp | 933 | ||||
-rw-r--r-- | qt-ui/diveplanner.h | 111 | ||||
-rw-r--r-- | qt-ui/maintab.cpp | 2 | ||||
-rw-r--r-- | qt-ui/mainwindow.cpp | 1 | ||||
-rw-r--r-- | qt-ui/modeldelegates.cpp | 1 | ||||
-rw-r--r-- | qt-ui/profile/diveprofileitem.cpp | 3 | ||||
-rw-r--r-- | qt-ui/profile/profilewidget2.cpp | 3 |
7 files changed, 19 insertions, 1035 deletions
diff --git a/qt-ui/diveplanner.cpp b/qt-ui/diveplanner.cpp index c82bc0463..7ab0aac86 100644 --- a/qt-ui/diveplanner.cpp +++ b/qt-ui/diveplanner.cpp @@ -3,8 +3,10 @@ #include "mainwindow.h" #include "planner.h" #include "helpers.h" +#include "cylindermodel.h" #include "models.h" #include "profile/profilewidget2.h" +#include "diveplannermodel.h" #include <QGraphicsSceneMouseEvent> #include <QMessageBox> @@ -18,182 +20,7 @@ #define UNIT_FACTOR ((prefs.units.length == units::METERS) ? 1000.0 / 60.0 : feet_to_mm(1.0) / 60.0) -QString gasToStr(struct gasmix gas) -{ - uint o2 = (get_o2(&gas) + 5) / 10, he = (get_he(&gas) + 5) / 10; - QString result = gasmix_is_air(&gas) ? QObject::tr("AIR") : he == 0 ? (o2 == 100 ? QObject::tr("OXYGEN") : QString("EAN%1").arg(o2, 2, 10, QChar('0'))) : QString("%1/%2").arg(o2).arg(he); - return result; -} - -QString dpGasToStr(const divedatapoint &p) -{ - return gasToStr(p.gasmix); -} - -static DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); - -bool intLessThan(int a, int b) -{ - return a <= b; -} -void DivePlannerPointsModel::removeSelectedPoints(const QVector<int> &rows) -{ - if (!rows.count()) - return; - int firstRow = rowCount() - rows.count(); - QVector<int> v2 = rows; - std::sort(v2.begin(), v2.end(), intLessThan); - - beginRemoveRows(QModelIndex(), firstRow, rowCount() - 1); - for (int i = v2.count() - 1; i >= 0; i--) { - divepoints.remove(v2[i]); - } - endRemoveRows(); -} - -void DivePlannerPointsModel::createSimpleDive() -{ - struct gasmix gas = { 0 }; - - // initialize the start time in the plan - diveplan.when = displayed_dive.when; - - if (isPlanner()) - // let's use the gas from the first cylinder - gas = displayed_dive.cylinder[0].gasmix; - - // If we're in drop_stone_mode, don't add a first point. - // It will be added implicit. - if (!prefs.drop_stone_mode) - plannerModel->addStop(M_OR_FT(15, 45), 1 * 60, &gas, 0, true); - - plannerModel->addStop(M_OR_FT(15, 45), 20 * 60, &gas, 0, true); - if (!isPlanner()) { - plannerModel->addStop(M_OR_FT(5, 15), 42 * 60, &gas, 0, true); - plannerModel->addStop(M_OR_FT(5, 15), 45 * 60, &gas, 0, true); - } -} - -void DivePlannerPointsModel::setupStartTime() -{ - // if the latest dive is in the future, then start an hour after it ends - // otherwise start an hour from now - startTime = QDateTime::currentDateTimeUtc().addSecs(3600 + gettimezoneoffset()); - if (dive_table.nr) { - struct dive *d = get_dive(dive_table.nr - 1); - time_t ends = d->when + d->duration.seconds; - time_t diff = ends - startTime.toTime_t(); - if (diff > 0) { - startTime = startTime.addSecs(diff + 3600); - } - } - emit startTimeChanged(startTime); -} - -void DivePlannerPointsModel::loadFromDive(dive *d) -{ - int depthsum = 0; - int samplecount = 0; - bool oldRec = recalc; - recalc = false; - CylindersModel::instance()->updateDive(); - duration_t lasttime = {}; - duration_t newtime = {}; - struct gasmix gas; - free_dps(&diveplan); - diveplan.when = d->when; - // is this a "new" dive where we marked manually entered samples? - // if yes then the first sample should be marked - // if it is we only add the manually entered samples as waypoints to the diveplan - // otherwise we have to add all of them - bool hasMarkedSamples = d->dc.sample[0].manually_entered; - // if this dive has more than 100 samples (so it is probably a logged dive), - // average samples so we end up with a total of 100 samples. - int plansamples = d->dc.samples <= 100 ? d->dc.samples : 100; - int j = 0; - for (int i = 0; i < plansamples - 1; i++) { - while (j * plansamples <= i * d->dc.samples) { - const sample &s = d->dc.sample[j]; - if (s.time.seconds != 0 && (!hasMarkedSamples || s.manually_entered)) { - depthsum += s.depth.mm; - ++samplecount; - newtime = s.time; - } - j++; - } - if (samplecount) { - get_gas_at_time(d, &d->dc, lasttime, &gas); - plannerModel->addStop(depthsum / samplecount, newtime.seconds, &gas, 0, true); - lasttime = newtime; - depthsum = 0; - samplecount = 0; - } - } - recalc = oldRec; - emitDataChanged(); -} - -// copy the tanks from the current dive, or the default cylinder -// or an unknown cylinder -// setup the cylinder widget accordingly -void DivePlannerPointsModel::setupCylinders() -{ - if (mode == PLAN && current_dive) { - // take the displayed cylinders from the selected dive as starting point - CylindersModel::instance()->copyFromDive(current_dive); - copy_cylinders(current_dive, &displayed_dive, !prefs.display_unused_tanks); - reset_cylinders(&displayed_dive, true); - return; - } - if (!same_string(prefs.default_cylinder, "")) { - fill_default_cylinder(&displayed_dive.cylinder[0]); - } else { - // roughly an AL80 - displayed_dive.cylinder[0].type.description = strdup(tr("unknown").toUtf8().constData()); - displayed_dive.cylinder[0].type.size.mliter = 11100; - displayed_dive.cylinder[0].type.workingpressure.mbar = 207000; - } - reset_cylinders(&displayed_dive, false); - CylindersModel::instance()->copyFromDive(&displayed_dive); -} - -QStringList &DivePlannerPointsModel::getGasList() -{ - static QStringList list; - list.clear(); - for (int i = 0; i < MAX_CYLINDERS; i++) { - cylinder_t *cyl = &displayed_dive.cylinder[i]; - if (cylinder_nodata(cyl)) - break; - list.push_back(gasToStr(cyl->gasmix)); - } - return list; -} - -void DivePlannerPointsModel::removeDeco() -{ - bool oldrec = setRecalc(false); - QVector<int> computedPoints; - for (int i = 0; i < plannerModel->rowCount(); i++) - if (!plannerModel->at(i).entered) - computedPoints.push_back(i); - removeSelectedPoints(computedPoints); - setRecalc(oldrec); -} - -#if 0 -void DivePlannerGraphics::drawProfile() -{ - // Code ported to the new profile is deleted. This part that I left here - // is because I didn't fully understood the reason of the magic with - // the plannerModel. - bool oldRecalc = plannerModel->setRecalc(false); - plannerModel->removeDeco(); - // Here we plotted the old planner profile. why there's the magic with the plannerModel here? - plannerModel->setRecalc(oldRecalc); - plannerModel->deleteTemporaryPlan(); -} -#endif +static DivePlannerPointsModel* plannerModel = DivePlannerPointsModel::instance(); DiveHandler::DiveHandler() : QGraphicsEllipseItem() { @@ -223,7 +50,7 @@ void DiveHandler::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) m.addAction(action); } // don't allow removing the last point - if (DivePlannerPointsModel::instance()->rowCount() > 1) { + if (plannerModel->rowCount() > 1) { m.addSeparator(); m.addAction(QObject::tr("Remove this point"), this, SLOT(selfRemove())); m.exec(event->screenPos()); @@ -275,8 +102,8 @@ DivePlannerWidget::DivePlannerWidget(QWidget *parent, Qt::WindowFlags f) : QWidg ui.setupUi(this); ui.dateEdit->setDisplayFormat(getDateFormat()); ui.tableWidget->setTitle(tr("Dive planner points")); - ui.tableWidget->setModel(DivePlannerPointsModel::instance()); - DivePlannerPointsModel::instance()->setRecalc(true); + ui.tableWidget->setModel(plannerModel); + plannerModel->setRecalc(true); ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::GAS, new AirTypesDelegate(this)); ui.cylinderTableWidget->setTitle(tr("Available gases")); ui.cylinderTableWidget->setModel(CylindersModel::instance()); @@ -285,8 +112,8 @@ DivePlannerWidget::DivePlannerWidget(QWidget *parent, Qt::WindowFlags f) : QWidg view->setColumnHidden(CylindersModel::END, true); view->setColumnHidden(CylindersModel::DEPTH, false); view->setItemDelegateForColumn(CylindersModel::TYPE, new TankInfoDelegate(this)); - connect(ui.cylinderTableWidget, SIGNAL(addButtonClicked()), DivePlannerPointsModel::instance(), SLOT(addCylinder_clicked())); - connect(ui.tableWidget, SIGNAL(addButtonClicked()), DivePlannerPointsModel::instance(), SLOT(addStop())); + connect(ui.cylinderTableWidget, SIGNAL(addButtonClicked()), plannerModel, SLOT(addCylinder_clicked())); + connect(ui.tableWidget, SIGNAL(addButtonClicked()), plannerModel, SLOT(addStop())); connect(CylindersModel::instance(), SIGNAL(dataChanged(QModelIndex, QModelIndex)), GasSelectionModel::instance(), SLOT(repopulate())); @@ -307,7 +134,7 @@ DivePlannerWidget::DivePlannerWidget(QWidget *parent, Qt::WindowFlags f) : QWidg connect(ui.ATMPressure, SIGNAL(valueChanged(int)), this, SLOT(atmPressureChanged(int))); connect(ui.atmHeight, SIGNAL(valueChanged(int)), this, SLOT(heightChanged(int))); connect(ui.salinity, SIGNAL(valueChanged(double)), this, SLOT(salinityChanged(double))); - connect(DivePlannerPointsModel::instance(), SIGNAL(startTimeChanged(QDateTime)), this, SLOT(setupStartTime(QDateTime))); + connect(plannerModel, SIGNAL(startTimeChanged(QDateTime)), this, SLOT(setupStartTime(QDateTime))); // Creating (and canceling) the plan replanButton = ui.buttonBox->addButton(tr("Save new"), QDialogButtonBox::ActionRole); @@ -355,11 +182,6 @@ void DivePlannerWidget::settingsChanged() ui.atmHeight->blockSignals(false); } -void DivePlannerPointsModel::addCylinder_clicked() -{ - CylindersModel::instance()->add(); -} - void DivePlannerWidget::atmPressureChanged(const int pressure) { plannerModel->setSurfacePressure(pressure); @@ -483,7 +305,7 @@ PlannerSettingsWidget::PlannerSettingsWidget(QWidget *parent, Qt::WindowFlags f) connect(ui.gflow, SIGNAL(editingFinished()), plannerModel, SLOT(triggerGFLow())); connect(ui.backgasBreaks, SIGNAL(toggled(bool)), this, SLOT(setBackgasBreaks(bool))); connect(ui.rebreathermode, SIGNAL(currentIndexChanged(int)), plannerModel, SLOT(setRebreatherMode(int))); - connect(DivePlannerPointsModel::instance(), SIGNAL(recreationChanged(bool)), this, SLOT(disableDecoElements(bool))); + connect(plannerModel, SIGNAL(recreationChanged(bool)), this, SLOT(disableDecoElements(bool))); settingsChanged(); ui.gflow->setValue(prefs.gflow); @@ -623,741 +445,6 @@ void PlannerSettingsWidget::setBackgasBreaks(bool dobreaks) plannerModel->emitDataChanged(); } - -void DivePlannerPointsModel::setPlanMode(Mode m) -{ - mode = m; - // the planner may reset our GF settings that are used to show deco - // reset them to what's in the preferences - if (m != PLAN) - set_gf(prefs.gflow, prefs.gfhigh, prefs.gf_low_at_maxdepth); -} - -bool DivePlannerPointsModel::isPlanner() -{ - return mode == PLAN; -} - -/* When the planner adds deco stops to the model, adding those should not trigger a new deco calculation. - * We thus start the planner only when recalc is true. */ - -bool DivePlannerPointsModel::setRecalc(bool rec) -{ - bool old = recalc; - recalc = rec; - return old; -} - -bool DivePlannerPointsModel::recalcQ() -{ - return recalc; -} - -int DivePlannerPointsModel::columnCount(const QModelIndex &parent) const -{ - return COLUMNS; // to disable CCSETPOINT subtract one -} - -QVariant DivePlannerPointsModel::data(const QModelIndex &index, int role) const -{ - divedatapoint p = divepoints.at(index.row()); - if (role == Qt::DisplayRole || role == Qt::EditRole) { - switch (index.column()) { - case CCSETPOINT: - return (double)p.setpoint / 1000; - case DEPTH: - return (int) rint(get_depth_units(p.depth, NULL, NULL)); - case RUNTIME: - return p.time / 60; - case DURATION: - if (index.row()) - return (p.time - divepoints.at(index.row() - 1).time) / 60; - else - return p.time / 60; - case GAS: - return dpGasToStr(p); - } - } else if (role == Qt::DecorationRole) { - switch (index.column()) { - case REMOVE: - if (rowCount() > 1) - return p.entered ? trashIcon() : QVariant(); - } - } else if (role == Qt::SizeHintRole) { - switch (index.column()) { - case REMOVE: - if (rowCount() > 1) - return p.entered ? trashIcon().size() : QVariant(); - } - } else if (role == Qt::FontRole) { - if (divepoints.at(index.row()).entered) { - return defaultModelFont(); - } else { - QFont font = defaultModelFont(); - font.setBold(true); - return font; - } - } - return QVariant(); -} - -bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - struct gasmix gas = { 0 }; - int i, shift; - if (role == Qt::EditRole) { - divedatapoint &p = divepoints[index.row()]; - switch (index.column()) { - case DEPTH: - if (value.toInt() >= 0) - p.depth = units_to_depth(value.toInt()); - break; - case RUNTIME: - p.time = value.toInt() * 60; - break; - case DURATION: - i = index.row(); - if (i) - shift = divepoints[i].time - divepoints[i - 1].time - value.toInt() * 60; - else - shift = divepoints[i].time - value.toInt() * 60; - while (i < divepoints.size()) - divepoints[i++].time -= shift; - break; - case CCSETPOINT: { - int po2 = 0; - QByteArray gasv = value.toByteArray(); - if (validate_po2(gasv.data(), &po2)) - p.setpoint = po2; - } break; - case GAS: - QByteArray gasv = value.toByteArray(); - if (validate_gas(gasv.data(), &gas)) - p.gasmix = gas; - break; - } - editStop(index.row(), p); - } - return QAbstractItemModel::setData(index, value, role); -} - -void DivePlannerPointsModel::gaschange(const QModelIndex &index, QString newgas) -{ - int i = index.row(); - gasmix oldgas = divepoints[i].gasmix; - gasmix gas = { 0 }; - if (!validate_gas(newgas.toUtf8().data(), &gas)) - return; - while (i < plannerModel->rowCount() && gasmix_distance(&oldgas, &divepoints[i].gasmix) == 0) - divepoints[i++].gasmix = gas; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -QVariant DivePlannerPointsModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { - switch (section) { - case DEPTH: - return tr("Final depth"); - case RUNTIME: - return tr("Run time"); - case DURATION: - return tr("Duration"); - case GAS: - return tr("Used gas"); - case CCSETPOINT: - return tr("CC set point"); - } - } else if (role == Qt::FontRole) { - return defaultModelFont(); - } - return QVariant(); -} - -Qt::ItemFlags DivePlannerPointsModel::flags(const QModelIndex &index) const -{ - if (index.column() != REMOVE) - return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; - else - return QAbstractItemModel::flags(index); -} - -int DivePlannerPointsModel::rowCount(const QModelIndex &parent) const -{ - return divepoints.count(); -} - -DivePlannerPointsModel::DivePlannerPointsModel(QObject *parent) : QAbstractTableModel(parent), - mode(NOTHING), - recalc(false), - tempGFHigh(100), - tempGFLow(100) -{ - memset(&diveplan, 0, sizeof(diveplan)); -} - -DivePlannerPointsModel *DivePlannerPointsModel::instance() -{ - static QScopedPointer<DivePlannerPointsModel> self(new DivePlannerPointsModel()); - return self.data(); -} - -void DivePlannerPointsModel::emitDataChanged() -{ - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setBottomSac(double sac) -{ - diveplan.bottomsac = units_to_sac(sac); - prefs.bottomsac = diveplan.bottomsac; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setDecoSac(double sac) -{ - diveplan.decosac = units_to_sac(sac); - prefs.decosac = diveplan.decosac; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setGFHigh(const int gfhigh) -{ - tempGFHigh = gfhigh; - // GFHigh <= 34 can cause infinite deco at 6m - don't trigger a recalculation - // for smaller GFHigh unless the user explicitly leaves the field - if (tempGFHigh > 34) - triggerGFHigh(); -} - -void DivePlannerPointsModel::triggerGFHigh() -{ - if (diveplan.gfhigh != tempGFHigh) { - diveplan.gfhigh = tempGFHigh; - plannerModel->emitDataChanged(); - } -} - -void DivePlannerPointsModel::setGFLow(const int ghflow) -{ - tempGFLow = ghflow; - triggerGFLow(); -} - -void DivePlannerPointsModel::setRebreatherMode(int mode) -{ - int i; - displayed_dive.dc.divemode = (dive_comp_type) mode; - for (i=0; i < rowCount(); i++) - divepoints[i].setpoint = mode == CCR ? prefs.defaultsetpoint : 0; - emitDataChanged(); -} - -void DivePlannerPointsModel::triggerGFLow() -{ - if (diveplan.gflow != tempGFLow) { - diveplan.gflow = tempGFLow; - plannerModel->emitDataChanged(); - } -} - -void DivePlannerPointsModel::setSurfacePressure(int pressure) -{ - diveplan.surface_pressure = pressure; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setSalinity(int salinity) -{ - diveplan.salinity = salinity; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -int DivePlannerPointsModel::getSurfacePressure() -{ - return diveplan.surface_pressure; -} - -void DivePlannerPointsModel::setLastStop6m(bool value) -{ - set_last_stop(value); - prefs.last_stop = value; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setVerbatim(bool value) -{ - set_verbatim(value); - prefs.verbatim_plan = value; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setDisplayRuntime(bool value) -{ - set_display_runtime(value); - prefs.display_runtime = value; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setDisplayDuration(bool value) -{ - set_display_duration(value); - prefs.display_duration = value; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setDisplayTransitions(bool value) -{ - set_display_transitions(value); - prefs.display_transitions = value; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setRecreationalMode(bool value) -{ - prefs.recreational_mode = value; - emit recreationChanged(value); - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS -1)); -} - -void DivePlannerPointsModel::setSafetyStop(bool value) -{ - prefs.safetystop = value; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS -1)); -} - -void DivePlannerPointsModel::setReserveGas(int reserve) -{ - prefs.reserve_gas = reserve * 1000; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setDropStoneMode(bool value) -{ - prefs.drop_stone_mode = value; - if (prefs.drop_stone_mode) { - /* Remove the first entry if we enable drop_stone_mode */ - if (rowCount() >= 2) { - beginRemoveRows(QModelIndex(), 0, 0); - divepoints.remove(0); - endRemoveRows(); - } - } else { - /* Add a first entry if we disable drop_stone_mode */ - beginInsertRows(QModelIndex(), 0, 0); - /* Copy the first current point */ - divedatapoint p = divepoints.at(0); - p.time = p.depth / prefs.descrate; - divepoints.push_front(p); - endInsertRows(); - } - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setStartDate(const QDate &date) -{ - startTime.setDate(date); - diveplan.when = startTime.toTime_t(); - displayed_dive.when = diveplan.when; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::setStartTime(const QTime &t) -{ - startTime.setTime(t); - diveplan.when = startTime.toTime_t(); - displayed_dive.when = diveplan.when; - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -bool divePointsLessThan(const divedatapoint &p1, const divedatapoint &p2) -{ - return p1.time <= p2.time; -} - -bool DivePlannerPointsModel::addGas(struct gasmix mix) -{ - sanitize_gasmix(&mix); - - for (int i = 0; i < MAX_CYLINDERS; i++) { - cylinder_t *cyl = &displayed_dive.cylinder[i]; - if (cylinder_nodata(cyl)) { - fill_default_cylinder(cyl); - cyl->gasmix = mix; - /* The depth to change to that gas is given by the depth where its pO₂ is 1.6 bar. - * The user should be able to change this depth manually. */ - pressure_t modpO2; - if (displayed_dive.dc.divemode == PSCR) - modpO2.mbar = prefs.decopo2 + (1000 - get_o2(&mix)) * SURFACE_PRESSURE * - prefs.o2consumption / prefs.decosac / prefs.pscr_ratio; - else - modpO2.mbar = prefs.decopo2; - cyl->depth = gas_mod(&mix, modpO2, M_OR_FT(3,10)); - - - - - // FIXME -- need to get rid of stagingDIve - // the following now uses displayed_dive !!!! - - - - CylindersModel::instance()->updateDive(); - return true; - } - if (!gasmix_distance(&cyl->gasmix, &mix)) - return true; - } - qDebug("too many gases"); - return false; -} - -int DivePlannerPointsModel::lastEnteredPoint() -{ - for (int i = divepoints.count() - 1; i >= 0; i--) - if (divepoints.at(i).entered) - return i; - return -1; -} - -int DivePlannerPointsModel::addStop(int milimeters, int seconds, gasmix *gas_in, int ccpoint, bool entered) -{ - struct gasmix air = { 0 }; - struct gasmix gas = { 0 }; - bool usePrevious = false; - if (gas_in) - gas = *gas_in; - else - usePrevious = true; - if (recalcQ()) - removeDeco(); - - int row = divepoints.count(); - if (seconds == 0 && milimeters == 0 && row != 0) { - /* this is only possible if the user clicked on the 'plus' sign on the DivePoints Table */ - const divedatapoint t = divepoints.at(lastEnteredPoint()); - milimeters = t.depth; - seconds = t.time + 600; // 10 minutes. - gas = t.gasmix; - ccpoint = t.setpoint; - } else if (seconds == 0 && milimeters == 0 && row == 0) { - milimeters = M_OR_FT(5, 15); // 5m / 15ft - seconds = 600; // 10 min - //Default to the first defined gas, if we got one. - cylinder_t *cyl = &displayed_dive.cylinder[0]; - if (cyl) - gas = cyl->gasmix; - } - if (!usePrevious) - if (!addGas(gas)) - qDebug("addGas failed"); // FIXME add error propagation - - // check if there's already a new stop before this one: - for (int i = 0; i < row; i++) { - const divedatapoint &dp = divepoints.at(i); - if (dp.time == seconds) { - row = i; - beginRemoveRows(QModelIndex(), row, row); - divepoints.remove(row); - endRemoveRows(); - break; - } - if (dp.time > seconds) { - row = i; - break; - } - } - // Previous, actually means next as we are typically subdiving a segment and the gas for - // the segment is determined by the waypoint at the end. - if (usePrevious) { - if (row < divepoints.count()) { - gas = divepoints.at(row).gasmix; - } else if (row > 0) { - gas = divepoints.at(row - 1).gasmix; - } else { - if (!addGas(air)) - qDebug("addGas failed"); // FIXME add error propagation - - } - } - - // add the new stop - beginInsertRows(QModelIndex(), row, row); - divedatapoint point; - point.depth = milimeters; - point.time = seconds; - point.gasmix = gas; - point.setpoint = ccpoint; - point.entered = entered; - point.next = NULL; - divepoints.append(point); - std::sort(divepoints.begin(), divepoints.end(), divePointsLessThan); - endInsertRows(); - return row; -} - -void DivePlannerPointsModel::editStop(int row, divedatapoint newData) -{ - /* - * When moving divepoints rigorously, we might end up with index - * out of range, thus returning the last one instead. - */ - if (row >= divepoints.count()) - return; - divepoints[row] = newData; - std::sort(divepoints.begin(), divepoints.end(), divePointsLessThan); - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -int DivePlannerPointsModel::size() -{ - return divepoints.size(); -} - -divedatapoint DivePlannerPointsModel::at(int row) -{ - /* - * When moving divepoints rigorously, we might end up with index - * out of range, thus returning the last one instead. - */ - if (row >= divepoints.count()) - return divepoints.at(divepoints.count() - 1); - return divepoints.at(row); -} - -void DivePlannerPointsModel::remove(const QModelIndex &index) -{ - int i; - int rows = rowCount(); - if (index.column() != REMOVE || rowCount() == 1) - return; - - divedatapoint dp = at(index.row()); - if (!dp.entered) - return; - - if (QApplication::keyboardModifiers() & Qt::ControlModifier) { - beginRemoveRows(QModelIndex(), index.row(), rows - 1); - for (i = rows - 1; i >= index.row(); i--) - divepoints.remove(i); - } else { - beginRemoveRows(QModelIndex(), index.row(), index.row()); - divepoints.remove(index.row()); - } - endRemoveRows(); -} - -struct diveplan &DivePlannerPointsModel::getDiveplan() -{ - return diveplan; -} - -void DivePlannerPointsModel::cancelPlan() -{ - if (mode == PLAN && rowCount()) { - if (QMessageBox::warning(MainWindow::instance(), TITLE_OR_TEXT(tr("Discard the plan?"), - tr("You are about to discard your plan.")), - QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Discard) != QMessageBox::Discard) { - return; - } - } - setPlanMode(NOTHING); - free_dps(&diveplan); - - emit planCanceled(); -} - -DivePlannerPointsModel::Mode DivePlannerPointsModel::currentMode() const -{ - return mode; -} - -QVector<QPair<int, int> > DivePlannerPointsModel::collectGases(struct dive *d) -{ - QVector<QPair<int, int> > l; - for (int i = 0; i < MAX_CYLINDERS; i++) { - cylinder_t *cyl = &d->cylinder[i]; - if (!cylinder_nodata(cyl)) - l.push_back(qMakePair(get_o2(&cyl->gasmix), get_he(&cyl->gasmix))); - } - return l; -} -void DivePlannerPointsModel::rememberTanks() -{ - oldGases = collectGases(&displayed_dive); -} - -bool DivePlannerPointsModel::tankInUse(struct gasmix gasmix) -{ - for (int j = 0; j < rowCount(); j++) { - divedatapoint &p = divepoints[j]; - if (p.time == 0) // special entries that hold the available gases - continue; - if (!p.entered) // removing deco gases is ok - continue; - if (gasmix_distance(&p.gasmix, &gasmix) < 100) - return true; - } - return false; -} - -void DivePlannerPointsModel::tanksUpdated() -{ - // we don't know exactly what changed - what we care about is - // "did a gas change on us". So we look through the diveplan to - // see if there is a gas that is now missing and if there is, we - // replace it with the matching new gas. - QVector<QPair<int, int> > gases = collectGases(&displayed_dive); - if (gases.count() == oldGases.count()) { - // either nothing relevant changed, or exactly ONE gasmix changed - for (int i = 0; i < gases.count(); i++) { - if (gases.at(i) != oldGases.at(i)) { - if (oldGases.count(oldGases.at(i)) > 1) { - // we had this gas more than once, so don't - // change segments that used this gas as it still exists - break; - } - for (int j = 0; j < rowCount(); j++) { - divedatapoint &p = divepoints[j]; - struct gasmix gas; - gas.o2.permille = oldGases.at(i).first; - gas.he.permille = oldGases.at(i).second; - if (gasmix_distance(&gas, &p.gasmix) < 100) { - p.gasmix.o2.permille = gases.at(i).first; - p.gasmix.he.permille = gases.at(i).second; - } - } - break; - } - } - } - emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); -} - -void DivePlannerPointsModel::clear() -{ - bool oldRecalc = setRecalc(false); - - CylindersModel::instance()->updateDive(); - if (rowCount() > 0) { - beginRemoveRows(QModelIndex(), 0, rowCount() - 1); - divepoints.clear(); - endRemoveRows(); - } - CylindersModel::instance()->clear(); - setRecalc(oldRecalc); -} - -void DivePlannerPointsModel::createTemporaryPlan() -{ - // Get the user-input and calculate the dive info - free_dps(&diveplan); - int lastIndex = -1; - for (int i = 0; i < rowCount(); i++) { - divedatapoint p = at(i); - int deltaT = lastIndex != -1 ? p.time - at(lastIndex).time : p.time; - lastIndex = i; - if (i == 0 && prefs.drop_stone_mode) { - /* Okay, we add a fist segment where we go down to depth */ - plan_add_segment(&diveplan, p.depth / prefs.descrate, p.depth, p.gasmix, p.setpoint, true); - deltaT -= p.depth / prefs.descrate; - } - if (p.entered) - plan_add_segment(&diveplan, deltaT, p.depth, p.gasmix, p.setpoint, true); - } - - // what does the cache do??? - char *cache = NULL; - struct divedatapoint *dp = NULL; - for (int i = 0; i < MAX_CYLINDERS; i++) { - cylinder_t *cyl = &displayed_dive.cylinder[i]; - if (cyl->depth.mm) { - dp = create_dp(0, cyl->depth.mm, cyl->gasmix, 0); - if (diveplan.dp) { - dp->next = diveplan.dp; - diveplan.dp = dp; - } else { - dp->next = NULL; - diveplan.dp = dp; - } - } - } -#if DEBUG_PLAN - dump_plan(&diveplan); -#endif - if (plannerModel->recalcQ() && !diveplan_empty(&diveplan)) { - plan(&diveplan, &cache, isPlanner(), false); - MainWindow::instance()->setPlanNotes(displayed_dive.notes); - } - // throw away the cache - free(cache); -#if DEBUG_PLAN - save_dive(stderr, &displayed_dive); - dump_plan(&diveplan); -#endif -} - -void DivePlannerPointsModel::deleteTemporaryPlan() -{ - free_dps(&diveplan); -} - -void DivePlannerPointsModel::savePlan() -{ - createPlan(false); -} - -void DivePlannerPointsModel::saveDuplicatePlan() -{ - createPlan(true); -} - -void DivePlannerPointsModel::createPlan(bool replanCopy) -{ - // Ok, so, here the diveplan creates a dive - char *cache = NULL; - bool oldRecalc = plannerModel->setRecalc(false); - removeDeco(); - createTemporaryPlan(); - plannerModel->setRecalc(oldRecalc); - - //TODO: C-based function here? - bool did_deco = plan(&diveplan, &cache, isPlanner(), true); - if (!current_dive || displayed_dive.id != current_dive->id) { - // we were planning a new dive, not re-planning an existing on - record_dive(clone_dive(&displayed_dive)); - } else if (current_dive && displayed_dive.id == current_dive->id) { - // we are replanning a dive - make sure changes are reflected - // correctly in the dive structure and copy it back into the dive table - displayed_dive.maxdepth.mm = 0; - displayed_dive.dc.maxdepth.mm = 0; - fixup_dive(&displayed_dive); - if (replanCopy) { - struct dive *copy = alloc_dive(); - copy_dive(current_dive, copy); - copy->id = 0; - copy->divetrip = NULL; - if (current_dive->divetrip) - add_dive_to_trip(copy, current_dive->divetrip); - record_dive(copy); - QString oldnotes(current_dive->notes); - if (oldnotes.indexOf(QString(disclaimer)) >= 0) - oldnotes.truncate(oldnotes.indexOf(QString(disclaimer))); - if (did_deco) - oldnotes.append(displayed_dive.notes); - displayed_dive.notes = strdup(oldnotes.toUtf8().data()); - } - copy_dive(&displayed_dive, current_dive); - } - mark_divelist_changed(true); - - // Remove and clean the diveplan, so we don't delete - // the dive by mistake. - free_dps(&diveplan); - setPlanMode(NOTHING); - planCreated(); -} - PlannerDetails::PlannerDetails(QWidget *parent) : QWidget(parent) { ui.setupUi(this); diff --git a/qt-ui/diveplanner.h b/qt-ui/diveplanner.h index 42e0dc44a..8c7ff9c46 100644 --- a/qt-ui/diveplanner.h +++ b/qt-ui/diveplanner.h @@ -10,113 +10,7 @@ class QListView; class QModelIndex; - -class DivePlannerPointsModel : public QAbstractTableModel { - Q_OBJECT -public: - static DivePlannerPointsModel *instance(); - enum Sections { - REMOVE, - DEPTH, - DURATION, - RUNTIME, - GAS, - CCSETPOINT, - COLUMNS - }; - enum Mode { - NOTHING, - PLAN, - ADD - }; - virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - void gaschange(const QModelIndex &index, QString newgas); - void removeSelectedPoints(const QVector<int> &rows); - void setPlanMode(Mode mode); - bool isPlanner(); - void createSimpleDive(); - void setupStartTime(); - void clear(); - Mode currentMode() const; - bool setRecalc(bool recalc); - bool recalcQ(); - void tanksUpdated(); - void rememberTanks(); - bool tankInUse(struct gasmix gasmix); - void setupCylinders(); - /** - * @return the row number. - */ - void editStop(int row, divedatapoint newData); - divedatapoint at(int row); - int size(); - struct diveplan &getDiveplan(); - QStringList &getGasList(); - QVector<QPair<int, int> > collectGases(dive *d); - int lastEnteredPoint(); - void removeDeco(); - static bool addingDeco; - -public -slots: - int addStop(int millimeters = 0, int seconds = 0, struct gasmix *gas = 0, int ccpoint = 0, bool entered = true); - void addCylinder_clicked(); - void setGFHigh(const int gfhigh); - void triggerGFHigh(); - void setGFLow(const int ghflow); - void triggerGFLow(); - void setSurfacePressure(int pressure); - void setSalinity(int salinity); - int getSurfacePressure(); - void setBottomSac(double sac); - void setDecoSac(double sac); - void setStartTime(const QTime &t); - void setStartDate(const QDate &date); - void setLastStop6m(bool value); - void setDropStoneMode(bool value); - void setVerbatim(bool value); - void setDisplayRuntime(bool value); - void setDisplayDuration(bool value); - void setDisplayTransitions(bool value); - void setRecreationalMode(bool value); - void setSafetyStop(bool value); - void savePlan(); - void saveDuplicatePlan(); - void remove(const QModelIndex &index); - void cancelPlan(); - void createTemporaryPlan(); - void deleteTemporaryPlan(); - void loadFromDive(dive *d); - void emitDataChanged(); - void setRebreatherMode(int mode); - void setReserveGas(int reserve); - -signals: - void planCreated(); - void planCanceled(); - void cylinderModelEdited(); - void startTimeChanged(QDateTime); - void recreationChanged(bool); - -private: - explicit DivePlannerPointsModel(QObject *parent = 0); - bool addGas(struct gasmix mix); - void createPlan(bool replanCopy); - struct diveplan diveplan; - Mode mode; - bool recalc; - QVector<divedatapoint> divepoints; - QVector<sample> backupSamples; // For editing added dives. - QVector<QPair<int, int> > oldGases; - QDateTime startTime; - int tempGFHigh; - int tempGFLow; -}; +class DivePlannerPointsModel; class DiveHandler : public QObject, public QGraphicsEllipseItem { Q_OBJECT @@ -205,7 +99,4 @@ private: Ui::plannerDetails ui; }; - -QString dpGasToStr(const divedatapoint &p); - #endif // DIVEPLANNER_H diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp index 3d17bcdbf..0159029e2 100644 --- a/qt-ui/maintab.cpp +++ b/qt-ui/maintab.cpp @@ -10,12 +10,14 @@ #include "helpers.h" #include "statistics.h" #include "modeldelegates.h" +#include "diveplannermodel.h" #include "models.h" #include "divelistview.h" #include "display.h" #include "profile/profilewidget2.h" #include "diveplanner.h" #include "divesitehelpers.h" +#include "cylindermodel.h" #if defined(FBSUPPORT) #include "socialnetworks.h" diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp index e94bce136..9c36b6731 100644 --- a/qt-ui/mainwindow.cpp +++ b/qt-ui/mainwindow.cpp @@ -29,6 +29,7 @@ #include <QPrintDialog> #include "printdialog.h" #endif +#include "diveplannermodel.h" #include "divelogimportdialog.h" #include "divelogexportdialog.h" #include "usersurvey.h" diff --git a/qt-ui/modeldelegates.cpp b/qt-ui/modeldelegates.cpp index 66533b652..21d497562 100644 --- a/qt-ui/modeldelegates.cpp +++ b/qt-ui/modeldelegates.cpp @@ -2,6 +2,7 @@ #include "dive.h" #include "gettextfromc.h" #include "mainwindow.h" +#include "cylindermodel.h" #include "models.h" #include "starwidget.h" #include "profile/profilewidget2.h" diff --git a/qt-ui/profile/diveprofileitem.cpp b/qt-ui/profile/diveprofileitem.cpp index 7d29d28b4..373dd0027 100644 --- a/qt-ui/profile/diveprofileitem.cpp +++ b/qt-ui/profile/diveprofileitem.cpp @@ -6,6 +6,7 @@ #include "dive.h" #include "profile.h" #include "preferences.h" +#include "diveplannermodel.h" #include "helpers.h" #include "libdivecomputer/parser.h" #include "mainwindow.h" @@ -758,7 +759,7 @@ void DiveGasPressureItem::plotPressureValue(int mbar, int sec, QFlags<Qt::Alignm void DiveGasPressureItem::plotGasValue(int mbar, int sec, struct gasmix gasmix, QFlags<Qt::AlignmentFlag> align, double gasname_offset) { - QString gas = gasToStr(gasmix); + QString gas = get_gas_string(gasmix); DiveTextItem *text = new DiveTextItem(this); text->setPos(hAxis->posAtValue(sec), vAxis->posAtValue(mbar) + gasname_offset ); text->setText(gas); diff --git a/qt-ui/profile/profilewidget2.cpp b/qt-ui/profile/profilewidget2.cpp index a426ceef2..d70d88763 100644 --- a/qt-ui/profile/profilewidget2.cpp +++ b/qt-ui/profile/profilewidget2.cpp @@ -11,6 +11,7 @@ #include "tankitem.h" #include "pref.h" #include "divepicturewidget.h" +#include "diveplannermodel.h" #include "models.h" #include "maintab.h" #include "diveplanner.h" @@ -1562,7 +1563,7 @@ void ProfileWidget2::repositionDiveHandlers() QLineF line(p1, p2); QPointF pos = line.pointAt(0.5); gases[i]->setPos(pos); - gases[i]->setText(dpGasToStr(datapoint)); + gases[i]->setText(get_divepoint_gas_string(datapoint)); gases[i]->setVisible(datapoint.entered && (i == 0 || gases[i]->text() != gases[i-1]->text())); } |