2019-01-25 17:27:31 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
|
|
|
|
#include "command_edit.h"
|
|
|
|
#include "core/divelist.h"
|
2019-03-20 20:46:58 +00:00
|
|
|
#include "core/qthelper.h" // for copy_qstring
|
2019-01-25 17:27:31 +00:00
|
|
|
|
|
|
|
namespace Command {
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
EditBase<T>::EditBase(const QVector<dive *> &divesIn, T newValue, T oldValue) :
|
|
|
|
value(std::move(newValue)),
|
|
|
|
old(std::move(oldValue)),
|
|
|
|
dives(divesIn.toStdVector())
|
|
|
|
{
|
|
|
|
// If there is nothing to do, clear the dives vector.
|
|
|
|
// This signals that no action has to be taken.
|
|
|
|
if (old == value)
|
|
|
|
dives.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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()
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
if (num_dives > 0)
|
|
|
|
//: remove the part in parantheses for %n = 1
|
|
|
|
setText(tr("Edit %1 (%n dive(s))", "", num_dives).arg(fieldName()));
|
|
|
|
|
|
|
|
return num_dives;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
invalidate_dive_cache(d); // Ensure that dive is written in git_save()
|
|
|
|
}
|
|
|
|
|
|
|
|
std::swap(old, value);
|
|
|
|
|
2019-01-27 21:08:13 +00:00
|
|
|
emit diveListNotifier.divesEdited(QVector<dive *>::fromStdVector(dives), fieldId());
|
|
|
|
|
2019-01-25 17:27:31 +00:00
|
|
|
mark_divelist_changed(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
EditBase<QString>::EditBase(const QVector<dive *> &dives, QString oldValue, QString newValue);
|
2019-01-28 21:35:07 +00:00
|
|
|
template
|
|
|
|
EditBase<int>::EditBase(const QVector<dive *> &dives, int oldValue, int newValue);
|
2019-03-20 20:46:58 +00:00
|
|
|
template
|
|
|
|
EditBase<struct dive_site *>::EditBase(const QVector<dive *> &dives, struct dive_site *oldValue, struct dive_site *newValue);
|
2019-01-25 17:27:31 +00:00
|
|
|
|
|
|
|
// Undo and redo do the same as just the stored value is exchanged
|
|
|
|
template<typename T>
|
|
|
|
void EditBase<T>::redo()
|
|
|
|
{
|
2019-03-20 20:46:58 +00: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 17:27:31 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 17:35:27 +00:00
|
|
|
// Implementation of virtual functions
|
|
|
|
|
|
|
|
// ***** Notes *****
|
2019-01-25 17:27:31 +00:00
|
|
|
void EditNotes::set(struct dive *d, QString s) const
|
|
|
|
{
|
|
|
|
free(d->notes);
|
|
|
|
d->notes = strdup(qPrintable(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString EditNotes::data(struct dive *d) const
|
|
|
|
{
|
|
|
|
return QString(d->notes);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString EditNotes::fieldName() const
|
|
|
|
{
|
|
|
|
return tr("notes");
|
|
|
|
}
|
|
|
|
|
2019-01-27 21:08:13 +00:00
|
|
|
DiveField EditNotes::fieldId() const
|
|
|
|
{
|
|
|
|
return DiveField::NOTES;
|
|
|
|
}
|
|
|
|
|
2019-01-28 20:42:59 +00:00
|
|
|
// ***** Suit *****
|
|
|
|
void EditSuit::set(struct dive *d, QString s) const
|
|
|
|
{
|
|
|
|
free(d->suit);
|
|
|
|
d->suit = strdup(qPrintable(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString EditSuit::data(struct dive *d) const
|
|
|
|
{
|
|
|
|
return QString(d->suit);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString EditSuit::fieldName() const
|
|
|
|
{
|
|
|
|
return tr("suit");
|
|
|
|
}
|
|
|
|
|
|
|
|
DiveField EditSuit::fieldId() const
|
|
|
|
{
|
|
|
|
return DiveField::SUIT;
|
|
|
|
}
|
|
|
|
|
2019-01-28 21:35:07 +00:00
|
|
|
// ***** Rating *****
|
|
|
|
void EditRating::set(struct dive *d, int value) const
|
|
|
|
{
|
|
|
|
d->rating = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int EditRating::data(struct dive *d) const
|
|
|
|
{
|
|
|
|
return d->rating;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString EditRating::fieldName() const
|
|
|
|
{
|
|
|
|
return tr("rating");
|
|
|
|
}
|
|
|
|
|
|
|
|
DiveField EditRating::fieldId() const
|
|
|
|
{
|
|
|
|
return DiveField::RATING;
|
|
|
|
}
|
|
|
|
|
2019-01-30 21:13:24 +00:00
|
|
|
// ***** Visibility *****
|
2019-01-28 21:35:07 +00:00
|
|
|
void EditVisibility::set(struct dive *d, int value) const
|
|
|
|
{
|
|
|
|
d->visibility = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int EditVisibility::data(struct dive *d) const
|
|
|
|
{
|
|
|
|
return d->visibility;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString EditVisibility::fieldName() const
|
|
|
|
{
|
|
|
|
return tr("visibility");
|
|
|
|
}
|
|
|
|
|
|
|
|
DiveField EditVisibility::fieldId() const
|
|
|
|
{
|
|
|
|
return DiveField::VISIBILITY;
|
|
|
|
}
|
|
|
|
|
2019-01-30 21:13:24 +00: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
|
|
|
|
{
|
|
|
|
return tr("air temperature");
|
|
|
|
}
|
|
|
|
|
|
|
|
DiveField EditAirTemp::fieldId() const
|
|
|
|
{
|
|
|
|
return DiveField::AIR_TEMP;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***** Water Temperature *****
|
|
|
|
void EditWaterTemp::set(struct dive *d, int value) const
|
|
|
|
{
|
|
|
|
d->watertemp.mkelvin = value > 0 ? (uint32_t)value : 0u;
|
|
|
|
}
|
|
|
|
|
|
|
|
int EditWaterTemp::data(struct dive *d) const
|
|
|
|
{
|
|
|
|
return (int)d->watertemp.mkelvin;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString EditWaterTemp::fieldName() const
|
|
|
|
{
|
|
|
|
return tr("water temperature");
|
|
|
|
}
|
|
|
|
|
|
|
|
DiveField EditWaterTemp::fieldId() const
|
|
|
|
{
|
|
|
|
return DiveField::WATER_TEMP;
|
|
|
|
}
|
|
|
|
|
2019-03-20 20:46:58 +00: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
|
|
|
|
{
|
|
|
|
return tr("dive site");
|
|
|
|
}
|
|
|
|
|
|
|
|
DiveField EditDiveSite::fieldId() const
|
|
|
|
{
|
|
|
|
return DiveField::DIVESITE;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dive_site *createDiveSite(const QString &name, struct dive_site *old)
|
|
|
|
{
|
|
|
|
struct dive_site *ds = alloc_dive_site();
|
|
|
|
if (old) {
|
|
|
|
copy_dive_site(old, ds);
|
|
|
|
free(ds->name); // Free name, as we will overwrite it with our own version
|
|
|
|
}
|
|
|
|
ds->name = copy_qstring(name);
|
|
|
|
return ds;
|
|
|
|
}
|
|
|
|
|
|
|
|
EditDiveSiteNew::EditDiveSiteNew(const QVector<dive *> &dives, const QString &newName, struct dive_site *oldValue) :
|
|
|
|
EditDiveSite(dives, createDiveSite(newName, oldValue), oldValue),
|
|
|
|
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 17:35:27 +00: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.
|
|
|
|
EditMode::EditMode(const QVector<dive *> &dives, int indexIn, int newValue, int oldValue)
|
|
|
|
: EditBase(dives, newValue, oldValue), index(indexIn)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
return tr("dive mode");
|
|
|
|
}
|
|
|
|
|
|
|
|
DiveField EditMode::fieldId() const
|
|
|
|
{
|
|
|
|
return DiveField::MODE;
|
|
|
|
}
|
|
|
|
|
2019-01-25 17:27:31 +00:00
|
|
|
} // namespace Command
|