diff options
Diffstat (limited to 'qt-ui/diveplanner.cpp')
-rw-r--r-- | qt-ui/diveplanner.cpp | 718 |
1 files changed, 551 insertions, 167 deletions
diff --git a/qt-ui/diveplanner.cpp b/qt-ui/diveplanner.cpp index 95b6c211c..ceb5ebdba 100644 --- a/qt-ui/diveplanner.cpp +++ b/qt-ui/diveplanner.cpp @@ -1,34 +1,54 @@ #include "diveplanner.h" #include "graphicsview-common.h" +#include "models.h" +#include "modeldelegates.h" +#include "ui_diveplanner.h" +#include "mainwindow.h" +#include "tableview.h" +#include "graphicsview-common.h" #include "../dive.h" #include "../divelist.h" -#include <cmath> +#include "../planner.h" + #include <QMouseEvent> #include <QDebug> -#include <QGraphicsWidget> -#include <QGraphicsProxyWidget> -#include <QPushButton> #include <QGraphicsSceneMouseEvent> #include <QMessageBox> #include <QStringListModel> -#include <QGraphicsProxyWidget> #include <QListView> -#include <QDesktopWidget> #include <QModelIndex> - -#include "ui_diveplanner.h" -#include "mainwindow.h" +#include <QSettings> +#include <QTableView> +#include <QColor> #define TIME_INITIAL_MAX 30 #define MAX_DEEPNESS 150 #define MIN_DEEPNESS 40 -bool handlerLessThenMinutes(DiveHandler *d1, DiveHandler *d2){ - return d1->sec < d2->sec; +QStringListModel *airTypes(){ + static QStringListModel *self = new QStringListModel(QStringList() + << QObject::tr("AIR") + << QObject::tr("EAN32") + << QObject::tr("EAN36")); + return self; +} + +QString strForAir(const divedatapoint& p){ + return p.o2 == 209 ? QObject::tr("AIR") + : p.o2 == 320 ? QObject::tr("EAN32") + : p.o2 == 360 ? QObject::tr("EAN36") + : QObject::tr("Choose Gas"); } +QColor getColor(const color_indice_t i) +{ + return profile_color[i].at(0); +} + +static DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); + DivePlannerGraphics::DivePlannerGraphics(QWidget* parent): QGraphicsView(parent), activeDraggedHandler(0) { fill_profile_color(); @@ -53,6 +73,7 @@ DivePlannerGraphics::DivePlannerGraphics(QWidget* parent): QGraphicsView(parent) fromPercent(100, Qt::Horizontal), fromPercent(0, Qt::Vertical) ); + horizontalLine->setPen(QPen(Qt::DotLine)); scene()->addItem(horizontalLine); @@ -60,6 +81,7 @@ DivePlannerGraphics::DivePlannerGraphics(QWidget* parent): QGraphicsView(parent) timeLine->setMinimum(0); timeLine->setMaximum(TIME_INITIAL_MAX); timeLine->setTickInterval(10); + timeLine->setColor(getColor(TIME_GRID)); timeLine->setLine( fromPercent(10, Qt::Horizontal), fromPercent(90, Qt::Vertical), @@ -68,7 +90,7 @@ DivePlannerGraphics::DivePlannerGraphics(QWidget* parent): QGraphicsView(parent) ); timeLine->setOrientation(Qt::Horizontal); timeLine->setTickSize(fromPercent(1, Qt::Vertical)); - timeLine->setColor(profile_color[TIME_GRID].at(0)); + timeLine->setTextColor(getColor(TIME_TEXT)); timeLine->updateTicks(); scene()->addItem(timeLine); @@ -84,7 +106,8 @@ DivePlannerGraphics::DivePlannerGraphics(QWidget* parent): QGraphicsView(parent) ); depthLine->setOrientation(Qt::Vertical); depthLine->setTickSize(fromPercent(1, Qt::Horizontal)); - depthLine->setColor(profile_color[DEPTH_GRID].at(0)); + depthLine->setColor(getColor(DEPTH_GRID)); + depthLine->setTextColor(getColor(SAMPLE_DEEP)); depthLine->updateTicks(); scene()->addItem(depthLine); @@ -111,16 +134,10 @@ DivePlannerGraphics::DivePlannerGraphics(QWidget* parent): QGraphicsView(parent) connect(obj, SIGNAL(clicked()), this, SLOT(slot)); ADDBTN(plusDepth, ":plus", "" , 5, 5, tr("Increase maximum depth by 10m"), increaseDepth()); - ADDBTN(plusTime, ":plus", "" , 95, 5, tr("Increase minimum time by 10m"), increaseTime()); + ADDBTN(plusTime, ":plus", "" , 95, 95, tr("Increase minimum time by 10m"), increaseTime()); ADDBTN(lessDepth, ":minimum","" , 2, 5, tr("Decreases maximum depth by 10m"), decreaseDepth()); ADDBTN(lessTime, ":minimum","" , 92, 95, tr("Decreases minimum time by 10m"), decreaseTime()); - ADDBTN(okBtn, "", tr("Ok"), 1, 95, "", okClicked()); - ADDBTN(cancelBtn, "", tr("Cancel"), 0,0, "", cancelClicked()); #undef ADDBTN - - cancelBtn->setPos(okBtn->pos().x() + okBtn->boundingRect().width() - + fromPercent(2, Qt::Horizontal), fromPercent(95, Qt::Vertical)); - minMinutes = TIME_INITIAL_MAX; QAction *action = NULL; @@ -141,30 +158,50 @@ DivePlannerGraphics::DivePlannerGraphics(QWidget* parent): QGraphicsView(parent) #undef ADD_ACTION // Prepare the stuff for the gas-choices. - gasChoices = new QStringListModel(QStringList() << tr("AIR") << tr("EAN32") << tr("EAN36")); gasListView = new QListView(); - gasListView->setWindowFlags(Qt::FramelessWindowHint); - gasListView->setModel(gasChoices); + gasListView->setWindowFlags(Qt::Popup); + gasListView->setModel(airTypes()); gasListView->hide(); connect(gasListView, SIGNAL(activated(QModelIndex)), this, SLOT(selectGas(QModelIndex))); + connect(plannerModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(createDecoStops())); + + connect(plannerModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), + this, SLOT(pointInserted(const QModelIndex&, int, int))); + connect(plannerModel, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), + this, SLOT(pointsRemoved(const QModelIndex&, int, int))); setRenderHint(QPainter::Antialiasing); } +void DivePlannerGraphics::pointInserted(const QModelIndex& parent, int start , int end) +{ + DiveHandler *item = new DiveHandler (); + scene()->addItem(item); + handles << item; + + Button *gasChooseBtn = new Button(); + scene()->addItem(gasChooseBtn); + gasChooseBtn->setZValue(10); + connect(gasChooseBtn, SIGNAL(clicked()), this, SLOT(prepareSelectGas())); + + gases << gasChooseBtn; + createDecoStops(); +} + void DivePlannerGraphics::keyDownAction() { if(scene()->selectedItems().count()){ Q_FOREACH(QGraphicsItem *i, scene()->selectedItems()){ if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler*>(i)){ - if (handler->mm / 1000 >= depthLine->maximum()) + int row = handles.indexOf(handler); + divedatapoint dp = plannerModel->at(row); + if (dp.depth / 1000 >= depthLine->maximum()) continue; - handler->mm += 1000; - double ypos = depthLine->posAtValue(handler->mm / 1000); - handler->setPos(handler->pos().x(), ypos); + dp.depth += 1000; + plannerModel->editStop(row, dp); } } - createDecoStops(); } } @@ -172,12 +209,14 @@ void DivePlannerGraphics::keyUpAction() { Q_FOREACH(QGraphicsItem *i, scene()->selectedItems()){ if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler*>(i)){ - if (handler->mm / 1000 <= 0) + int row = handles.indexOf(handler); + divedatapoint dp = plannerModel->at(row); + + if (dp.depth / 1000 <= 0) continue; - handler->mm -= 1000; - double ypos = depthLine->posAtValue(handler->mm / 1000); - handler->setPos(handler->pos().x(), ypos); + dp.depth -= 1000; + plannerModel->editStop(row, dp); } } createDecoStops(); @@ -187,12 +226,15 @@ void DivePlannerGraphics::keyLeftAction() { Q_FOREACH(QGraphicsItem *i, scene()->selectedItems()){ if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler*>(i)){ - if (handler->sec / 60 <= 0) + int row = handles.indexOf(handler); + divedatapoint dp = plannerModel->at(row); + + if (dp.time / 60 <= 0) continue; // don't overlap positions. // maybe this is a good place for a 'goto'? - double xpos = timeLine->posAtValue((handler->sec - 60) / 60); + double xpos = timeLine->posAtValue((dp.time - 60) / 60); bool nextStep = false; Q_FOREACH(DiveHandler *h, handles){ if (h->pos().x() == xpos){ @@ -203,23 +245,24 @@ void DivePlannerGraphics::keyLeftAction() if(nextStep) continue; - handler->sec -= 60; - handler->setPos(xpos, handler->pos().y()); + dp.time -= 60; + plannerModel->editStop(row, dp); } } - createDecoStops(); } void DivePlannerGraphics::keyRightAction() { Q_FOREACH(QGraphicsItem *i, scene()->selectedItems()){ if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler*>(i)){ - if (handler->sec / 60 >= timeLine->maximum()) + int row = handles.indexOf(handler); + divedatapoint dp = plannerModel->at(row); + if (dp.time / 60 >= timeLine->maximum()) continue; // don't overlap positions. // maybe this is a good place for a 'goto'? - double xpos = timeLine->posAtValue((handler->sec + 60) / 60); + double xpos = timeLine->posAtValue((dp.time + 60) / 60); bool nextStep = false; Q_FOREACH(DiveHandler *h, handles){ if (h->pos().x() == xpos){ @@ -230,32 +273,52 @@ void DivePlannerGraphics::keyRightAction() if(nextStep) continue; - handler->sec += 60; - handler->setPos(xpos, handler->pos().y()); + dp.time += 60; + plannerModel->editStop(row, dp); } - } createDecoStops(); + } } void DivePlannerGraphics::keyDeleteAction() { int selCount = scene()->selectedItems().count(); if(selCount){ - - while(selCount--){ - Button *btn = gases.takeLast(); - delete btn; - } - + QVector<int> selectedIndexes; Q_FOREACH(QGraphicsItem *i, scene()->selectedItems()){ if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler*>(i)){ - handles.removeAll(handler); - scene()->removeItem(handler); - delete i; + selectedIndexes.push_back(handles.indexOf(handler)); } } + plannerModel->removeSelectedPoints(selectedIndexes); + } +} - createDecoStops(); +void DivePlannerGraphics::pointsRemoved(const QModelIndex& , int start, int end) +{ // start and end are inclusive. + int num = (end - start) + 1; + for(int i = num; i != 0; i--){ + delete handles.back(); + handles.pop_back(); + delete gases.back(); + gases.pop_back(); } + scene()->clearSelection(); + createDecoStops(); +} + +bool intLessThan(int a, int b){ + return a <= b; +} +void DivePlannerPointsModel::removeSelectedPoints(const QVector< int >& rows) +{ + 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 DivePlannerGraphics::keyEscAction() @@ -264,8 +327,7 @@ void DivePlannerGraphics::keyEscAction() scene()->clearSelection(); return; } - - cancelClicked(); + plannerModel->cancelPlan(); } qreal DivePlannerGraphics::fromPercent(qreal percent, Qt::Orientation orientation) @@ -275,23 +337,6 @@ qreal DivePlannerGraphics::fromPercent(qreal percent, Qt::Orientation orientatio return result; } -void DivePlannerGraphics::cancelClicked() -{ - if (handles.size()){ - if (QMessageBox::warning(mainWindow(), tr("Save the Plan?"), - tr("You have a working plan, \n are you sure that you wanna cancel it?"), - QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok){ - return; - } - } - mainWindow()->showProfile(); -} - -void DivePlannerGraphics::okClicked() -{ - // todo. -} - void DivePlannerGraphics::increaseDepth() { if (depthLine->maximum() + 10 > MAX_DEEPNESS) @@ -323,7 +368,6 @@ void DivePlannerGraphics::decreaseDepth() return; } } - depthLine->setMaximum(depthLine->maximum() - 10); depthLine->updateTicks(); createDecoStops(); @@ -352,31 +396,7 @@ void DivePlannerGraphics::mouseDoubleClickEvent(QMouseEvent* event) int minutes = rint(timeLine->valueAt(mappedPos)); int meters = rint(depthLine->valueAt(mappedPos)); - double xpos = timeLine->posAtValue(minutes); - double ypos = depthLine->posAtValue(meters); - Q_FOREACH(DiveHandler* handler, handles){ - if (xpos == handler->pos().x()){ - qDebug() << "There's already an point at that place."; - //TODO: Move this later to a KMessageWidget. - return; - } - } - - DiveHandler *item = new DiveHandler (); - item->sec = minutes * 60; - item->mm = meters * 1000; - item->setPos(QPointF(xpos, ypos)); - scene()->addItem(item); - handles << item; - - Button *gasChooseBtn = new Button(); - gasChooseBtn ->setText(tr("Air")); - scene()->addItem(gasChooseBtn); - gasChooseBtn->setZValue(10); - connect(gasChooseBtn, SIGNAL(clicked()), this, SLOT(prepareSelectGas())); - - gases << gasChooseBtn; - createDecoStops(); + plannerModel->addStop(meters * 1000, minutes * 60, tr("Air"), 0); } void DivePlannerGraphics::prepareSelectGas() @@ -390,77 +410,40 @@ void DivePlannerGraphics::prepareSelectGas() void DivePlannerGraphics::selectGas(const QModelIndex& index) { QString gasSelected = gasListView->model()->data(index, Qt::DisplayRole).toString(); - currentGasChoice->setText(gasSelected); + int idx = gases.indexOf(currentGasChoice); + plannerModel->setData(plannerModel->index(idx, DivePlannerPointsModel::GAS), gasSelected); gasListView->hide(); } - void DivePlannerGraphics::createDecoStops() { qDeleteAll(lines); lines.clear(); - qSort(handles.begin(), handles.end(), handlerLessThenMinutes); - - // This needs to be done in the following steps: - // Get the user-input and calculate the dive info - // Not sure if this is the place to create the diveplan... - // We just start with a surface node at time = 0 - struct diveplan diveplan; - struct divedatapoint *dp = create_dp(0, 0, 209, 0, 0); - dp->entered = TRUE; - diveplan.dp = dp; - diveplan.gflow = 30; - diveplan.gfhigh = 70; - diveplan.surface_pressure = 1013; - DiveHandler *lastH = NULL; - Q_FOREACH(DiveHandler *h, handles) { - // these values need to come from the planner UI, eventually - int o2 = 209; - int he = 0; - int po2 = 0; - int deltaT = lastH ? h->sec - lastH->sec : h->sec; - lastH = h; - dp = plan_add_segment(&diveplan, deltaT, h->mm, o2, he, po2); - dp->entered = TRUE; - qDebug("time %d, depth %d", h->sec, h->mm); - } -#if DEBUG_PLAN - dump_plan(&diveplan); -#endif - char *cache = NULL; - struct dive *dive = NULL; - char *errorString = NULL; - plan(&diveplan, &cache, &dive, &errorString); -#if DEBUG_PLAN - dump_plan(&diveplan); -#endif - while(dp->next) + plannerModel->createTemporaryPlan(); + struct diveplan diveplan = plannerModel->getDiveplan(); + struct divedatapoint *dp = diveplan.dp; + while(dp->next){ dp = dp->next; + } - dpMaxTime = dp->time / 60.0 + 5; - - if (timeLine->maximum() < dp->time / 60.0 + 5 || - dp->time / 60.0 + 15 < timeLine->maximum()) { + if (timeLine->maximum() < dp->time / 60.0 + 5 || dp->time / 60.0 + 15 < timeLine->maximum()) { double newMax = fmax(dp->time / 60.0 + 5, minMinutes); timeLine->setMaximum(newMax); timeLine->updateTicks(); } // Re-position the user generated dive handlers - Q_FOREACH(DiveHandler *h, handles){ - h->setPos(timeLine->posAtValue(h->sec / 60), depthLine->posAtValue(h->mm / 1000)); - } - - int gasCount = gases.count(); - for(int i = 0; i < gasCount; i++){ + for(int i = 0; i < plannerModel->rowCount(); i++){ + divedatapoint dp = plannerModel->at(i); + DiveHandler *h = handles.at(i); + h->setPos(timeLine->posAtValue(dp.time / 60), depthLine->posAtValue(dp.depth / 1000)); QPointF p1 = (i == 0) ? QPointF(timeLine->posAtValue(0), depthLine->posAtValue(0)) : handles[i-1]->pos(); QPointF p2 = handles[i]->pos(); - QLineF line(p1, p2); QPointF pos = line.pointAt(0.5); gases[i]->setPos(pos); - qDebug() << "Adding a gas at" << pos; + gases[i]->setText( strForAir(dp)); } // (re-) create the profile with different colors for segments that were @@ -470,6 +453,7 @@ void DivePlannerGraphics::createDecoStops() QPolygonF poly; poly.append(QPointF(lastx, lasty)); + for (dp = diveplan.dp; dp != NULL; dp = dp->next) { double xpos = timeLine->posAtValue(dp->time / 60.0); double ypos = depthLine->posAtValue(dp->depth / 1000.0); @@ -497,16 +481,7 @@ void DivePlannerGraphics::createDecoStops() pat.setColorAt(0, profile_color[DEPTH_TOP].first()); diveBg->setBrush(pat); - deleteTemporaryDivePlan(diveplan.dp); - delete_single_dive(get_divenr(dive)); -} - -void DivePlannerGraphics::deleteTemporaryDivePlan(divedatapoint* dp) -{ - if (!dp) - return; - deleteTemporaryDivePlan(dp->next); - free(dp); + plannerModel->deleteTemporaryPlan(); } void DivePlannerGraphics::resizeEvent(QResizeEvent* event) @@ -619,8 +594,14 @@ void DivePlannerGraphics::mouseReleaseEvent(QMouseEvent* event) } } - activeDraggedHandler->sec = rint(timeLine->valueAt(mappedPos)) * 60; - activeDraggedHandler->mm = rint(depthLine->valueAt(mappedPos)) * 1000; + int pos = handles.indexOf(activeDraggedHandler); + divedatapoint data = plannerModel->at(pos); + + data.depth = rint(depthLine->valueAt(mappedPos)) * 1000; + data.time = rint(timeLine->valueAt(mappedPos)) * 60; + + plannerModel->editStop(pos, data); + activeDraggedHandler->setBrush(QBrush(Qt::white)); activeDraggedHandler->setPos(QPointF(xpos, ypos)); @@ -645,6 +626,10 @@ void DiveHandler::mousePressEvent(QGraphicsSceneMouseEvent* event) } // mousePressEvent 'grabs' the mouse and keyboard, annoying. ungrabMouse(); + + /* hack. Sometimes the keyboard is grabbed, sometime it's not, + so, let's force a grab and release, to get rid of a warning. */ + grabKeyboard(); ungrabKeyboard(); } @@ -658,6 +643,11 @@ void Ruler::setMinimum(double minimum) min = minimum; } +void Ruler::setTextColor(const QColor& color) +{ + textColor = color; +} + Ruler::Ruler() : orientation(Qt::Horizontal) { } @@ -665,39 +655,70 @@ Ruler::Ruler() : orientation(Qt::Horizontal) void Ruler::setOrientation(Qt::Orientation o) { orientation = o; + // position the elements on the screen. + setMinimum(minimum()); + setMaximum(maximum()); } void Ruler::updateTicks() { qDeleteAll(ticks); ticks.clear(); + qDeleteAll(labels); + labels.clear(); + QLineF m = line(); QGraphicsLineItem *item = NULL; + QGraphicsSimpleTextItem *label = NULL; + + double steps = (max - min) / interval; + qreal pos; + double currValue = min; if (orientation == Qt::Horizontal) { - double steps = (max - min) / interval; double stepSize = (m.x2() - m.x1()) / steps; - qreal pos; - for (pos = m.x1(); pos < m.x2(); pos += stepSize) { + for (pos = m.x1(); pos < m.x2(); pos += stepSize, currValue += interval) { item = new QGraphicsLineItem(pos, m.y1(), pos, m.y1() + tickSize, this); item->setPen(pen()); ticks.push_back(item); + + label = new QGraphicsSimpleTextItem(QString::number(currValue), this); + label->setBrush(QBrush(textColor)); + label->setFlag(ItemIgnoresTransformations); + label->setPos(pos - label->boundingRect().width()/2, m.y1() + tickSize + 5); + labels.push_back(label); } item = new QGraphicsLineItem(pos, m.y1(), pos, m.y1() + tickSize, this); item->setPen(pen()); ticks.push_back(item); + + label = new QGraphicsSimpleTextItem(QString::number(currValue), this); + label->setBrush(QBrush(textColor)); + label->setFlag(ItemIgnoresTransformations); + label->setPos(pos - label->boundingRect().width()/2, m.y1() + tickSize + 5); + labels.push_back(label); } else { - double steps = (max - min) / interval; double stepSize = (m.y2() - m.y1()) / steps; - qreal pos; - for (pos = m.y1(); pos < m.y2(); pos += stepSize) { + for (pos = m.y1(); pos < m.y2(); pos += stepSize, currValue += interval) { item = new QGraphicsLineItem(m.x1(), pos, m.x1() - tickSize, pos, this); item->setPen(pen()); ticks.push_back(item); + + label = new QGraphicsSimpleTextItem(QString::number(currValue), this); + label->setBrush(QBrush(textColor)); + label->setFlag(ItemIgnoresTransformations); + label->setPos(m.x2() - 80, pos); + labels.push_back(label); } item = new QGraphicsLineItem(m.x1(), pos, m.x1() - tickSize, pos, this); item->setPen(pen()); ticks.push_back(item); + + label = new QGraphicsSimpleTextItem(QString::number(currValue), this); + label->setBrush(QBrush(textColor)); + label->setFlag(ItemIgnoresTransformations); + label->setPos(m.x2() - 80, pos); + labels.push_back(label); } } @@ -757,12 +778,17 @@ double Ruler::minimum() const void Ruler::setColor(const QColor& color) { - setPen(QPen(color)); + QPen defaultPen(color); + defaultPen.setJoinStyle(Qt::RoundJoin); + defaultPen.setCapStyle(Qt::RoundCap); + defaultPen.setWidth(2); + defaultPen.setCosmetic(true); + setPen(defaultPen); } Button::Button(QObject* parent): QObject(parent), QGraphicsRectItem() { - icon = new QGraphicsPixmapItem(this); + icon = new QGraphicsPixmapItem(this); text = new QGraphicsSimpleTextItem(this); icon->setPos(0,0); text->setPos(0,0); @@ -799,3 +825,361 @@ void Button::mousePressEvent(QGraphicsSceneMouseEvent* event) event->ignore(); emit clicked(); } + +DivePlannerWidget::DivePlannerWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f), ui(new Ui::DivePlanner()) +{ + ui->setupUi(this); + ui->tableWidget->setTitle(tr("Dive Planner Points")); + ui->tableWidget->setModel(DivePlannerPointsModel::instance()); + ui->tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::GAS, new AirTypesDelegate(this)); + + connect(ui->tableWidget, SIGNAL(addButtonClicked()), DivePlannerPointsModel::instance(), SLOT(addStop())); + connect(ui->startTime, SIGNAL(timeChanged(QTime)), this, SLOT(startTimeChanged(QTime))); + connect(ui->ATMPressure, SIGNAL(textChanged(QString)), this, SLOT(atmPressureChanged(QString))); + connect(ui->bottomSAC, SIGNAL(textChanged(QString)), this, SLOT(bottomSacChanged(QString))); + connect(ui->decoStopSAC, SIGNAL(textChanged(QString)), this, SLOT(decoSacChanged(QString))); + connect(ui->highGF, SIGNAL(textChanged(QString)), this, SLOT(gfhighChanged(QString))); + connect(ui->lowGF, SIGNAL(textChanged(QString)), this, SLOT(gflowChanged(QString))); + connect(ui->highGF, SIGNAL(textChanged(QString)), this, SLOT(gfhighChanged(QString))); + connect(ui->lastStop, SIGNAL(toggled(bool)), this, SLOT(lastStopChanged(bool))); + + // Creating the plan + connect(ui->buttonBox, SIGNAL(accepted()), plannerModel, SLOT(createPlan())); + connect(ui->buttonBox, SIGNAL(rejected()), plannerModel, SLOT(cancelPlan())); + connect(plannerModel, SIGNAL(planCreated()), mainWindow(), SLOT(showProfile())); + connect(plannerModel, SIGNAL(planCreated()), mainWindow(), SLOT(refreshDisplay())); + connect(plannerModel, SIGNAL(planCanceled()), mainWindow(), SLOT(showProfile())); + + /* set defaults. */ + ui->startTime->setTime( QTime(1, 0) ); + ui->ATMPressure->setText( "1013" ); + ui->bottomSAC->setText("20"); + ui->decoStopSAC->setText("17"); + ui->lowGF->setText("30"); + ui->highGF->setText("75"); +} + +void DivePlannerWidget::startTimeChanged(const QTime& time) +{ + plannerModel->setStartTime(time); +} + +void DivePlannerWidget::atmPressureChanged(const QString& pressure) +{ + plannerModel->setSurfacePressure(pressure.toInt()); +} + +void DivePlannerWidget::bottomSacChanged(const QString& bottomSac) +{ + plannerModel->setBottomSac(bottomSac.toInt()); +} + +void DivePlannerWidget::decoSacChanged(const QString& decosac) +{ + plannerModel->setDecoSac(decosac.toInt()); +} + +void DivePlannerWidget::gfhighChanged(const QString& gfhigh) +{ + plannerModel->setGFHigh(gfhigh.toShort()); +} + +void DivePlannerWidget::gflowChanged(const QString& gflow) +{ + plannerModel->setGFLow(gflow.toShort()); +} + +void DivePlannerWidget::lastStopChanged(bool checked) +{ + plannerModel->setLastStop6m(checked); +} + +int DivePlannerPointsModel::columnCount(const QModelIndex& parent) const +{ + return COLUMNS; +} + +QVariant DivePlannerPointsModel::data(const QModelIndex& index, int role) const +{ + if(role == Qt::DisplayRole){ + divedatapoint p = divepoints.at(index.row()); + switch(index.column()){ + case CCSETPOINT: return p.po2; + case DEPTH: return p.depth / 1000; + case DURATION: return p.time / 60; + case GAS: return strForAir(p); + } + } + else if (role == Qt::DecorationRole){ + switch(index.column()){ + case REMOVE : return QIcon(":trash"); + } + } + else if (role == Qt::FontRole){ + return defaultModelFont(); + } + return QVariant(); +} + +bool DivePlannerPointsModel::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if(role == Qt::EditRole){ + divedatapoint& p = divepoints[index.row()]; + switch(index.column()){ + case DEPTH: p.depth = value.toInt() * 1000; break; + case DURATION: p.time = value.toInt() * 60; break; + case CCSETPOINT:{ + int po2 = 0; + QByteArray gasv = value.toByteArray(); + if (validate_po2(gasv.data(), &po2)) + p.po2 = po2; + } break; + case GAS: { + int o2 = 0; + int he = 0; + QByteArray gasv = value.toByteArray(); + if (validate_gas(gasv.data(), &o2, &he)) { + p.o2 = o2; + p.he = he; + }break; + } + } + editStop(index.row(), p); + } + return QAbstractItemModel::setData(index, value, role); +} + +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 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 +{ + return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; +} + +int DivePlannerPointsModel::rowCount(const QModelIndex& parent) const +{ + return divepoints.count(); +} + +DivePlannerPointsModel::DivePlannerPointsModel(QObject* parent): QAbstractTableModel(parent) +{ +} + +DivePlannerPointsModel* DivePlannerPointsModel::instance() +{ + static DivePlannerPointsModel* self = new DivePlannerPointsModel(); + return self; +} + +void DivePlannerPointsModel::setBottomSac(int sac) +{ + diveplan.bottomsac = sac; + emit dataChanged(createIndex(0, 0), createIndex(rowCount()-1, COLUMNS-1)); +} + +void DivePlannerPointsModel::setDecoSac(int sac) +{ + diveplan.decosac = sac; + emit dataChanged(createIndex(0, 0), createIndex(rowCount()-1, COLUMNS-1)); +} + +void DivePlannerPointsModel::setGFHigh(short int gfhigh) +{ + diveplan.gfhigh = gfhigh; + emit dataChanged(createIndex(0, 0), createIndex(rowCount()-1, COLUMNS-1)); +} + +void DivePlannerPointsModel::setGFLow(short int ghflow) +{ + diveplan.gflow = ghflow; + emit dataChanged(createIndex(0, 0), createIndex(rowCount()-1, COLUMNS-1)); +} + +void DivePlannerPointsModel::setSurfacePressure(int pressure) +{ + diveplan.surface_pressure = pressure; + emit dataChanged(createIndex(0, 0), createIndex(rowCount()-1, COLUMNS-1)); +} + +void DivePlannerPointsModel::setLastStop6m(bool value) +{ +} + +void DivePlannerPointsModel::setStartTime(const QTime& t) +{ + diveplan.when = t.msec(); + emit dataChanged(createIndex(0, 0), createIndex(rowCount()-1, COLUMNS-1)); +} + +bool divePointsLessThan(const divedatapoint& p1, const divedatapoint& p2){ + return p1.time <= p2.time; +} +int DivePlannerPointsModel::addStop(int meters, int minutes, const QString& gas, int ccpoint) +{ + int row = divepoints.count(); + if(meters == 0 && minutes == 0){ + if(row == 0){ + meters = 10000; + minutes = 600; + } + else{ + divedatapoint p = at(row-1); + meters = p.depth; + minutes = p.time + 600; + } + } + + // check if there's already a new stop before this one: + for(int i = 0; i < divepoints.count(); i++){ + const divedatapoint& dp = divepoints.at(i); + if (dp.time > minutes ){ + row = i; + break; + } + } + + // add the new stop + beginInsertRows(QModelIndex(), row, row); + divedatapoint point; + point.depth = meters; + point.time = minutes; + if (row == 0){ + point.o2 = 209; + point.he = 0; + point.po2 = 0; + }else{ + divedatapoint before = at(row-1); + point.o2 = before.o2; + point.he = before.he; + point.po2 = 0; + } + divepoints.append( point ); + std::sort(divepoints.begin(), divepoints.end(), divePointsLessThan); + endInsertRows(); + return row; +} + +void DivePlannerPointsModel::editStop(int row, divedatapoint newData) +{ + divepoints[row] = newData; + std::sort(divepoints.begin(), divepoints.end(), divePointsLessThan); + emit dataChanged(createIndex(0, 0), createIndex(rowCount()-1, COLUMNS-1)); +} + +divedatapoint DivePlannerPointsModel::at(int row) +{ + return divepoints.at(row); +} + +void DivePlannerPointsModel::remove(const QModelIndex& index) +{ + if (index.column() != REMOVE) + return; + + beginRemoveRows(QModelIndex(), index.row(), index.row()); + divepoints.remove(index.row()); + endRemoveRows(); +} + +struct diveplan DivePlannerPointsModel::getDiveplan() +{ + return diveplan; +} + +void DivePlannerPointsModel::cancelPlan() +{ + if(rowCount()){ + if (QMessageBox::warning(mainWindow(), tr("Save the Plan?"), + tr("You have a working plan, \n are you sure that you wanna cancel it?"), + QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok){ + return; + } + } + + beginRemoveRows(QModelIndex(), 0, rowCount()-1); + divepoints.clear(); + endRemoveRows(); + emit planCanceled(); +} + +void DivePlannerPointsModel::createTemporaryPlan() +{ + // This needs to be done in the following steps: + // Get the user-input and calculate the dive info + // Not sure if this is the place to create the diveplan... + // We just start with a surface node at time = 0 + struct divedatapoint *dp = create_dp(0, 0, 209, 0, 0); + dp->entered = TRUE; + diveplan.dp = dp; + 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; + dp = plan_add_segment(&diveplan, deltaT, p.depth, p.o2, p.he, p.po2); + } +#if DEBUG_PLAN + dump_plan(&diveplan); +#endif + char *cache = NULL; + tempDive = NULL; + char *errorString = NULL; + plan(&diveplan, &cache, &tempDive, &errorString); +#if DEBUG_PLAN + dump_plan(&diveplan); +#endif +} + +void DivePlannerPointsModel::deleteTemporaryPlan() +{ + deleteTemporaryPlan(diveplan.dp); + delete_single_dive(get_divenr(tempDive)); + tempDive = NULL; +} + +void DivePlannerPointsModel::deleteTemporaryPlan(struct divedatapoint *dp) +{ + if (!dp){ + return; + } + + deleteTemporaryPlan(dp->next); + free(dp); +} + +void DivePlannerPointsModel::createPlan() +{ + // Ok, so, here the diveplan creates a dive, + // puts it on the dive list, and we need to remember + // to not delete it later. mumble. ;p + char *cache = NULL; + tempDive = NULL; + char *errorString = NULL; + + createTemporaryPlan(); + plan(&diveplan, &cache, &tempDive, &errorString); + mark_divelist_changed(TRUE); + + // Remove and clean the diveplan, so we don't delete + // the dive by mistake. + diveplan.dp = NULL; + beginRemoveRows(QModelIndex(), 0, rowCount() -1 ); + divepoints.clear(); + endRemoveRows(); + + planCreated(); +} |