summaryrefslogtreecommitdiffstats
path: root/desktop-widgets/command_edit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'desktop-widgets/command_edit.cpp')
-rw-r--r--desktop-widgets/command_edit.cpp848
1 files changed, 0 insertions, 848 deletions
diff --git a/desktop-widgets/command_edit.cpp b/desktop-widgets/command_edit.cpp
deleted file mode 100644
index 638bfb792..000000000
--- a/desktop-widgets/command_edit.cpp
+++ /dev/null
@@ -1,848 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include "command_edit.h"
-#include "command_private.h"
-#include "core/divelist.h"
-#include "core/qthelper.h" // for copy_qstring
-#include "core/subsurface-string.h"
-#include "core/tag.h"
-
-namespace Command {
-
-static std::vector<dive *> getDives(bool currentDiveOnly)
-{
- 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;
-}
-
-EditDivesBase::EditDivesBase(bool currentDiveOnly) :
- dives(getDives(currentDiveOnly)),
- selectedDives(getDiveSelection()),
- current(current_dive)
-{
-}
-
-EditDivesBase::EditDivesBase(dive *d) :
- dives({ d }),
- selectedDives(getDiveSelection()),
- current(current_dive)
-{
-}
-
-int EditDivesBase::numDives() const
-{
- return dives.size();
-}
-
-template<typename T>
-EditBase<T>::EditBase(T newValue, bool currentDiveOnly) :
- EditDivesBase(currentDiveOnly),
- value(std::move(newValue))
-{
-}
-
-template<typename T>
-EditBase<T>::EditBase(T newValue, dive *d) :
- EditDivesBase(d),
- value(std::move(newValue))
-{
-}
-
-// 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()
-{
- // 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;
-
- 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 parentheses for %n = 1
- setText(tr("Edit %1 (%n dive(s))", "", num_dives).arg(fieldName()));
-
- return num_dives > 0;
-}
-
-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);
-
- // Send signals.
- DiveField id = fieldId();
- emit diveListNotifier.divesChanged(QVector<dive *>::fromStdVector(dives), id);
-
- setSelection(selectedDives, current);
-}
-
-// 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(QString newValue, bool currentDiveOnly);
-template
-EditBase<int>::EditBase(int newValue, bool currentDiveOnly);
-template
-EditBase<struct dive_site *>::EditBase(struct dive_site *newValue, bool currentDiveOnly);
-
-// Undo and redo do the same as just the stored value is exchanged
-template<typename T>
-void EditBase<T>::redo()
-{
- // 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();
-}
-
-// 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;
-}
-
-// ***** 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;
-
- // re-populate the temperatures - easiest way to do this is by calling fixup_dive
- fixup_dive(d);
-}
-
-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;
-}
-
-// ***** 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
-{
- return tr("Atm. pressure");
-}
-
-DiveField EditAtmPress::fieldId() const
-{
- return DiveField::ATM_PRESS;
-}
-
-// ***** 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
-{
- return tr("duration");
-}
-
-DiveField EditDuration::fieldId() const
-{
- return DiveField::DURATION;
-}
-
-// ***** 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
-{
- return tr("depth");
-}
-
-DiveField EditDepth::fieldId() const
-{
- return DiveField::DEPTH;
-}
-
-// ***** 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 *ds = alloc_dive_site();
- struct dive_site *old = current_dive ? current_dive->dive_site : nullptr;
- if (old) {
- copy_dive_site(old, ds);
- free(ds->name); // Free name, as we will overwrite it with our own version
- }
-
- // 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;
- }
-
- ds->name = copy_qstring(name);
- return ds;
-}
-
-EditDiveSiteNew::EditDiveSiteNew(const QString &newName, bool currentDiveOnly) :
- EditDiveSite(createDiveSite(newName), currentDiveOnly),
- 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();
-}
-
-// ***** 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(int indexIn, int newValue, bool currentDiveOnly)
- : EditBase(newValue, currentDiveOnly), 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;
-}
-
-// ***** Number *****
-void EditNumber::set(struct dive *d, int number) const
-{
- d->number = number;
-}
-
-int EditNumber::data(struct dive *d) const
-{
- return d->number;
-}
-
-QString EditNumber::fieldName() const
-{
- return tr("number");
-}
-
-DiveField EditNumber::fieldId() const
-{
- return DiveField::NR;
-}
-
-
-// ***** Tag based commands *****
-EditTagsBase::EditTagsBase(const QStringList &newListIn, bool currentDiveOnly) :
- EditDivesBase(currentDiveOnly),
- newList(newListIn)
-{
-}
-
-// 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
-
- // If there is no current dive, bail.
- if (!current)
- return false;
-
- // Calculate tags to add and tags to remove
- QStringList oldList = data(current);
- 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();
- if (num_dives > 0)
- //: remove the part in parentheses for %n = 1
- setText(tr("Edit %1 (%n dive(s))", "", num_dives).arg(fieldName()));
-
- return num_dives != 0;
-}
-
-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);
- }
- invalidate_dive_cache(d); // Ensure that dive is written in git_save()
- set(d, tags);
- }
-
- std::swap(tagsToAdd, tagsToRemove);
-
- // Send signals.
- DiveField id = fieldId();
- emit diveListNotifier.divesChanged(QVector<dive *>::fromStdVector(dives), id);
-
- setSelection(selectedDives, current);
-}
-
-// 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
-{
- return tr("tags");
-}
-
-DiveField EditTags::fieldId() const
-{
- return DiveField::TAGS;
-}
-
-// String list helper
-static QStringList stringToList(const QString &s)
-{
- QStringList res = s.split(",", QString::SkipEmptyParts);
- for (QString &str: res)
- str = str.trimmed();
- return res;
-}
-
-// ***** 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
-{
- return tr("buddies");
-}
-
-DiveField EditBuddies::fieldId() const
-{
- return DiveField::BUDDY;
-}
-
-// ***** 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
-{
- return tr("dive master");
-}
-
-DiveField EditDiveMaster::fieldId() const
-{
- return DiveField::DIVEMASTER;
-}
-
-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),
- tags(nullptr)
-{
- memset(&cylinders, 0, sizeof(cylinders));
- memset(&weightsystems, 0, sizeof(weightsystems));
- 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;
- if (what.divesite)
- divesite = data->dive_site;
- if (what.tags)
- tags = taglist_copy(data->tag_list);
- if (what.cylinders)
- copy_cylinders(&data->cylinders, &cylinders);
- if (what.weights)
- copy_weights(&data->weightsystems, &weightsystems);
-}
-
-PasteState::~PasteState()
-{
- taglist_free(tags);
- clear_cylinder_table(&cylinders);
- clear_weightsystem_table(&weightsystems);
- free(weightsystems.weightsystems);
-}
-
-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);
- if (what.divesite)
- std::swap(divesite, d->dive_site);
- if (what.tags)
- std::swap(tags, d->tag_list);
- if (what.cylinders)
- std::swap(cylinders, d->cylinders);
- if (what.weights)
- std::swap(weightsystems, d->weightsystems);
-}
-
-// ***** Paste *****
-PasteDives::PasteDives(const dive *data, dive_components whatIn) : what(whatIn),
- current(current_dive)
-{
- std::vector<dive *> selection = getDiveSelection();
- dives.reserve(selection.size());
- for (dive *d: selection)
- dives.emplace_back(d, data, what);
-
- setText(tr("Paste onto %n dive(s)", "", dives.size()));
-}
-
-bool PasteDives::workToBeDone()
-{
- return !dives.empty();
-}
-
-void PasteDives::undo()
-{
- QVector<dive *> divesToNotify; // Remember dives so that we can send signals later
- 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.
- 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;
- fields.divesite = what.divesite;
- fields.tags = what.tags;
- emit diveListNotifier.divesChanged(divesToNotify, fields);
- if (what.cylinders)
- emit diveListNotifier.cylindersReset(divesToNotify);
- if (what.weights)
- emit diveListNotifier.weightsystemsReset(divesToNotify);
-}
-
-// Redo and undo do the same
-void PasteDives::redo()
-{
- undo();
-}
-
-// ***** Paste *****
-ReplanDive::ReplanDive(dive *source) : d(current_dive),
- dc({ 0 }),
- notes(nullptr)
-{
- memset(&cylinders, 0, sizeof(cylinders));
- if (!d)
- return;
-
- 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.
- std::swap(source->cylinders, cylinders);
- std::swap(source->dc, dc);
-
- setText(tr("Replan dive"));
-}
-
-ReplanDive::~ReplanDive()
-{
- clear_cylinder_table(&cylinders);
- 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);
- std::swap(d->cylinders, cylinders);
- 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 };
- // 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);
- emit diveListNotifier.divesChanged(divesToNotify, DiveField::DATETIME | DiveField::DURATION | DiveField::DEPTH | DiveField::MODE |
- DiveField::NOTES | DiveField::SALINITY | DiveField::ATM_PRESS);
-}
-
-// Redo and undo do the same
-void ReplanDive::redo()
-{
- undo();
-}
-
-} // namespace Command