Undo: Implement undo of dive site name editing

Implement an undo command that edits the name of a dive site.
Connect it to the dive site table, so that names can be edited
directly in the table.

Send signals on undo / redo so that the dive site table and
the dive site edit widget can be updated.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2019-03-12 23:51:39 +01:00 committed by Dirk Hohndel
parent 8e1f736d2b
commit 0e1b0cf1da
9 changed files with 97 additions and 2 deletions

View file

@ -48,6 +48,7 @@ signals:
void diveSiteAdded(dive_site *ds, int idx);
void diveSiteDeleted(dive_site *ds, int idx);
void diveSiteDiveCountChanged(dive_site *ds);
void diveSiteChanged(dive_site *ds, int field); // field according to LocationInformationModel
public:
// Desktop uses the QTreeView class to present the list of dives. The layout
// of this class gives us a very fundamental problem, as we can not easily

View file

@ -83,4 +83,9 @@ void deleteDiveSites(const QVector <dive_site *> &sites)
execute(new DeleteDiveSites(sites));
}
void editDiveSiteName(dive_site *ds, const QString &value)
{
execute(new EditDiveSiteName(ds, value));
}
} // namespace Command

View file

@ -41,6 +41,7 @@ void mergeDives(const QVector <dive *> &dives);
// 3) Dive-site related commands
void deleteDiveSites(const QVector <dive_site *> &sites);
void editDiveSiteName(dive_site *ds, const QString &value);
} // namespace Command

View file

@ -3,6 +3,8 @@
#include "command_divesite.h"
#include "core/divesite.h"
#include "core/subsurface-qt/DiveListNotifier.h"
#include "core/qthelper.h"
#include "qt-models/divelocationmodel.h"
namespace Command {
@ -80,4 +82,29 @@ void DeleteDiveSites::undo()
sitesToRemove = std::move(addDiveSites(sitesToAdd));
}
EditDiveSiteName::EditDiveSiteName(dive_site *dsIn, const QString &name) : ds(dsIn),
value(name)
{
}
bool EditDiveSiteName::workToBeDone()
{
return value != QString(ds->name);
}
void EditDiveSiteName::redo()
{
QString s = ds->name;
free(ds->name);
ds->name = copy_qstring(value);
value = s;
emit diveListNotifier.diveSiteChanged(ds, LocationInformationModel::NAME); // Inform frontend of changed dive site.
}
void EditDiveSiteName::undo()
{
// Undo and redo do the same
redo();
}
} // namespace Command

View file

@ -16,14 +16,26 @@ public:
DeleteDiveSites(const QVector<dive_site *> &sites);
private:
bool workToBeDone() override;
void undo() override;
void redo() override;
// For redo
std::vector<dive_site *> sitesToRemove;
// For undo
std::vector<OwningDiveSitePtr> sitesToAdd;
};
class EditDiveSiteName : public Base {
public:
EditDiveSiteName(dive_site *ds, const QString &name);
private:
bool workToBeDone() override;
void undo() override;
void redo() override;
dive_site *ds;
QString value; // Value to be set
};
} // namespace Command

View file

