// SPDX-License-Identifier: GPL-2.0 #include "command_edit.h" #include "core/divelist.h" namespace Command { template EditBase::EditBase(const QVector &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 bool EditBase::workToBeDone() { std::vector 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 void EditBase::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); emit diveListNotifier.divesEdited(QVector::fromStdVector(dives), fieldId()); 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::EditBase(const QVector &dives, QString oldValue, QString newValue); template EditBase::EditBase(const QVector &dives, int oldValue, int newValue); // Undo and redo do the same as just the stored value is exchanged template void EditBase::redo() { undo(); } // Implementation of virtual functions // ***** Notes ***** 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"); } DiveField EditNotes::fieldId() const { return DiveField::NOTES; } // ***** 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; } // ***** 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; } // ***** Visibility **** 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; } // ***** 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 &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; } } // namespace Command