From 45ef87954669c765cb7b317384066c6eb88dc5d3 Mon Sep 17 00:00:00 2001
From: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Date: Sun, 27 Jan 2019 22:08:13 +0100
Subject: [PATCH] Undo: update notes field if changed by undo commands

To keep the UI in a consistent state, update the notes field if
it is changed by an undo command. To that purpose, add a new
signal to diveListNotifier with a list of dives and a field-id
as payload.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
---
 core/subsurface-qt/DiveListNotifier.h   | 24 ++++++++++++--
 desktop-widgets/command_edit.cpp        |  7 +++++
 desktop-widgets/command_edit.h          |  3 ++
 desktop-widgets/tab-widgets/maintab.cpp | 42 +++++++++++++++++++------
 desktop-widgets/tab-widgets/maintab.h   |  3 ++
 5 files changed, 67 insertions(+), 12 deletions(-)

diff --git a/core/subsurface-qt/DiveListNotifier.h b/core/subsurface-qt/DiveListNotifier.h
index 40343791f..5051bf73a 100644
--- a/core/subsurface-qt/DiveListNotifier.h
+++ b/core/subsurface-qt/DiveListNotifier.h
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 
-// The DiveListNotifier emits signals when the dive-list changes (dives/trips created/deleted/moved)
+// The DiveListNotifier emits signals when the dive-list changes (dives/trips created/deleted/moved/edited)
 // Note that vectors are passed by reference, so this will only work for signals inside the UI thread!
 
 #ifndef DIVELISTNOTIFIER_H
@@ -10,6 +10,23 @@
 
 #include <QObject>
 
+// Dive fields that can be edited.
+// Use "enum class" to not polute the global name space.
+enum class DiveField {
+	DATETIME,
+	AIR_TEMP,
+	WATER_TEMP,
+	LOCATION,
+	DIVEMASTER,
+	BUDDY,
+	RATING,
+	VISIBILITY,
+	SUIT,
+	TAGS,
+	MODE,
+	NOTES,
+};
+
 class DiveListNotifier : public QObject {
 	Q_OBJECT
 signals:
@@ -49,6 +66,9 @@ signals:
 	void diveSiteDeleted(dive_site *ds, int idx);
 	void diveSiteDiveCountChanged(dive_site *ds);
 	void diveSiteChanged(dive_site *ds, int field); // field according to LocationInformationModel
+
+	// Signals emitted when dives are edited.
+	void divesEdited(const QVector<dive *> &dives, DiveField);
 public:
 	// Desktop uses the QTreeView class to present the list of dives. The layout
 	// of this class gives us a very fundamental problem, as we can not easily
@@ -60,7 +80,7 @@ public:
 	bool inCommand() const;
 
 	// The following class and function are used by divelist-modifying commands
-	// to signalize that are in-flight. If the returned object goes out of scope,
+	// to signal that they are in-flight. If the returned object goes out of scope,
 	// the command-in-flight status is reset to its previous value. Thus, the
 	// function can be called recursively.
 	class InCommandMarker {
diff --git a/desktop-widgets/command_edit.cpp b/desktop-widgets/command_edit.cpp
index f39f9339d..aab3dc791 100644
--- a/desktop-widgets/command_edit.cpp
+++ b/desktop-widgets/command_edit.cpp
@@ -57,6 +57,8 @@ void EditBase<T>::undo()
 
 	std::swap(old, value);
 
+	emit diveListNotifier.divesEdited(QVector<dive *>::fromStdVector(dives), fieldId());
+
 	mark_divelist_changed(true);
 }
 
@@ -90,4 +92,9 @@ QString EditNotes::fieldName() const
 	return tr("notes");
 }
 
+DiveField EditNotes::fieldId() const
+{
+	return DiveField::NOTES;
+}
+
 } // namespace Command
diff --git a/desktop-widgets/command_edit.h b/desktop-widgets/command_edit.h
index 0bcb8114c..5f5924e67 100644
--- a/desktop-widgets/command_edit.h
+++ b/desktop-widgets/command_edit.h
@@ -5,6 +5,7 @@
 #define COMMAND_EDIT_H
 
 #include "command_base.h"
+#include "core/subsurface-qt/DiveListNotifier.h"
 
 #include <QVector>
 
@@ -43,6 +44,7 @@ protected:
 	virtual void set(struct dive *d, T) const = 0;
 	virtual T data(struct dive *d) const = 0;
 	virtual QString fieldName() const = 0;	// Name of the field, used to create the undo menu-entry
