| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | // SPDX-License-Identifier: GPL-2.0
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "command_edit.h"
 | 
					
						
							|  |  |  | #include "core/divelist.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-16 23:10:47 +01:00
										 |  |  | #include "core/fulltext.h"
 | 
					
						
							| 
									
										
										
										
											2019-03-20 21:46:58 +01:00
										 |  |  | #include "core/qthelper.h" // for copy_qstring
 | 
					
						
							| 
									
										
										
										
											2019-11-24 13:26:29 +01:00
										 |  |  | #include "core/selection.h"
 | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | #include "core/subsurface-string.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-30 18:29:36 +02:00
										 |  |  | #include "core/tag.h"
 | 
					
						
							| 
									
										
										
										
											2019-11-08 22:47:38 +01:00
										 |  |  | #include "qt-models/weightsysteminfomodel.h"
 | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | #include "qt-models/tankinfomodel.h"
 | 
					
						
							| 
									
										
										
										
											2020-01-10 08:25:37 +08:00
										 |  |  | #ifdef SUBSURFACE_MOBILE
 | 
					
						
							|  |  |  | #include "qt-models/divelocationmodel.h"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Command { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-21 17:36:58 +01:00
										 |  |  | template <typename T, DiveField::Flags ID> | 
					
						
							|  |  |  | DiveField EditTemplate<T, ID>::fieldId() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return ID; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <DiveField::Flags ID> | 
					
						
							|  |  |  | DiveField EditTagsTemplate<ID>::fieldId() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return ID; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-21 18:10:54 +01:00
										 |  |  | template <typename T, DiveField::Flags ID, T dive::*PTR> | 
					
						
							|  |  |  | void EditDefaultSetter<T, ID, PTR>::set(struct dive *d, T v) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	d->*PTR = v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename T, DiveField::Flags ID, T dive::*PTR> | 
					
						
							|  |  |  | T EditDefaultSetter<T, ID, PTR>::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return d->*PTR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-21 18:30:49 +01:00
										 |  |  | template <DiveField::Flags ID, char *dive::*PTR> | 
					
						
							|  |  |  | void EditStringSetter<ID, PTR>::set(struct dive *d, QString v) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free(d->*PTR); | 
					
						
							|  |  |  | 	d->*PTR = copy_qstring(v); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <DiveField::Flags ID, char *dive::*PTR> | 
					
						
							|  |  |  | QString EditStringSetter<ID, PTR>::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return QString(d->*PTR); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 21:30:11 +01:00
										 |  |  | static std::vector<dive *> getDives(bool currentDiveOnly) | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (currentDiveOnly) | 
					
						
							|  |  |  | 		return current_dive ? std::vector<dive *> { current_dive } | 
					
						
							|  |  |  | 				    : std::vector<dive *> { }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	std::vector<dive *> res; | 
					
						
							|  |  |  | 	struct dive *d; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	for_each_dive (i, d) { | 
					
						
							|  |  |  | 		if (d->selected) | 
					
						
							|  |  |  | 			res.push_back(d); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-23 20:27:19 +02:00
										 |  |  | EditDivesBase::EditDivesBase(bool currentDiveOnly) : | 
					
						
							| 
									
										
										
										
											2019-02-18 21:30:11 +01:00
										 |  |  | 	dives(getDives(currentDiveOnly)), | 
					
						
							|  |  |  | 	selectedDives(getDiveSelection()), | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | 	current(current_dive) | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 15:49:45 +02:00
										 |  |  | EditDivesBase::EditDivesBase(dive *d) : | 
					
						
							|  |  |  | 	dives({ d }), | 
					
						
							|  |  |  | 	selectedDives(getDiveSelection()), | 
					
						
							|  |  |  | 	current(current_dive) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-23 20:27:19 +02:00
										 |  |  | int EditDivesBase::numDives() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return dives.size(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename T> | 
					
						
							|  |  |  | EditBase<T>::EditBase(T newValue, bool currentDiveOnly) : | 
					
						
							|  |  |  | 	EditDivesBase(currentDiveOnly), | 
					
						
							|  |  |  | 	value(std::move(newValue)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 15:49:45 +02:00
										 |  |  | template<typename T> | 
					
						
							|  |  |  | EditBase<T>::EditBase(T newValue, dive *d) : | 
					
						
							|  |  |  | 	EditDivesBase(d), | 
					
						
							|  |  |  | 	value(std::move(newValue)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | // This is quite hackish: we can't use virtual functions in the constructor and
 | 
					
						
							|  |  |  | // therefore can't initialize the list of dives [the values of the dives are
 | 
					
						
							|  |  |  | // accessed by virtual functions]. Therefore, we (mis)use the fact that workToBeDone()
 | 
					
						
							|  |  |  | // is called exactly once before adding the Command to the system and perform this here.
 | 
					
						
							|  |  |  | // To be more explicit about this, we might think about renaming workToBeDone() to init().
 | 
					
						
							|  |  |  | template<typename T> | 
					
						
							|  |  |  | bool EditBase<T>::workToBeDone() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | 	// First, let's fetch the old value, i.e. the value of the current dive.
 | 
					
						
							|  |  |  | 	// If no current dive exists, bail.
 | 
					
						
							|  |  |  | 	if (!current) | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	old = data(current); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If there is no change - do nothing.
 | 
					
						
							|  |  |  | 	if (old == value) | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | 	std::vector<dive *> divesNew; | 
					
						
							|  |  |  | 	divesNew.reserve(dives.size()); | 
					
						
							|  |  |  | 	for (dive *d: dives) { | 
					
						
							|  |  |  | 		if (data(d) == old) | 
					
						
							|  |  |  | 			divesNew.push_back(d); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dives = std::move(divesNew); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a text for the menu entry. In the case of multiple dives add the number
 | 
					
						
							|  |  |  | 	size_t num_dives = dives.size(); | 
					
						
							| 
									
										
										
										
											2019-12-04 15:30:59 +01:00
										 |  |  | 	if (num_dives == 1) | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 		setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Edit %1").arg(fieldName())).arg(diveNumberOrDate(dives[0]))); | 
					
						
							| 
									
										
										
										
											2019-12-04 15:30:59 +01:00
										 |  |  | 	else if (num_dives > 0) | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 		setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Edit %1 (%n dive(s))", "", num_dives).arg(fieldName())).arg(getListOfDives(dives))); | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | 	return num_dives > 0; | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename T> | 
					
						
							|  |  |  | void EditBase<T>::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (dives.empty()) { | 
					
						
							|  |  |  | 		qWarning("Edit command called with empty dives list (shouldn't happen)"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (dive *d: dives) { | 
					
						
							|  |  |  | 		set(d, value); | 
					
						
							| 
									
										
										
										
											2020-03-16 23:10:47 +01:00
										 |  |  | 		fulltext_register(d); // Update the fulltext cache
 | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | 		invalidate_dive_cache(d); // Ensure that dive is written in git_save()
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	std::swap(old, value); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 15:34:43 +01:00
										 |  |  | 	// Send signals.
 | 
					
						
							|  |  |  | 	DiveField id = fieldId(); | 
					
						
							| 
									
										
										
										
											2020-01-06 12:21:14 -08:00
										 |  |  | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
 | 
					
						
							|  |  |  | 	emit diveListNotifier.divesChanged(QVector<dive *>(dives.begin(), dives.end()), id); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2019-06-23 09:22:26 +02:00
										 |  |  | 	emit diveListNotifier.divesChanged(QVector<dive *>::fromStdVector(dives), id); | 
					
						
							| 
									
										
										
										
											2020-01-06 12:21:14 -08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:08:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-23 12:13:25 +02:00
										 |  |  | 	setSelection(selectedDives, current); | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // We have to manually instantiate the constructors of the EditBase class,
 | 
					
						
							|  |  |  | // because the base class is never constructed and the derived classes
 | 
					
						
							|  |  |  | // don't have their own constructor. They simply delegate to the base
 | 
					
						
							|  |  |  | // class by virtue of a "using" declaration.
 | 
					
						
							|  |  |  | template | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | EditBase<QString>::EditBase(QString newValue, bool currentDiveOnly); | 
					
						
							| 
									
										
										
										
											2019-01-28 22:35:07 +01:00
										 |  |  | template | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | EditBase<int>::EditBase(int newValue, bool currentDiveOnly); | 
					
						
							| 
									
										
										
										
											2019-03-20 21:46:58 +01:00
										 |  |  | template | 
					
						
							| 
									
										
										
										
											2020-03-21 18:10:54 +01:00
										 |  |  | EditBase<bool>::EditBase(bool newValue, bool currentDiveOnly); | 
					
						
							|  |  |  | template | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | EditBase<struct dive_site *>::EditBase(struct dive_site *newValue, bool currentDiveOnly); | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Undo and redo do the same as just the stored value is exchanged
 | 
					
						
							|  |  |  | template<typename T> | 
					
						
							|  |  |  | void EditBase<T>::redo() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-20 21:46:58 +01:00
										 |  |  | 	// Note: here, we explicitly call the undo function of EditBase<T> and don't do
 | 
					
						
							|  |  |  | 	// virtual dispatch. Thus, derived classes can call this redo function without
 | 
					
						
							|  |  |  | 	// having their own undo() function called.
 | 
					
						
							|  |  |  | 	EditBase<T>::undo(); | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-28 18:35:27 +01:00
										 |  |  | // Implementation of virtual functions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ***** Notes *****
 | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | QString EditNotes::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("notes"); | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-28 21:42:59 +01:00
										 |  |  | // ***** Suit *****
 | 
					
						
							|  |  |  | QString EditSuit::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("suit"); | 
					
						
							| 
									
										
										
										
											2019-01-28 21:42:59 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-28 22:35:07 +01:00
										 |  |  | // ***** Rating *****
 | 
					
						
							|  |  |  | QString EditRating::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("rating"); | 
					
						
							| 
									
										
										
										
											2019-01-28 22:35:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-30 22:13:24 +01:00
										 |  |  | // ***** Visibility *****
 | 
					
						
							| 
									
										
										
										
											2019-01-28 22:35:07 +01:00
										 |  |  | QString EditVisibility::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("visibility"); | 
					
						
							| 
									
										
										
										
											2019-01-28 22:35:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 21:04:52 +02:00
										 |  |  | // ***** WaveSize *****
 | 
					
						
							|  |  |  | QString EditWaveSize::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("wavesize"); | 
					
						
							| 
									
										
										
										
											2019-11-28 21:04:52 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ***** Current *****
 | 
					
						
							|  |  |  | QString EditCurrent::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("current"); | 
					
						
							| 
									
										
										
										
											2019-11-28 21:04:52 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ***** Surge *****
 | 
					
						
							|  |  |  | QString EditSurge::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("surge"); | 
					
						
							| 
									
										
										
										
											2019-11-28 21:04:52 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ***** Chill *****
 | 
					
						
							|  |  |  | QString EditChill::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("chill"); | 
					
						
							| 
									
										
										
										
											2019-11-28 21:04:52 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-30 22:13:24 +01:00
										 |  |  | // ***** Air Temperature *****
 | 
					
						
							|  |  |  | void EditAirTemp::set(struct dive *d, int value) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	d->airtemp.mkelvin = value > 0 ? (uint32_t)value : 0u; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EditAirTemp::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (int)d->airtemp.mkelvin; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditAirTemp::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("air temperature"); | 
					
						
							| 
									
										
										
										
											2019-01-30 22:13:24 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ***** Water Temperature *****
 | 
					
						
							|  |  |  | void EditWaterTemp::set(struct dive *d, int value) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	d->watertemp.mkelvin = value > 0 ? (uint32_t)value : 0u; | 
					
						
							| 
									
										
										
										
											2019-02-24 21:46:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// re-populate the temperatures - easiest way to do this is by calling fixup_dive
 | 
					
						
							|  |  |  | 	fixup_dive(d); | 
					
						
							| 
									
										
										
										
											2019-01-30 22:13:24 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EditWaterTemp::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (int)d->watertemp.mkelvin; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditWaterTemp::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("water temperature"); | 
					
						
							| 
									
										
										
										
											2019-01-30 22:13:24 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-19 19:16:45 +02:00
										 |  |  | // ***** Water Type *****
 | 
					
						
							|  |  |  | void EditWaterTypeUser::set(struct dive *d, int value) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	d->user_salinity = value > 0 ? value : 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EditWaterTypeUser::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return d->user_salinity; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditWaterTypeUser::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("salinity"); | 
					
						
							| 
									
										
										
										
											2019-11-19 19:16:45 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-30 12:42:33 +02:00
										 |  |  | // ***** Atmospheric pressure *****
 | 
					
						
							|  |  |  | void EditAtmPress::set(struct dive *d, int value) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	d->surface_pressure.mbar = value > 0 ? (uint32_t)value : 0u; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EditAtmPress::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (int)d->surface_pressure.mbar; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditAtmPress::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("Atm. pressure"); | 
					
						
							| 
									
										
										
										
											2019-04-30 12:42:33 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 17:37:06 +01:00
										 |  |  | // ***** Duration *****
 | 
					
						
							|  |  |  | void EditDuration::set(struct dive *d, int value) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	d->dc.duration.seconds = value; | 
					
						
							|  |  |  | 	d->duration = d->dc.duration; | 
					
						
							|  |  |  | 	d->dc.meandepth.mm = 0; | 
					
						
							|  |  |  | 	d->dc.samples = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EditDuration::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return d->duration.seconds; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditDuration::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("duration"); | 
					
						
							| 
									
										
										
										
											2019-02-10 17:37:06 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ***** Depth *****
 | 
					
						
							|  |  |  | void EditDepth::set(struct dive *d, int value) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	d->dc.maxdepth.mm = value; | 
					
						
							|  |  |  | 	d->maxdepth = d->dc.maxdepth; | 
					
						
							|  |  |  | 	d->dc.meandepth.mm = 0; | 
					
						
							|  |  |  | 	d->dc.samples = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EditDepth::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return d->maxdepth.mm; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditDepth::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("depth"); | 
					
						
							| 
									
										
										
										
											2019-02-10 17:37:06 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-20 21:46:58 +01:00
										 |  |  | // ***** DiveSite *****
 | 
					
						
							|  |  |  | void EditDiveSite::set(struct dive *d, struct dive_site *dive_site) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unregister_dive_from_dive_site(d); | 
					
						
							|  |  |  | 	add_dive_to_dive_site(d, dive_site); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct dive_site *EditDiveSite::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return d->dive_site; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditDiveSite::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("dive site"); | 
					
						
							| 
									
										
										
										
											2019-03-20 21:46:58 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditDiveSite::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// Do the normal undo thing, then send dive site changed signals
 | 
					
						
							|  |  |  | 	EditBase<dive_site *>::undo(); | 
					
						
							|  |  |  | 	if (value) | 
					
						
							|  |  |  | 		emit diveListNotifier.diveSiteDivesChanged(value); | 
					
						
							|  |  |  | 	if (old) | 
					
						
							|  |  |  | 		emit diveListNotifier.diveSiteDivesChanged(old); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditDiveSite::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	EditDiveSite::undo(); // Undo and redo do the same
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | static struct dive_site *createDiveSite(const QString &name) | 
					
						
							| 
									
										
										
										
											2019-03-20 21:46:58 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct dive_site *ds = alloc_dive_site(); | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | 	struct dive_site *old = current_dive ? current_dive->dive_site : nullptr; | 
					
						
							| 
									
										
										
										
											2019-03-20 21:46:58 +01:00
										 |  |  | 	if (old) { | 
					
						
							|  |  |  | 		copy_dive_site(old, ds); | 
					
						
							|  |  |  | 		free(ds->name); // Free name, as we will overwrite it with our own version
 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-04-24 23:59:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// If the current dive has a location, use that as location for the new dive site
 | 
					
						
							|  |  |  | 	if (current_dive) { | 
					
						
							|  |  |  | 		location_t loc = dive_get_gps_location(current_dive); | 
					
						
							|  |  |  | 		if (has_location(&loc)) | 
					
						
							|  |  |  | 			ds->location = loc; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-20 21:46:58 +01:00
										 |  |  | 	ds->name = copy_qstring(name); | 
					
						
							|  |  |  | 	return ds; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | EditDiveSiteNew::EditDiveSiteNew(const QString &newName, bool currentDiveOnly) : | 
					
						
							|  |  |  | 	EditDiveSite(createDiveSite(newName), currentDiveOnly), | 
					
						
							| 
									
										
										
										
											2019-03-20 21:46:58 +01:00
										 |  |  | 	diveSiteToAdd(value), | 
					
						
							|  |  |  | 	diveSiteToRemove(nullptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditDiveSiteNew::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	EditDiveSite::undo(); | 
					
						
							|  |  |  | 	int idx = unregister_dive_site(diveSiteToRemove); | 
					
						
							|  |  |  | 	diveSiteToAdd.reset(diveSiteToRemove); | 
					
						
							|  |  |  | 	emit diveListNotifier.diveSiteDeleted(diveSiteToRemove, idx); // Inform frontend of removed dive site.
 | 
					
						
							|  |  |  | 	diveSiteToRemove = nullptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditDiveSiteNew::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	diveSiteToRemove = diveSiteToAdd.get(); | 
					
						
							|  |  |  | 	int idx = register_dive_site(diveSiteToAdd.release()); // Return ownership to backend.
 | 
					
						
							|  |  |  | 	emit diveListNotifier.diveSiteAdded(diveSiteToRemove, idx); // Inform frontend of new dive site.
 | 
					
						
							|  |  |  | 	EditDiveSite::redo(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-28 18:35:27 +01:00
										 |  |  | // ***** Mode *****
 | 
					
						
							|  |  |  | // Editing the dive mode has very peculiar semantics for historic reasons:
 | 
					
						
							|  |  |  | // Since the dive-mode depends on the dive computer, the i-th dive computer
 | 
					
						
							|  |  |  | // of each dive will be edited. If the dive has less than i dive computers,
 | 
					
						
							|  |  |  | // the default dive computer will be edited.
 | 
					
						
							|  |  |  | // The index "i" will be stored as an additional payload with the command.
 | 
					
						
							|  |  |  | // Thus, we need an explicit constructor. Since the actual handling is done
 | 
					
						
							|  |  |  | // by the base class, which knows nothing about this index, it will not be
 | 
					
						
							|  |  |  | // sent via signals. Currently this is not needed. Should it turn out to
 | 
					
						
							|  |  |  | // become necessary, then we might either
 | 
					
						
							|  |  |  | //	- Not derive EditMode from EditBase.
 | 
					
						
							|  |  |  | //	- Change the semantics of the mode-editing.
 | 
					
						
							|  |  |  | // The future will tell.
 | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | EditMode::EditMode(int indexIn, int newValue, bool currentDiveOnly) | 
					
						
							| 
									
										
										
										
											2020-03-21 17:36:58 +01:00
										 |  |  | 	: EditTemplate(newValue, currentDiveOnly), index(indexIn) | 
					
						
							| 
									
										
										
										
											2019-01-28 18:35:27 +01:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditMode::set(struct dive *d, int i) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	get_dive_dc(d, index)->divemode = (enum divemode_t)i; | 
					
						
							|  |  |  | 	update_setpoint_events(d, get_dive_dc(d, index)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EditMode::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return get_dive_dc(d, index)->divemode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditMode::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("dive mode"); | 
					
						
							| 
									
										
										
										
											2019-01-28 18:35:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-12 23:07:17 +01:00
										 |  |  | // ***** Invalid *****
 | 
					
						
							|  |  |  | QString EditInvalid::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("invalid"); | 
					
						
							| 
									
										
										
										
											2019-12-12 23:07:17 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-07 19:59:34 +01:00
										 |  |  | // ***** Tag based commands *****
 | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | EditTagsBase::EditTagsBase(const QStringList &newListIn, bool currentDiveOnly) : | 
					
						
							| 
									
										
										
										
											2019-05-23 20:27:19 +02:00
										 |  |  | 	EditDivesBase(currentDiveOnly), | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | 	newList(newListIn) | 
					
						
							| 
									
										
										
										
											2019-02-07 19:59:34 +01:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Two helper functions: returns true if first list contains any tag or
 | 
					
						
							|  |  |  | // misses any tag of second list.
 | 
					
						
							|  |  |  | static bool containsAny(const QStringList &tags1, const QStringList &tags2) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return std::any_of(tags2.begin(), tags2.end(), [&tags1](const QString &tag) | 
					
						
							|  |  |  | 			   { return tags1.contains(tag); }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool missesAny(const QStringList &tags1, const QStringList &tags2) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return std::any_of(tags2.begin(), tags2.end(), [&tags1](const QString &tag) | 
					
						
							|  |  |  | 			   { return !tags1.contains(tag); }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This is quite hackish: we can't use virtual functions in the constructor and
 | 
					
						
							|  |  |  | // therefore can't initialize the list of dives [the values of the dives are
 | 
					
						
							|  |  |  | // accessed by virtual functions]. Therefore, we (mis)use the fact that workToBeDone()
 | 
					
						
							|  |  |  | // is called exactly once before adding the Command to the system and perform this here.
 | 
					
						
							|  |  |  | // To be more explicit about this, we might think about renaming workToBeDone() to init().
 | 
					
						
							|  |  |  | bool EditTagsBase::workToBeDone() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// changing the tags on multiple dives is semantically strange - what's the right thing to do?
 | 
					
						
							|  |  |  | 	// here's what I think... add the tags that were added to the displayed dive and remove the tags
 | 
					
						
							|  |  |  | 	// that were removed from it
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | 	// If there is no current dive, bail.
 | 
					
						
							|  |  |  | 	if (!current) | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-07 19:59:34 +01:00
										 |  |  | 	// Calculate tags to add and tags to remove
 | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | 	QStringList oldList = data(current); | 
					
						
							| 
									
										
										
										
											2019-02-07 19:59:34 +01:00
										 |  |  | 	for (const QString &s: newList) { | 
					
						
							|  |  |  | 		if (!oldList.contains(s)) | 
					
						
							|  |  |  | 			tagsToAdd.push_back(s); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for (const QString &s: oldList) { | 
					
						
							|  |  |  | 		if (!newList.contains(s)) | 
					
						
							|  |  |  | 			tagsToRemove.push_back(s); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Now search for all dives that either
 | 
					
						
							|  |  |  | 	//	- miss a tag to be added
 | 
					
						
							|  |  |  | 	//	- have a tag to be removed
 | 
					
						
							|  |  |  | 	std::vector<dive *> divesNew; | 
					
						
							|  |  |  | 	divesNew.reserve(dives.size()); | 
					
						
							|  |  |  | 	for (dive *d: dives) { | 
					
						
							|  |  |  | 		QStringList tags = data(d); | 
					
						
							|  |  |  | 		if (missesAny(tags, tagsToAdd) || containsAny(tags, tagsToRemove)) | 
					
						
							|  |  |  | 			divesNew.push_back(d); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dives = std::move(divesNew); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a text for the menu entry. In the case of multiple dives add the number
 | 
					
						
							|  |  |  | 	size_t num_dives = dives.size(); | 
					
						
							| 
									
										
										
										
											2019-12-04 15:30:59 +01:00
										 |  |  | 	if (num_dives == 1) | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 		setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Edit %1").arg(fieldName())).arg(diveNumberOrDate(dives[0]))); | 
					
						
							| 
									
										
										
										
											2019-12-04 15:30:59 +01:00
										 |  |  | 	else if (num_dives > 0) | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 		setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Edit %1 (%n dive(s))", "", num_dives).arg(fieldName())).arg(getListOfDives(dives))); | 
					
						
							| 
									
										
										
										
											2019-02-07 19:59:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 23:07:12 +01:00
										 |  |  | 	return num_dives != 0; | 
					
						
							| 
									
										
										
										
											2019-02-07 19:59:34 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditTagsBase::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (dives.empty()) { | 
					
						
							|  |  |  | 		qWarning("Edit command called with empty dives list (shouldn't happen)"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (dive *d: dives) { | 
					
						
							|  |  |  | 		QStringList tags = data(d); | 
					
						
							|  |  |  | 		for (const QString &tag: tagsToRemove) | 
					
						
							|  |  |  | 			tags.removeAll(tag); | 
					
						
							|  |  |  | 		for (const QString &tag: tagsToAdd) { | 
					
						
							|  |  |  | 			if (!tags.contains(tag)) | 
					
						
							|  |  |  | 				tags.push_back(tag); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		set(d, tags); | 
					
						
							| 
									
										
										
										
											2020-03-16 23:10:47 +01:00
										 |  |  | 		fulltext_register(d); // Update the fulltext cache
 | 
					
						
							|  |  |  | 		invalidate_dive_cache(d); // Ensure that dive is written in git_save()
 | 
					
						
							| 
									
										
										
										
											2019-02-07 19:59:34 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	std::swap(tagsToAdd, tagsToRemove); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 15:34:43 +01:00
										 |  |  | 	// Send signals.
 | 
					
						
							|  |  |  | 	DiveField id = fieldId(); | 
					
						
							| 
									
										
										
										
											2020-01-06 12:21:14 -08:00
										 |  |  | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
 | 
					
						
							|  |  |  | 	emit diveListNotifier.divesChanged(QVector<dive *>(dives.begin(), dives.end()), id); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2019-06-23 09:22:26 +02:00
										 |  |  | 	emit diveListNotifier.divesChanged(QVector<dive *>::fromStdVector(dives), id); | 
					
						
							| 
									
										
										
										
											2020-01-06 12:21:14 -08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-06-23 12:13:25 +02:00
										 |  |  | 	setSelection(selectedDives, current); | 
					
						
							| 
									
										
										
										
											2019-02-07 19:59:34 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Undo and redo do the same as just the stored value is exchanged
 | 
					
						
							|  |  |  | void EditTagsBase::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	undo(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ***** Tags *****
 | 
					
						
							|  |  |  | QStringList EditTags::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	QStringList res; | 
					
						
							|  |  |  | 	for (const struct tag_entry *tag = d->tag_list; tag; tag = tag->next) | 
					
						
							|  |  |  | 		res.push_back(tag->tag->name); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditTags::set(struct dive *d, const QStringList &v) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	taglist_free(d->tag_list); | 
					
						
							|  |  |  | 	d->tag_list = NULL; | 
					
						
							|  |  |  | 	for (const QString &tag: v) | 
					
						
							|  |  |  | 		taglist_add_tag(&d->tag_list, qPrintable(tag)); | 
					
						
							|  |  |  | 	taglist_cleanup(&d->tag_list); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditTags::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("tags"); | 
					
						
							| 
									
										
										
										
											2019-02-07 19:59:34 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-07 21:00:09 +01:00
										 |  |  | // ***** Buddies *****
 | 
					
						
							|  |  |  | QStringList EditBuddies::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return stringToList(d->buddy); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditBuddies::set(struct dive *d, const QStringList &v) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	QString text = v.join(", "); | 
					
						
							|  |  |  | 	free(d->buddy); | 
					
						
							|  |  |  | 	d->buddy = copy_qstring(text); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditBuddies::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("buddies"); | 
					
						
							| 
									
										
										
										
											2019-02-07 21:00:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-07 21:23:00 +01:00
										 |  |  | // ***** DiveMaster *****
 | 
					
						
							|  |  |  | QStringList EditDiveMaster::data(struct dive *d) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return stringToList(d->divemaster); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditDiveMaster::set(struct dive *d, const QStringList &v) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	QString text = v.join(", "); | 
					
						
							|  |  |  | 	free(d->divemaster); | 
					
						
							|  |  |  | 	d->divemaster = copy_qstring(text); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString EditDiveMaster::fieldName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	return Command::Base::tr("dive master"); | 
					
						
							| 
									
										
										
										
											2019-02-07 21:23:00 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | static void swapCandQString(QString &q, char *&c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	QString tmp(c); | 
					
						
							|  |  |  | 	free(c); | 
					
						
							|  |  |  | 	c = copy_qstring(q); | 
					
						
							|  |  |  | 	q = std::move(tmp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dIn), | 
					
						
							| 
									
										
										
										
											2019-08-04 18:44:57 +02:00
										 |  |  | 	tags(nullptr) | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-08-04 18:44:57 +02:00
										 |  |  | 	memset(&cylinders, 0, sizeof(cylinders)); | 
					
						
							| 
									
										
										
										
											2019-08-24 13:42:49 +02:00
										 |  |  | 	memset(&weightsystems, 0, sizeof(weightsystems)); | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | 	if (what.notes) | 
					
						
							|  |  |  | 		notes = data->notes; | 
					
						
							|  |  |  | 	if (what.divemaster) | 
					
						
							|  |  |  | 		divemaster = data->divemaster; | 
					
						
							|  |  |  | 	if (what.buddy) | 
					
						
							|  |  |  | 		buddy = data->buddy; | 
					
						
							|  |  |  | 	if (what.suit) | 
					
						
							|  |  |  | 		suit = data->suit; | 
					
						
							|  |  |  | 	if (what.rating) | 
					
						
							|  |  |  | 		rating = data->rating; | 
					
						
							|  |  |  | 	if (what.visibility) | 
					
						
							|  |  |  | 		visibility = data->visibility; | 
					
						
							| 
									
										
										
										
											2019-11-28 21:04:52 +02:00
										 |  |  | 	if (what.wavesize) | 
					
						
							|  |  |  | 		wavesize = data->wavesize; | 
					
						
							|  |  |  | 	if (what.current) | 
					
						
							|  |  |  | 		current = data->current; | 
					
						
							|  |  |  | 	if (what.surge) | 
					
						
							|  |  |  | 		surge = data->surge; | 
					
						
							|  |  |  | 	if (what.chill) | 
					
						
							|  |  |  | 		chill = data->chill; | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | 	if (what.divesite) | 
					
						
							|  |  |  | 		divesite = data->dive_site; | 
					
						
							|  |  |  | 	if (what.tags) | 
					
						
							|  |  |  | 		tags = taglist_copy(data->tag_list); | 
					
						
							| 
									
										
										
										
											2019-08-04 18:44:57 +02:00
										 |  |  | 	if (what.cylinders) | 
					
						
							|  |  |  | 		copy_cylinders(&data->cylinders, &cylinders); | 
					
						
							| 
									
										
										
										
											2019-06-26 17:21:03 +02:00
										 |  |  | 	if (what.weights) | 
					
						
							|  |  |  | 		copy_weights(&data->weightsystems, &weightsystems); | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PasteState::~PasteState() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	taglist_free(tags); | 
					
						
							| 
									
										
										
										
											2019-08-04 18:44:57 +02:00
										 |  |  | 	clear_cylinder_table(&cylinders); | 
					
						
							| 
									
										
										
										
											2019-06-26 17:21:03 +02:00
										 |  |  | 	clear_weightsystem_table(&weightsystems); | 
					
						
							|  |  |  | 	free(weightsystems.weightsystems); | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PasteState::swap(dive_components what) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (what.notes) | 
					
						
							|  |  |  | 		swapCandQString(notes, d->notes); | 
					
						
							|  |  |  | 	if (what.divemaster) | 
					
						
							|  |  |  | 		swapCandQString(divemaster, d->divemaster); | 
					
						
							|  |  |  | 	if (what.buddy) | 
					
						
							|  |  |  | 		swapCandQString(buddy, d->buddy); | 
					
						
							|  |  |  | 	if (what.suit) | 
					
						
							|  |  |  | 		swapCandQString(suit, d->suit); | 
					
						
							|  |  |  | 	if (what.rating) | 
					
						
							|  |  |  | 		std::swap(rating, d->rating); | 
					
						
							|  |  |  | 	if (what.visibility) | 
					
						
							|  |  |  | 		std::swap(visibility, d->visibility); | 
					
						
							| 
									
										
										
										
											2019-11-28 21:04:52 +02:00
										 |  |  | 	if (what.wavesize) | 
					
						
							|  |  |  | 		std::swap(wavesize, d->wavesize); | 
					
						
							|  |  |  | 	if (what.current) | 
					
						
							|  |  |  | 		std::swap(current, d->current); | 
					
						
							|  |  |  | 	if (what.surge) | 
					
						
							|  |  |  | 		std::swap(surge, d->surge); | 
					
						
							|  |  |  | 	if (what.chill) | 
					
						
							|  |  |  | 		std::swap(chill, d->chill); | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | 	if (what.divesite) | 
					
						
							|  |  |  | 		std::swap(divesite, d->dive_site); | 
					
						
							|  |  |  | 	if (what.tags) | 
					
						
							|  |  |  | 		std::swap(tags, d->tag_list); | 
					
						
							| 
									
										
										
										
											2019-08-04 18:44:57 +02:00
										 |  |  | 	if (what.cylinders) | 
					
						
							|  |  |  | 		std::swap(cylinders, d->cylinders); | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | 	if (what.weights) | 
					
						
							| 
									
										
										
										
											2019-06-26 17:21:03 +02:00
										 |  |  | 		std::swap(weightsystems, d->weightsystems); | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ***** Paste *****
 | 
					
						
							| 
									
										
										
										
											2020-01-06 12:24:53 -08:00
										 |  |  | PasteDives::PasteDives(const dive *data, dive_components whatIn) : what(whatIn) | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	std::vector<dive *> selection = getDiveSelection(); | 
					
						
							|  |  |  | 	dives.reserve(selection.size()); | 
					
						
							|  |  |  | 	for (dive *d: selection) | 
					
						
							|  |  |  | 		dives.emplace_back(d, data, what); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Paste onto %n dive(s)", "", dives.size())).arg(getListOfDives(selection))); | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool PasteDives::workToBeDone() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return !dives.empty(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PasteDives::undo() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-23 09:22:26 +02:00
										 |  |  | 	QVector<dive *> divesToNotify; // Remember dives so that we can send signals later
 | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | 	divesToNotify.reserve(dives.size()); | 
					
						
							|  |  |  | 	for (PasteState &state: dives) { | 
					
						
							|  |  |  | 		divesToNotify.push_back(state.d); | 
					
						
							|  |  |  | 		state.swap(what); | 
					
						
							|  |  |  | 		invalidate_dive_cache(state.d); // Ensure that dive is written in git_save()
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Send signals.
 | 
					
						
							| 
									
										
										
										
											2019-10-13 12:44:39 +02:00
										 |  |  | 	DiveField fields(DiveField::NONE); | 
					
						
							|  |  |  | 	fields.notes = what.notes; | 
					
						
							|  |  |  | 	fields.divemaster = what.divemaster; | 
					
						
							|  |  |  | 	fields.buddy = what.buddy; | 
					
						
							|  |  |  | 	fields.suit = what.suit; | 
					
						
							|  |  |  | 	fields.rating = what.rating; | 
					
						
							|  |  |  | 	fields.visibility = what.visibility; | 
					
						
							| 
									
										
										
										
											2019-11-28 21:04:52 +02:00
										 |  |  | 	fields.wavesize = what.wavesize; | 
					
						
							|  |  |  | 	fields.current = what.current; | 
					
						
							|  |  |  | 	fields.surge = what.surge; | 
					
						
							|  |  |  | 	fields.chill = what.chill; | 
					
						
							| 
									
										
										
										
											2019-10-13 12:44:39 +02:00
										 |  |  | 	fields.divesite = what.divesite; | 
					
						
							|  |  |  | 	fields.tags = what.tags; | 
					
						
							|  |  |  | 	emit diveListNotifier.divesChanged(divesToNotify, fields); | 
					
						
							| 
									
										
										
										
											2019-06-23 09:22:26 +02:00
										 |  |  | 	if (what.cylinders) | 
					
						
							|  |  |  | 		emit diveListNotifier.cylindersReset(divesToNotify); | 
					
						
							|  |  |  | 	if (what.weights) | 
					
						
							|  |  |  | 		emit diveListNotifier.weightsystemsReset(divesToNotify); | 
					
						
							| 
									
										
										
										
											2019-02-23 18:17:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Redo and undo do the same
 | 
					
						
							|  |  |  | void PasteDives::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	undo(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-06 12:11:04 -08:00
										 |  |  | // ***** ReplanDive *****
 | 
					
						
							| 
									
										
										
										
											2019-11-30 15:51:34 +01:00
										 |  |  | ReplanDive::ReplanDive(dive *source, bool edit_profile) : d(current_dive), | 
					
						
							| 
									
										
										
										
											2020-01-06 12:11:04 -08:00
										 |  |  | 	when(0), | 
					
						
							|  |  |  | 	maxdepth({0}), | 
					
						
							|  |  |  | 	meandepth({0}), | 
					
						
							| 
									
										
										
										
											2019-10-06 20:54:25 +02:00
										 |  |  | 	dc({ 0 }), | 
					
						
							| 
									
										
										
										
											2020-01-06 12:11:04 -08:00
										 |  |  | 	notes(nullptr), | 
					
						
							|  |  |  | 	surface_pressure({0}), | 
					
						
							|  |  |  | 	duration({0}), | 
					
						
							|  |  |  | 	salinity(0) | 
					
						
							| 
									
										
										
										
											2019-10-06 20:54:25 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-08-04 18:44:57 +02:00
										 |  |  | 	memset(&cylinders, 0, sizeof(cylinders)); | 
					
						
							| 
									
										
										
										
											2019-10-06 20:54:25 +02:00
										 |  |  | 	if (!d) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-30 15:51:34 +01:00
										 |  |  | 	// Fix source. Things might be inconsistent after modifying the profile.
 | 
					
						
							|  |  |  | 	source->maxdepth.mm = source->dc.maxdepth.mm = 0; | 
					
						
							|  |  |  | 	fixup_dive(source); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-06 20:54:25 +02:00
										 |  |  | 	when = source->when; | 
					
						
							|  |  |  | 	maxdepth = source->maxdepth; | 
					
						
							|  |  |  | 	meandepth = source->meandepth; | 
					
						
							|  |  |  | 	notes = copy_string(source->notes); | 
					
						
							|  |  |  | 	duration = source->duration; | 
					
						
							|  |  |  | 	salinity = source->salinity; | 
					
						
							|  |  |  | 	surface_pressure = source->surface_pressure; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// This resets the dive computers and cylinders of the source dive, avoiding deep copies.
 | 
					
						
							| 
									
										
										
										
											2019-08-04 18:44:57 +02:00
										 |  |  | 	std::swap(source->cylinders, cylinders); | 
					
						
							| 
									
										
										
										
											2019-10-06 20:54:25 +02:00
										 |  |  | 	std::swap(source->dc, dc); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	setText((edit_profile ? Command::Base::tr("Replan dive") : Command::Base::tr("Edit profile")) + diveNumberOrDate(d)); | 
					
						
							| 
									
										
										
										
											2019-10-06 20:54:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ReplanDive::~ReplanDive() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-08-04 18:44:57 +02:00
										 |  |  | 	clear_cylinder_table(&cylinders); | 
					
						
							| 
									
										
										
										
											2019-10-06 20:54:25 +02:00
										 |  |  | 	free_dive_dcs(&dc); | 
					
						
							|  |  |  | 	free(notes); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ReplanDive::workToBeDone() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return !!d; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReplanDive::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	std::swap(d->when, when); | 
					
						
							|  |  |  | 	std::swap(d->maxdepth, maxdepth); | 
					
						
							|  |  |  | 	std::swap(d->meandepth, meandepth); | 
					
						
							| 
									
										
										
										
											2019-08-04 18:44:57 +02:00
										 |  |  | 	std::swap(d->cylinders, cylinders); | 
					
						
							| 
									
										
										
										
											2019-10-06 20:54:25 +02:00
										 |  |  | 	std::swap(d->dc, dc); | 
					
						
							|  |  |  | 	std::swap(d->notes, notes); | 
					
						
							|  |  |  | 	std::swap(d->surface_pressure, surface_pressure); | 
					
						
							|  |  |  | 	std::swap(d->duration, duration); | 
					
						
							|  |  |  | 	std::swap(d->salinity, salinity); | 
					
						
							|  |  |  | 	fixup_dive(d); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	QVector<dive *> divesToNotify = { d }; | 
					
						
							| 
									
										
										
										
											2019-08-04 18:44:57 +02:00
										 |  |  | 	// Note that we have to emit cylindersReset before divesChanged, because the divesChanged
 | 
					
						
							|  |  |  | 	// updates the DivePlotDataModel, which is out-of-sync and gets confused.
 | 
					
						
							|  |  |  | 	emit diveListNotifier.cylindersReset(divesToNotify); | 
					
						
							| 
									
										
										
										
											2019-10-13 12:44:39 +02:00
										 |  |  | 	emit diveListNotifier.divesChanged(divesToNotify, DiveField::DATETIME | DiveField::DURATION | DiveField::DEPTH | DiveField::MODE | | 
					
						
							|  |  |  | 							  DiveField::NOTES | DiveField::SALINITY | DiveField::ATM_PRESS); | 
					
						
							| 
									
										
										
										
											2019-10-06 20:54:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Redo and undo do the same
 | 
					
						
							|  |  |  | void ReplanDive::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	undo(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-02 21:19:29 +01:00
										 |  |  | // ***** Add Weight *****
 | 
					
						
							|  |  |  | AddWeight::AddWeight(bool currentDiveOnly) : | 
					
						
							|  |  |  | 	EditDivesBase(currentDiveOnly) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-12-04 15:30:59 +01:00
										 |  |  | 	if (dives.size() == 1) | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 		setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Add weight")).arg(diveNumberOrDate(dives[0]))); | 
					
						
							| 
									
										
										
										
											2019-12-04 15:30:59 +01:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 		setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Add weight (%n dive(s))", "", dives.size())).arg(getListOfDives(dives))); | 
					
						
							| 
									
										
										
										
											2019-11-02 21:19:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AddWeight::workToBeDone() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AddWeight::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (dive *d: dives) { | 
					
						
							|  |  |  | 		if (d->weightsystems.nr <= 0) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		remove_weightsystem(d, d->weightsystems.nr - 1); | 
					
						
							|  |  |  | 		emit diveListNotifier.weightRemoved(d, d->weightsystems.nr); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AddWeight::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (dive *d: dives) { | 
					
						
							| 
									
										
										
										
											2019-11-03 23:08:32 +01:00
										 |  |  | 		add_cloned_weightsystem(&d->weightsystems, empty_weightsystem); | 
					
						
							| 
									
										
										
										
											2019-11-02 21:19:29 +01:00
										 |  |  | 		emit diveListNotifier.weightAdded(d, d->weightsystems.nr - 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | static int find_weightsystem_index(const struct dive *d, weightsystem_t ws) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (int idx = 0; idx < d->weightsystems.nr; ++idx) { | 
					
						
							|  |  |  | 		if (same_weightsystem(d->weightsystems.weightsystems[idx], ws)) | 
					
						
							|  |  |  | 			return idx; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-08 22:47:38 +01:00
										 |  |  | EditWeightBase::EditWeightBase(int index, bool currentDiveOnly) : | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | 	EditDivesBase(currentDiveOnly), | 
					
						
							| 
									
										
										
										
											2019-11-03 23:08:32 +01:00
										 |  |  | 	ws(empty_weightsystem) | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	// Get the old weightsystem, bail if index is invalid
 | 
					
						
							|  |  |  | 	if (!current || index < 0 || index >= current->weightsystems.nr) { | 
					
						
							|  |  |  | 		dives.clear(); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ws = clone_weightsystem(current->weightsystems.weightsystems[index]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Deleting a weightsystem from multiple dives is semantically ill-defined.
 | 
					
						
							|  |  |  | 	// What we will do is trying to delete the same weightsystem if it exists.
 | 
					
						
							|  |  |  | 	// For that purpose, we will determine the indices of the same weightsystem.
 | 
					
						
							|  |  |  | 	std::vector<dive *> divesNew; | 
					
						
							|  |  |  | 	divesNew.reserve(dives.size()); | 
					
						
							| 
									
										
										
										
											2020-03-11 11:30:51 +01:00
										 |  |  | 	indices.reserve(dives.size()); | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (dive *d: dives) { | 
					
						
							|  |  |  | 		if (d == current) { | 
					
						
							|  |  |  | 			divesNew.push_back(d); | 
					
						
							| 
									
										
										
										
											2020-03-11 11:30:51 +01:00
										 |  |  | 			indices.push_back(index); | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		int idx = find_weightsystem_index(d, ws); | 
					
						
							|  |  |  | 		if (idx >= 0) { | 
					
						
							|  |  |  | 			divesNew.push_back(d); | 
					
						
							| 
									
										
										
										
											2020-03-11 11:30:51 +01:00
										 |  |  | 			indices.push_back(idx); | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dives = std::move(divesNew); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-08 22:47:38 +01:00
										 |  |  | EditWeightBase::~EditWeightBase() | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-11-03 23:14:35 +01:00
										 |  |  | 	free_weightsystem(ws); | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-08 22:47:38 +01:00
										 |  |  | bool EditWeightBase::workToBeDone() | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	return !dives.empty(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | // ***** Remove Weight *****
 | 
					
						
							| 
									
										
										
										
											2019-11-08 22:47:38 +01:00
										 |  |  | RemoveWeight::RemoveWeight(int index, bool currentDiveOnly) : | 
					
						
							|  |  |  | 	EditWeightBase(index, currentDiveOnly) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-05 09:00:00 -08:00
										 |  |  | 	size_t num_dives = dives.size(); | 
					
						
							|  |  |  | 	if (num_dives == 1) | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 		setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Remove weight")).arg(diveNumberOrDate(dives[0]))); | 
					
						
							| 
									
										
										
										
											2019-12-04 15:30:59 +01:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 		setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Remove weight (%n dive(s))", "", num_dives)).arg(getListOfDives(dives))); | 
					
						
							| 
									
										
										
										
											2019-11-08 22:47:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | void RemoveWeight::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (size_t i = 0; i < dives.size(); ++i) { | 
					
						
							| 
									
										
										
										
											2020-03-11 11:30:51 +01:00
										 |  |  | 		add_to_weightsystem_table(&dives[i]->weightsystems, indices[i], clone_weightsystem(ws)); | 
					
						
							|  |  |  | 		emit diveListNotifier.weightAdded(dives[i], indices[i]); | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoveWeight::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (size_t i = 0; i < dives.size(); ++i) { | 
					
						
							| 
									
										
										
										
											2020-03-11 11:30:51 +01:00
										 |  |  | 		remove_weightsystem(dives[i], indices[i]); | 
					
						
							|  |  |  | 		emit diveListNotifier.weightRemoved(dives[i], indices[i]); | 
					
						
							| 
									
										
										
										
											2019-11-03 15:04:48 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | // ***** Edit Weight *****
 | 
					
						
							| 
									
										
										
										
											2019-11-08 22:47:38 +01:00
										 |  |  | EditWeight::EditWeight(int index, weightsystem_t wsIn, bool currentDiveOnly) : | 
					
						
							|  |  |  | 	EditWeightBase(index, currentDiveOnly), | 
					
						
							|  |  |  | 	new_ws(empty_weightsystem) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (dives.empty()) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 09:00:00 -08:00
										 |  |  | 	size_t num_dives = dives.size(); | 
					
						
							|  |  |  | 	if (num_dives == 1) | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 		setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Edit weight")).arg(diveNumberOrDate(dives[0]))); | 
					
						
							| 
									
										
										
										
											2019-12-04 15:30:59 +01:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 		setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Edit weight (%n dive(s))", "", num_dives)).arg(getListOfDives(dives))); | 
					
						
							| 
									
										
										
										
											2019-11-08 22:47:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Try to untranslate the weightsystem name
 | 
					
						
							|  |  |  | 	new_ws = clone_weightsystem(wsIn); | 
					
						
							|  |  |  | 	QString vString(new_ws.description); | 
					
						
							|  |  |  | 	for (int i = 0; i < MAX_WS_INFO && ws_info[i].name; ++i) { | 
					
						
							|  |  |  | 		if (gettextFromC::tr(ws_info[i].name) == vString) { | 
					
						
							|  |  |  | 			free_weightsystem(new_ws); | 
					
						
							|  |  |  | 			new_ws.description = copy_string(ws_info[i].name); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If that doesn't change anything, do nothing
 | 
					
						
							|  |  |  | 	if (same_weightsystem(ws, new_ws)) { | 
					
						
							|  |  |  | 		dives.clear(); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	WSInfoModel *wsim = WSInfoModel::instance(); | 
					
						
							|  |  |  | 	QModelIndexList matches = wsim->match(wsim->index(0, 0), Qt::DisplayRole, gettextFromC::tr(new_ws.description)); | 
					
						
							|  |  |  | 	if (!matches.isEmpty()) | 
					
						
							|  |  |  | 		wsim->setData(wsim->index(matches.first().row(), WSInfoModel::GR), new_ws.weight.grams); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EditWeight::~EditWeight() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free_weightsystem(new_ws); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditWeight::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (size_t i = 0; i < dives.size(); ++i) { | 
					
						
							| 
									
										
										
										
											2020-03-11 11:30:51 +01:00
										 |  |  | 		set_weightsystem(dives[i], indices[i], new_ws); | 
					
						
							|  |  |  | 		emit diveListNotifier.weightEdited(dives[i], indices[i]); | 
					
						
							| 
									
										
										
										
											2019-11-08 22:47:38 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	std::swap(ws, new_ws); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Undo and redo do the same as just the stored value is exchanged
 | 
					
						
							|  |  |  | void EditWeight::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	redo(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | // ***** Add Cylinder *****
 | 
					
						
							|  |  |  | AddCylinder::AddCylinder(bool currentDiveOnly) : | 
					
						
							|  |  |  | 	EditDivesBase(currentDiveOnly), | 
					
						
							|  |  |  | 	cyl(empty_cylinder) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (dives.empty()) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	else if (dives.size() == 1) | 
					
						
							|  |  |  | 		setText(tr("Add cylinder")); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		setText(tr("Add cylinder (%n dive(s))", "", dives.size())); | 
					
						
							|  |  |  | 	cyl = create_new_cylinder(dives[0]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AddCylinder::~AddCylinder() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free_cylinder(cyl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AddCylinder::workToBeDone() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AddCylinder::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (dive *d: dives) { | 
					
						
							|  |  |  | 		if (d->cylinders.nr <= 0) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		remove_cylinder(d, d->cylinders.nr - 1); | 
					
						
							|  |  |  | 		emit diveListNotifier.cylinderRemoved(d, d->cylinders.nr); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AddCylinder::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (dive *d: dives) { | 
					
						
							|  |  |  | 		add_cloned_cylinder(&d->cylinders, cyl); | 
					
						
							|  |  |  | 		emit diveListNotifier.cylinderAdded(d, d->cylinders.nr - 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int find_cylinder_index(const struct dive *d, const cylinder_t &cyl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (int idx = 0; idx < d->cylinders.nr; ++idx) { | 
					
						
							|  |  |  | 		if (same_cylinder(d->cylinders.cylinders[idx], cyl)) | 
					
						
							|  |  |  | 			return idx; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-24 10:57:36 +01:00
										 |  |  | EditCylinderBase::EditCylinderBase(int index, bool currentDiveOnly, bool nonProtectedOnly) : | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | 	EditDivesBase(currentDiveOnly), | 
					
						
							|  |  |  | 	cyl(empty_cylinder) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// Get the old cylinder, bail if index is invalid
 | 
					
						
							|  |  |  | 	if (!current || index < 0 || index >= current->cylinders.nr) { | 
					
						
							|  |  |  | 		dives.clear(); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	cyl = clone_cylinder(current->cylinders.cylinders[index]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	std::vector<dive *> divesNew; | 
					
						
							|  |  |  | 	divesNew.reserve(dives.size()); | 
					
						
							|  |  |  | 	indexes.reserve(dives.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (dive *d: dives) { | 
					
						
							|  |  |  | 		if (d == current) { | 
					
						
							| 
									
										
										
										
											2020-02-24 10:57:36 +01:00
										 |  |  | 			if (nonProtectedOnly && is_cylinder_prot(d, index)) | 
					
						
							|  |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | 			divesNew.push_back(d); | 
					
						
							|  |  |  | 			indexes.push_back(index); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		int idx = find_cylinder_index(d, cyl); | 
					
						
							| 
									
										
										
										
											2020-02-24 10:57:36 +01:00
										 |  |  | 		if (idx < 0 || (nonProtectedOnly && is_cylinder_prot(d, idx))) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		divesNew.push_back(d); | 
					
						
							|  |  |  | 		indexes.push_back(idx); | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	dives = std::move(divesNew); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EditCylinderBase::~EditCylinderBase() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free_cylinder(cyl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool EditCylinderBase::workToBeDone() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return !dives.empty(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ***** Remove Cylinder *****
 | 
					
						
							|  |  |  | RemoveCylinder::RemoveCylinder(int index, bool currentDiveOnly) : | 
					
						
							| 
									
										
										
										
											2020-02-24 10:57:36 +01:00
										 |  |  | 	EditCylinderBase(index, currentDiveOnly, true) | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (dives.size() == 1) | 
					
						
							|  |  |  | 		setText(tr("Remove cylinder")); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		setText(tr("Remove cylinder (%n dive(s))", "", dives.size())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoveCylinder::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (size_t i = 0; i < dives.size(); ++i) { | 
					
						
							| 
									
										
										
										
											2020-02-23 19:24:06 +01:00
										 |  |  | 		std::vector<int> mapping = get_cylinder_map_for_add(dives[i]->cylinders.nr, indexes[i]); | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | 		add_to_cylinder_table(&dives[i]->cylinders, indexes[i], clone_cylinder(cyl)); | 
					
						
							|  |  |  | 		emit diveListNotifier.cylinderAdded(dives[i], indexes[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RemoveCylinder::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (size_t i = 0; i < dives.size(); ++i) { | 
					
						
							| 
									
										
										
										
											2020-02-23 19:24:06 +01:00
										 |  |  | 		std::vector<int> mapping = get_cylinder_map_for_remove(dives[i]->cylinders.nr, indexes[i]); | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | 		remove_cylinder(dives[i], indexes[i]); | 
					
						
							| 
									
										
										
										
											2020-02-23 19:24:06 +01:00
										 |  |  | 		cylinder_renumber(dives[i], &mapping[0]); | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | 		emit diveListNotifier.cylinderRemoved(dives[i], indexes[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ***** Edit Cylinder *****
 | 
					
						
							|  |  |  | EditCylinder::EditCylinder(int index, cylinder_t cylIn, bool currentDiveOnly) : | 
					
						
							| 
									
										
										
										
											2020-02-24 10:57:36 +01:00
										 |  |  | 	EditCylinderBase(index, currentDiveOnly, false), | 
					
						
							| 
									
										
										
										
											2020-02-23 11:43:50 +01:00
										 |  |  | 	new_cyl(empty_cylinder) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (dives.empty()) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dives.size() == 1) | 
					
						
							|  |  |  | 		setText(tr("Edit cylinder")); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		setText(tr("Edit cylinder (%n dive(s))", "", dives.size())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Try to untranslate the cylinder type
 | 
					
						
							|  |  |  | 	new_cyl = clone_cylinder(cylIn); | 
					
						
							|  |  |  | 	QString vString(new_cyl.type.description); | 
					
						
							|  |  |  | 	for (int i = 0; i < MAX_TANK_INFO && tank_info[i].name; ++i) { | 
					
						
							|  |  |  | 		if (gettextFromC::tr(tank_info[i].name) == vString) { | 
					
						
							|  |  |  | 			free_cylinder(new_cyl); | 
					
						
							|  |  |  | 			new_cyl.type.description = copy_string(tank_info[i].name); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If that doesn't change anything, do nothing
 | 
					
						
							|  |  |  | 	if (same_cylinder(cyl, new_cyl)) { | 
					
						
							|  |  |  | 		dives.clear(); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	TankInfoModel *tim = TankInfoModel::instance(); | 
					
						
							|  |  |  | 	QModelIndexList matches = tim->match(tim->index(0, 0), Qt::DisplayRole, gettextFromC::tr(new_cyl.type.description)); | 
					
						
							|  |  |  | 	if (!matches.isEmpty()) { | 
					
						
							|  |  |  | 		if (new_cyl.type.size.mliter != cyl.type.size.mliter) | 
					
						
							|  |  |  | 			tim->setData(tim->index(matches.first().row(), TankInfoModel::ML), new_cyl.type.size.mliter); | 
					
						
							|  |  |  | 		if (new_cyl.type.workingpressure.mbar != cyl.type.workingpressure.mbar) | 
					
						
							|  |  |  | 			tim->setData(tim->index(matches.first().row(), TankInfoModel::BAR), new_cyl.type.workingpressure.mbar / 1000.0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EditCylinder::~EditCylinder() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free_cylinder(new_cyl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditCylinder::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (size_t i = 0; i < dives.size(); ++i) { | 
					
						
							|  |  |  | 		set_cylinder(dives[i], indexes[i], new_cyl); | 
					
						
							|  |  |  | 		emit diveListNotifier.cylinderEdited(dives[i], indexes[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	std::swap(cyl, new_cyl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Undo and redo do the same as just the stored value is exchanged
 | 
					
						
							|  |  |  | void EditCylinder::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	redo(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-10 08:25:37 +08:00
										 |  |  | #ifdef SUBSURFACE_MOBILE
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EditDive::EditDive(dive *oldDiveIn, dive *newDiveIn, dive_site *createDs, dive_site *editDs, location_t dsLocationIn) | 
					
						
							|  |  |  | 	: oldDive(oldDiveIn) | 
					
						
							|  |  |  | 	, newDive(newDiveIn) | 
					
						
							| 
									
										
										
										
											2020-04-04 16:35:24 +02:00
										 |  |  | 	, newDiveSite(newDiveIn->dive_site) | 
					
						
							| 
									
										
										
										
											2020-01-10 08:25:37 +08:00
										 |  |  | 	, changedFields(DiveField::NONE) | 
					
						
							|  |  |  | 	, siteToRemove(nullptr) | 
					
						
							|  |  |  | 	, siteToAdd(createDs) | 
					
						
							|  |  |  | 	, siteToEdit(editDs) | 
					
						
							|  |  |  | 	, dsLocation(dsLocationIn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-04-04 16:35:24 +02:00
										 |  |  | 	if (!oldDive || !newDive) | 
					
						
							| 
									
										
										
										
											2020-01-10 08:25:37 +08:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-21 16:46:36 -07:00
										 |  |  | 	setText(Command::Base::tr("Edit dive [%1]").arg(diveNumberOrDate(oldDive))); | 
					
						
							| 
									
										
										
										
											2020-01-10 08:25:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Calculate the fields that changed.
 | 
					
						
							|  |  |  | 	// Note: Probably not needed, as on mobile we don't have that granularity.
 | 
					
						
							|  |  |  | 	// However, for future-proofeness let's just do it.
 | 
					
						
							|  |  |  | 	changedFields = DiveField::NONE; | 
					
						
							|  |  |  | 	if (oldDive->number != newDive->number) | 
					
						
							|  |  |  | 		changedFields |= DiveField::NR; | 
					
						
							|  |  |  | 	if (oldDive->when != newDive->when) | 
					
						
							|  |  |  | 		changedFields |= DiveField::DATETIME; | 
					
						
							|  |  |  | 	if (oldDive->maxdepth.mm != newDive->maxdepth.mm) | 
					
						
							|  |  |  | 		changedFields |= DiveField::DEPTH; | 
					
						
							|  |  |  | 	if (oldDive->duration.seconds != newDive->duration.seconds) | 
					
						
							|  |  |  | 		changedFields |= DiveField::DURATION; | 
					
						
							|  |  |  | 	if (oldDive->airtemp.mkelvin != newDive->airtemp.mkelvin) | 
					
						
							|  |  |  | 		changedFields |= DiveField::AIR_TEMP; | 
					
						
							|  |  |  | 	if (oldDive->watertemp.mkelvin != newDive->watertemp.mkelvin) | 
					
						
							|  |  |  | 		changedFields |= DiveField::WATER_TEMP; | 
					
						
							|  |  |  | 	if (oldDive->surface_pressure.mbar != newDive->surface_pressure.mbar) | 
					
						
							|  |  |  | 		changedFields |= DiveField::ATM_PRESS; | 
					
						
							|  |  |  | 	if (oldDive->dive_site != newDive->dive_site) | 
					
						
							|  |  |  | 		changedFields |= DiveField::DIVESITE; | 
					
						
							|  |  |  | 	if (!same_string(oldDive->divemaster, newDive->divemaster)) | 
					
						
							|  |  |  | 		changedFields |= DiveField::DIVEMASTER; | 
					
						
							|  |  |  | 	if (!same_string(oldDive->buddy, newDive->buddy)) | 
					
						
							|  |  |  | 		changedFields |= DiveField::BUDDY; | 
					
						
							|  |  |  | 	if (oldDive->rating != newDive->rating) | 
					
						
							|  |  |  | 		changedFields |= DiveField::RATING; | 
					
						
							|  |  |  | 	if (oldDive->visibility != newDive->visibility) | 
					
						
							|  |  |  | 		changedFields |= DiveField::VISIBILITY; | 
					
						
							|  |  |  | 	if (oldDive->wavesize != newDive->wavesize) | 
					
						
							|  |  |  | 		changedFields |= DiveField::WAVESIZE; | 
					
						
							|  |  |  | 	if (oldDive->current != newDive->current) | 
					
						
							|  |  |  | 		changedFields |= DiveField::CURRENT; | 
					
						
							|  |  |  | 	if (oldDive->surge != newDive->surge) | 
					
						
							|  |  |  | 		changedFields |= DiveField::SURGE; | 
					
						
							|  |  |  | 	if (oldDive->chill != newDive->chill) | 
					
						
							|  |  |  | 		changedFields |= DiveField::CHILL; | 
					
						
							|  |  |  | 	if (!same_string(oldDive->suit, newDive->suit)) | 
					
						
							|  |  |  | 		changedFields |= DiveField::SUIT; | 
					
						
							|  |  |  | 	if (get_taglist_string(oldDive->tag_list) != get_taglist_string(newDive->tag_list)) // This is cheating. Do we have a taglist comparison function?
 | 
					
						
							|  |  |  | 		changedFields |= DiveField::TAGS; | 
					
						
							|  |  |  | 	if (oldDive->dc.divemode != newDive->dc.divemode) | 
					
						
							|  |  |  | 		changedFields |= DiveField::MODE; | 
					
						
							|  |  |  | 	if (!same_string(oldDive->notes, newDive->notes)) | 
					
						
							|  |  |  | 		changedFields |= DiveField::NOTES; | 
					
						
							|  |  |  | 	if (oldDive->salinity != newDive->salinity) | 
					
						
							|  |  |  | 		changedFields |= DiveField::SALINITY; | 
					
						
							| 
									
										
										
										
											2020-04-04 16:35:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	newDive->dive_site = nullptr; // We will add the dive to the site manually and therefore saved the dive site.
 | 
					
						
							| 
									
										
										
										
											2020-01-10 08:25:37 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditDive::undo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (siteToRemove) { | 
					
						
							|  |  |  | 		int idx = unregister_dive_site(siteToRemove); | 
					
						
							|  |  |  | 		siteToAdd.reset(siteToRemove); | 
					
						
							|  |  |  | 		emit diveListNotifier.diveSiteDeleted(siteToRemove, idx); // Inform frontend of removed dive site.
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	exchangeDives(); | 
					
						
							|  |  |  | 	editDs(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditDive::redo() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (siteToAdd) { | 
					
						
							|  |  |  | 		siteToRemove = siteToAdd.get(); | 
					
						
							|  |  |  | 		int idx = register_dive_site(siteToAdd.release()); // Return ownership to backend.
 | 
					
						
							|  |  |  | 		emit diveListNotifier.diveSiteAdded(siteToRemove, idx); // Inform frontend of new dive site.
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	exchangeDives(); | 
					
						
							|  |  |  | 	editDs(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditDive::exchangeDives() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-27 23:06:07 +01:00
										 |  |  | 	// Set the filter flag of the new dive to the old dive.
 | 
					
						
							|  |  |  | 	// Reason: When we send the dive-changed signal, the model will
 | 
					
						
							|  |  |  | 	// track the *change* of the filter flag, so we must not overwrite
 | 
					
						
							|  |  |  | 	// it by swapping the dive data.
 | 
					
						
							|  |  |  | 	newDive->hidden_by_filter = oldDive->hidden_by_filter; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 23:21:37 +01:00
										 |  |  | 	// Bluntly exchange dive data by shallow copy.
 | 
					
						
							|  |  |  | 	// Don't forget to unregister the old and register the new dive!
 | 
					
						
							| 
									
										
										
										
											2020-04-04 16:35:24 +02:00
										 |  |  | 	// Likewise take care to add/remove the dive from the dive site.
 | 
					
						
							| 
									
										
										
										
											2020-03-27 23:21:37 +01:00
										 |  |  | 	fulltext_unregister(oldDive); | 
					
						
							| 
									
										
										
										
											2020-04-04 16:35:24 +02:00
										 |  |  | 	dive_site *oldDiveSite = oldDive->dive_site; | 
					
						
							|  |  |  | 	if (oldDiveSite) | 
					
						
							|  |  |  | 		unregister_dive_from_dive_site(oldDive); // the dive-site pointer in the dive is now NULL
 | 
					
						
							| 
									
										
										
										
											2020-01-10 08:25:37 +08:00
										 |  |  | 	std::swap(*newDive, *oldDive); | 
					
						
							| 
									
										
										
										
											2020-03-27 23:21:37 +01:00
										 |  |  | 	fulltext_register(oldDive); | 
					
						
							| 
									
										
										
										
											2020-04-04 16:35:24 +02:00
										 |  |  | 	if (newDiveSite) | 
					
						
							|  |  |  | 		add_dive_to_dive_site(oldDive, newDiveSite); | 
					
						
							|  |  |  | 	newDiveSite = oldDiveSite; // remember the previous dive site
 | 
					
						
							| 
									
										
										
										
											2020-01-10 08:25:37 +08:00
										 |  |  | 	invalidate_dive_cache(oldDive); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Changing times may have unsorted the dive and trip tables
 | 
					
						
							|  |  |  | 	QVector<dive *> dives = { oldDive }; | 
					
						
							|  |  |  | 	timestamp_t delta = oldDive->when - newDive->when; | 
					
						
							|  |  |  | 	if (delta != 0) { | 
					
						
							|  |  |  | 		sort_dive_table(&dive_table); | 
					
						
							|  |  |  | 		sort_trip_table(&trip_table); | 
					
						
							|  |  |  | 		if (newDive->divetrip != oldDive->divetrip) | 
					
						
							|  |  |  | 			qWarning("Command::EditDive::redo(): This command does not support moving between trips!"); | 
					
						
							|  |  |  | 		if (oldDive->divetrip) | 
					
						
							|  |  |  | 			sort_dive_table(&newDive->divetrip->dives); // Keep the trip-table in order
 | 
					
						
							|  |  |  | 		emit diveListNotifier.divesTimeChanged(delta, dives); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Send signals
 | 
					
						
							|  |  |  | 	emit diveListNotifier.divesChanged(dives, changedFields); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Select the changed dives
 | 
					
						
							|  |  |  | 	setSelection( { oldDive }, oldDive); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditDive::editDs() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (siteToEdit) { | 
					
						
							|  |  |  | 		std::swap(siteToEdit->location, dsLocation); | 
					
						
							|  |  |  | 		emit diveListNotifier.diveSiteChanged(siteToEdit, LocationInformationModel::LOCATION); // Inform frontend of changed dive site.
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool EditDive::workToBeDone() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// We trust the frontend that an EditDive command is only created if there are changes.
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif // SUBSURFACE_MOBILE
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-25 18:27:31 +01:00
										 |  |  | } // namespace Command
 |