undo: more fine-grained undo of profile editing

Place undo commands for every change of the profile, not
only on "saving". Move the edit-mode from the mainwindow
and the maintab to the profile widget.

This is still very rough. For example, the only way to exit
the edit mode is changing the current dive.

The undo-commands are placed by the desktop-profile widget.
We might think about moving that down to the profile-view so
that this will be useable on mobile.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2022-02-19 11:58:36 +01:00
parent c5c8bfec65
commit fce48367cd
12 changed files with 162 additions and 100 deletions

View file

@ -145,8 +145,6 @@ MainWindow::MainWindow() : QMainWindow(),
registerApplicationState(ApplicationState::Default, { true, { mainTab.get(), FLAG_NONE }, { profile.get(), FLAG_NONE },
{ diveList.get(), FLAG_NONE }, { mapWidget.get(), FLAG_NONE } });
registerApplicationState(ApplicationState::EditDive, { false, { mainTab.get(), FLAG_NONE }, { profile.get(), FLAG_NONE },
{ diveList.get(), FLAG_NONE }, { mapWidget.get(), FLAG_NONE } });
registerApplicationState(ApplicationState::PlanDive, { false, { &plannerWidgets->plannerWidget, FLAG_NONE }, { profile.get(), FLAG_NONE },
{ &plannerWidgets->plannerSettingsWidget, FLAG_NONE }, { &plannerWidgets->plannerDetails, FLAG_NONE } });
registerApplicationState(ApplicationState::EditPlannedDive, { true, { &plannerWidgets->plannerWidget, FLAG_NONE }, { profile.get(), FLAG_NONE },
@ -246,8 +244,6 @@ MainWindow::MainWindow() : QMainWindow(),
set_git_update_cb(&updateProgress);
set_error_cb(&showErrorFromC);
connect(profile->view.get(), &ProfileWidget2::editCurrentDive, this, &MainWindow::editCurrentDive);
// full screen support is buggy on Windows and Ubuntu.
// require the FULLSCREEN_SUPPORT macro to enable it!
#ifndef FULLSCREEN_SUPPORT
@ -1408,25 +1404,6 @@ void MainWindow::on_actionImportDiveSites_triggered()
divesiteImport.exec();
}
void MainWindow::editCurrentDive()
{
// We only allow editing of the profile for manually added dives.
if (!current_dive || (!same_string(current_dive->dc.model, "manually added dive") && current_dive->dc.samples) || !userMayChangeAppState())
return;
// This shouldn't be possible, but let's make sure no weird "double editing" takes place.
if (mainTab->isEditing() || DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING)
return;
disableShortcuts(false);
copy_dive(current_dive, &displayed_dive); // Work on a copy of the dive
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD);
DivePlannerPointsModel::instance()->loadFromDive(&displayed_dive);
profile->setEditState(&displayed_dive, 0);
setApplicationState(ApplicationState::EditDive);
mainTab->enableEdition();
}
void MainWindow::on_actionExport_triggered()
{
DiveLogExportDialog diveLogExport;

View file

@ -54,7 +54,6 @@ public:
enum class ApplicationState {
Default,
EditDive,
PlanDive,
EditPlannedDive,
EditDiveSite,
@ -155,7 +154,6 @@ slots:
void refreshDisplay();
void showProfile();
void refreshProfile();
void editCurrentDive();
void planCanceled();
void planCreated();
// Some shortcuts like "change DC" or "copy/paste dive components"

View file

@ -2,9 +2,11 @@
#include "profilewidget.h"
#include "profile-widget/profilewidget2.h"
#include "commands/command.h"
#include "core/color.h"
#include "core/settings/qPrefTechnicalDetails.h"
#include "core/settings/qPrefPartialPressureGas.h"
#include "core/subsurface-string.h"
#include "qt-models/diveplannermodel.h"
#include <QToolBar>
@ -49,7 +51,7 @@ void EmptyView::resizeEvent(QResizeEvent *)
update();
}
ProfileWidget::ProfileWidget()
ProfileWidget::ProfileWidget() : originalDive(nullptr)
{
ui.setupUi(this);
@ -116,6 +118,10 @@ ProfileWidget::ProfileWidget()
connect(ui.profPO2, &QAction::triggered, pp_gas, &qPrefPartialPressureGas::set_po2);
connect(&diveListNotifier, &DiveListNotifier::settingsChanged, view.get(), &ProfileWidget2::settingsChanged);
connect(view.get(), &ProfileWidget2::editCurrentDive, this, &ProfileWidget::editDive);
connect(view.get(), &ProfileWidget2::stopAdded, this, &ProfileWidget::stopAdded);
connect(view.get(), &ProfileWidget2::stopRemoved, this, &ProfileWidget::stopRemoved);
connect(view.get(), &ProfileWidget2::stopMoved, this, &ProfileWidget::stopMoved);
ui.profCalcAllTissues->setChecked(qPrefTechnicalDetails::calcalltissues());
ui.profCalcCeiling->setChecked(qPrefTechnicalDetails::calcceiling());
@ -149,6 +155,7 @@ void ProfileWidget::setEnabledToolbar(bool enabled)
void ProfileWidget::setDive(const struct dive *d)
{
// If the user was currently editing a dive, exit edit mode.
stack->setCurrentIndex(1); // show profile
bool freeDiveMode = d->dc.divemode == FREEDIVE;
@ -176,8 +183,14 @@ void ProfileWidget::setDive(const struct dive *d)
void ProfileWidget::plotCurrentDive()
{
// Exit edit mode if the dive changed
if (editedDive && originalDive != current_dive)
exitEditMode();
setEnabledToolbar(current_dive != nullptr);
if (current_dive) {
if (editedDive) {
view->plotDive(editedDive.get(), editedDc);
} else if (current_dive) {
setDive(current_dive);
view->setProfileState(current_dive, dc_number);
view->resetZoom(); // when switching dive, reset the zoomLevel
@ -190,14 +203,9 @@ void ProfileWidget::plotCurrentDive()
void ProfileWidget::setPlanState(const struct dive *d, int dc)
{
setDive(d); // show subsurface logo
view->setPlanState(d, dc);
}
void ProfileWidget::setEditState(const struct dive *d, int dc)
{
exitEditMode();
setDive(d);
view->setEditState(d, dc);
view->setPlanState(d, dc);
}
void ProfileWidget::unsetProfHR()
@ -211,3 +219,63 @@ void ProfileWidget::unsetProfTissues()
ui.profTissues->setChecked(false);
qPrefTechnicalDetails::set_percentagegraph(false);
}
void ProfileWidget::editDive()
{
// We only allow editing of the profile for manually added dives
// and when no other editing is in progress.
if (!current_dive ||
(!same_string(current_dive->dc.model, "manually added dive") && current_dive->dc.samples) ||
(DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING) ||
editedDive)
return;
editedDive.reset(alloc_dive());
editedDc = dc_number;
copy_dive(current_dive, editedDive.get()); // Work on a copy of the dive
originalDive = current_dive;
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD);
DivePlannerPointsModel::instance()->loadFromDive(editedDive.get());
view->setEditState(editedDive.get(), 0);
}
void ProfileWidget::exitEditMode()
{
if (!editedDive)
return;
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::NOTHING);
view->setProfileState(current_dive, dc_number); // switch back to original dive before erasing the copy.
editedDive.reset();
originalDive = nullptr;
}
// Update depths of edited dive
static void calcDepth(dive &d, int dcNr)
{
d.maxdepth.mm = get_dive_dc(&d, dcNr)->maxdepth.mm = 0;
fixup_dive(&d);
}
void ProfileWidget::stopAdded()
{
if (!editedDive)
return;
calcDepth(*editedDive, editedDc);
Command::editProfile(editedDive.get(), Command::EditProfileType::ADD, 0);
}
void ProfileWidget::stopRemoved(int count)
{
if (!editedDive)
return;
calcDepth(*editedDive, editedDc);
Command::editProfile(editedDive.get(), Command::EditProfileType::REMOVE, count);
}
void ProfileWidget::stopMoved(int count)
{
if (!editedDive)
return;
calcDepth(*editedDive, editedDc);
Command::editProfile(editedDive.get(), Command::EditProfileType::MOVE, count);
}

View file

@ -9,10 +9,13 @@
#include <vector>
#include <memory>
struct dive;
class ProfileWidget2;
class EmptyView;
class QStackedWidget;
extern "C" void free_dive(struct dive *);
class ProfileWidget : public QWidget {
Q_OBJECT
public:
@ -21,18 +24,30 @@ public:
std::unique_ptr<ProfileWidget2> view;
void plotCurrentDive();
void setPlanState(const struct dive *d, int dc);
void setEditState(const struct dive *d, int dc);
void setEnabledToolbar(bool enabled);
private
slots:
void unsetProfHR();
void unsetProfTissues();
void stopAdded();
void stopRemoved(int count);
void stopMoved(int count);
private:
// The same code is in command/command_base.h. Should we make that a global feature?
struct DiveDeleter {
void operator()(dive *d) { free_dive(d); }
};
std::unique_ptr<EmptyView> emptyView;
std::vector<QAction *> toolbarActions;
Ui::ProfileWidget ui;
QStackedWidget *stack;
void setDive(const struct dive *d);
void editDive();
void exitEditMode();
std::unique_ptr<dive, DiveDeleter> editedDive;
int editedDc;
dive *originalDive;
};
#endif // PROFILEWIDGET_H

View file

@ -221,21 +221,6 @@ void MainTab::displayMessage(QString str)
ui.diveNotesMessage->animatedShow();
}
void MainTab::enableEdition()
{
if (current_dive == NULL || editMode)
return;
ui.editDiveSiteButton->setEnabled(false);
MainWindow::instance()->diveList->setEnabled(false);
MainWindow::instance()->setEnabledToolbar(false);
ui.dateEdit->setEnabled(true);
displayMessage(tr("This dive is being edited."));
editMode = true;
}
// This function gets called if a field gets updated by an undo command.
// Refresh the corresponding UI field.
void MainTab::divesChanged(const QVector<dive *> &dives, DiveField field)

View file

@ -57,7 +57,6 @@ slots:
void closeMessage();
void closeWarning();
void displayMessage(QString str);
void enableEdition();
void escDetected(void);
void updateDateTimeFields();
void colorsChanged();