summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--planner.c2
-rw-r--r--planner.h9
-rw-r--r--qt-ui/diveplanner.cpp505
-rw-r--r--qt-ui/diveplanner.h82
-rw-r--r--qt-ui/diveplanner.ui128
-rw-r--r--qt-ui/maintab.cpp10
-rw-r--r--qt-ui/maintab.ui62
-rw-r--r--qt-ui/mainwindow.cpp2
-rw-r--r--qt-ui/mainwindow.ui57
-rw-r--r--qt-ui/modeldelegates.cpp18
-rw-r--r--qt-ui/modeldelegates.h9
-rw-r--r--subsurface.qrc1
12 files changed, 642 insertions, 243 deletions
diff --git a/planner.c b/planner.c
index 56fc0ac46..7c77555ac 100644
--- a/planner.c
+++ b/planner.c
@@ -712,7 +712,6 @@ error_exit:
free(gaschanges);
}
-#if USE_GTK_UI
/*
* Get a value in tenths (so "10.2" == 102, "9" = 90)
*
@@ -980,6 +979,7 @@ int validate_volume(const char *text, int *sac)
return 1;
}
+#if USE_GTK_UI
struct diveplan diveplan = {};
char *cache_data = NULL;
struct dive *planned_dive = NULL;
diff --git a/planner.h b/planner.h
index 4de3c4669..d97a21fa7 100644
--- a/planner.h
+++ b/planner.h
@@ -1,6 +1,11 @@
#ifndef PLANNER_H
#define PLANNER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern void plan(struct diveplan *diveplan, char **cache_datap, struct dive **divep, char **error_string_p);
extern int validate_gas(const char *text, int *o2_p, int *he_p);
extern int validate_time(const char *text, int *sec_p, int *rel_p);
@@ -19,4 +24,8 @@ extern char *cache_data;
extern char *disclaimer;
extern double plangflow, plangfhigh;
+
+#ifdef __cplusplus
+}
+#endif
#endif /* PLANNER_H */
diff --git a/qt-ui/diveplanner.cpp b/qt-ui/diveplanner.cpp
index 39d3b20a8..e7c1b1962 100644
--- a/qt-ui/diveplanner.cpp
+++ b/qt-ui/diveplanner.cpp
@@ -1,34 +1,45 @@
#include "diveplanner.h"
#include "graphicsview-common.h"
+#include "models.h"
+#include "modeldelegates.h"
+#include "ui_diveplanner.h"
+#include "mainwindow.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>
#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");
+}
+
+static DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
+
DivePlannerGraphics::DivePlannerGraphics(QWidget* parent): QGraphicsView(parent), activeDraggedHandler(0)
{
fill_profile_color();
@@ -111,16 +122,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,31 +146,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(this);
- gasListView->setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);
- gasListView->setModel(gasChoices);
- gasListView->setWindowModality(Qt::WindowModal);
+ gasListView = new QListView();
+ 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();
}
}
@@ -173,12 +197,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();
@@ -188,12 +214,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){
@@ -204,23 +233,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){
@@ -231,32 +261,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()
@@ -265,8 +315,7 @@ void DivePlannerGraphics::keyEscAction()
scene()->clearSelection();
return;
}
-
- cancelClicked();
+ cancelPlan();
}
qreal DivePlannerGraphics::fromPercent(qreal percent, Qt::Orientation orientation)
@@ -276,7 +325,7 @@ qreal DivePlannerGraphics::fromPercent(qreal percent, Qt::Orientation orientatio
return result;
}
-void DivePlannerGraphics::cancelClicked()
+void DivePlannerGraphics::cancelPlan()
{
if (handles.size()){
if (QMessageBox::warning(mainWindow(), tr("Save the Plan?"),
@@ -288,11 +337,6 @@ void DivePlannerGraphics::cancelClicked()
mainWindow()->showProfile();
}
-void DivePlannerGraphics::okClicked()
-{
- // todo.
-}
-
void DivePlannerGraphics::increaseDepth()
{
if (depthLine->maximum() + 10 > MAX_DEEPNESS)
@@ -324,7 +368,6 @@ void DivePlannerGraphics::decreaseDepth()
return;
}
}
-
depthLine->setMaximum(depthLine->maximum() - 10);
depthLine->updateTicks();
createDecoStops();
@@ -353,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()
@@ -391,16 +410,15 @@ 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
@@ -413,18 +431,16 @@ void DivePlannerGraphics::createDecoStops()
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);
+
+ int rowCount = plannerModel->rowCount();
+ int lastIndex = -1;
+ for(int i = 0; i < rowCount; i++){
+ divedatapoint p = plannerModel->at(i);
+ int deltaT = lastIndex != -1 ? p.time - plannerModel->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
@@ -449,19 +465,16 @@ void DivePlannerGraphics::createDecoStops()
}
// 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
@@ -620,8 +633,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));
@@ -646,6 +665,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();
}
@@ -763,7 +786,7 @@ void Ruler::setColor(const QColor& color)
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);
@@ -800,3 +823,263 @@ 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->tablePoints->setModel(DivePlannerPointsModel::instance());
+ ui->tablePoints->setItemDelegateForColumn(DivePlannerPointsModel::GAS, new AirTypesDelegate(this));
+
+ connect(ui->tablePoints, SIGNAL(clicked(QModelIndex)), plannerModel, SLOT(removePoint(const QModelIndex)));
+ 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)));
+
+ QFile cssFile(":table-css");
+ cssFile.open(QIODevice::ReadOnly);
+ QTextStream reader(&cssFile);
+ QString css = reader.readAll();
+
+ ui->tablePoints->setStyleSheet(css);
+ QFontMetrics metrics(defaultModelFont());
+
+ ui->tablePoints->horizontalHeader()->setResizeMode(DivePlannerPointsModel::REMOVE, QHeaderView::Fixed);
+ ui->tablePoints->verticalHeader()->setDefaultSectionSize( metrics.height() +8 );
+ initialUiSetup();
+}
+
+void DivePlannerWidget::hideEvent(QHideEvent* event)
+{
+ QSettings s;
+ s.beginGroup("DivePlanner");
+ s.beginGroup("PointTables");
+ for (int i = 0; i < CylindersModel::COLUMNS; i++) {
+ s.setValue(QString("colwidth%1").arg(i), ui->tablePoints->columnWidth(i));
+ }
+ s.endGroup();
+ s.sync();
+}
+
+void DivePlannerWidget::initialUiSetup()
+{
+ QSettings s;
+ s.beginGroup("DivePlanner");
+ s.beginGroup("PointTables");
+ for (int i = 0; i < CylindersModel::COLUMNS; i++) {
+ QVariant width = s.value(QString("colwidth%1").arg(i));
+ if (width.isValid())
+ ui->tablePoints->setColumnWidth(i, width.toInt());
+ else
+ ui->tablePoints->resizeColumnToContents(i);
+ }
+ s.endGroup();
+}
+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 0;
+ case DEPTH: return p.depth / 1000;
+ case DURATION: return p.time / 60;
+ case GAS: return strForAir(p);
+ }
+ }
+ if (role == Qt::DecorationRole){
+ switch(index.column()){
+ case REMOVE : return QIcon(":trash");
+ }
+ }
+ 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: /* what do I do here? */
+ 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");
+ }
+ }
+ 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::createPlan()
+{
+
+}
+
+void DivePlannerPointsModel::setBottomSac(int sac)
+{
+ diveplan.bottomsac = sac;
+}
+
+void DivePlannerPointsModel::setDecoSac(int sac)
+{
+ diveplan.decosac = sac;
+}
+
+void DivePlannerPointsModel::setGFHigh(short int gfhigh)
+{
+ diveplan.gfhigh = gfhigh;
+}
+
+void DivePlannerPointsModel::setGFLow(short int ghflow)
+{
+ diveplan.gflow = ghflow;
+}
+
+void DivePlannerPointsModel::setSurfacePressure(int pressure)
+{
+ diveplan.surface_pressure = pressure;
+}
+
+void DivePlannerPointsModel::setLastStop6m(bool value)
+{
+}
+
+void DivePlannerPointsModel::setStartTime(const QTime& t)
+{
+ diveplan.when = t.msec();
+}
+
+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();
+ // 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;
+ point.o2 = 209;
+ point.he = 0;
+ 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::removePoint(const QModelIndex& index)
+{
+ if (index.column() != REMOVE)
+ return;
+
+ beginRemoveRows(QModelIndex(), index.row(), index.row());
+ divepoints.remove(index.row());
+ endRemoveRows();
+}
diff --git a/qt-ui/diveplanner.h b/qt-ui/diveplanner.h
index 2239e013d..0aea77788 100644
--- a/qt-ui/diveplanner.h
+++ b/qt-ui/diveplanner.h
@@ -4,11 +4,58 @@
#include <QGraphicsView>
#include <QGraphicsPathItem>
#include <QDialog>
+#include <QAbstractTableModel>
+#include <QDateTime>
+
+#include "dive.h"
+
+namespace Ui{
+ class DivePlanner;
+};
class QListView;
class QStringListModel;
class QModelIndex;
+// Return a Model containing the air types.
+QStringListModel *airTypes();
+
+class DivePlannerPointsModel : public QAbstractTableModel{
+ Q_OBJECT
+public:
+ static DivePlannerPointsModel* instance();
+ enum Sections{REMOVE, DEPTH, DURATION, GAS, CCSETPOINT, COLUMNS};
+ 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 removeSelectedPoints(const QVector<int>& rows);
+
+ /**
+ * @return the row number.
+ */
+ int addStop(int meters, int minutes,const QString& gas, int ccpoint );
+ void editStop(int row, divedatapoint newData );
+ divedatapoint at(int row);
+public slots:
+ void setGFHigh(short gfhigh);
+ void setGFLow(short ghflow);
+ void setSurfacePressure(int pressure);
+ void setBottomSac(int sac);
+ void setDecoSac(int sac);
+ void setStartTime(const QTime& t);
+ void setLastStop6m(bool value);
+ void createPlan();
+ void removePoint(const QModelIndex& index);
+
+private:
+ explicit DivePlannerPointsModel(QObject* parent = 0);
+ struct diveplan diveplan;
+ QVector<divedatapoint> divepoints;
+};
+
class Button : public QObject, public QGraphicsRectItem {
Q_OBJECT
public:
@@ -28,10 +75,8 @@ private:
class DiveHandler : public QGraphicsEllipseItem{
public:
DiveHandler();
- int sec;
- int mm;
protected:
- void mousePressEvent(QGraphicsSceneMouseEvent* event);
+ void mousePressEvent(QGraphicsSceneMouseEvent* event);
};
class Ruler : public QGraphicsLineItem{
@@ -72,8 +117,6 @@ protected:
virtual void mouseMoveEvent(QMouseEvent* event);
virtual void mousePressEvent(QMouseEvent* event);
virtual void mouseReleaseEvent(QMouseEvent* event);
-
- void createDecoStops();
bool isPointOutOfBoundaries(const QPointF& point);
void deleteTemporaryDivePlan(struct divedatapoint* dp);
qreal fromPercent(qreal percent, Qt::Orientation orientation);
@@ -88,11 +131,12 @@ private slots:
void increaseDepth();
void decreaseTime();
void decreaseDepth();;
- void okClicked();
- void cancelClicked();
+ void createDecoStops();
+ void cancelPlan();
void prepareSelectGas();
void selectGas(const QModelIndex& index);
-
+ void pointInserted(const QModelIndex&, int start, int end);
+ void pointsRemoved(const QModelIndex&, int start, int end);
private:
void moveActiveHandler(const QPointF& pos);
@@ -138,11 +182,29 @@ private:
Button *plusDepth; // adds 10 meters to the depth ruler.
Button *lessTime; // remove 10 minutes to the time ruler.
Button *lessDepth; // remove 10 meters to the depth ruler.
- Button *okBtn; // accepts, and creates a new dive based on the plan.
- Button *cancelBtn; // rejects, and clears the dive plan.
int minMinutes; // this holds the minimum duration of the dive.
int dpMaxTime; // this is the time of the dive calculated by the deco.
};
+class DivePlannerWidget : public QWidget {
+ Q_OBJECT
+ void initialUiSetup();
+public:
+ explicit DivePlannerWidget(QWidget* parent = 0, Qt::WindowFlags f = 0);
+
+public slots:
+ void startTimeChanged(const QTime& time);
+ void atmPressureChanged(const QString& pressure);
+ void bottomSacChanged(const QString& bottomSac);
+ void decoSacChanged(const QString& decosac);
+ void gflowChanged(const QString& gflow);
+ void gfhighChanged(const QString& gfhigh);
+ void lastStopChanged(bool checked);
+protected:
+ virtual void hideEvent(QHideEvent* );
+private:
+ Ui::DivePlanner *ui;
+};
+
#endif
diff --git a/qt-ui/diveplanner.ui b/qt-ui/diveplanner.ui
index e4903f0f8..d2d52172b 100644
--- a/qt-ui/diveplanner.ui
+++ b/qt-ui/diveplanner.ui
@@ -1,27 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DivePlanner</class>
- <widget class="QDialog" name="DivePlanner">
+ <widget class="QWidget" name="DivePlanner">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
- <width>575</width>
- <height>451</height>
+ <width>400</width>
+ <height>352</height>
</rect>
</property>
<property name="windowTitle">
- <string>Dialog</string>
+ <string>Form</string>
</property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="DivePlannerGraphics" name="graphicsView"/>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Start Time</string>
+ </property>
+ </widget>
</item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>ATM Pressure</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QTimeEdit" name="startTime"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="ATMPressure"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="decoStopSAC"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Low GF</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLineEdit" name="lowGF"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Bottom SAC</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>High GF</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>SAC on DECO Stop</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLineEdit" name="bottomSAC"/>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLineEdit" name="highGF"/>
+ </item>
+ <item row="6" column="0">
+ <widget class="QCheckBox" name="lastStop">
+ <property name="text">
+ <string>Last Stop at 6m</string>
</property>
+ </widget>
+ </item>
+ <item row="7" column="0" colspan="2">
+ <widget class="QTableView" name="tablePoints"/>
+ </item>
+ <item row="8" column="0" colspan="2">
+ <widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
@@ -29,46 +93,6 @@
</item>
</layout>
</widget>
- <customwidgets>
- <customwidget>
- <class>DivePlannerGraphics</class>
- <extends>QGraphicsView</extends>
- <header>diveplanner.h</header>
- </customwidget>
- </customwidgets>
<resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>DivePlanner</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>248</x>
- <y>254</y>
- </hint>
- <hint type="destinationlabel">
- <x>157</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>DivePlanner</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>316</x>
- <y>260</y>
- </hint>
- <hint type="destinationlabel">
- <x>286</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- </connections>
+ <connections/>
</ui>
diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp
index 13709ba23..8a0e2f93c 100644
--- a/qt-ui/maintab.cpp
+++ b/qt-ui/maintab.cpp
@@ -18,6 +18,8 @@
#include <QCompleter>
#include <QDebug>
#include <QSet>
+#include <QTextStream>
+#include <QFile>
#include <QSettings>
MainTab::MainTab(QWidget *parent) : QTabWidget(parent),
@@ -85,7 +87,6 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent),
connect(ui->weights, SIGNAL(clicked(QModelIndex)), this, SLOT(editWeigthWidget(QModelIndex)));
QFontMetrics metrics(defaultModelFont());
- QFontMetrics metrics2(font());
ui->cylinders->horizontalHeader()->setResizeMode(CylindersModel::REMOVE, QHeaderView::Fixed);
ui->cylinders->verticalHeader()->setDefaultSectionSize( metrics.height() +8 );
@@ -106,6 +107,13 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent),
ui->location->setCompleter(completers.location);
ui->suit->setCompleter(completers.suit);
+ QFile cssFile(":table-css");
+ cssFile.open(QIODevice::ReadOnly);
+ QTextStream reader(&cssFile);
+ QString css = reader.readAll();
+
+ ui->cylinders->setStyleSheet(css);
+ ui->weights->setStyleSheet(css);
initialUiSetup();
}
diff --git a/qt-ui/maintab.ui b/qt-ui/maintab.ui
index cdddc4cf9..ba3f6a73d 100644
--- a/qt-ui/maintab.ui
+++ b/qt-ui/maintab.ui
@@ -14,7 +14,7 @@
<string>TabWidget</string>
</property>
<property name="currentIndex">
- <number>0</number>
+ <number>1</number>
</property>
<widget class="QWidget" name="notesTab">
<attribute name="title">
@@ -159,35 +159,7 @@
<item>
<widget class="QTableView" name="cylinders">
<property name="styleSheet">
- <string notr="true"> QTableView {
- show-decoration-selected: 1;
- }
-
- QTableView::item {
- border: 1px solid #d9d9d9;
- border-top-color: transparent;
- border-bottom-color: transparent;
- padding: 2px;
- }
-
- QTableView::item:hover {
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1);
- border: 1px solid #bfcde4;
- }
-
- QTableView::item:selected {
- border: 1px solid #567dbc;
- }
-
- QTableView::item:selected:active{
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6ea1f1, stop: 1 #567dbc);
- }
-
- QTableView::item:selected:!active {
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6b9be8, stop: 1 #577fbf);
- }
-
-</string>
+ <string notr="true"/>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
@@ -210,35 +182,7 @@
<item>
<widget class="QTableView" name="weights">
<property name="styleSheet">
- <string notr="true"> QTableView {
- show-decoration-selected: 1;
- }
-
- QTableView::item {
- border: 1px solid #d9d9d9;
- border-top-color: transparent;
- border-bottom-color: transparent;
- padding: 2px;
- }
-
- QTableView::item:hover {
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1);
- border: 1px solid #bfcde4;
- }
-
- QTableView::item:selected {
- border: 1px solid #567dbc;
- }
-
- QTableView::item:selected:active{
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6ea1f1, stop: 1 #567dbc);
- }
-
- QTableView::item:selected:!active {
- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6b9be8, stop: 1 #577fbf);
- }
-
-</string>
+ <string notr="true"/>
</property>
<property name="showGrid">
<bool>false</bool>
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 75f18000c..4726899e5 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -238,12 +238,14 @@ void MainWindow::on_actionDivePlanner_triggered()
{
disableDcShortcuts();
ui->stackedWidget->setCurrentIndex(1);
+ ui->infoPane->setCurrentIndex(1);
}
void MainWindow::showProfile()
{
enableDcShortcuts();
ui->stackedWidget->setCurrentIndex(0);
+ ui->infoPane->setCurrentIndex(0);
}
diff --git a/qt-ui/mainwindow.ui b/qt-ui/mainwindow.ui
index 731013538..445d121df 100644
--- a/qt-ui/mainwindow.ui
+++ b/qt-ui/mainwindow.ui
@@ -24,17 +24,44 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
- <widget class="MainTab" name="InfoWidget" native="true"/>
+ <widget class="QStackedWidget" name="infoPane">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <widget class="QWidget" name="page">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="MainTab" name="InfoWidget" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_2">
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="DivePlannerWidget" name="widget" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
- <number>0</number>
+ <number>1</number>
</property>
<widget class="QWidget" name="page_5">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -47,7 +74,16 @@
<property name="spacing">
<number>0</number>
</property>
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -123,10 +159,7 @@
</widget>
</item>
<item>
- <widget class="KMessageWidget" name="mainErrorMessage" native="true">
- <zorder>mainSplitter</zorder>
- <zorder>mainSplitter</zorder>
- </widget>
+ <widget class="KMessageWidget" name="mainErrorMessage" native="true"/>
</item>
</layout>
</widget>
@@ -136,7 +169,7 @@
<x>0</x>
<y>0</y>
<width>763</width>
- <height>20</height>
+ <height>19</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@@ -443,6 +476,12 @@
<extends>QGraphicsView</extends>
<header>diveplanner.h</header>
</customwidget>
+ <customwidget>
+ <class>DivePlannerWidget</class>
+ <extends>QWidget</extends>
+ <header>diveplanner.h</header>
+ <container>1</container>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>
diff --git a/qt-ui/modeldelegates.cpp b/qt-ui/modeldelegates.cpp
index 998c246b8..9bc633191 100644
--- a/qt-ui/modeldelegates.cpp
+++ b/qt-ui/modeldelegates.cpp
@@ -3,6 +3,7 @@
#include "../divelist.h"
#include "starwidget.h"
#include "models.h"
+#include "diveplanner.h"
#include <QtDebug>
#include <QPainter>
@@ -14,6 +15,7 @@
#include <QLineEdit>
#include <QKeyEvent>
#include <QAbstractItemView>
+#include <QStringListModel>
// Gets the index of the model in the currentRow and column.
// currCombo is defined below.
@@ -253,3 +255,19 @@ QWidget* WSInfoDelegate::createEditor(QWidget* parent, const QStyleOptionViewIte
currWeigth.weigth = ws->weight.grams;
return editor;
}
+
+void AirTypesDelegate::revertModelData(QWidget* widget, QAbstractItemDelegate::EndEditHint hint)
+{
+}
+
+void AirTypesDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
+{
+ if (!index.isValid())
+ return;
+ QComboBox *combo = qobject_cast<QComboBox*>(editor);
+ model->setData(index, QVariant(combo->currentText()));
+}
+
+AirTypesDelegate::AirTypesDelegate(QObject* parent) : ComboBoxDelegate(airTypes(), parent)
+{
+}
diff --git a/qt-ui/modeldelegates.h b/qt-ui/modeldelegates.h
index 9603d5dce..29d4f3717 100644
--- a/qt-ui/modeldelegates.h
+++ b/qt-ui/modeldelegates.h
@@ -49,4 +49,13 @@ public slots:
void revertModelData(QWidget* widget, QAbstractItemDelegate::EndEditHint hint);
};
+class AirTypesDelegate : public ComboBoxDelegate{
+ Q_OBJECT
+public:
+ explicit AirTypesDelegate(QObject* parent = 0);
+ virtual void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
+public slots:
+ void revertModelData(QWidget* widget, QAbstractItemDelegate::EndEditHint hint);
+};
+
#endif
diff --git a/subsurface.qrc b/subsurface.qrc
index e94505cea..cf7864b27 100644
--- a/subsurface.qrc
+++ b/subsurface.qrc
@@ -10,5 +10,6 @@
<file alias="minimum">icons/minimum.svg</file>
<file alias="maximum">icons/maximum.svg</file>
<file alias="average">icons/average.svg</file>
+ <file alias="table-css">qt-ui/css/tableviews.css</file>
</qresource>
</RCC>