diff options
-rw-r--r-- | planner.c | 2 | ||||
-rw-r--r-- | planner.h | 9 | ||||
-rw-r--r-- | qt-ui/diveplanner.cpp | 505 | ||||
-rw-r--r-- | qt-ui/diveplanner.h | 82 | ||||
-rw-r--r-- | qt-ui/diveplanner.ui | 128 | ||||
-rw-r--r-- | qt-ui/maintab.cpp | 10 | ||||
-rw-r--r-- | qt-ui/maintab.ui | 62 | ||||
-rw-r--r-- | qt-ui/mainwindow.cpp | 2 | ||||
-rw-r--r-- | qt-ui/mainwindow.ui | 57 | ||||
-rw-r--r-- | qt-ui/modeldelegates.cpp | 18 | ||||
-rw-r--r-- | qt-ui/modeldelegates.h | 9 | ||||
-rw-r--r-- | subsurface.qrc | 1 |
12 files changed, 642 insertions, 243 deletions
@@ -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; @@ -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> |