summaryrefslogtreecommitdiffstats
path: root/qt-ui/diveplanner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qt-ui/diveplanner.cpp')
-rw-r--r--qt-ui/diveplanner.cpp718
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();
+}