Undo: remove ADD mode from main tab

Instead of letting the user edit the fields before adding a dive,
simply add an empty dive. Thus, the ADD mode of the main tab can
be removed.

Constructing a new dive with default-depth and making sure that
the dive is displayed correctly is very subtle. This all needs
to be detangled in due course.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2019-03-28 17:23:35 +01:00 committed by Dirk Hohndel
parent 8287d86d2b
commit 4a3ffeba05
8 changed files with 98 additions and 174 deletions

View file

@ -9,9 +9,9 @@
namespace Command { namespace Command {
// Dive-list related commands // Dive-list related commands
void addDive(dive *d, const QString &newDS, bool autogroup, bool newNumber) void addDive(dive *d, bool autogroup, bool newNumber)
{ {
execute(new AddDive(d, newDS, autogroup, newNumber)); execute(new AddDive(d, autogroup, newNumber));
} }
void importDives(struct dive_table *dives, struct trip_table *trips, struct dive_site_table *sites, int flags, const QString &source) void importDives(struct dive_table *dives, struct trip_table *trips, struct dive_site_table *sites, int flags, const QString &source)

View file

@ -20,9 +20,7 @@ QAction *redoAction(QObject *parent); // Create an redo action.
// distance are added to a trip. dive d is consumed (the structure is reset)! // distance are added to a trip. dive d is consumed (the structure is reset)!
// If newNumber is true, the dive is assigned a new number, depending on the // If newNumber is true, the dive is assigned a new number, depending on the
// insertion position. // insertion position.
// Id newDS is not empty, a dive site with that name will be created. d->dive_site void addDive(dive *d, const bool autogroup, bool newNumber);
// should be null in this case.
void addDive(dive *d, const QString &newDS, bool autogroup, bool newNumber);
void importDives(struct dive_table *dives, struct trip_table *trips, struct dive_site_table *sites, int flags, const QString &source); void importDives(struct dive_table *dives, struct trip_table *trips, struct dive_site_table *sites, int flags, const QString &source);
void deleteDive(const QVector<struct dive*> &divesToDelete); void deleteDive(const QVector<struct dive*> &divesToDelete);
void shiftTime(const QVector<dive *> &changedDives, int amount); void shiftTime(const QVector<dive *> &changedDives, int amount);

View file

@ -359,22 +359,14 @@ void DiveListBase::redo()
finishWork(); finishWork();
} }
AddDive::AddDive(dive *d, const QString &newDS, bool autogroup, bool newNumber) AddDive::AddDive(dive *d, bool autogroup, bool newNumber)
{ {
setText(tr("add dive")); setText(tr("add dive"));
// By convention, d is "displayed dive" and can be overwritten. // By convention, d is a pointer to "displayed dive" or a temporary variable and can be overwritten.
d->maxdepth.mm = 0; d->maxdepth.mm = 0;
d->dc.maxdepth.mm = 0; d->dc.maxdepth.mm = 0;
fixup_dive(d); fixup_dive(d);
// Create new dive site if requested.
if (!newDS.isEmpty()) {
struct dive_site *ds = alloc_dive_site();
ds->name = copy_qstring(newDS);
d->dive_site = ds;
divesToAdd.sites.emplace_back(ds);
}
// Get an owning pointer to a copied or moved dive // Get an owning pointer to a copied or moved dive
// Note: if move is true, this destroys the old dive! // Note: if move is true, this destroys the old dive!
OwningDivePtr divePtr(clone_dive(d)); OwningDivePtr divePtr(clone_dive(d));

View file

@ -91,7 +91,7 @@ private:
class AddDive : public DiveListBase { class AddDive : public DiveListBase {
public: public:
AddDive(dive *dive, const QString &newDS, bool autogroup, bool newNumber); AddDive(dive *dive, bool autogroup, bool newNumber);
private: private:
void undoit() override; void undoit() override;
void redoit() override; void redoit() override;

View file

@ -177,7 +177,6 @@ MainWindow::MainWindow() : QMainWindow(),
disabledList.push_back(disabled); disabledList.push_back(disabled);
registerApplicationState("Default", mainTab, profileContainer, diveList, mapWidget ); registerApplicationState("Default", mainTab, profileContainer, diveList, mapWidget );
registerApplicationState("AddDive", mainTab, profileContainer, diveList, mapWidget );
registerApplicationState("EditDive", mainTab, profileContainer, diveList, mapWidget ); registerApplicationState("EditDive", mainTab, profileContainer, diveList, mapWidget );
registerApplicationState("PlanDive", divePlannerWidget, profileContainer, divePlannerSettingsWidget, plannerDetails ); registerApplicationState("PlanDive", divePlannerWidget, profileContainer, divePlannerSettingsWidget, plannerDetails );
registerApplicationState("EditPlannedDive", divePlannerWidget, profileContainer, diveList, mapWidget ); registerApplicationState("EditPlannedDive", divePlannerWidget, profileContainer, diveList, mapWidget );
@ -185,7 +184,6 @@ MainWindow::MainWindow() : QMainWindow(),
registerApplicationState("FilterDive", mainTab, profileContainer, diveList, &filterWidget2); registerApplicationState("FilterDive", mainTab, profileContainer, diveList, &filterWidget2);
setStateProperties("Default", enabledList, enabledList, enabledList, enabledList); setStateProperties("Default", enabledList, enabledList, enabledList, enabledList);
setStateProperties("AddDive", enabledList, enabledList, enabledList, enabledList);
setStateProperties("EditDive", enabledList, enabledList, enabledList, enabledList); setStateProperties("EditDive", enabledList, enabledList, enabledList, enabledList);
setStateProperties("PlanDive", enabledList, enabledList, enabledList, enabledList); setStateProperties("PlanDive", enabledList, enabledList, enabledList, enabledList);
setStateProperties("EditPlannedDive", enabledList, enabledList, enabledList, enabledList); setStateProperties("EditPlannedDive", enabledList, enabledList, enabledList, enabledList);
@ -212,7 +210,6 @@ MainWindow::MainWindow() : QMainWindow(),
connect(actionsRecent[i], SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool))); connect(actionsRecent[i], SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool)));
} }
ui.menuFile->insertSeparator(ui.actionQuit); ui.menuFile->insertSeparator(ui.actionQuit);
connect(mainTab, SIGNAL(addDiveFinished()), graphics, SLOT(setProfileState()));
connect(DivePlannerPointsModel::instance(), SIGNAL(planCreated()), this, SLOT(planCreated())); connect(DivePlannerPointsModel::instance(), SIGNAL(planCreated()), this, SLOT(planCreated()));
connect(DivePlannerPointsModel::instance(), SIGNAL(planCanceled()), this, SLOT(planCanceled())); connect(DivePlannerPointsModel::instance(), SIGNAL(planCanceled()), this, SLOT(planCanceled()));
connect(DivePlannerPointsModel::instance(), SIGNAL(variationsComputed(QString)), this, SLOT(updateVariations(QString))); connect(DivePlannerPointsModel::instance(), SIGNAL(variationsComputed(QString)), this, SLOT(updateVariations(QString)));
@ -897,7 +894,6 @@ void MainWindow::setupForAddAndPlan(const char *model)
// setup the dive cylinders // setup the dive cylinders
DivePlannerPointsModel::instance()->clear(); DivePlannerPointsModel::instance()->clear();
DivePlannerPointsModel::instance()->setupCylinders(); DivePlannerPointsModel::instance()->setupCylinders();
} }
void MainWindow::on_actionReplanDive_triggered() void MainWindow::on_actionReplanDive_triggered()
@ -958,31 +954,27 @@ void MainWindow::on_actionAddDive_triggered()
if (!plannerStateClean()) if (!plannerStateClean())
return; return;
if (diveList->selectedTrips().count() >= 1) { // TODO: We (mis)use displayed_dive to construct a default dive using the dive planner.
diveList->rememberSelection(); // This means that we have to do all this in a setPlanState()/setProfileState() pair,
diveList->clearSelection(); // to avoid the profile and planner going out of sync (which in turn can lead to crashes).
} // This should all be simplified. There is no apparent no reason to go via the planner
// to create a default profile.
setApplicationState("AddDive"); clear_dive(&displayed_dive);
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD); graphics->setPlanState();
DivePlannerPointsModel::instance()->setupStartTime();
// setup things so we can later create our starting dive
setupForAddAndPlan("manually added dive"); // don't translate, stored in the XML file
// now show the mostly empty main tab
mainTab->updateDiveInfo();
mainTab->addDiveStarted();
graphics->setAddState();
DivePlannerPointsModel::instance()->createSimpleDive(); DivePlannerPointsModel::instance()->createSimpleDive();
configureToolbar(); displayed_dive.id = dive_getUniqID();
graphics->plotDive(nullptr, false, true); displayed_dive.when = QDateTime::currentMSecsSinceEpoch() / 1000L + gettimezoneoffset() + 3600;
displayed_dive.dc.model = strdup("manually added dive"); // don't translate! this is stored in the XML file
fixup_dc_duration(&displayed_dive.dc); fixup_dc_duration(&displayed_dive.dc);
displayed_dive.duration = displayed_dive.dc.duration; displayed_dive.duration = displayed_dive.dc.duration;
graphics->setProfileState();
// now that we have the correct depth and duration, update the dive info Command::addDive(&displayed_dive, autogroup, true);
mainTab->updateDepthDuration();
// Plot dive actually copies current_dive to displayed_dive and therefore ensures that the
// correct data are displayed!
graphics->plotDive(nullptr, false, true);
} }
void MainWindow::on_actionRenumber_triggered() void MainWindow::on_actionRenumber_triggered()