+	virtual DiveField fieldId() const = 0;
 };
 
 class EditNotes : public EditBase<QString> {
@@ -51,6 +53,7 @@ public:
 	void set(struct dive *d, QString s) const override;
 	QString data(struct dive *d) const override;
 	QString fieldName() const override;
+	DiveField fieldId() const override;
 };
 
 } // namespace Command
diff --git a/desktop-widgets/tab-widgets/maintab.cpp b/desktop-widgets/tab-widgets/maintab.cpp
index ab2eabd4c..02e0a65be 100644
--- a/desktop-widgets/tab-widgets/maintab.cpp
+++ b/desktop-widgets/tab-widgets/maintab.cpp
@@ -82,6 +82,7 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent),
 	ui.weights->setModel(weightModel);
 	closeMessage();
 
+	connect(&diveListNotifier, &DiveListNotifier::divesEdited, this, &MainTab::divesEdited);
 	connect(ui.editDiveSiteButton, &QToolButton::clicked, MainWindow::instance(), &MainWindow::startDiveSiteEdit);
 	connect(ui.location, &DiveLocationLineEdit::entered, MapWidget::instance(), &MapWidget::centerOnIndex);
 	connect(ui.location, &DiveLocationLineEdit::currentChanged, MapWidget::instance(), &MapWidget::centerOnIndex);
@@ -260,7 +261,7 @@ void MainTab::closeMessage()
 {
 	hideMessage();
 	ui.diveNotesMessage->setCloseButtonVisible(false);
-	}
+}
 
 void MainTab::displayMessage(QString str)
 {
@@ -332,6 +333,23 @@ void MainTab::enableEdition(EditMode newEditMode)
 	}
 }
 
+// This function gets called if a field gets updated by an undo command.
+// Refresh the corresponding UI field.
+void MainTab::divesEdited(const QVector<dive *> &, DiveField field)
+{
+	// If there is no current dive, no point in updating anything
+	if (!current_dive)
+		return;
+
+	switch(field) {
+	case DiveField::NOTES:
+		updateNotes(current_dive);
+		break;
+	default:
+		break;
+	}
+}
+
 void MainTab::clearEquipment()
 {
 	cylindersModel->clear();
@@ -370,6 +388,17 @@ void MainTab::updateDepthDuration()
 	ui.depth->setText(get_depth_string(displayed_dive.maxdepth, true));
 }
 
+void MainTab::updateNotes(const struct dive *d)
+{
+	QString tmp(d->notes);
+	if (tmp.indexOf("<div") != -1) {
+		tmp.replace(QString("\n"), QString("<br>"));
+		ui.notes->setHtml(tmp);
+	} else {
+		ui.notes->setPlainText(tmp);
+	}
+}
+
 void MainTab::updateDiveInfo(bool clear)
 {
 	ui.location->refreshDiveSiteCache();
@@ -388,15 +417,8 @@ void MainTab::updateDiveInfo(bool clear)
 	}
 
 	ui.notes->setText(QString());
-	if (!clear) {
-		QString tmp(displayed_dive.notes);
-		if (tmp.indexOf("<div") != -1) {
-			tmp.replace(QString("\n"), QString("<br>"));
-			ui.notes->setHtml(tmp);
-		} else {
-			ui.notes->setPlainText(tmp);
-		}
-	}
+	if (!clear)
+		updateNotes(&displayed_dive);
 	UPDATE_TEXT(displayed_dive, suit);
 	UPDATE_TEXT(displayed_dive, divemaster);
 	UPDATE_TEXT(displayed_dive, buddy);
diff --git a/desktop-widgets/tab-widgets/maintab.h b/desktop-widgets/tab-widgets/maintab.h
index 00b94d1a0..e8fdd0ac4 100644
--- a/desktop-widgets/tab-widgets/maintab.h
+++ b/desktop-widgets/tab-widgets/maintab.h
@@ -17,6 +17,7 @@
 #include "qt-models/completionmodels.h"
 #include "qt-models/divelocationmodel.h"
 #include "core/dive.h"
+#include "core/subsurface-qt/DiveListNotifier.h"
 
 class WeightModel;
 class CylindersModel;
@@ -62,9 +63,11 @@ signals:
 	void diveSiteChanged();
 public
 slots:
+	void divesEdited(const QVector<dive *> &dives, DiveField field);
 	void addCylinder_clicked();
 	void addWeight_clicked();
 	void updateDiveInfo(bool clear = false);
+	void updateNotes(const struct dive *d);
 	void updateDepthDuration();
 	void acceptChanges();
 	void rejectChanges();