2017-04-27 18:26:05 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2013-04-14 03:44:02 +00:00
|
|
|
/*
|
|
|
|
* maintab.cpp
|
|
|
|
*
|
|
|
|
* classes for the "notebook" area of the main window of Subsurface
|
|
|
|
*
|
|
|
|
*/
|
2017-04-04 17:21:30 +00:00
|
|
|
#include "desktop-widgets/tab-widgets/maintab.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "desktop-widgets/mainwindow.h"
|
2017-07-15 20:37:02 +00:00
|
|
|
#include "desktop-widgets/mapwidget.h"
|
2018-06-03 20:15:19 +00:00
|
|
|
#include "core/qthelper.h"
|
2019-05-31 14:09:14 +00:00
|
|
|
#include "core/trip.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "qt-models/diveplannermodel.h"
|
|
|
|
#include "desktop-widgets/divelistview.h"
|
2019-11-24 14:02:34 +00:00
|
|
|
#include "core/selection.h"
|
2015-09-03 18:56:37 +00:00
|
|
|
#include "profile-widget/profilewidget2.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "desktop-widgets/diveplanner.h"
|
|
|
|
#include "core/divesitehelpers.h"
|
|
|
|
#include "qt-models/divecomputerextradatamodel.h"
|
|
|
|
#include "qt-models/divelocationmodel.h"
|
2017-11-26 21:21:58 +00:00
|
|
|
#include "qt-models/filtermodels.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "core/divesite.h"
|
2019-08-05 17:41:15 +00:00
|
|
|
#include "core/errorhelper.h"
|
2018-05-11 15:25:41 +00:00
|
|
|
#include "core/subsurface-string.h"
|
2018-06-17 06:48:54 +00:00
|
|
|
#include "core/gettextfromc.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "desktop-widgets/locationinformation.h"
|
2018-10-21 16:00:02 +00:00
|
|
|
#include "desktop-widgets/simplewidgets.h"
|
2019-11-13 14:08:40 +00:00
|
|
|
#include "commands/command.h"
|
2015-06-01 19:58:23 +00:00
|
|
|
|
2019-04-13 15:43:45 +00:00
|
|
|
#include "TabDiveEquipment.h"
|
2017-04-04 17:21:30 +00:00
|
|
|
#include "TabDiveExtraInfo.h"
|
|
|
|
#include "TabDiveInformation.h"
|
|
|
|
#include "TabDivePhotos.h"
|
|
|
|
#include "TabDiveStatistics.h"
|
2019-03-09 21:32:16 +00:00
|
|
|
#include "TabDiveSite.h"
|
2017-04-04 17:21:30 +00:00
|
|
|
|
2013-08-13 13:49:59 +00:00
|
|
|
#include <QCompleter>
|
2013-11-28 11:17:30 +00:00
|
|
|
#include <QSettings>
|
2013-12-12 01:08:56 +00:00
|
|
|
#include <QScrollBar>
|
2014-06-03 22:29:28 +00:00
|
|
|
#include <QShortcut>
|
2014-06-04 01:01:00 +00:00
|
|
|
#include <QMessageBox>
|
2014-06-27 12:17:33 +00:00
|
|
|
#include <QDesktopServices>
|
2015-05-11 17:38:50 +00:00
|
|
|
#include <QStringList>
|
2013-04-07 22:20:43 +00:00
|
|
|
|
2019-04-13 16:14:50 +00:00
|
|
|
struct Completers {
|
|
|
|
QCompleter *divemaster;
|
|
|
|
QCompleter *buddy;
|
|
|
|
QCompleter *tags;
|
|
|
|
};
|
|
|
|
|
2013-04-07 22:20:43 +00:00
|
|
|
MainTab::MainTab(QWidget *parent) : QTabWidget(parent),
|
2014-06-02 22:50:42 +00:00
|
|
|
editMode(NONE),
|
2018-03-15 21:41:59 +00:00
|
|
|
lastSelectedDive(true),
|
2017-11-30 19:33:43 +00:00
|
|
|
lastTabSelectedDive(0),
|
2017-12-19 22:05:42 +00:00
|
|
|
lastTabSelectedDiveTrip(0),
|
2019-12-04 07:15:20 +00:00
|
|
|
currentTrip(0)
|
2013-04-07 22:20:43 +00:00
|
|
|
{
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.setupUi(this);
|
2017-04-04 17:21:30 +00:00
|
|
|
|
2019-04-13 15:43:45 +00:00
|
|
|
extraWidgets << new TabDiveEquipment();
|
|
|
|
ui.tabWidget->addTab(extraWidgets.last(), tr("Equipment"));
|
2017-04-04 18:01:47 +00:00
|
|
|
extraWidgets << new TabDiveInformation();
|
2017-04-13 18:23:07 +00:00
|
|
|
ui.tabWidget->addTab(extraWidgets.last(), tr("Information"));
|
2017-04-04 18:01:47 +00:00
|
|
|
extraWidgets << new TabDiveStatistics();
|
2017-04-13 18:23:07 +00:00
|
|
|
ui.tabWidget->addTab(extraWidgets.last(), tr("Statistics"));
|
2017-04-04 18:01:47 +00:00
|
|
|
extraWidgets << new TabDivePhotos();
|
2018-07-13 18:46:45 +00:00
|
|
|
ui.tabWidget->addTab(extraWidgets.last(), tr("Media"));
|
2017-04-21 16:33:38 +00:00
|
|
|
extraWidgets << new TabDiveExtraInfo();
|
|
|
|
ui.tabWidget->addTab(extraWidgets.last(), tr("Extra Info"));
|
2019-03-09 21:32:16 +00:00
|
|
|
extraWidgets << new TabDiveSite();
|
|
|
|
ui.tabWidget->addTab(extraWidgets.last(), tr("Dive sites"));
|
2017-04-04 17:21:30 +00:00
|
|
|
|
2015-10-29 23:57:43 +00:00
|
|
|
ui.dateEdit->setDisplayFormat(prefs.date_format);
|
2018-05-04 03:58:47 +00:00
|
|
|
ui.timeEdit->setDisplayFormat(prefs.time_format);
|
2014-02-09 18:49:15 +00:00
|
|
|
|
2014-07-02 18:50:28 +00:00
|
|
|
memset(&displayed_dive, 0, sizeof(displayed_dive));
|
2014-02-09 18:49:15 +00:00
|
|
|
|
2013-12-03 20:44:48 +00:00
|
|
|
closeMessage();
|
2013-09-26 20:02:27 +00:00
|
|
|
|
2019-02-11 14:34:43 +00:00
|
|
|
connect(&diveListNotifier, &DiveListNotifier::divesChanged, this, &MainTab::divesChanged);
|
2019-02-24 20:22:33 +00:00
|
|
|
connect(&diveListNotifier, &DiveListNotifier::tripChanged, this, &MainTab::tripChanged);
|
2019-03-29 16:48:08 +00:00
|
|
|
connect(&diveListNotifier, &DiveListNotifier::diveSiteChanged, this, &MainTab::diveSiteEdited);
|
2019-05-24 19:38:56 +00:00
|
|
|
connect(&diveListNotifier, &DiveListNotifier::commandExecuted, this, &MainTab::closeWarning);
|
2019-02-24 20:22:33 +00:00
|
|
|
|
2019-03-16 10:51:42 +00:00
|
|
|
connect(ui.editDiveSiteButton, &QToolButton::clicked, MainWindow::instance(), &MainWindow::startDiveSiteEdit);
|
2017-07-15 20:37:02 +00:00
|
|
|
connect(ui.location, &DiveLocationLineEdit::entered, MapWidget::instance(), &MapWidget::centerOnIndex);
|
|
|
|
connect(ui.location, &DiveLocationLineEdit::currentChanged, MapWidget::instance(), &MapWidget::centerOnIndex);
|
2019-06-30 21:08:02 +00:00
|
|
|
connect(ui.location, &DiveLocationLineEdit::editingFinished, this, &MainTab::on_location_diveSiteSelected);
|
2015-02-11 15:32:29 +00:00
|
|
|
|
2014-11-23 15:41:25 +00:00
|
|
|
QAction *action = new QAction(tr("Apply changes"), this);
|
2013-12-02 17:33:00 +00:00
|
|
|
connect(action, SIGNAL(triggered(bool)), this, SLOT(acceptChanges()));
|
2019-05-24 18:50:25 +00:00
|
|
|
ui.diveNotesMessage->addAction(action);
|
2013-12-02 17:33:00 +00:00
|
|
|
|
2014-11-23 15:41:25 +00:00
|
|
|
action = new QAction(tr("Discard changes"), this);
|
2013-12-02 17:33:00 +00:00
|
|
|
connect(action, SIGNAL(triggered(bool)), this, SLOT(rejectChanges()));
|
2019-05-24 18:50:25 +00:00
|
|
|
ui.diveNotesMessage->addAction(action);
|
2014-06-03 22:29:28 +00:00
|
|
|
|
2019-05-24 19:11:20 +00:00
|
|
|
action = new QAction(tr("OK"), this);
|
|
|
|
connect(action, &QAction::triggered, this, &MainTab::closeWarning);
|
|
|
|
ui.multiDiveWarningMessage->addAction(action);
|
|
|
|
|
2019-05-24 19:50:17 +00:00
|
|
|
action = new QAction(tr("Undo"), this);
|
|
|
|
connect(action, &QAction::triggered, Command::undoAction(this), &QAction::trigger);
|
|
|
|
connect(action, &QAction::triggered, this, &MainTab::closeWarning);
|
|
|
|
ui.multiDiveWarningMessage->addAction(action);
|
|
|
|
|
2014-06-03 22:29:28 +00:00
|
|
|
QShortcut *closeKey = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
|
|
|
connect(closeKey, SIGNAL(activated()), this, SLOT(escDetected()));
|
|
|
|
|
2013-09-26 20:02:27 +00:00
|
|
|
if (qApp->style()->objectName() == "oxygen")
|
2013-09-26 19:51:11 +00:00
|
|
|
setDocumentMode(true);
|
2013-09-26 20:02:27 +00:00
|
|
|
else
|
|
|
|
setDocumentMode(false);
|
|
|
|
|
2013-05-20 00:38:20 +00:00
|
|
|
// we start out with the fields read-only; once things are
|
|
|
|
// filled from a dive, they are made writeable
|
2013-09-19 00:56:53 +00:00
|
|
|
setEnabled(false);
|
2013-05-19 14:45:01 +00:00
|
|
|
|
2019-04-13 16:14:50 +00:00
|
|
|
Completers completers;
|
2014-02-11 17:46:14 +00:00
|
|
|
completers.buddy = new QCompleter(&buddyModel, ui.buddy);
|
|
|
|
completers.divemaster = new QCompleter(&diveMasterModel, ui.divemaster);
|
|
|
|
completers.tags = new QCompleter(&tagModel, ui.tagWidget);
|
2014-01-06 22:00:10 +00:00
|
|
|
completers.buddy->setCaseSensitivity(Qt::CaseInsensitive);
|
|
|
|
completers.divemaster->setCaseSensitivity(Qt::CaseInsensitive);
|
2013-11-15 00:39:02 +00:00
|
|
|
completers.tags->setCaseSensitivity(Qt::CaseInsensitive);
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.buddy->setCompleter(completers.buddy);
|
|
|
|
ui.divemaster->setCompleter(completers.divemaster);
|
2013-11-02 01:20:02 +00:00
|
|
|
ui.tagWidget->setCompleter(completers.tags);
|
2015-06-04 01:08:57 +00:00
|
|
|
ui.diveNotesMessage->hide();
|
2019-05-24 19:11:20 +00:00
|
|
|
ui.multiDiveWarningMessage->hide();
|
2017-02-04 21:12:50 +00:00
|
|
|
ui.depth->hide();
|
|
|
|
ui.depthLabel->hide();
|
|
|
|
ui.duration->hide();
|
|
|
|
ui.durationLabel->hide();
|
2013-09-26 21:14:09 +00:00
|
|
|
setMinimumHeight(0);
|
|
|
|
setMinimumWidth(0);
|
2013-09-27 15:52:01 +00:00
|
|
|
|
|
|
|
// Current display of things on Gnome3 looks like shit, so
|
2019-04-13 15:43:45 +00:00
|
|
|
// let's fix that.
|
2013-09-27 15:52:01 +00:00
|
|
|
if (isGnome3Session()) {
|
|
|
|
QPalette p;
|
|
|
|
p.setColor(QPalette::Window, QColor(Qt::white));
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.scrollArea->viewport()->setPalette(p);
|
2013-12-04 20:24:37 +00:00
|
|
|
|
|
|
|
// GroupBoxes in Gnome3 looks like I'v drawn them...
|
2019-04-01 21:15:23 +00:00
|
|
|
static const QString gnomeCss = QStringLiteral(
|
2013-12-04 20:24:37 +00:00
|
|
|
"QGroupBox {"
|
2019-04-01 21:15:23 +00:00
|
|
|
"background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
|
|
|
|
"stop: 0 #E0E0E0, stop: 1 #FFFFFF);"
|
|
|
|
"border: 2px solid gray;"
|
|
|
|
"border-radius: 5px;"
|
|
|
|
"margin-top: 1ex;"
|
2013-12-04 20:24:37 +00:00
|
|
|
"}"
|
|
|
|
"QGroupBox::title {"
|
2019-04-01 21:15:23 +00:00
|
|
|
"subcontrol-origin: margin;"
|
|
|
|
"subcontrol-position: top center;"
|
|
|
|
"padding: 0 3px;"
|
|
|
|
"background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
|
|
|
|
"stop: 0 #E0E0E0, stop: 1 #FFFFFF);"
|
2013-12-04 20:24:37 +00:00
|
|
|
"}");
|
2014-05-22 18:40:22 +00:00
|
|
|
Q_FOREACH (QGroupBox *box, findChildren<QGroupBox *>()) {
|
2013-12-04 20:24:37 +00:00
|
|
|
box->setStyleSheet(gnomeCss);
|
|
|
|
}
|
2013-09-27 15:52:01 +00:00
|
|
|
}
|
2014-12-23 18:16:11 +00:00
|
|
|
// QLineEdit and QLabels should have minimal margin on the left and right but not waste vertical space
|
2015-01-02 20:42:02 +00:00
|
|
|
QMargins margins(3, 2, 1, 0);
|
2014-12-23 18:16:11 +00:00
|
|
|
Q_FOREACH (QLabel *label, findChildren<QLabel *>()) {
|
|
|
|
label->setContentsMargins(margins);
|
|
|
|
}
|
2014-08-06 21:05:54 +00:00
|
|
|
|
2015-09-23 19:03:28 +00:00
|
|
|
connect(ui.diveNotesMessage, &KMessageWidget::showAnimationFinished,
|
|
|
|
ui.location, &DiveLocationLineEdit::fixPopupPosition);
|
2019-05-24 19:11:20 +00:00
|
|
|
connect(ui.multiDiveWarningMessage, &KMessageWidget::showAnimationFinished,
|
|
|
|
ui.location, &DiveLocationLineEdit::fixPopupPosition);
|
2015-09-23 19:03:28 +00:00
|
|
|
|
2015-11-16 04:56:24 +00:00
|
|
|
// enable URL clickability in notes:
|
|
|
|
new TextHyperlinkEventFilter(ui.notes);//destroyed when ui.notes is destroyed
|
|
|
|
|
2015-10-01 20:54:13 +00:00
|
|
|
ui.diveTripLocation->hide();
|
2013-11-28 11:17:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MainTab::~MainTab()
|
|
|
|
{
|
2013-06-27 12:33:43 +00:00
|
|
|
}
|
2013-05-22 12:17:18 +00:00
|
|
|
|
2013-12-03 20:44:48 +00:00
|
|
|
void MainTab::hideMessage()
|
|
|
|
{
|
|
|
|
ui.diveNotesMessage->animatedHide();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainTab::closeMessage()
|
|
|
|
{
|
|
|
|
hideMessage();
|
|
|
|
ui.diveNotesMessage->setCloseButtonVisible(false);
|
2019-01-27 21:08:13 +00:00
|
|
|
}
|
2013-12-03 20:44:48 +00:00
|
|
|
|
2019-05-24 19:11:20 +00:00
|
|
|
void MainTab::closeWarning()
|
|
|
|
{
|
2019-05-24 19:38:56 +00:00
|
|
|
ui.multiDiveWarningMessage->hide();
|
2019-05-24 19:11:20 +00:00
|
|
|
}
|
|
|
|
|
2013-12-03 20:44:48 +00:00
|
|
|
void MainTab::displayMessage(QString str)
|
|
|
|
{
|
2014-08-05 05:45:17 +00:00
|
|
|
ui.diveNotesMessage->setCloseButtonVisible(false);
|
2013-12-03 20:44:48 +00:00
|
|
|
ui.diveNotesMessage->setText(str);
|
|
|
|
ui.diveNotesMessage->animatedShow();
|
|
|
|
}
|
|
|
|
|
2013-11-01 15:48:34 +00:00
|
|
|
void MainTab::enableEdition(EditMode newEditMode)
|
2013-08-13 11:34:04 +00:00
|
|
|
{
|
2014-07-03 21:45:01 +00:00
|
|
|
if (((newEditMode == DIVE || newEditMode == NONE) && current_dive == NULL) || editMode != NONE)
|
2013-08-13 11:34:04 +00:00
|
|
|
return;
|
2013-12-27 16:18:53 +00:00
|
|
|
if ((newEditMode == DIVE || newEditMode == NONE) &&
|
2014-01-03 12:49:17 +00:00
|
|
|
current_dive->dc.model &&
|
2013-12-27 16:18:53 +00:00
|
|
|
strcmp(current_dive->dc.model, "manually added dive") == 0) {
|
|
|
|
// editCurrentDive will call enableEdition with newEditMode == MANUALLY_ADDED_DIVE
|
|
|
|
// so exit this function here after editCurrentDive() returns
|
2014-07-03 21:45:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// FIXME : can we get rid of this recursive crap?
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-02-12 14:22:54 +00:00
|
|
|
MainWindow::instance()->editCurrentDive();
|
2013-12-27 16:18:53 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-09-23 20:11:43 +00:00
|
|
|
|
|
|
|
ui.editDiveSiteButton->setEnabled(false);
|
2018-10-12 14:13:42 +00:00
|
|
|
MainWindow::instance()->diveList->setEnabled(false);
|
2014-08-04 15:58:21 +00:00
|
|
|
MainWindow::instance()->setEnabledToolbar(false);
|
2018-05-03 17:19:54 +00:00
|
|
|
MainWindow::instance()->enterEditState();
|
2018-09-13 15:33:07 +00:00
|
|
|
ui.tabWidget->setTabEnabled(2, false);
|
|
|
|
ui.tabWidget->setTabEnabled(3, false);
|
|
|
|
ui.tabWidget->setTabEnabled(5, false);
|
2014-07-03 21:45:01 +00:00
|
|
|
|
2019-02-24 20:22:33 +00:00
|
|
|
ui.dateEdit->setEnabled(true);
|
|
|
|
if (amount_selected > 1) {
|
|
|
|
displayMessage(tr("Multiple dives are being edited."));
|
2013-09-19 00:56:53 +00:00
|
|
|
} else {
|
2019-02-24 20:22:33 +00:00
|
|
|
displayMessage(tr("This dive is being edited."));
|
2013-09-19 00:56:53 +00:00
|
|
|
}
|
2019-02-24 20:22:33 +00:00
|
|
|
editMode = newEditMode != NONE ? newEditMode : DIVE;
|
2013-08-13 11:34:04 +00:00
|
|
|
}
|
|
|
|
|
2019-01-27 21:08:13 +00:00
|
|
|
// This function gets called if a field gets updated by an undo command.
|
|
|
|
// Refresh the corresponding UI field.
|
2019-06-23 07:22:26 +00:00
|
|
|
void MainTab::divesChanged(const QVector<dive *> &dives, DiveField field)
|
2019-01-27 21:08:13 +00:00
|
|
|
{
|
2019-02-11 14:34:43 +00:00
|
|
|
// If the current dive is not in list of changed dives, do nothing
|
|
|
|
if (!current_dive || !dives.contains(current_dive))
|
2019-01-27 21:08:13 +00:00
|
|
|
return;
|
|
|
|
|
2019-10-13 10:44:39 +00:00
|
|
|
if (field.duration)
|
2019-02-10 16:37:06 +00:00
|
|
|
ui.duration->setText(render_seconds_to_string(current_dive->duration.seconds));
|
2019-10-13 10:44:39 +00:00
|
|
|
if (field.depth)
|
2019-02-10 16:37:06 +00:00
|
|
|
ui.depth->setText(get_depth_string(current_dive->maxdepth, true));
|
2019-10-13 10:44:39 +00:00
|
|
|
if (field.rating)
|
2019-01-28 21:35:07 +00:00
|
|
|
ui.rating->setCurrentStars(current_dive->rating);
|
2019-10-13 10:44:39 +00:00
|
|
|
if (field.notes)
|
2019-01-27 21:08:13 +00:00
|
|
|
updateNotes(current_dive);
|
2019-10-13 10:44:39 +00:00
|
|
|
if (field.datetime) {
|
2019-03-19 21:05:52 +00:00
|
|
|
updateDateTime(current_dive);
|
|
|
|
MainWindow::instance()->graphics->dateTimeChanged();
|
|
|
|
DivePlannerPointsModel::instance()->getDiveplan().when = current_dive->when;
|
2019-10-13 10:44:39 +00:00
|
|
|
}
|
|
|
|
if (field.divesite)
|
2019-03-20 20:46:58 +00:00
|
|
|
updateDiveSite(current_dive);
|
2019-10-13 10:44:39 +00:00
|
|
|
if (field.tags)
|
2019-02-07 18:59:34 +00:00
|
|
|
ui.tagWidget->setText(get_taglist_string(current_dive->tag_list));
|
2019-10-13 10:44:39 +00:00
|
|
|
if (field.buddy)
|
2019-02-07 20:00:09 +00:00
|
|
|
ui.buddy->setText(current_dive->buddy);
|
2019-10-13 10:44:39 +00:00
|
|
|
if (field.divemaster)
|
2019-02-07 20:23:00 +00:00
|
|
|
ui.divemaster->setText(current_dive->divemaster);
|
2019-10-13 10:44:39 +00:00
|
|
|
|
|
|
|
// If duration or depth changed, the profile needs to be replotted
|
|
|
|
if (field.duration || field.depth)
|
2019-10-14 18:21:15 +00:00
|
|
|
MainWindow::instance()->graphics->plotDive(current_dive, true);
|
2019-01-27 21:08:13 +00:00
|
|
|
}
|
|
|
|
|
2019-03-29 16:48:08 +00:00
|
|
|
void MainTab::diveSiteEdited(dive_site *ds, int)
|
|
|
|
{
|
|
|
|
if (current_dive && current_dive->dive_site == ds)
|
|
|
|
updateDiveSite(current_dive);
|
|
|
|
}
|
|
|
|
|
2019-02-24 20:22:33 +00:00
|
|
|
// This function gets called if a trip-field gets updated by an undo command.
|
|
|
|
// Refresh the corresponding UI field.
|
|
|
|
void MainTab::tripChanged(dive_trip *trip, TripField field)
|
|
|
|
{
|
|
|
|
// If the current dive is not in list of changed dives, do nothing
|
|
|
|
if (currentTrip != trip)
|
|
|
|
return;
|
|
|
|
|
2019-10-13 10:44:39 +00:00
|
|
|
if (field.notes)
|
2019-02-24 20:22:33 +00:00
|
|
|
ui.notes->setText(currentTrip->notes);
|
2019-10-13 10:44:39 +00:00
|
|
|
if (field.location)
|
2019-02-24 20:22:33 +00:00
|
|
|
ui.diveTripLocation->setText(currentTrip->location);
|
|
|
|
}
|
|
|
|
|
2014-05-16 06:12:46 +00:00
|
|
|
void MainTab::nextInputField(QKeyEvent *event)
|
|
|
|
{
|
|
|
|
keyPressEvent(event);
|
|
|
|
}
|
|
|
|
|
2013-11-10 21:23:18 +00:00
|
|
|
bool MainTab::isEditing()
|
|
|
|
{
|
|
|
|
return editMode != NONE;
|
|
|
|
}
|
|
|
|
|
2019-08-29 21:16:38 +00:00
|
|
|
static bool isHtml(const QString &s)
|
|
|
|
{
|
|
|
|
return s.contains("<div", Qt::CaseInsensitive) || s.contains("<table", Qt::CaseInsensitive);
|
|
|
|
}
|
|
|
|
|
2019-01-27 21:08:13 +00:00
|
|
|
void MainTab::updateNotes(const struct dive *d)
|
|
|
|
{
|
|
|
|
QString tmp(d->notes);
|
2019-08-29 21:16:38 +00:00
|
|
|
if (isHtml(tmp)) {
|
2019-01-27 21:08:13 +00:00
|
|
|
ui.notes->setHtml(tmp);
|
|
|
|
} else {
|
|
|
|
ui.notes->setPlainText(tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 19:53:50 +00:00
|
|
|
static QDateTime timestampToDateTime(timestamp_t when)
|
2019-03-19 21:05:52 +00:00
|
|
|
{
|
|
|
|
// Subsurface always uses "local time" as in "whatever was the local time at the location"
|
|
|
|
// so all time stamps have no time zone information and are in UTC
|
2019-08-07 19:53:50 +00:00
|
|
|
QDateTime localTime = QDateTime::fromMSecsSinceEpoch(1000 * when, Qt::UTC);
|
2019-03-19 21:05:52 +00:00
|
|
|
localTime.setTimeSpec(Qt::UTC);
|
2019-08-07 19:53:50 +00:00
|
|
|
return localTime;
|
|
|
|
}
|
|
|
|
void MainTab::updateDateTime(const struct dive *d)
|
|
|
|
{
|
|
|
|
QDateTime localTime = timestampToDateTime(d->when);
|
2019-03-19 21:05:52 +00:00
|
|
|
ui.dateEdit->setDate(localTime.date());
|
|
|
|
ui.timeEdit->setTime(localTime.time());
|
|
|
|
}
|
|
|
|
|
2019-08-07 19:53:50 +00:00
|
|
|
void MainTab::updateTripDate(const struct dive_trip *t)
|
|
|
|
{
|
|
|
|
QDateTime localTime = timestampToDateTime(trip_date(t));
|
|
|
|
ui.dateEdit->setDate(localTime.date());
|
|
|
|
}
|
|
|
|
|
2019-03-20 20:46:58 +00:00
|
|
|
void MainTab::updateDiveSite(struct dive *d)
|
|
|
|
{
|
|
|
|
struct dive_site *ds = d->dive_site;
|
2019-04-24 22:26:48 +00:00
|
|
|
ui.location->setCurrentDiveSite(d);
|
2019-03-20 20:46:58 +00:00
|
|
|
if (ds) {
|
|
|
|
ui.locationTags->setText(constructLocationTags(&ds->taxonomy, true));
|
|
|
|
|
|
|
|
if (ui.locationTags->text().isEmpty() && has_location(&ds->location))
|
|
|
|
ui.locationTags->setText(printGPSCoords(&ds->location));
|
|
|
|
ui.editDiveSiteButton->setEnabled(true);
|
|
|
|
} else {
|
|
|
|
ui.locationTags->clear();
|
|
|
|
ui.editDiveSiteButton->setEnabled(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-29 17:29:08 +00:00
|
|
|
void MainTab::updateDiveInfo()
|
2013-05-06 16:23:14 +00:00
|
|
|
{
|
2015-09-21 17:01:58 +00:00
|
|
|
ui.location->refreshDiveSiteCache();
|
2015-07-16 17:42:56 +00:00
|
|
|
EditMode rememberEM = editMode;
|
2014-05-26 22:17:34 +00:00
|
|
|
// don't execute this while adding / planning a dive
|
2019-03-28 16:23:35 +00:00
|
|
|
if (editMode == MANUALLY_ADDED_DIVE || MainWindow::instance()->graphics->isPlanner())
|
2013-11-12 07:33:27 +00:00
|
|
|
return;
|
2019-04-12 18:33:43 +00:00
|
|
|
|
|
|
|
// If there is no current dive, disable all widgets except the last, which is the dive site tab.
|
|
|
|
// TODO: Conceptually, the dive site tab shouldn't even be a tab here!
|
|
|
|
bool enabled = current_dive != nullptr;
|
|
|
|
ui.notesTab->setEnabled(enabled);
|
|
|
|
for (int i = 0; i < extraWidgets.size() - 1; ++i)
|
|
|
|
extraWidgets[i]->setEnabled(enabled);
|
|
|
|
|
2019-08-28 09:21:24 +00:00
|
|
|
editMode = IGNORE_MODE; // don't trigger on changes to the widgets
|
2014-07-03 05:15:08 +00:00
|
|
|
|
2019-04-13 15:43:45 +00:00
|
|
|
for (TabBase *widget: extraWidgets)
|
2017-04-04 17:21:30 +00:00
|
|
|
widget->updateData();
|
2014-07-21 23:34:15 +00:00
|
|
|
|
2019-03-29 17:29:08 +00:00
|
|
|
if (current_dive) {
|
2019-05-04 12:23:46 +00:00
|
|
|
// If we're on the dive-site tab, we don't want to switch tab when entering / exiting
|
|
|
|
// trip mode. The reason is that
|
|
|
|
// 1) this disrupts the user-experience and
|
|
|
|
// 2) the filter is reset, potentially erasing the current trip under our feet.
|
|
|
|
// TODO: Don't hard code tab location!
|
|
|
|
bool onDiveSiteTab = ui.tabWidget->currentIndex() == 6;
|
2018-10-12 14:13:42 +00:00
|
|
|
if (MainWindow::instance() && MainWindow::instance()->diveList->selectedTrips().count() == 1) {
|
2019-05-04 12:23:46 +00:00
|
|
|
currentTrip = MainWindow::instance()->diveList->selectedTrips().front();
|
|
|
|
// Remember the tab selected for last dive but only if we're not on the dive site tab
|
|
|
|
if (lastSelectedDive && !onDiveSiteTab)
|
2017-11-30 19:33:43 +00:00
|
|
|
lastTabSelectedDive = ui.tabWidget->currentIndex();
|
2017-11-30 18:36:05 +00:00
|
|
|
ui.tabWidget->setTabText(0, tr("Trip notes"));
|
2017-11-30 19:33:43 +00:00
|
|
|
ui.tabWidget->setTabEnabled(1, false);
|
|
|
|
ui.tabWidget->setTabEnabled(2, false);
|
|
|
|
ui.tabWidget->setTabEnabled(5, false);
|
2019-05-04 12:23:46 +00:00
|
|
|
// Recover the tab selected for last dive trip but only if we're not on the dive site tab
|
|
|
|
if (lastSelectedDive && !onDiveSiteTab)
|
2017-11-30 19:33:43 +00:00
|
|
|
ui.tabWidget->setCurrentIndex(lastTabSelectedDiveTrip);
|
|
|
|
lastSelectedDive = false;
|
2013-06-14 16:17:46 +00:00
|
|
|
// only use trip relevant fields
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.divemaster->setVisible(false);
|
|
|
|
ui.DivemasterLabel->setVisible(false);
|
|
|
|
ui.buddy->setVisible(false);
|
|
|
|
ui.BuddyLabel->setVisible(false);
|
|
|
|
ui.rating->setVisible(false);
|
|
|
|
ui.RatingLabel->setVisible(false);
|
2013-11-04 19:28:03 +00:00
|
|
|
ui.tagWidget->setVisible(false);
|
|
|
|
ui.TagLabel->setVisible(false);
|
2016-01-17 10:53:50 +00:00
|
|
|
ui.dateEdit->setReadOnly(true);
|
2017-11-16 06:35:57 +00:00
|
|
|
ui.timeLabel->setVisible(false);
|
2016-01-17 10:53:51 +00:00
|
|
|
ui.timeEdit->setVisible(false);
|
2015-10-01 20:41:38 +00:00
|
|
|
ui.diveTripLocation->show();
|
|
|
|
ui.location->hide();
|
2019-06-03 20:44:37 +00:00
|
|
|
ui.locationPopupButton->hide();
|
2015-10-01 20:41:38 +00:00
|
|
|
ui.editDiveSiteButton->hide();
|
2013-06-14 16:17:46 +00:00
|
|
|
// rename the remaining fields and fill data from selected trip
|
2014-07-10 23:06:42 +00:00
|
|
|
ui.LocationLabel->setText(tr("Trip location"));
|
2015-10-01 21:11:03 +00:00
|
|
|
ui.diveTripLocation->setText(currentTrip->location);
|
2019-08-07 19:53:50 +00:00
|
|
|
updateTripDate(currentTrip);
|
2015-07-01 23:38:22 +00:00
|
|
|
ui.locationTags->clear();
|
2015-09-25 17:51:10 +00:00
|
|
|
//TODO: Fix this.
|
|
|
|
//ui.location->setText(currentTrip->location);
|
2014-07-10 23:06:42 +00:00
|
|
|
ui.NotesLabel->setText(tr("Trip notes"));
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.notes->setText(currentTrip->notes);
|
2017-02-04 21:44:10 +00:00
|
|
|
ui.depth->setVisible(false);
|
|
|
|
ui.depthLabel->setVisible(false);
|
|
|
|
ui.duration->setVisible(false);
|
|
|
|
ui.durationLabel->setVisible(false);
|
2013-06-14 16:17:46 +00:00
|
|
|
} else {
|
2019-05-04 12:23:46 +00:00
|
|
|
// Remember the tab selected for last dive trip but only if we're not on the dive site tab
|
|
|
|
if (!lastSelectedDive && !onDiveSiteTab)
|
2017-11-30 19:33:43 +00:00
|
|
|
lastTabSelectedDiveTrip = ui.tabWidget->currentIndex();
|
2017-11-30 18:36:05 +00:00
|
|
|
ui.tabWidget->setTabText(0, tr("Notes"));
|
2017-11-30 19:33:43 +00:00
|
|
|
ui.tabWidget->setTabEnabled(1, true);
|
|
|
|
ui.tabWidget->setTabEnabled(2, true);
|
2018-09-13 15:33:07 +00:00
|
|
|
ui.tabWidget->setTabEnabled(3, true);
|
|
|
|
ui.tabWidget->setTabEnabled(4, true);
|
2017-11-30 19:33:43 +00:00
|
|
|
ui.tabWidget->setTabEnabled(5, true);
|
2019-05-04 12:23:46 +00:00
|
|
|
// Recover the tab selected for last dive but only if we're not on the dive site tab
|
|
|
|
if (!lastSelectedDive && !onDiveSiteTab)
|
2017-11-30 19:33:43 +00:00
|
|
|
ui.tabWidget->setCurrentIndex(lastTabSelectedDive);
|
|
|
|
lastSelectedDive = true;
|
2014-07-30 15:52:11 +00:00
|
|
|
currentTrip = NULL;
|
2013-06-14 16:17:46 +00:00
|
|
|
// make all the fields visible writeable
|
2015-10-01 20:41:38 +00:00
|
|
|
ui.diveTripLocation->hide();
|
|
|
|
ui.location->show();
|
2019-06-03 20:44:37 +00:00
|
|
|
ui.locationPopupButton->show();
|
2015-10-01 20:41:38 +00:00
|
|
|
ui.editDiveSiteButton->show();
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.divemaster->setVisible(true);
|
|
|
|
ui.buddy->setVisible(true);
|
|
|
|
ui.rating->setVisible(true);
|
|
|
|
ui.RatingLabel->setVisible(true);
|
|
|
|
ui.BuddyLabel->setVisible(true);
|
|
|
|
ui.DivemasterLabel->setVisible(true);
|
2013-11-04 19:28:03 +00:00
|
|
|
ui.TagLabel->setVisible(true);
|
|
|
|
ui.tagWidget->setVisible(true);
|
2016-01-17 10:53:50 +00:00
|
|
|
ui.dateEdit->setReadOnly(false);
|
2017-11-16 06:35:57 +00:00
|
|
|
ui.timeLabel->setVisible(true);
|
2016-01-17 10:53:51 +00:00
|
|
|
ui.timeEdit->setVisible(true);
|
2013-06-14 16:17:46 +00:00
|
|
|
/* and fill them from the dive */
|
2019-03-29 17:29:08 +00:00
|
|
|
ui.rating->setCurrentStars(current_dive->rating);
|
2013-06-14 16:17:46 +00:00
|
|
|
// reset labels in case we last displayed trip notes
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.LocationLabel->setText(tr("Location"));
|
|
|
|
ui.NotesLabel->setText(tr("Notes"));
|
2019-03-29 17:29:08 +00:00
|
|
|
ui.tagWidget->setText(get_taglist_string(current_dive->tag_list));
|
|
|
|
bool isManual = same_string(current_dive->dc.model, "manually added dive");
|
|
|
|
ui.depth->setVisible(isManual);
|
|
|
|
ui.depthLabel->setVisible(isManual);
|
|
|
|
ui.duration->setVisible(isManual);
|
|
|
|
ui.durationLabel->setVisible(isManual);
|
2019-04-26 07:39:33 +00:00
|
|
|
|
|
|
|
updateNotes(current_dive);
|
|
|
|
updateDiveSite(current_dive);
|
|
|
|
updateDateTime(current_dive);
|
|
|
|
ui.divemaster->setText(current_dive->divemaster);
|
|
|
|
ui.buddy->setText(current_dive->buddy);
|
2013-06-14 16:17:46 +00:00
|
|
|
}
|
2019-03-29 17:29:08 +00:00
|
|
|
ui.duration->setText(render_seconds_to_string(current_dive->duration.seconds));
|
|
|
|
ui.depth->setText(get_depth_string(current_dive->maxdepth, true));
|
2015-06-25 18:42:28 +00:00
|
|
|
|
|
|
|
if(ui.locationTags->text().isEmpty())
|
|
|
|
ui.locationTags->hide();
|
|
|
|
else
|
|
|
|
ui.locationTags->show();
|
2017-10-06 14:51:02 +00:00
|
|
|
ui.editDiveSiteButton->setEnabled(!ui.location->text().isEmpty());
|
2015-10-08 06:38:26 +00:00
|
|
|
/* unset the special value text for date and time, just in case someone dove at midnight */
|
2019-04-03 17:34:52 +00:00
|
|
|
ui.dateEdit->setSpecialValueText(QString());
|
|
|
|
ui.timeEdit->setSpecialValueText(QString());
|
2013-05-08 19:08:00 +00:00
|
|
|
} else {
|
2013-05-20 00:38:20 +00:00
|
|
|
/* clear the fields */
|
2017-04-04 17:21:30 +00:00
|
|
|
clearTabs();
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.rating->setCurrentStars(0);
|
2015-02-12 20:46:21 +00:00
|
|
|
ui.location->clear();
|
2019-04-26 07:39:33 +00:00
|
|
|
ui.divemaster->clear();
|
|
|
|
ui.buddy->clear();
|
2019-07-10 21:13:54 +00:00
|
|
|
ui.notes->clear();
|
2015-10-08 06:38:26 +00:00
|
|
|
/* set date and time to minimums which triggers showing the special value text */
|
|
|
|
ui.dateEdit->setSpecialValueText(QString("-"));
|
|
|
|
ui.dateEdit->setMinimumDate(QDate(1, 1, 1));
|
|
|
|
ui.dateEdit->setDate(QDate(1, 1, 1));
|
|
|
|
ui.timeEdit->setSpecialValueText(QString("-"));
|
|
|
|
ui.timeEdit->setMinimumTime(QTime(0, 0, 0, 0));
|
|
|
|
ui.timeEdit->setTime(QTime(0, 0, 0, 0));
|
2018-01-01 07:49:40 +00:00
|
|
|
ui.tagWidget->clear();
|
2013-05-08 19:08:00 +00:00
|
|
|
}
|
2015-07-16 17:42:56 +00:00
|
|
|
editMode = rememberEM;
|
2015-06-04 01:44:16 +00:00
|
|
|
|
2019-03-29 17:29:08 +00:00
|
|
|
if (verbose && current_dive && current_dive->dive_site)
|
|
|
|
qDebug() << "Set the current dive site:" << current_dive->dive_site->uuid;
|
2013-05-06 16:23:14 +00:00
|
|
|
}
|
|
|
|
|
2013-04-13 13:17:59 +00:00
|
|
|
void MainTab::reload()
|
|
|
|
{
|
2014-02-11 17:46:14 +00:00
|
|
|
buddyModel.updateModel();
|
|
|
|
diveMasterModel.updateModel();
|
|
|
|
tagModel.updateModel();
|
2015-07-01 22:31:35 +00:00
|
|
|
LocationInformationModel::instance()->update();
|
2013-04-07 22:20:43 +00:00
|
|
|
}
|
2013-05-18 23:42:59 +00:00
|
|
|
|
2015-08-29 23:00:22 +00:00
|
|
|
void MainTab::refreshDisplayedDiveSite()
|
|
|
|
{
|
2019-04-24 22:26:48 +00:00
|
|
|
ui.location->setCurrentDiveSite(current_dive);
|
2015-08-29 23:00:22 +00:00
|
|
|
}
|
|
|
|
|
2013-09-19 00:56:53 +00:00
|
|
|
void MainTab::acceptChanges()
|
2013-05-18 23:42:59 +00:00
|
|
|
{
|
2019-02-05 07:01:04 +00:00
|
|
|
if (ui.location->hasFocus())
|
2019-04-01 19:07:51 +00:00
|
|
|
stealFocus();
|
2015-07-13 18:38:46 +00:00
|
|
|
|
2019-02-10 17:06:38 +00:00
|
|
|
EditMode lastMode = editMode;
|
2019-08-28 09:21:24 +00:00
|
|
|
editMode = IGNORE_MODE;
|
2014-08-23 14:49:28 +00:00
|
|
|
ui.dateEdit->setEnabled(true);
|
2013-12-03 20:44:48 +00:00
|
|
|
hideMessage();
|
2019-03-03 16:10:09 +00:00
|
|
|
|
2019-04-13 15:43:45 +00:00
|
|
|
// TODO: This is a temporary hack until the equipment tab is included in the undo system:
|
|
|
|
// The equipment tab is hardcoded at the first place of the "extra widgets".
|
|
|
|
((TabDiveEquipment *)extraWidgets[0])->acceptChanges();
|
2013-09-25 17:57:41 +00:00
|
|
|
|
2019-02-10 17:06:38 +00:00
|
|
|
if (lastMode == MANUALLY_ADDED_DIVE) {
|
2014-02-12 14:22:54 +00:00
|
|
|
MainWindow::instance()->showProfile();
|
2013-11-09 00:09:46 +00:00
|
|
|
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::NOTHING);
|
2019-11-30 14:51:34 +00:00
|
|
|
Command::editProfile(&displayed_dive);
|
2013-09-19 04:33:39 +00:00
|
|
|
}
|
2018-10-12 14:13:42 +00:00
|
|
|
int scrolledBy = MainWindow::instance()->diveList->verticalScrollBar()->sliderPosition();
|
2019-02-10 17:06:38 +00:00
|
|
|
if (lastMode == MANUALLY_ADDED_DIVE) {
|
2018-11-04 16:54:38 +00:00
|
|
|
MainWindow::instance()->diveList->reload();
|
2014-02-12 14:22:54 +00:00
|
|
|
MainWindow::instance()->refreshDisplay();
|
2018-10-12 13:07:40 +00:00
|
|
|
MainWindow::instance()->graphics->replot();
|
2013-12-10 05:17:15 +00:00
|
|
|
} else {
|
2014-08-07 17:23:08 +00:00
|
|
|
MainWindow::instance()->refreshDisplay();
|
2013-12-03 22:34:05 +00:00
|
|
|
}
|
2014-02-19 17:43:34 +00:00
|
|
|
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::NOTHING);
|
2018-10-12 14:13:42 +00:00
|
|
|
MainWindow::instance()->diveList->verticalScrollBar()->setSliderPosition(scrolledBy);
|
|
|
|
MainWindow::instance()->diveList->setFocus();
|
2018-05-03 17:19:54 +00:00
|
|
|
MainWindow::instance()->exitEditState();
|
2014-08-04 15:58:21 +00:00
|
|
|
MainWindow::instance()->setEnabledToolbar(true);
|
2017-10-06 14:51:02 +00:00
|
|
|
ui.editDiveSiteButton->setEnabled(!ui.location->text().isEmpty());
|
2019-02-10 17:06:38 +00:00
|
|
|
editMode = NONE;
|
2013-09-25 17:36:59 +00:00
|
|
|
}
|
|
|
|
|
2019-06-26 15:21:03 +00:00
|
|
|
bool weightsystems_equal(const dive *d1, const dive *d2)
|
|
|
|
{
|
|
|
|
if (d1->weightsystems.nr != d2->weightsystems.nr)
|
|
|
|
return false;
|
|
|
|
for (int i = 0; i < d1->weightsystems.nr; ++i) {
|
2019-07-27 14:44:24 +00:00
|
|
|
if (!same_weightsystem(d1->weightsystems.weightsystems[i], d2->weightsystems.weightsystems[i]))
|
2019-06-26 15:21:03 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
bool cylinders_equal(const dive *d1, const dive *d2)
|
|
|
|
{
|
|
|
|
if (d1->cylinders.nr != d2->cylinders.nr)
|
|
|
|
return false;
|
|
|
|
for (int i = 0; i < d1->cylinders.nr; ++i) {
|
2019-08-04 20:13:49 +00:00
|
|
|
if (!same_cylinder(*get_cylinder(d1, i), *get_cylinder(d2, i)))
|
2019-08-04 16:44:57 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-19 00:56:53 +00:00
|
|
|
void MainTab::rejectChanges()
|
2013-05-18 23:42:59 +00:00
|
|
|
{
|
2013-11-12 05:41:29 +00:00
|
|
|
EditMode lastMode = editMode;
|
2014-07-03 04:33:03 +00:00
|
|
|
|
2020-02-26 21:53:36 +00:00
|
|
|
if (lastMode != NONE && current_dive && !cylinders_equal(current_dive, &displayed_dive)) {
|
2014-07-11 08:21:38 +00:00
|
|
|
if (QMessageBox::warning(MainWindow::instance(), TITLE_OR_TEXT(tr("Discard the changes?"),
|
2014-06-04 01:01:00 +00:00
|
|
|
tr("You are about to discard your changes.")),
|
|
|
|
QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Discard) != QMessageBox::Discard) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-08-23 14:49:28 +00:00
|
|
|
ui.dateEdit->setEnabled(true);
|
2014-05-28 03:31:18 +00:00
|
|
|
editMode = NONE;
|
2013-12-03 20:44:48 +00:00
|
|
|
hideMessage();
|
2019-03-28 16:23:35 +00:00
|
|
|
// no harm done to call cancelPlan even if we were not PLAN mode...
|
2014-07-06 19:36:25 +00:00
|
|
|
DivePlannerPointsModel::instance()->cancelPlan();
|
|
|
|
|
|
|
|
// now make sure that the correct dive is displayed
|
Undo: select dives after add, remove, merge, split dive commands
Select the proper dives after the add, remove, split and merge
dives commands on undo *and* redo. Generally, select the added
dives. For undo of add, remember the pre-addition selection.
For redo of remove, select the closest dive to the first removed
dive.
The biggest part of the commit is the signal-interface between
the dive commands and the dive-list model and dive-list view.
This is done in two steps:
1) To the DiveTripModel in batches of trips. The dive trip model
transforms the dives into indices.
2) To the DiveListView. The DiveListView has to translate the
DiveTripModel indexes to actual indexes via its QSortFilterProxy-
model.
For code-reuse, derive all divelist-changing commands from a new base-class,
which has a flag that describes whether the divelist changed. The helper
functions which add and remove dives are made members of the base class and
set the flag is a selected dive is added or removed.
To properly detect when the current dive was deleted it
became necessary to turn the current dive from an index
to a pointer, because indices are not stable.
Unfortunately, in some cases an index was expected and these
places now have to transform the dive into an index. These
should be converted in due course.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-08-03 09:35:43 +00:00
|
|
|
if (current_dive)
|
2014-07-06 19:36:25 +00:00
|
|
|
copy_dive(current_dive, &displayed_dive);
|
|
|
|
else
|
|
|
|
clear_dive(&displayed_dive);
|
2019-03-29 17:29:08 +00:00
|
|
|
updateDiveInfo();
|
2017-04-04 17:21:30 +00:00
|
|
|
|
2019-04-13 15:43:45 +00:00
|
|
|
// TODO: This is a temporary hack until the equipment tab is included in the undo system:
|
|
|
|
// The equipment tab is hardcoded at the first place of the "extra widgets".
|
|
|
|
((TabDiveEquipment *)extraWidgets[0])->rejectChanges();
|
|
|
|
|
2014-05-02 04:26:18 +00:00
|
|
|
// the user could have edited the location and then canceled the edit
|
|
|
|
// let's get the correct location back in view
|
2019-03-29 17:29:08 +00:00
|
|
|
MapWidget::instance()->centerOnDiveSite(current_dive ? current_dive->dive_site : nullptr);
|
2014-07-06 19:36:25 +00:00
|
|
|
// show the profile and dive info
|
2018-10-12 13:07:40 +00:00
|
|
|
MainWindow::instance()->graphics->replot();
|
2014-08-04 15:58:21 +00:00
|
|
|
MainWindow::instance()->setEnabledToolbar(true);
|
2018-05-03 17:19:54 +00:00
|
|
|
MainWindow::instance()->exitEditState();
|
2017-10-06 14:51:02 +00:00
|
|
|
ui.editDiveSiteButton->setEnabled(!ui.location->text().isEmpty());
|
2013-05-18 23:42:59 +00:00
|
|
|
}
|
2013-08-16 18:52:40 +00:00
|
|
|
|
2019-05-24 19:11:20 +00:00
|
|
|
void MainTab::divesEdited(int i)
|
|
|
|
{
|
|
|
|
// No warning if only one dive was edited
|
|
|
|
if (i <= 1)
|
|
|
|
return;
|
|
|
|
ui.multiDiveWarningMessage->setCloseButtonVisible(false);
|
|
|
|
ui.multiDiveWarningMessage->setText(tr("Warning: edited %1 dives").arg(i));
|
2019-05-24 19:38:56 +00:00
|
|
|
ui.multiDiveWarningMessage->show();
|
2019-05-24 19:11:20 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 20:00:09 +00:00
|
|
|
void MainTab::on_buddy_editingFinished()
|
|
|
|
{
|
2019-08-28 09:21:24 +00:00
|
|
|
if (editMode == IGNORE_MODE || !current_dive)
|
2015-02-01 19:25:27 +00:00
|
|
|
return;
|
|
|
|
|
2019-05-24 19:11:20 +00:00
|
|
|
divesEdited(Command::editBuddies(stringToList(ui.buddy->toPlainText()), false));
|
2013-05-18 23:42:59 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 20:23:00 +00:00
|
|
|
void MainTab::on_divemaster_editingFinished()
|
2013-05-18 23:42:59 +00:00
|
|
|
{
|
2019-08-28 09:21:24 +00:00
|
|
|
if (editMode == IGNORE_MODE || !current_dive)
|
2015-02-01 19:25:27 +00:00
|
|
|
return;
|
|
|
|
|
2019-05-24 19:11:20 +00:00
|
|
|
divesEdited(Command::editDiveMaster(stringToList(ui.divemaster->toPlainText()), false));
|
2013-05-18 23:42:59 +00:00
|
|
|
}
|
|
|
|
|
2019-02-10 16:37:06 +00:00
|
|
|
void MainTab::on_duration_editingFinished()
|
2017-02-04 21:59:20 +00:00
|
|
|
{
|
2019-08-28 09:21:24 +00:00
|
|
|
if (editMode == IGNORE_MODE || !current_dive)
|
2017-02-04 21:59:20 +00:00
|
|
|
return;
|
2017-02-26 05:00:09 +00:00
|
|
|
|
2019-02-10 16:37:06 +00:00
|
|
|
// Duration editing is special: we only edit the current dive.
|
2019-05-24 19:11:20 +00:00
|
|
|
divesEdited(Command::editDuration(parseDurationToSeconds(ui.duration->text()), true));
|
2017-02-04 21:59:20 +00:00
|
|
|
}
|
|
|
|
|
2019-02-10 16:37:06 +00:00
|
|
|
void MainTab::on_depth_editingFinished()
|
2017-02-04 21:59:20 +00:00
|
|
|
{
|
2019-08-28 09:21:24 +00:00
|
|
|
if (editMode == IGNORE_MODE || !current_dive)
|
2017-02-04 21:59:20 +00:00
|
|
|
return;
|
2019-02-10 16:37:06 +00:00
|
|
|
|
|
|
|
// Depth editing is special: we only edit the current dive.
|
2019-05-24 19:11:20 +00:00
|
|
|
divesEdited(Command::editDepth(parseLengthToMm(ui.depth->text()), true));
|
2017-02-04 21:59:20 +00:00
|
|
|
}
|
|
|
|
|
2019-03-19 21:05:52 +00:00
|
|
|
// Editing of the dive time is different. If multiple dives are edited,
|
|
|
|
// all dives are shifted by an offset.
|
|
|
|
static void shiftTime(QDateTime &dateTime)
|
|
|
|
{
|
|
|
|
timestamp_t when = dateTime.toTime_t();
|
|
|
|
if (current_dive && current_dive->when != when) {
|
2019-06-24 04:04:50 +00:00
|
|
|
timestamp_t offset = when - current_dive->when;
|
2020-01-03 15:04:54 +00:00
|
|
|
Command::shiftTime(getDiveSelection(), (int)offset);
|
2019-03-19 21:05:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-26 17:57:25 +00:00
|
|
|
void MainTab::on_dateEdit_dateChanged(const QDate &date)
|
2013-09-20 23:41:42 +00:00
|
|
|
{
|
2019-08-28 09:21:24 +00:00
|
|
|
if (editMode == IGNORE_MODE || !current_dive)
|
2014-06-03 01:13:50 +00:00
|
|
|
return;
|
2019-03-19 21:05:52 +00:00
|
|
|
QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(1000*current_dive->when, Qt::UTC);
|
2014-06-26 17:57:25 +00:00
|
|
|
dateTime.setTimeSpec(Qt::UTC);
|
|
|
|
dateTime.setDate(date);
|
2019-03-19 21:05:52 +00:00
|
|
|
shiftTime(dateTime);
|
2013-09-20 23:41:42 +00:00
|
|
|
}
|
|
|
|
|
2014-06-26 17:54:16 +00:00
|
|
|
void MainTab::on_timeEdit_timeChanged(const QTime &time)
|
|
|
|
{
|
2019-08-28 09:21:24 +00:00
|
|
|
if (editMode == IGNORE_MODE || !current_dive)
|
2014-06-26 17:54:16 +00:00
|
|
|
return;
|
2019-03-19 21:05:52 +00:00
|
|
|
QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(1000*current_dive->when, Qt::UTC);
|
2014-06-26 17:57:25 +00:00
|
|
|
dateTime.setTimeSpec(Qt::UTC);
|
2014-06-26 17:54:16 +00:00
|
|
|
dateTime.setTime(time);
|
2019-03-19 21:05:52 +00:00
|
|
|
shiftTime(dateTime);
|
2014-06-26 17:54:16 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 18:59:34 +00:00
|
|
|
void MainTab::on_tagWidget_editingFinished()
|
2013-11-02 01:20:02 +00:00
|
|
|
{
|
2019-08-28 09:21:24 +00:00
|
|
|
if (editMode == IGNORE_MODE || !current_dive)
|
2015-02-01 19:25:27 +00:00
|
|
|
return;
|
|
|
|
|
2019-05-24 19:11:20 +00:00
|
|
|
divesEdited(Command::editTags(ui.tagWidget->getBlockStringList(), false));
|
2013-11-02 01:20:02 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 17:46:29 +00:00
|
|
|
void MainTab::on_location_diveSiteSelected()
|
2013-05-18 23:42:59 +00:00
|
|
|
{
|
2019-08-28 09:21:24 +00:00
|
|
|
if (editMode == IGNORE_MODE || !current_dive)
|
2014-05-07 21:51:39 +00:00
|
|
|
return;
|
2015-06-04 01:32:13 +00:00
|
|
|
|
2019-03-20 20:46:58 +00:00
|
|
|
struct dive_site *newDs = ui.location->currDiveSite();
|
|
|
|
if (newDs == RECENTLY_ADDED_DIVESITE)
|
2019-05-24 19:11:20 +00:00
|
|
|
divesEdited(Command::editDiveSiteNew(ui.location->text(), false));
|
2019-03-20 20:46:58 +00:00
|
|
|
else
|
2019-05-24 19:11:20 +00:00
|
|
|
divesEdited(Command::editDiveSite(newDs, false));
|
2015-10-01 20:52:00 +00:00
|
|
|
}
|
|
|
|
|
2019-04-25 11:16:30 +00:00
|
|
|
void MainTab::on_locationPopupButton_clicked()
|
|
|
|
{
|
|
|
|
ui.location->showAllSites();
|
|
|
|
}
|
|
|
|
|
2019-02-24 20:22:33 +00:00
|
|
|
void MainTab::on_diveTripLocation_editingFinished()
|
2015-10-01 20:52:00 +00:00
|
|
|
{
|
2019-02-24 20:22:33 +00:00
|
|
|
if (!currentTrip)
|
|
|
|
return;
|
|
|
|
Command::editTripLocation(currentTrip, ui.diveTripLocation->text());
|
2013-05-18 23:42:59 +00:00
|
|
|
}
|
|
|
|
|
2019-01-25 17:27:31 +00:00
|
|
|
void MainTab::on_notes_editingFinished()
|
|
|
|
{
|
2019-02-24 20:22:33 +00:00
|
|
|
if (!currentTrip && !current_dive)
|
|
|
|
return;
|
2019-01-25 17:27:31 +00:00
|
|
|
|
2019-08-29 21:16:38 +00:00
|
|
|
QString html = ui.notes->toHtml();
|
|
|
|
QString notes = isHtml(html) ? html : ui.notes->toPlainText();
|
2019-01-25 17:27:31 +00:00
|
|
|
|
2019-02-24 20:22:33 +00:00
|
|
|
if (currentTrip)
|
|
|
|
Command::editTripNotes(currentTrip, notes);
|
|
|
|
else
|
2019-05-24 19:11:20 +00:00
|
|
|
divesEdited(Command::editNotes(notes, false));
|
2013-05-18 23:42:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MainTab::on_rating_valueChanged(int value)
|
|
|
|
{
|
2019-08-28 09:21:24 +00:00
|
|
|
if (editMode == IGNORE_MODE || !current_dive)
|
2015-01-04 18:06:33 +00:00
|
|
|
return;
|
2019-01-28 21:35:07 +00:00
|
|
|
|
2019-05-24 19:11:20 +00:00
|
|
|
divesEdited(Command::editRating(value, false));
|
2013-05-18 23:42:59 +00:00
|
|
|
}
|
2013-05-20 13:25:16 +00:00
|
|
|
|
2019-04-01 19:07:51 +00:00
|
|
|
// Remove focus from any active field to update the corresponding value in the dive.
|
|
|
|
// Do this by setting the focus to ourself
|
|
|
|
void MainTab::stealFocus()
|
|
|
|
{
|
|
|
|
setFocus();
|
|
|
|
}
|
|
|
|
|
2014-06-03 22:29:28 +00:00
|
|
|
void MainTab::escDetected()
|
|
|
|
{
|
2019-02-05 07:01:04 +00:00
|
|
|
// In edit mode, pressing escape cancels the current changes.
|
|
|
|
// In standard mode, remove focus of any active widget to
|
2014-06-03 22:29:28 +00:00
|
|
|
if (editMode != NONE)
|
|
|
|
rejectChanges();
|
2019-02-05 07:01:04 +00:00
|
|
|
else
|
2019-04-01 19:07:51 +00:00
|
|
|
stealFocus();
|
2014-06-03 22:29:28 +00:00
|
|
|
}
|
2014-06-27 12:17:33 +00:00
|
|
|
|
2019-02-23 17:31:02 +00:00
|
|
|
void MainTab::clearTabs()
|
|
|
|
{
|
|
|
|
for (auto widget: extraWidgets)
|
2017-04-04 17:21:30 +00:00
|
|
|
widget->clear();
|
2015-10-20 20:36:59 +00:00
|
|
|
}
|