@ -8,6 +8,7 @@
#include "qt-models/filtermodels.h"
#include "core/divesitehelpers.h"
#include "desktop-widgets/modeldelegates.h"
#include "core/subsurface-qt/DiveListNotifier.h"
#include <QDebug>
#include <QShowEvent>
@ -38,6 +39,8 @@ LocationInformationWidget::LocationInformationWidget(QWidget *parent) : QGroupBo
connect(ui.diveSiteCoordinates, SIGNAL(returnPressed()), this, SLOT(updateLocationOnMap()));
ui.diveSiteCoordinates->installEventFilter(this);
connect(&diveListNotifier, &DiveListNotifier::diveSiteChanged, this, &LocationInformationWidget::diveSiteChanged);
ui.diveSiteListView->setModel(&filter_model);
ui.diveSiteListView->setModelColumn(LocationInformationModel::NAME);
ui.diveSiteListView->installEventFilter(this);
@ -121,6 +124,18 @@ void LocationInformationWidget::updateLabels()
ui.locationTags->setText(constructLocationTags(&taxonomy, false));
}
void LocationInformationWidget::diveSiteChanged(struct dive_site *ds, int field)
{
if (diveSite != ds)
return; // A different dive site was changed -> do nothing.
switch (field) {
case LocationInformationModel::NAME:
ui.diveSiteName->setText(diveSite->name);
default:
return;
}
}
void LocationInformationWidget::clearLabels()
{
ui.diveSiteName->clear();

View file

@ -39,6 +39,7 @@ public slots:
private slots:
void updateLabels();
void updateLocationOnMap();
void diveSiteChanged(struct dive_site *ds, int field);
signals:
void endEditDiveSite();
void nameChanged(const QString &oldName, const QString &newName);

View file

@ -26,6 +26,7 @@ LocationInformationModel::LocationInformationModel(QObject *obj) : QAbstractTabl
connect(&diveListNotifier, &DiveListNotifier::diveSiteDiveCountChanged, this, &LocationInformationModel::diveSiteDiveCountChanged);
connect(&diveListNotifier, &DiveListNotifier::diveSiteAdded, this, &LocationInformationModel::diveSiteAdded);
connect(&diveListNotifier, &DiveListNotifier::diveSiteDeleted, this, &LocationInformationModel::diveSiteDeleted);
connect(&diveListNotifier, &DiveListNotifier::diveSiteChanged, this, &LocationInformationModel::diveSiteChanged);
}
int LocationInformationModel::columnCount(const QModelIndex &) const
@ -173,6 +174,14 @@ void LocationInformationModel::diveSiteDeleted(struct dive_site *, int idx)
endRemoveRows();
}
void LocationInformationModel::diveSiteChanged(struct dive_site *ds, int field)
{
int idx = get_divesite_idx(ds, &dive_site_table);
if (idx < 0)
return;
dataChanged(createIndex(idx, field), createIndex(idx, field));
}
bool DiveSiteSortedModel::filterAcceptsRow(int sourceRow, const QModelIndex &source_parent) const
{
// TODO: filtering
@ -223,14 +232,33 @@ QStringList DiveSiteSortedModel::allSiteNames() const
return locationNames;
}
struct dive_site *DiveSiteSortedModel::getDiveSite(const QModelIndex &idx)
{
return get_dive_site(mapToSource(idx).row(), &dive_site_table);
}
#ifndef SUBSURFACE_MOBILE
bool DiveSiteSortedModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
struct dive_site *ds = getDiveSite(index);
if (!ds || value.isNull())
return false;
switch (index.column()) {
case LocationInformationModel::NAME:
Command::editDiveSiteName(ds, value.toString());
return true;
default:
return false;
}
}
// TODO: Remove from model. It doesn't make sense to call the model here, which calls the undo command,
// which in turn calls the model.
void DiveSiteSortedModel::remove(const QModelIndex &index)
{
if (index.column() != LocationInformationModel::REMOVE)
return;
struct dive_site *ds = get_dive_site(mapToSource(index).row(), &dive_site_table);
struct dive_site *ds = getDiveSite(index);
if (!ds)
return;
if (ds->dives.nr > 0 &&
@ -240,7 +268,7 @@ void DiveSiteSortedModel::remove(const QModelIndex &index)
return;
Command::deleteDiveSites(QVector<dive_site *>{ds});
}
#endif
#endif // SUBSURFACE_MOBILE
GeoReferencingOptionsModel *GeoReferencingOptionsModel::instance()
{

View file

@ -35,15 +35,20 @@ public slots:
void diveSiteDiveCountChanged(struct dive_site *ds);
void diveSiteAdded(struct dive_site *ds, int idx);
void diveSiteDeleted(struct dive_site *ds, int idx);
void diveSiteChanged(struct dive_site *ds, int field);
};
class DiveSiteSortedModel : public QSortFilterProxyModel {
Q_OBJECT
private:
struct dive_site *getDiveSite(const QModelIndex &idx);
bool filterAcceptsRow(int sourceRow, const QModelIndex &source_parent) const override;
bool lessThan(const QModelIndex &i1, const QModelIndex &i2) const override;
#ifndef SUBSURFACE_MOBILE
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
public slots:
void remove(const QModelIndex &index);
#endif // SUBSURFACE_MOBILE
public:
DiveSiteSortedModel();
QStringList allSiteNames() const;