View file

@ -234,16 +234,6 @@ void MainTab::toggleTriggeredColumn()
view->hideColumn(col); view->hideColumn(col);
} }
void MainTab::addDiveStarted()
{
ui.tabWidget->setCurrentIndex(0);
ui.tabWidget->setTabEnabled(2, false);
ui.tabWidget->setTabEnabled(3, false);
ui.tabWidget->setTabEnabled(4, false);
ui.tabWidget->setTabEnabled(5, false);
enableEdition(ADD);
}
void MainTab::addMessageAction(QAction *action) void MainTab::addMessageAction(QAction *action)
{ {
ui.diveNotesMessage->addAction(action); ui.diveNotesMessage->addAction(action);
@ -320,9 +310,14 @@ void MainTab::enableEdition(EditMode newEditMode)
static void profileFromDive(struct dive *d) static void profileFromDive(struct dive *d)
{ {
// TODO: We have to put these manipulations into a setPlanState()/setProfileState() pair,
// because otherwise the DivePlannerPointsModel and the profile get out of sync.
// This can lead to crashes. Let's try to detangle these subtleties.
MainWindow::instance()->graphics->setPlanState();
DivePlannerPointsModel::instance()->loadFromDive(d); DivePlannerPointsModel::instance()->loadFromDive(d);
MainWindow::instance()->graphics->setReplot(true); MainWindow::instance()->graphics->setReplot(true);
MainWindow::instance()->graphics->plotDive(current_dive, true); MainWindow::instance()->graphics->plotDive(current_dive, true);
MainWindow::instance()->graphics->setProfileState();
} }
// This function gets called if a field gets updated by an undo command. // This function gets called if a field gets updated by an undo command.
@ -434,16 +429,6 @@ bool MainTab::isEditing()
return editMode != NONE; return editMode != NONE;
} }
void MainTab::updateDepthDuration()
{
ui.depth->setVisible(true);
ui.depthLabel->setVisible(true);
ui.duration->setVisible(true);
ui.durationLabel->setVisible(true);
ui.duration->setText(render_seconds_to_string(displayed_dive.duration.seconds));
ui.depth->setText(get_depth_string(displayed_dive.maxdepth, true));
}
void MainTab::updateNotes(const struct dive *d) void MainTab::updateNotes(const struct dive *d)
{ {
QString tmp(d->notes); QString tmp(d->notes);
@ -493,7 +478,7 @@ void MainTab::updateDiveInfo(bool clear)
ui.location->refreshDiveSiteCache(); ui.location->refreshDiveSiteCache();
EditMode rememberEM = editMode; EditMode rememberEM = editMode;
// don't execute this while adding / planning a dive // don't execute this while adding / planning a dive
if (editMode == ADD || editMode == MANUALLY_ADDED_DIVE || MainWindow::instance()->graphics->isPlanner()) if (editMode == MANUALLY_ADDED_DIVE || MainWindow::instance()->graphics->isPlanner())
return; return;
if (!isEnabled() && !clear ) if (!isEnabled() && !clear )
setEnabled(true); setEnabled(true);
@ -748,33 +733,7 @@ void MainTab::acceptChanges()
ui.dateEdit->setEnabled(true); ui.dateEdit->setEnabled(true);
hideMessage(); hideMessage();
ui.equipmentTab->setEnabled(true); ui.equipmentTab->setEnabled(true);
if (lastMode == ADD) {
// Handle dive site
struct dive_site *pickedDs = ui.location->currDiveSite();
QString newDiveSiteName;
if (pickedDs == RECENTLY_ADDED_DIVESITE) {
newDiveSiteName = ui.location->text();
displayed_dive.dive_site = nullptr;
} else {
displayed_dive.dive_site = pickedDs;
}
copyTagsToDisplayedDive();
Command::addDive(&displayed_dive, newDiveSiteName, autogroup, true);
editMode = NONE;
MainWindow::instance()->exitEditState();
cylindersModel->changed = false;
weightModel->changed = false;
MainWindow::instance()->setEnabledToolbar(true);
ui.editDiveSiteButton->setEnabled(!ui.location->text().isEmpty());
emit addDiveFinished();
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::NOTHING);
MainWindow::instance()->diveList->setFocus();
displayed_dive.divetrip = nullptr; // Should not be necessary, just in case!
return;
} else {
// Get list of selected dives, but put the current dive last; // Get list of selected dives, but put the current dive last;
// this is required in case the invocation wants to compare things // this is required in case the invocation wants to compare things
// to the original value in current_dive like it should // to the original value in current_dive like it should
@ -848,7 +807,6 @@ void MainTab::acceptChanges()
cd->weightsystem[i].description = copy_string(displayed_dive.weightsystem[i].description); cd->weightsystem[i].description = copy_string(displayed_dive.weightsystem[i].description);
} }
} }
}
if (lastMode == MANUALLY_ADDED_DIVE) { if (lastMode == MANUALLY_ADDED_DIVE) {
// we just added or edited the dive, let fixup_dive() make // we just added or edited the dive, let fixup_dive() make
// sure we get the max. depth right // sure we get the max. depth right
@ -904,10 +862,8 @@ void MainTab::rejectChanges()
tabBar()->setTabIcon(0, QIcon()); // Notes tabBar()->setTabIcon(0, QIcon()); // Notes
tabBar()->setTabIcon(1, QIcon()); // Equipment tabBar()->setTabIcon(1, QIcon()); // Equipment
hideMessage(); hideMessage();
// no harm done to call cancelPlan even if we were not in ADD or PLAN mode... // no harm done to call cancelPlan even if we were not PLAN mode...
DivePlannerPointsModel::instance()->cancelPlan(); DivePlannerPointsModel::instance()->cancelPlan();
if(lastMode == ADD)
MainWindow::instance()->diveList->restoreSelection();
// now make sure that the correct dive is displayed // now make sure that the correct dive is displayed
if (current_dive) if (current_dive)
@ -1027,15 +983,6 @@ void MainTab::on_timeEdit_timeChanged(const QTime &time)
shiftTime(dateTime); shiftTime(dateTime);
} }
void MainTab::copyTagsToDisplayedDive()
{
taglist_free(displayed_dive.tag_list);
displayed_dive.tag_list = NULL;
Q_FOREACH (const QString &tag, ui.tagWidget->getBlockStringList())
taglist_add_tag(&displayed_dive.tag_list, qPrintable(tag));
taglist_cleanup(&displayed_dive.tag_list);
}
void MainTab::on_tagWidget_editingFinished() void MainTab::on_tagWidget_editingFinished()
{ {
if (editMode == IGNORE || !current_dive) if (editMode == IGNORE || !current_dive)

View file

@ -39,7 +39,6 @@ public:
enum EditMode { enum EditMode {
NONE, NONE,
DIVE, DIVE,
ADD,
MANUALLY_ADDED_DIVE, MANUALLY_ADDED_DIVE,
IGNORE IGNORE
}; };
@ -56,7 +55,6 @@ public:
void nextInputField(QKeyEvent *event); void nextInputField(QKeyEvent *event);
signals: signals:
void addDiveFinished();
void diveSiteChanged(); void diveSiteChanged();
public public
slots: slots:
@ -69,7 +67,6 @@ slots:
void updateMode(struct dive *d); void updateMode(struct dive *d);
void updateDateTime(struct dive *d); void updateDateTime(struct dive *d);
void updateDiveSite(struct dive *d); void updateDiveSite(struct dive *d);
void updateDepthDuration();
void acceptChanges(); void acceptChanges();
void rejectChanges(); void rejectChanges();
void on_location_diveSiteSelected(); void on_location_diveSiteSelected();
@ -90,7 +87,6 @@ slots:
void on_tagWidget_editingFinished(); void on_tagWidget_editingFinished();
void editCylinderWidget(const QModelIndex &index); void editCylinderWidget(const QModelIndex &index);
void editWeightWidget(const QModelIndex &index); void editWeightWidget(const QModelIndex &index);
void addDiveStarted();
void addMessageAction(QAction *action); void addMessageAction(QAction *action);
void hideMessage(); void hideMessage();
void closeMessage(); void closeMessage();
@ -114,7 +110,6 @@ private:
bool lastSelectedDive; bool lastSelectedDive;
int lastTabSelectedDive; int lastTabSelectedDive;
int lastTabSelectedDiveTrip; int lastTabSelectedDiveTrip;
void copyTagsToDisplayedDive();
dive_trip_t *currentTrip; dive_trip_t *currentTrip;
QList<TabBase*> extraWidgets; QList<TabBase*> extraWidgets;
}; };

View file

@ -1145,11 +1145,11 @@ void DivePlannerPointsModel::createPlan(bool replanCopy)
if (!current_dive || displayed_dive.id != current_dive->id) { if (!current_dive || displayed_dive.id != current_dive->id) {
// we were planning a new dive, not re-planning an existing one // we were planning a new dive, not re-planning an existing one
displayed_dive.divetrip = nullptr; // Should not be necessary, just in case! displayed_dive.divetrip = nullptr; // Should not be necessary, just in case!
Command::addDive(&displayed_dive, QString(), autogroup, true); Command::addDive(&displayed_dive, autogroup, true);
} else if (replanCopy) { } else if (replanCopy) {
// we were planning an old dive and save as a new dive // we were planning an old dive and save as a new dive
displayed_dive.id = dive_getUniqID(); // Things will break horribly if we create dives with the same id. displayed_dive.id = dive_getUniqID(); // Things will break horribly if we create dives with the same id.
Command::addDive(&displayed_dive, QString(), false, false); Command::addDive(&displayed_dive, false, false);
} else { } else {
// we were planning an old dive and rewrite the plan // we were planning an old dive and rewrite the plan
mark_divelist_changed(true); mark_divelist_changed(true);