mirror of
https://github.com/subsurface/subsurface.git
synced 2025-01-31 22:03:23 +00:00
fix copy/paste of dive-site
The copy/pasting of dive-sites was fundamentally broken in at least two ways: 1) The dive-site pointer in struct dive was simply overwritten, which breaks internal consistency. Also, no dive-site changed signals where sent. 2) The copied dive-site was stored as a pointer in a struct dive. Thus, the user could copy a dive, then delete the dive-site and paste. This would lead to a dangling pointer and ultimately crash the application. Fix this by storing the UUID of the dive-site, not a pointer. To do that, don't store a copy of the dive, but collect all the data in a `dive_paste_data` structure. If the dive site has been deleted on paste, do nothing. Send the appropriate signals on pasting. The mobile version had an additional bug: It kept a pointer to the dive to be copied, which might become stale by undo. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
48b4308a7d
commit
152e6966c9
17 changed files with 359 additions and 425 deletions
|
@ -267,9 +267,9 @@ int editDiveGuide(const QStringList &newList, bool currentDiveOnly)
|
|||
return execute_edit(new EditDiveGuide(newList, currentDiveOnly));
|
||||
}
|
||||
|
||||
void pasteDives(const dive *d, dive_components what)
|
||||
void pasteDives(const dive_paste_data &data)
|
||||
{
|
||||
execute(new PasteDives(d, what));
|
||||
execute(new PasteDives(data));
|
||||
}
|
||||
|
||||
void replanDive(dive *d)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
struct divecomputer;
|
||||
struct divelog;
|
||||
struct dive_components;
|
||||
struct dive_paste_data;
|
||||
struct dive_site;
|
||||
struct dive_trip;
|
||||
struct event;
|
||||
|
@ -95,7 +96,7 @@ int editDiveSiteNew(const QString &newName, bool currentDiveOnly);
|
|||
int editTags(const QStringList &newList, bool currentDiveOnly);
|
||||
int editBuddies(const QStringList &newList, bool currentDiveOnly);
|
||||
int editDiveGuide(const QStringList &newList, bool currentDiveOnly);
|
||||
void pasteDives(const dive *d, dive_components what);
|
||||
void pasteDives(const dive_paste_data &data);
|
||||
enum class EditProfileType {
|
||||
ADD,
|
||||
REMOVE,
|
||||
|
|
|
@ -613,41 +613,51 @@ QString EditDiveGuide::fieldName() const
|
|||
return Command::Base::tr("dive guide");
|
||||
}
|
||||
|
||||
PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dIn)
|
||||
template <typename T>
|
||||
ptrdiff_t comp_ptr(T *v1, T *v2)
|
||||
{
|
||||
if (what.notes)
|
||||
notes = data->notes;
|
||||
if (what.diveguide)
|
||||
diveguide = data->diveguide;
|
||||
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.wavesize)
|
||||
wavesize = data->wavesize;
|
||||
if (what.current)
|
||||
current = data->current;
|
||||
if (what.surge)
|
||||
surge = data->surge;
|
||||
if (what.chill)
|
||||
chill = data->chill;
|
||||
if (what.divesite)
|
||||
divesite = data->dive_site;
|
||||
if (what.tags)
|
||||
tags = data->tags;
|
||||
if (what.cylinders) {
|
||||
cylinders = data->cylinders;
|
||||
return v1 - v2;
|
||||
}
|
||||
|
||||
PasteState::PasteState(dive &d, const dive_paste_data &data, std::vector<dive_site *> &dive_sites_changed) : d(d)
|
||||
{
|
||||
notes = data.notes;
|
||||
diveguide = data.diveguide;
|
||||
buddy = data.buddy;
|
||||
suit = data.suit;
|
||||
rating = data.rating;
|
||||
visibility = data.visibility;
|
||||
wavesize = data.wavesize;
|
||||
current = data.current;
|
||||
surge = data.surge;
|
||||
chill = data.chill;
|
||||
if (data.divesite.has_value()) {
|
||||
if (data.divesite) {
|
||||
// In the undo system, we can turn the uuid into a pointer,
|
||||
// because everything is serialized.
|
||||
dive_site *ds = divelog.sites.get_by_uuid(*data.divesite);
|
||||
if (ds)
|
||||
divesite = ds;
|
||||
} else {
|
||||
divesite = nullptr;
|
||||
}
|
||||
}
|
||||
if (divesite.has_value() && *divesite != d.dive_site) {
|
||||
if (d.dive_site)
|
||||
range_insert_sorted_unique(dive_sites_changed, d.dive_site, comp_ptr<dive_site>); // Use <=> once on C++20
|
||||
if (*divesite)
|
||||
range_insert_sorted_unique(dive_sites_changed, *divesite, comp_ptr<dive_site>); // Use <=> once on C++20
|
||||
}
|
||||
tags = data.tags;
|
||||
if (data.cylinders.has_value()) {
|
||||
cylinders = data.cylinders;
|
||||
// Paste cylinders is "special":
|
||||
// 1) For cylinders that exist in the destination dive we keep the gas-mix and pressures.
|
||||
// 2) For cylinders that do not yet exist in the destination dive, we set the pressures to 0, i.e. unset.
|
||||
// Moreover, for these we set the manually_added flag, because they weren't downloaded from a DC.
|
||||
for (size_t i = 0; i < d->cylinders.size() && i < cylinders.size(); ++i) {
|
||||
const cylinder_t &src = d->cylinders[i];
|
||||
cylinder_t &dst = cylinders[i];
|
||||
for (size_t i = 0; i < data.cylinders->size() && i < cylinders->size(); ++i) {
|
||||
const cylinder_t &src = (*data.cylinders)[i];
|
||||
cylinder_t &dst = (*cylinders)[i];
|
||||
dst.gasmix = src.gasmix;
|
||||
dst.start = src.start;
|
||||
dst.end = src.end;
|
||||
|
@ -661,8 +671,8 @@ PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dI
|
|||
dst.bestmix_o2 = src.bestmix_o2;
|
||||
dst.bestmix_he = src.bestmix_he;
|
||||
}
|
||||
for (size_t i = d->cylinders.size(); i < cylinders.size(); ++i) {
|
||||
cylinder_t &cyl = cylinders[i];
|
||||
for (size_t i = data.cylinders->size(); i < cylinders->size(); ++i) {
|
||||
cylinder_t &cyl = (*cylinders)[i];
|
||||
cyl.start.mbar = 0;
|
||||
cyl.end.mbar = 0;
|
||||
cyl.sample_start.mbar = 0;
|
||||
|
@ -670,61 +680,62 @@ PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dI
|
|||
cyl.manually_added = true;
|
||||
}
|
||||
}
|
||||
if (what.weights)
|
||||
weightsystems = data->weightsystems;
|
||||
if (what.number)
|
||||
number = data->number;
|
||||
if (what.when)
|
||||
when = data->when;
|
||||
weightsystems = data.weights;
|
||||
number = data.number;
|
||||
when = data.when;
|
||||
}
|
||||
|
||||
PasteState::~PasteState()
|
||||
{
|
||||
}
|
||||
|
||||
void PasteState::swap(dive_components what)
|
||||
void PasteState::swap()
|
||||
{
|
||||
if (what.notes)
|
||||
std::swap(notes, d->notes);
|
||||
if (what.diveguide)
|
||||
std::swap(diveguide, d->diveguide);
|
||||
if (what.buddy)
|
||||
std::swap(buddy, d->buddy);
|
||||
if (what.suit)
|
||||
std::swap(suit, d->suit);
|
||||
if (what.rating)
|
||||
std::swap(rating, d->rating);
|
||||
if (what.visibility)
|
||||
std::swap(visibility, d->visibility);
|
||||
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);
|
||||
if (what.divesite)
|
||||
std::swap(divesite, d->dive_site);
|
||||
if (what.tags)
|
||||
std::swap(tags, d->tags);
|
||||
if (what.cylinders)
|
||||
std::swap(cylinders, d->cylinders);
|
||||
if (what.weights)
|
||||
std::swap(weightsystems, d->weightsystems);
|
||||
if (what.number)
|
||||
std::swap(number, d->number);
|
||||
if (what.when)
|
||||
std::swap(when, d->when);
|
||||
if (notes.has_value())
|
||||
std::swap(*notes, d.notes);
|
||||
if (diveguide.has_value())
|
||||
std::swap(*diveguide, d.diveguide);
|
||||
if (buddy.has_value())
|
||||
std::swap(*buddy, d.buddy);
|
||||
if (suit.has_value())
|
||||
std::swap(*suit, d.suit);
|
||||
if (rating.has_value())
|
||||
std::swap(*rating, d.rating);
|
||||
if (visibility.has_value())
|
||||
std::swap(*visibility, d.visibility);
|
||||
if (wavesize.has_value())
|
||||
std::swap(*wavesize, d.wavesize);
|
||||
if (current.has_value())
|
||||
std::swap(*current, d.current);
|
||||
if (surge.has_value())
|
||||
std::swap(*surge, d.surge);
|
||||
if (chill.has_value())
|
||||
std::swap(*chill, d.chill);
|
||||
if (divesite.has_value() && *divesite != d.dive_site) {
|
||||
auto old_ds = unregister_dive_from_dive_site(&d);
|
||||
if (*divesite)
|
||||
(*divesite)->add_dive(&d);
|
||||
divesite = old_ds;
|
||||
}
|
||||
if (tags.has_value())
|
||||
std::swap(*tags, d.tags);
|
||||
if (cylinders.has_value())
|
||||
std::swap(*cylinders, d.cylinders);
|
||||
if (weightsystems.has_value())
|
||||
std::swap(*weightsystems, d.weightsystems);
|
||||
if (number.has_value())
|
||||
std::swap(*number, d.number);
|
||||
if (when.has_value())
|
||||
std::swap(*when, d.when);
|
||||
}
|
||||
|
||||
// ***** Paste *****
|
||||
PasteDives::PasteDives(const dive *data, dive_components whatIn) : what(whatIn)
|
||||
PasteDives::PasteDives(const dive_paste_data &data)
|
||||
{
|
||||
std::vector<dive *> selection = getDiveSelection();
|
||||
dives.reserve(selection.size());
|
||||
for (dive *d: selection)
|
||||
dives.emplace_back(d, data, what);
|
||||
dives.emplace_back(*d, data, dive_sites_changed);
|
||||
|
||||
setText(QStringLiteral("%1 [%2]").arg(Command::Base::tr("Paste onto %n dive(s)", "", dives.size())).arg(getListOfDives(selection)));
|
||||
}
|
||||
|
@ -739,32 +750,35 @@ 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);
|
||||
state.d->invalidate_cache(); // Ensure that dive is written in git_save()
|
||||
divesToNotify.push_back(&state.d);
|
||||
state.swap();
|
||||
state.d.invalidate_cache(); // Ensure that dive is written in git_save()
|
||||
}
|
||||
|
||||
// Send signals.
|
||||
// Send signals. We use the first data item to determine what changed
|
||||
DiveField fields(DiveField::NONE);
|
||||
fields.notes = what.notes;
|
||||
fields.diveguide = what.diveguide;
|
||||
fields.buddy = what.buddy;
|
||||
fields.suit = what.suit;
|
||||
fields.rating = what.rating;
|
||||
fields.visibility = what.visibility;
|
||||
fields.wavesize = what.wavesize;
|
||||
fields.current = what.current;
|
||||
fields.surge = what.surge;
|
||||
fields.chill = what.chill;
|
||||
fields.divesite = what.divesite;
|
||||
fields.tags = what.tags;
|
||||
fields.datetime = what.when;
|
||||
fields.nr = what.number;
|
||||
const PasteState &state = dives[0];
|
||||
fields.notes = state.notes.has_value();
|
||||
fields.diveguide = state.diveguide.has_value();
|
||||
fields.buddy = state.buddy.has_value();
|
||||
fields.suit = state.suit.has_value();
|
||||
fields.rating = state.rating.has_value();
|
||||
fields.visibility = state.visibility.has_value();
|
||||
fields.wavesize = state.wavesize.has_value();
|
||||
fields.current = state.current.has_value();
|
||||
fields.surge = state.surge.has_value();
|
||||
fields.chill = state.chill.has_value();
|
||||
fields.divesite = !dive_sites_changed.empty();
|
||||
fields.tags = state.tags.has_value();
|
||||
fields.datetime = state.when.has_value();
|
||||
fields.nr = state.number.has_value();
|
||||
emit diveListNotifier.divesChanged(divesToNotify, fields);
|
||||
if (what.cylinders)
|
||||
if (state.cylinders.has_value())
|
||||
emit diveListNotifier.cylindersReset(divesToNotify);
|
||||
if (what.weights)
|
||||
if (state.weightsystems.has_value())
|
||||
emit diveListNotifier.weightsystemsReset(divesToNotify);
|
||||
for (dive_site *ds: dive_sites_changed)
|
||||
emit diveListNotifier.diveSiteDivesChanged(ds);
|
||||
}
|
||||
|
||||
// Redo and undo do the same
|
||||
|
|
|
@ -287,34 +287,35 @@ public:
|
|||
|
||||
// Fields we have to remember to undo paste
|
||||
struct PasteState {
|
||||
dive *d;
|
||||
dive_site *divesite;
|
||||
std::string notes;
|
||||
std::string diveguide;
|
||||
std::string buddy;
|
||||
std::string suit;
|
||||
int rating;
|
||||
int wavesize;
|
||||
int visibility;
|
||||
int current;
|
||||
int surge;
|
||||
int chill;
|
||||
tag_list tags;
|
||||
cylinder_table cylinders;
|
||||
weightsystem_table weightsystems;
|
||||
int number;
|
||||
timestamp_t when;
|
||||
dive &d;
|
||||
std::optional<dive_site *> divesite;
|
||||
std::optional<std::string> notes;
|
||||
std::optional<std::string> diveguide;
|
||||
std::optional<std::string> buddy;
|
||||
std::optional<std::string> suit;
|
||||
std::optional<int> rating;
|
||||
std::optional<int> wavesize;
|
||||
std::optional<int> visibility;
|
||||
std::optional<int> current;
|
||||
std::optional<int> surge;
|
||||
std::optional<int> chill;
|
||||
std::optional<tag_list> tags;
|
||||
std::optional<cylinder_table> cylinders;
|
||||
std::optional<weightsystem_table> weightsystems;
|
||||
std::optional<int> number;
|
||||
std::optional<timestamp_t> when;
|
||||
|
||||
PasteState(dive *d, const dive *data, dive_components what); // Read data from dive data for dive d
|
||||
PasteState(dive &d, const dive_paste_data &data, std::vector<dive_site *> &changed_dive_sites);
|
||||
~PasteState();
|
||||
void swap(dive_components what); // Exchange values here and in dive
|
||||
void swap(); // Exchange values here and in dive
|
||||
};
|
||||
|
||||
class PasteDives : public Base {
|
||||
dive_components what;
|
||||
dive_paste_data data;
|
||||
std::vector<PasteState> dives;
|
||||
std::vector<dive_site *> dive_sites_changed;
|
||||
public:
|
||||
PasteDives(const dive *d, dive_components what);
|
||||
PasteDives(const dive_paste_data &data);
|
||||
private:
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
|
|
@ -203,40 +203,6 @@ void copy_dive(const struct dive *s, struct dive *d)
|
|||
d->invalidate_cache();
|
||||
}
|
||||
|
||||
#define CONDITIONAL_COPY_STRING(_component) \
|
||||
if (what._component) \
|
||||
d->_component = s->_component
|
||||
|
||||
// copy elements, depending on bits in what that are set
|
||||
void selective_copy_dive(const struct dive *s, struct dive *d, struct dive_components what, bool clear)
|
||||
{
|
||||
if (clear)
|
||||
d->clear();
|
||||
CONDITIONAL_COPY_STRING(notes);
|
||||
CONDITIONAL_COPY_STRING(diveguide);
|
||||
CONDITIONAL_COPY_STRING(buddy);
|
||||
CONDITIONAL_COPY_STRING(suit);
|
||||
if (what.rating)
|
||||
d->rating = s->rating;
|
||||
if (what.visibility)
|
||||
d->visibility = s->visibility;
|
||||
if (what.divesite) {
|
||||
unregister_dive_from_dive_site(d);
|
||||
s->dive_site->add_dive(d);
|
||||
}
|
||||
if (what.tags)
|
||||
d->tags = s->tags;
|
||||
if (what.cylinders)
|
||||
copy_cylinder_types(s, d);
|
||||
if (what.weights)
|
||||
d->weightsystems = s->weightsystems;
|
||||
if (what.number)
|
||||
d->number = s->number;
|
||||
if (what.when)
|
||||
d->when = s->when;
|
||||
}
|
||||
#undef CONDITIONAL_COPY_STRING
|
||||
|
||||
/* copies all events from the given dive computer before a given time
|
||||
this is used when editing a dive in the planner to preserve the events
|
||||
of the old dive */
|
||||
|
|
39
core/dive.h
39
core/dive.h
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -146,24 +147,25 @@ struct dive_or_trip {
|
|||
extern void cylinder_renumber(struct dive &dive, int mapping[]);
|
||||
extern int same_gasmix_cylinder(const cylinder_t &cyl, int cylid, const struct dive *dive, bool check_unused);
|
||||
|
||||
/* when selectively copying dive information, which parts should be copied? */
|
||||
struct dive_components {
|
||||
unsigned int divesite : 1;
|
||||
unsigned int notes : 1;
|
||||
unsigned int diveguide : 1;
|
||||
unsigned int buddy : 1;
|
||||
unsigned int suit : 1;
|
||||
unsigned int rating : 1;
|
||||
unsigned int visibility : 1;
|
||||
unsigned int wavesize : 1;
|
||||
unsigned int current : 1;
|
||||
unsigned int surge : 1;
|
||||
unsigned int chill : 1;
|
||||
unsigned int tags : 1;
|
||||
unsigned int cylinders : 1;
|
||||
unsigned int weights : 1;
|
||||
unsigned int number : 1;
|
||||
unsigned int when : 1;
|
||||
/* Data stored when copying a dive */
|
||||
struct dive_paste_data {
|
||||
std::optional<uint32_t> divesite; // We save the uuid not a pointer, because the
|
||||
// user might copy and then delete the dive site.
|
||||
std::optional<std::string> notes;
|
||||
std::optional<std::string> diveguide;
|
||||
std::optional<std::string> buddy;
|
||||
std::optional<std::string> suit;
|
||||
std::optional<int> rating;
|
||||
std::optional<int> visibility;
|
||||
std::optional<int> wavesize;
|
||||
std::optional<int> current;
|
||||
std::optional<int> surge;
|
||||
std::optional<int> chill;
|
||||
std::optional<tag_list> tags;
|
||||
std::optional<cylinder_table> cylinders;
|
||||
std::optional<weightsystem_table> weights;
|
||||
std::optional<int> number;
|
||||
std::optional<timestamp_t> when;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<dive> clone_make_first_dc(const struct dive &d, int dc_number);
|
||||
|
@ -179,7 +181,6 @@ struct membuffer;
|
|||
extern void save_one_dive_to_mb(struct membuffer *b, const struct dive &dive, bool anonymize);
|
||||
|
||||
extern void copy_dive(const struct dive *s, struct dive *d);
|
||||
extern void selective_copy_dive(const struct dive *s, struct dive *d, struct dive_components what, bool clear);
|
||||
|
||||
extern int legacy_format_o2pressures(const struct dive *dive, const struct divecomputer *dc);
|
||||
|
||||
|
|
12
core/range.h
12
core/range.h
|
@ -181,13 +181,23 @@ bool range_contains(const Range &v, const Element &item)
|
|||
|
||||
// Insert into an already sorted range
|
||||
template<typename Range, typename Element, typename Comp>
|
||||
void range_insert_sorted(Range &v, Element &item, Comp &comp)
|
||||
void range_insert_sorted(Range &v, Element &item, Comp comp)
|
||||
{
|
||||
auto it = std::lower_bound(std::begin(v), std::end(v), item,
|
||||
[&comp](auto &a, auto &b) { return comp(a, b) < 0; });
|
||||
v.insert(it, std::move(item));
|
||||
}
|
||||
|
||||
// Insert into an already sorted range, but don't add an item twice
|
||||
template<typename Range, typename Element, typename Comp>
|
||||
void range_insert_sorted_unique(Range &v, Element &item, Comp comp)
|
||||
{
|
||||
auto it = std::lower_bound(std::begin(v), std::end(v), item,
|
||||
[&comp](auto &a, auto &b) { return comp(a, b) < 0; });
|
||||
if (it == std::end(v) || comp(item, *it) != 0)
|
||||
v.insert(it, std::move(item));
|
||||
}
|
||||
|
||||
template<typename Range, typename Element>
|
||||
void range_remove(Range &v, const Element &item)
|
||||
{
|
||||
|
|
|
@ -68,6 +68,8 @@ set(SUBSURFACE_INTERFACE
|
|||
about.h
|
||||
configuredivecomputerdialog.cpp
|
||||
configuredivecomputerdialog.h
|
||||
divecomponentselection.cpp
|
||||
divecomponentselection.h
|
||||
divelistview.cpp
|
||||
divelistview.h
|
||||
divelogexportdialog.cpp
|
||||
|
|
104
desktop-widgets/divecomponentselection.cpp
Normal file
104
desktop-widgets/divecomponentselection.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "divecomponentselection.h"
|
||||
#include "core/dive.h"
|
||||
#include "core/divesite.h"
|
||||
#include "core/format.h"
|
||||
#include "core/qthelper.h" // for get_dive_date_string()
|
||||
#include "core/selection.h"
|
||||
#include "core/string-format.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QShortcut>
|
||||
|
||||
template <typename T>
|
||||
static void assign_paste_data(QCheckBox &checkbox, const T &src, std::optional<T> &dest)
|
||||
{
|
||||
if (checkbox.isChecked())
|
||||
dest = src;
|
||||
else
|
||||
dest = {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void set_checked(QCheckBox &checkbox, const std::optional<T> &v)
|
||||
{
|
||||
checkbox.setChecked(v.has_value());
|
||||
}
|
||||
|
||||
DiveComponentSelection::DiveComponentSelection(dive_paste_data &data, QWidget *parent) :
|
||||
QDialog(parent), data(data)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
set_checked(*ui.divesite, data.divesite);
|
||||
set_checked(*ui.diveguide, data.diveguide);
|
||||
set_checked(*ui.buddy, data.buddy);
|
||||
set_checked(*ui.rating, data.rating);
|
||||
set_checked(*ui.visibility, data.visibility);
|
||||
set_checked(*ui.notes, data.notes);
|
||||
set_checked(*ui.suit, data.suit);
|
||||
set_checked(*ui.tags, data.tags);
|
||||
set_checked(*ui.cylinders, data.cylinders);
|
||||
set_checked(*ui.weights, data.weights);
|
||||
set_checked(*ui.number, data.number);
|
||||
set_checked(*ui.when, data.when);
|
||||
connect(ui.buttonBox, &QDialogButtonBox::clicked, this, &DiveComponentSelection::buttonClicked);
|
||||
QShortcut *close = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), this);
|
||||
connect(close, &QShortcut::activated, this, &DiveComponentSelection::close);
|
||||
QShortcut *quit = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this);
|
||||
connect(quit, &QShortcut::activated, parent, &QWidget::close);
|
||||
}
|
||||
|
||||
void DiveComponentSelection::buttonClicked(QAbstractButton *button)
|
||||
{
|
||||
if (current_dive && ui.buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) {
|
||||
// Divesite is special, as we store the uuid not the pointer, since the
|
||||
// user may delete the divesite after copying.
|
||||
assign_paste_data(*ui.divesite, current_dive->dive_site ? current_dive->dive_site->uuid : uint32_t(), data.divesite);
|
||||
assign_paste_data(*ui.diveguide, current_dive->diveguide, data.diveguide);
|
||||
assign_paste_data(*ui.buddy, current_dive->buddy, data.buddy);
|
||||
assign_paste_data(*ui.rating, current_dive->rating, data.rating);
|
||||
assign_paste_data(*ui.visibility, current_dive->visibility, data.visibility);
|
||||
assign_paste_data(*ui.notes, current_dive->notes, data.notes);
|
||||
assign_paste_data(*ui.suit, current_dive->suit, data.suit);
|
||||
assign_paste_data(*ui.tags, current_dive->tags, data.tags);
|
||||
assign_paste_data(*ui.cylinders, current_dive->cylinders, data.cylinders);
|
||||
assign_paste_data(*ui.weights, current_dive->weightsystems, data.weights);
|
||||
assign_paste_data(*ui.number, current_dive->number, data.number);
|
||||
assign_paste_data(*ui.when, current_dive->when, data.when);
|
||||
|
||||
std::string text;
|
||||
if (data.divesite && current_dive->dive_site)
|
||||
text += tr("Dive site: ").toStdString() + current_dive->dive_site->name + '\n';
|
||||
if (data.diveguide)
|
||||
text += tr("Dive guide: ").toStdString() + current_dive->diveguide + '\n';
|
||||
if (data.buddy)
|
||||
text += tr("Buddy: ").toStdString() + current_dive->buddy + '\n';
|
||||
if (data.rating)
|
||||
text += tr("Rating: ").toStdString() + std::string(current_dive->rating, '*') + '\n';
|
||||
if (data.visibility)
|
||||
text += tr("Visibility: ").toStdString() + std::string(current_dive->visibility, '*') + '\n';
|
||||
if (data.wavesize)
|
||||
text += tr("Wave size: ").toStdString() + std::string(current_dive->wavesize, '*') + '\n';
|
||||
if (data.current)
|
||||
text += tr("Current: ").toStdString() + std::string(current_dive->current, '*') + '\n';
|
||||
if (data.surge)
|
||||
text += tr("Surge: ").toStdString() + std::string(current_dive->surge, '*') + '\n';
|
||||
if (data.chill)
|
||||
text += tr("Chill: ").toStdString() + std::string(current_dive->chill, '*') + '\n';
|
||||
if (data.notes)
|
||||
text += tr("Notes:\n").toStdString() + current_dive->notes + '\n';
|
||||
if (data.suit)
|
||||
text += tr("Suit: ").toStdString() + current_dive->suit + '\n';
|
||||
if (data.tags)
|
||||
text += tr("Tags: ").toStdString() + taglist_get_tagstring(current_dive->tags) + '\n';
|
||||
if (data.cylinders)
|
||||
text += tr("Cylinders:\n").toStdString() + formatGas(current_dive).toStdString();
|
||||
if (data.weights)
|
||||
text += tr("Weights:\n").toStdString() + formatWeightList(current_dive).toStdString();
|
||||
if (data.number)
|
||||
text += tr("Dive number: ").toStdString() + casprintf_loc("%d", current_dive->number) + '\n';
|
||||
if (data.when)
|
||||
text += tr("Date / time: ").toStdString() + get_dive_date_string(current_dive->when).toStdString() + '\n';
|
||||
QApplication::clipboard()->setText(QString::fromStdString(text));
|
||||
}
|
||||
}
|
22
desktop-widgets/divecomponentselection.h
Normal file
22
desktop-widgets/divecomponentselection.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef DIVECOMPONENTSELECTION_H
|
||||
#define DIVECOMPONENTSELECTION_H
|
||||
|
||||
#include "ui_divecomponentselection.h"
|
||||
|
||||
struct dive_paste_data;
|
||||
|
||||
class DiveComponentSelection : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DiveComponentSelection(dive_paste_data &data, QWidget *parent = nullptr);
|
||||
private
|
||||
slots:
|
||||
void buttonClicked(QAbstractButton *button);
|
||||
|
||||
private:
|
||||
Ui::DiveComponentSelectionDialog ui;
|
||||
dive_paste_data &data;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -38,6 +38,7 @@
|
|||
#include "core/settings/qPrefDisplay.h"
|
||||
|
||||
#include "desktop-widgets/about.h"
|
||||
#include "desktop-widgets/divecomponentselection.h"
|
||||
#include "desktop-widgets/divelistview.h"
|
||||
#include "desktop-widgets/divelogexportdialog.h"
|
||||
#include "desktop-widgets/divelogimportdialog.h"
|
||||
|
@ -207,7 +208,6 @@ MainWindow::MainWindow() :
|
|||
#ifdef NO_USERMANUAL
|
||||
ui.menuHelp->removeAction(ui.actionUserManual);
|
||||
#endif
|
||||
memset(&what, 0, sizeof(what));
|
||||
|
||||
updateManager = new UpdateManager(this);
|
||||
undoAction = Command::undoAction(this);
|
||||
|
@ -1424,13 +1424,13 @@ void MainWindow::on_copy_triggered()
|
|||
{
|
||||
// open dialog to select what gets copied
|
||||
// copy the displayed dive
|
||||
DiveComponentSelection dialog(this, ©PasteDive, &what);
|
||||
DiveComponentSelection dialog(paste_data, this);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void MainWindow::on_paste_triggered()
|
||||
{
|
||||
Command::pasteDives(©PasteDive, what);
|
||||
Command::pasteDives(paste_data);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionFilterTags_triggered()
|
||||
|
|
|
@ -203,8 +203,7 @@ private:
|
|||
bool plannerStateClean();
|
||||
void setupSocialNetworkMenu();
|
||||
QDialog *findMovedImagesDialog;
|
||||
struct dive copyPasteDive;
|
||||
struct dive_components what;
|
||||
dive_paste_data paste_data;
|
||||
QStringList recentFiles;
|
||||
QAction *actionsRecent[NUM_RECENT_FILES];
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include <QAction>
|
||||
#include <QDesktopServices>
|
||||
#include <QToolTip>
|
||||
#include <QClipboard>
|
||||
#include <QCompleter>
|
||||
|
||||
#include "core/file.h"
|
||||
|
@ -277,93 +276,6 @@ QString URLDialog::url() const
|
|||
return ui.urlField->toPlainText();
|
||||
}
|
||||
|
||||
#define COMPONENT_FROM_UI(_component) what->_component = ui._component->isChecked()
|
||||
#define UI_FROM_COMPONENT(_component) ui._component->setChecked(what->_component)
|
||||
|
||||
DiveComponentSelection::DiveComponentSelection(QWidget *parent, struct dive *target, struct dive_components *_what) : targetDive(target)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
what = _what;
|
||||
UI_FROM_COMPONENT(divesite);
|
||||
UI_FROM_COMPONENT(diveguide);
|
||||
UI_FROM_COMPONENT(buddy);
|
||||
UI_FROM_COMPONENT(rating);
|
||||
UI_FROM_COMPONENT(visibility);
|
||||
UI_FROM_COMPONENT(notes);
|
||||
UI_FROM_COMPONENT(suit);
|
||||
UI_FROM_COMPONENT(tags);
|
||||
UI_FROM_COMPONENT(cylinders);
|
||||
UI_FROM_COMPONENT(weights);
|
||||
UI_FROM_COMPONENT(number);
|
||||
UI_FROM_COMPONENT(when);
|
||||
connect(ui.buttonBox, &QDialogButtonBox::clicked, this, &DiveComponentSelection::buttonClicked);
|
||||
QShortcut *close = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), this);
|
||||
connect(close, &QShortcut::activated, this, &DiveComponentSelection::close);
|
||||
QShortcut *quit = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this);
|
||||
connect(quit, &QShortcut::activated, parent, &QWidget::close);
|
||||
}
|
||||
|
||||
void DiveComponentSelection::buttonClicked(QAbstractButton *button)
|
||||
{
|
||||
if (current_dive && ui.buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) {
|
||||
COMPONENT_FROM_UI(divesite);
|
||||
COMPONENT_FROM_UI(diveguide);
|
||||
COMPONENT_FROM_UI(buddy);
|
||||
COMPONENT_FROM_UI(rating);
|
||||
COMPONENT_FROM_UI(visibility);
|
||||
COMPONENT_FROM_UI(notes);
|
||||
COMPONENT_FROM_UI(suit);
|
||||
COMPONENT_FROM_UI(tags);
|
||||
COMPONENT_FROM_UI(cylinders);
|
||||
COMPONENT_FROM_UI(weights);
|
||||
COMPONENT_FROM_UI(number);
|
||||
COMPONENT_FROM_UI(when);
|
||||
selective_copy_dive(current_dive, targetDive, *what, true);
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
QTextStream text;
|
||||
QString cliptext;
|
||||
text.setString(&cliptext);
|
||||
if (what->divesite && current_dive->dive_site)
|
||||
text << tr("Dive site: ") << QString::fromStdString(current_dive->dive_site->name) << "\n";
|
||||
if (what->diveguide)
|
||||
text << tr("Dive guide: ") << QString::fromStdString(current_dive->diveguide) << "\n";
|
||||
if (what->buddy)
|
||||
text << tr("Buddy: ") << QString::fromStdString(current_dive->buddy) << "\n";
|
||||
if (what->rating)
|
||||
text << tr("Rating: ") + QString("*").repeated(current_dive->rating) << "\n";
|
||||
if (what->visibility)
|
||||
text << tr("Visibility: ") + QString("*").repeated(current_dive->visibility) << "\n";
|
||||
if (what->notes)
|
||||
text << tr("Notes:\n") << QString::fromStdString(current_dive->notes) << "\n";
|
||||
if (what->suit)
|
||||
text << tr("Suit: ") << QString::fromStdString(current_dive->suit) << "\n";
|
||||
if (what-> tags) {
|
||||
text << tr("Tags: ");
|
||||
for (const divetag *tag: current_dive->tags)
|
||||
text << tag->name.c_str() << " ";
|
||||
text << "\n";
|
||||
}
|
||||
if (what->cylinders) {
|
||||
text << tr("Cylinders:\n");
|
||||
for (auto [idx, cyl]: enumerated_range(current_dive->cylinders)) {
|
||||
if (current_dive->is_cylinder_used(idx))
|
||||
text << QString::fromStdString(cyl.type.description) << " "
|
||||
<< QString::fromStdString(cyl.gasmix.name()) << "\n";
|
||||
}
|
||||
}
|
||||
if (what->weights) {
|
||||
text << tr("Weights:\n");
|
||||
for (auto &ws: current_dive->weightsystems)
|
||||
text << QString::fromStdString(ws.description) << ws.weight.grams / 1000 << "kg\n";
|
||||
}
|
||||
if (what->number)
|
||||
text << tr("Dive number: ") << current_dive->number << "\n";
|
||||
if (what->when)
|
||||
text << tr("Date / time: ") << get_dive_date_string(current_dive->when) << "\n";
|
||||
clipboard->setText(cliptext);
|
||||
}
|
||||
}
|
||||
|
||||
AddFilterPresetDialog::AddFilterPresetDialog(const QString &defaultName, QWidget *parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
|
|
@ -7,7 +7,6 @@ class QAbstractButton;
|
|||
class QNetworkReply;
|
||||
class FilterModelBase;
|
||||
struct dive;
|
||||
struct dive_components;
|
||||
|
||||
#include "core/units.h"
|
||||
#include <QWidget>
|
||||
|
@ -20,7 +19,6 @@ struct dive_components;
|
|||
#include "ui_shifttimes.h"
|
||||
#include "ui_shiftimagetimes.h"
|
||||
#include "ui_urldialog.h"
|
||||
#include "ui_divecomponentselection.h"
|
||||
#include "ui_listfilter.h"
|
||||
#include "ui_addfilterpreset.h"
|
||||
|
||||
|
@ -102,20 +100,6 @@ private:
|
|||
Ui::URLDialog ui;
|
||||
};
|
||||
|
||||
class DiveComponentSelection : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DiveComponentSelection(QWidget *parent, struct dive *target, struct dive_components *_what);
|
||||
private
|
||||
slots:
|
||||
void buttonClicked(QAbstractButton *button);
|
||||
|
||||
private:
|
||||
Ui::DiveComponentSelectionDialog ui;
|
||||
struct dive *targetDive;
|
||||
struct dive_components *what;
|
||||
};
|
||||
|
||||
class AddFilterPresetDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
|
|
@ -38,11 +38,8 @@ Kirigami.ScrollablePage {
|
|||
Layout.preferredWidth: gridWidth * 0.75
|
||||
}
|
||||
SsrfSwitch {
|
||||
checked: manager.toggleDiveSite(false)
|
||||
checked: manager.pasteDiveSite
|
||||
Layout.preferredWidth: gridWidth * 0.25
|
||||
onClicked: {
|
||||
manager.toggleDiveSite(true)
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
text: qsTr("Notes")
|
||||
|
@ -50,11 +47,8 @@ Kirigami.ScrollablePage {
|
|||
Layout.preferredWidth: gridWidth * 0.75
|
||||
}
|
||||
SsrfSwitch {
|
||||
checked: manager.toggleNotes(false)
|
||||
checked: manager.pasteNotes
|
||||
Layout.preferredWidth: gridWidth * 0.25
|
||||
onClicked: {
|
||||
manager.toggleNotes(true)
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
text: qsTr("Dive guide")
|
||||
|
@ -62,11 +56,8 @@ Kirigami.ScrollablePage {
|
|||
Layout.preferredWidth: gridWidth * 0.75
|
||||
}
|
||||
SsrfSwitch {
|
||||
checked: manager.toggleDiveGuide(false)
|
||||
checked: manager.pasteDiveGuide
|
||||
Layout.preferredWidth: gridWidth * 0.25
|
||||
onClicked: {
|
||||
manager.toggleDiveGuide(true)
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
text: qsTr("Buddy")
|
||||
|
@ -74,11 +65,8 @@ Kirigami.ScrollablePage {
|
|||
Layout.preferredWidth: gridWidth * 0.75
|
||||
}
|
||||
SsrfSwitch {
|
||||
checked: manager.toggleBuddy(false)
|
||||
checked: manager.pasteBuddy
|
||||
Layout.preferredWidth: gridWidth * 0.25
|
||||
onClicked: {
|
||||
manager.toggleBuddy(true)
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
text: qsTr("Suit")
|
||||
|
@ -86,11 +74,8 @@ Kirigami.ScrollablePage {
|
|||
Layout.preferredWidth: gridWidth * 0.75
|
||||
}
|
||||
SsrfSwitch {
|
||||
checked: manager.toggleSuit(false)
|
||||
checked: manager.pasteSuit
|
||||
Layout.preferredWidth: gridWidth * 0.25
|
||||
onClicked: {
|
||||
manager.toggleSuit(true)
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
text: qsTr("Rating")
|
||||
|
@ -98,11 +83,8 @@ Kirigami.ScrollablePage {
|
|||
Layout.preferredWidth: gridWidth * 0.75
|
||||
}
|
||||
SsrfSwitch {
|
||||
checked: manager.toggleRating(false)
|
||||
checked: manager.pasteRating
|
||||
Layout.preferredWidth: gridWidth * 0.25
|
||||
onClicked: {
|
||||
manager.toggleRating(true)
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
text: qsTr("Visibility")
|
||||
|
@ -110,11 +92,8 @@ Kirigami.ScrollablePage {
|
|||
Layout.preferredWidth: gridWidth * 0.75
|
||||
}
|
||||
SsrfSwitch {
|
||||
checked: manager.toggleVisibility(false)
|
||||
checked: manager.pasteVisibility
|
||||
Layout.preferredWidth: gridWidth * 0.25
|
||||
onClicked: {
|
||||
manager.toggleVisibility(true)
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
text: qsTr("Tags")
|
||||
|
@ -122,11 +101,8 @@ Kirigami.ScrollablePage {
|
|||
Layout.preferredWidth: gridWidth * 0.75
|
||||
}
|
||||
SsrfSwitch {
|
||||
checked: manager.toggleTags(false)
|
||||
checked: manager.pasteTags
|
||||
Layout.preferredWidth: gridWidth * 0.25
|
||||
onClicked: {
|
||||
manager.toggleTags(true)
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
text: qsTr("Cylinders")
|
||||
|
@ -134,11 +110,8 @@ Kirigami.ScrollablePage {
|
|||
Layout.preferredWidth: gridWidth * 0.75
|
||||
}
|
||||
SsrfSwitch {
|
||||
checked: manager.toggleCylinders(false)
|
||||
checked: manager.pasteCylinders
|
||||
Layout.preferredWidth: gridWidth * 0.25
|
||||
onClicked: {
|
||||
manager.toggleCylinders(true)
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
text: qsTr("Weights")
|
||||
|
@ -146,11 +119,8 @@ Kirigami.ScrollablePage {
|
|||
Layout.preferredWidth: gridWidth * 0.75
|
||||
}
|
||||
SsrfSwitch {
|
||||
checked: manager.toggleWeights(false)
|
||||
checked: manager.pasteWeights
|
||||
Layout.preferredWidth: gridWidth * 0.25
|
||||
onClicked: {
|
||||
manager.toggleWeights(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -303,17 +303,18 @@ QMLManager::QMLManager() :
|
|||
// make sure we know if the current cloud repo has been successfully synced
|
||||
syncLoadFromCloud();
|
||||
|
||||
memset(&m_copyPasteDive, 0, sizeof(m_copyPasteDive));
|
||||
memset(&what, 0, sizeof(what));
|
||||
|
||||
// Let's set some defaults to be copied so users don't necessarily need
|
||||
// to know how to configure this
|
||||
what.diveguide = true;
|
||||
what.buddy = true;
|
||||
what.suit = true;
|
||||
what.tags = true;
|
||||
what.cylinders = true;
|
||||
what.weights = true;
|
||||
m_pasteDiveSite = false;
|
||||
m_pasteNotes = false;
|
||||
m_pasteDiveGuide = true;
|
||||
m_pasteBuddy = true;
|
||||
m_pasteSuit = true;
|
||||
m_pasteRating = false;
|
||||
m_pasteVisibility = false;
|
||||
m_pasteTags = true;
|
||||
m_pasteCylinders = true;
|
||||
m_pasteWeights = true;
|
||||
|
||||
// monitor when dives changed - but only in verbose mode
|
||||
// careful - changing verbose at runtime isn't enough (of course that could be added if we want it)
|
||||
|
@ -1607,104 +1608,40 @@ void QMLManager::toggleDiveInvalid(int id)
|
|||
changesNeedSaving();
|
||||
}
|
||||
|
||||
bool QMLManager::toggleDiveSite(bool toggle)
|
||||
template <typename T>
|
||||
static void assign_paste_data(bool copy, const T &src, std::optional<T> &dest)
|
||||
{
|
||||
if (toggle)
|
||||
what.divesite = what.divesite ? false : true;
|
||||
|
||||
return what.divesite;
|
||||
}
|
||||
|
||||
bool QMLManager::toggleNotes(bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
what.notes = what.notes ? false : true;
|
||||
|
||||
return what.notes;
|
||||
}
|
||||
|
||||
bool QMLManager::toggleDiveGuide(bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
what.diveguide = what.diveguide ? false : true;
|
||||
|
||||
return what.diveguide;
|
||||
}
|
||||
|
||||
bool QMLManager::toggleBuddy(bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
what.buddy = what.buddy ? false : true;
|
||||
|
||||
return what.buddy;
|
||||
}
|
||||
|
||||
bool QMLManager::toggleSuit(bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
what.suit = what.suit ? false : true;
|
||||
|
||||
return what.suit;
|
||||
}
|
||||
|
||||
bool QMLManager::toggleRating(bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
what.rating = what.rating ? false : true;
|
||||
|
||||
return what.rating;
|
||||
}
|
||||
|
||||
bool QMLManager::toggleVisibility(bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
what.visibility = what.visibility ? false : true;
|
||||
|
||||
return what.visibility;
|
||||
}
|
||||
|
||||
bool QMLManager::toggleTags(bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
what.tags = what.tags ? false : true;
|
||||
|
||||
return what.tags;
|
||||
}
|
||||
|
||||
bool QMLManager::toggleCylinders(bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
what.cylinders = what.cylinders ? false : true;
|
||||
|
||||
return what.cylinders;
|
||||
}
|
||||
|
||||
bool QMLManager::toggleWeights(bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
what.weights = what.weights ? false : true;
|
||||
|
||||
return what.weights;
|
||||
if (copy)
|
||||
dest = src;
|
||||
else
|
||||
dest = {};
|
||||
}
|
||||
|
||||
void QMLManager::copyDiveData(int id)
|
||||
{
|
||||
m_copyPasteDive = divelog.dives.get_by_uniq_id(id);
|
||||
if (!m_copyPasteDive) {
|
||||
const dive *d = divelog.dives.get_by_uniq_id(id);
|
||||
if (!d) {
|
||||
appendTextToLog("trying to copy non-existing dive");
|
||||
return;
|
||||
}
|
||||
|
||||
assign_paste_data(m_pasteDiveSite, d->dive_site ? d->dive_site->uuid : uint32_t(), paste_data.divesite);
|
||||
assign_paste_data(m_pasteNotes, d->notes, paste_data.notes);
|
||||
assign_paste_data(m_pasteDiveGuide, d->diveguide, paste_data.diveguide);
|
||||
assign_paste_data(m_pasteBuddy, d->buddy, paste_data.buddy);
|
||||
assign_paste_data(m_pasteSuit, d->suit, paste_data.suit);
|
||||
assign_paste_data(m_pasteRating, d->rating, paste_data.rating);
|
||||
assign_paste_data(m_pasteVisibility, d->visibility, paste_data.visibility);
|
||||
assign_paste_data(m_pasteTags, d->tags, paste_data.tags);
|
||||
assign_paste_data(m_pasteCylinders, d->cylinders, paste_data.cylinders);
|
||||
assign_paste_data(m_pasteWeights, d->weightsystems, paste_data.weights);
|
||||
|
||||
setNotificationText("Copy");
|
||||
}
|
||||
|
||||
void QMLManager::pasteDiveData(int id)
|
||||
{
|
||||
if (!m_copyPasteDive) {
|
||||
appendTextToLog("dive to paste is not selected");
|
||||
return;
|
||||
}
|
||||
Command::pasteDives(m_copyPasteDive, what);
|
||||
Command::pasteDives(paste_data);
|
||||
changesNeedSaving();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,17 @@ class QMLManager : public QObject {
|
|||
Q_PROPERTY(QString progressMessage MEMBER m_progressMessage WRITE setProgressMessage NOTIFY progressMessageChanged)
|
||||
Q_PROPERTY(bool btEnabled MEMBER m_btEnabled WRITE setBtEnabled NOTIFY btEnabledChanged)
|
||||
|
||||
Q_PROPERTY(bool pasteDiveSite MEMBER m_pasteDiveSite)
|
||||
Q_PROPERTY(bool pasteNotes MEMBER m_pasteNotes)
|
||||
Q_PROPERTY(bool pasteDiveGuide MEMBER m_pasteDiveGuide)
|
||||
Q_PROPERTY(bool pasteBuddy MEMBER m_pasteBuddy)
|
||||
Q_PROPERTY(bool pasteSuit MEMBER m_pasteSuit)
|
||||
Q_PROPERTY(bool pasteRating MEMBER m_pasteRating)
|
||||
Q_PROPERTY(bool pasteVisibility MEMBER m_pasteVisibility)
|
||||
Q_PROPERTY(bool pasteTags MEMBER m_pasteTags)
|
||||
Q_PROPERTY(bool pasteCylinders MEMBER m_pasteCylinders)
|
||||
Q_PROPERTY(bool pasteWeights MEMBER m_pasteWeights)
|
||||
|
||||
Q_PROPERTY(QString DC_vendor READ DC_vendor WRITE DC_setVendor)
|
||||
Q_PROPERTY(QString DC_product READ DC_product WRITE DC_setProduct)
|
||||
Q_PROPERTY(QString DC_devName READ DC_devName WRITE DC_setDevName)
|
||||
|
@ -187,16 +198,6 @@ public slots:
|
|||
void toggleDiveInvalid(int id);
|
||||
void copyDiveData(int id);
|
||||
void pasteDiveData(int id);
|
||||
bool toggleDiveSite(bool toggle);
|
||||
bool toggleNotes(bool toggle);
|
||||
bool toggleDiveGuide(bool toggle);
|
||||
bool toggleBuddy(bool toggle);
|
||||
bool toggleSuit(bool toggle);
|
||||
bool toggleRating(bool toggle);
|
||||
bool toggleVisibility(bool toggle);
|
||||
bool toggleTags(bool toggle);
|
||||
bool toggleCylinders(bool toggle);
|
||||
bool toggleWeights(bool toggle);
|
||||
void undo();
|
||||
void redo();
|
||||
int addDive();
|
||||
|
@ -250,11 +251,21 @@ private:
|
|||
void updateAllGlobalLists();
|
||||
void updateHaveLocalChanges(bool status);
|
||||
|
||||
bool m_pasteDiveSite;
|
||||
bool m_pasteNotes;
|
||||
bool m_pasteDiveGuide;
|
||||
bool m_pasteBuddy;
|
||||
bool m_pasteSuit;
|
||||
bool m_pasteRating;
|
||||
bool m_pasteVisibility;
|
||||
bool m_pasteTags;
|
||||
bool m_pasteCylinders;
|
||||
bool m_pasteWeights;
|
||||
|
||||
location_t getGps(QString &gps);
|
||||
QString m_pluggedInDeviceName;
|
||||
bool m_showNonDiveComputers;
|
||||
struct dive *m_copyPasteDive = NULL;
|
||||
struct dive_components what;
|
||||
struct dive_paste_data paste_data;
|
||||
QAction *undoAction;
|
||||
|
||||
bool verifyCredentials(QString email, QString password, QString pin);
|
||||
|
|
Loading…
Add table
Reference in a new issue