diff --git a/CHANGELOG.md b/CHANGELOG.md index b342396a3..3fe7e054f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +desktop: remove divesite list from tab-widgets infobox: show an icon for warnings import: allow import of divesites without UUID profile: implement panning of the profile diff --git a/desktop-widgets/CMakeLists.txt b/desktop-widgets/CMakeLists.txt index eab95bd66..add1f170a 100644 --- a/desktop-widgets/CMakeLists.txt +++ b/desktop-widgets/CMakeLists.txt @@ -27,6 +27,7 @@ set (SUBSURFACE_UI divelogexportdialog.ui divelogimportdialog.ui divesiteimportdialog.ui + divesitelistview.ui diveplanner.ui diveshareexportdialog.ui downloadfromdivecomputer.ui @@ -57,7 +58,6 @@ set (SUBSURFACE_UI tab-widgets/TabDivePhotos.ui tab-widgets/TabDiveExtraInfo.ui tab-widgets/TabDiveEquipment.ui - tab-widgets/TabDiveSite.ui ) # the interface, in C++ @@ -80,6 +80,8 @@ set(SUBSURFACE_INTERFACE diveshareexportdialog.h divesiteimportdialog.cpp divesiteimportdialog.h + divesitelistview.cpp + divesitelistview.h downloadfromdivecomputer.cpp downloadfromdivecomputer.h filterconstraintwidget.cpp @@ -128,8 +130,6 @@ set(SUBSURFACE_INTERFACE tab-widgets/TabDivePhotos.h tab-widgets/TabDiveStatistics.cpp tab-widgets/TabDiveStatistics.h - tab-widgets/TabDiveSite.cpp - tab-widgets/TabDiveSite.h tab-widgets/maintab.cpp tab-widgets/maintab.h tableview.cpp diff --git a/desktop-widgets/tab-widgets/TabDiveSite.cpp b/desktop-widgets/divesitelistview.cpp similarity index 67% rename from desktop-widgets/tab-widgets/TabDiveSite.cpp rename to desktop-widgets/divesitelistview.cpp index 60f82a0ae..302fd3471 100644 --- a/desktop-widgets/tab-widgets/TabDiveSite.cpp +++ b/desktop-widgets/divesitelistview.cpp @@ -1,18 +1,28 @@ // SPDX-License-Identifier: GPL-2.0 -#include "TabDiveSite.h" +#include "divesitelistview.h" #include "core/subsurface-qt/divelistnotifier.h" #include "core/divesite.h" #include "core/divefilter.h" #include "qt-models/divelocationmodel.h" -#include "desktop-widgets/mainwindow.h" // to place message box +#include "desktop-widgets/mainwindow.h" #include "commands/command.h" #include -TabDiveSite::TabDiveSite(QWidget *parent) : TabBase(parent) +DiveSiteListView::DiveSiteListView(QWidget *parent) : QWidget(parent) { ui.setupUi(this); + // What follows is duplicate code with locationinformation.cpp. + // We might want to unify this. + ui.diveSiteMessage->setCloseButtonVisible(false); + + QAction *acceptAction = new QAction(tr("Done"), this); + connect(acceptAction, &QAction::triggered, this, &DiveSiteListView::done); + + ui.diveSiteMessage->setText(tr("Dive site management")); + ui.diveSiteMessage->addAction(acceptAction); + model = new DiveSiteSortedModel(this); ui.diveSites->setTitle(tr("Dive sites")); ui.diveSites->setModel(model); @@ -27,24 +37,21 @@ TabDiveSite::TabDiveSite(QWidget *parent) : TabBase(parent) for (int i = LocationInformationModel::LOCATION; i < LocationInformationModel::COLUMNS; ++i) ui.diveSites->view()->setColumnHidden(i, true); - connect(ui.diveSites, &TableView::addButtonClicked, this, &TabDiveSite::add); - connect(ui.diveSites, &TableView::itemClicked, this, &TabDiveSite::diveSiteClicked); - connect(ui.diveSites->view()->selectionModel(), &QItemSelectionModel::selectionChanged, this, &TabDiveSite::selectionChanged); + connect(ui.diveSites, &TableView::addButtonClicked, this, &DiveSiteListView::add); + connect(ui.diveSites, &TableView::itemClicked, this, &DiveSiteListView::diveSiteClicked); + connect(ui.diveSites->view()->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DiveSiteListView::selectionChanged); // Subtle: We depend on this slot being executed after the slot in the model. // This is realized because the model was constructed as a member object and connects in the constructor. - connect(&diveListNotifier, &DiveListNotifier::diveSiteChanged, this, &TabDiveSite::diveSiteChanged); + connect(&diveListNotifier, &DiveListNotifier::diveSiteChanged, this, &DiveSiteListView::diveSiteChanged); } -void TabDiveSite::updateData() +void DiveSiteListView::done() { + MainWindow::instance()->setApplicationState(MainWindow::ApplicationState::Default); } -void TabDiveSite::clear() -{ -} - -void TabDiveSite::diveSiteClicked(const QModelIndex &index) +void DiveSiteListView::diveSiteClicked(const QModelIndex &index) { struct dive_site *ds = model->getDiveSite(index); if (!ds) @@ -55,7 +62,7 @@ void TabDiveSite::diveSiteClicked(const QModelIndex &index) break; case LocationInformationModel::REMOVE: if (ds->dives.nr > 0 && - QMessageBox::warning(MainWindow::instance(), tr("Delete dive site?"), + QMessageBox::warning(this, tr("Delete dive site?"), tr("This dive site has %n dive(s). Do you really want to delete it?\n", "", ds->dives.nr), QMessageBox::Yes|QMessageBox::No) == QMessageBox::No) return; @@ -64,7 +71,7 @@ void TabDiveSite::diveSiteClicked(const QModelIndex &index) } } -void TabDiveSite::add() +void DiveSiteListView::add() { // This is mighty dirty: We hook into the "dive site added" signal and // select the name field of the added dive site when the command sends @@ -72,12 +79,12 @@ void TabDiveSite::add() // connection first. Very subtle! // After the command has finished, the signal is disconnected so that dive // site names are not selected on regular redo / undo. - connect(&diveListNotifier, &DiveListNotifier::diveSiteAdded, this, &TabDiveSite::diveSiteAdded); + connect(&diveListNotifier, &DiveListNotifier::diveSiteAdded, this, &DiveSiteListView::diveSiteAdded); Command::addDiveSite(tr("New dive site")); - disconnect(&diveListNotifier, &DiveListNotifier::diveSiteAdded, this, &TabDiveSite::diveSiteAdded); + disconnect(&diveListNotifier, &DiveListNotifier::diveSiteAdded, this, &DiveSiteListView::diveSiteAdded); } -void TabDiveSite::diveSiteAdded(struct dive_site *, int idx) +void DiveSiteListView::diveSiteAdded(struct dive_site *, int idx) { if (idx < 0) return; @@ -87,7 +94,7 @@ void TabDiveSite::diveSiteAdded(struct dive_site *, int idx) ui.diveSites->view()->edit(localIdx); } -void TabDiveSite::diveSiteChanged(struct dive_site *ds, int field) +void DiveSiteListView::diveSiteChanged(struct dive_site *ds, int field) { int idx = get_divesite_idx(ds, &dive_site_table); if (idx < 0) @@ -97,17 +104,17 @@ void TabDiveSite::diveSiteChanged(struct dive_site *ds, int field) ui.diveSites->view()->scrollTo(localIdx); } -void TabDiveSite::on_purgeUnused_clicked() +void DiveSiteListView::on_purgeUnused_clicked() { Command::purgeUnusedDiveSites(); } -void TabDiveSite::on_filterText_textChanged(const QString &text) +void DiveSiteListView::on_filterText_textChanged(const QString &text) { model->setFilter(text); } -QVector TabDiveSite::selectedDiveSites() +QVector DiveSiteListView::selectedDiveSites() { const QModelIndexList indices = ui.diveSites->view()->selectionModel()->selectedRows(); QVector sites; @@ -119,20 +126,21 @@ QVector TabDiveSite::selectedDiveSites() return sites; } -void TabDiveSite::selectionChanged(const QItemSelection &, const QItemSelection &) +void DiveSiteListView::selectionChanged(const QItemSelection &, const QItemSelection &) { DiveFilter::instance()->setFilterDiveSite(selectedDiveSites()); } -void TabDiveSite::showEvent(QShowEvent *) +void DiveSiteListView::hideEvent(QHideEvent *) +{ + // If the user switches to the dive site tab and there was already a selection, + // filter on that selection. + DiveFilter::instance()->stopFilterDiveSites(); +} + +void DiveSiteListView::showEvent(QShowEvent *) { // If the user switches to the dive site tab and there was already a selection, // filter on that selection. DiveFilter::instance()->startFilterDiveSites(selectedDiveSites()); } - -void TabDiveSite::hideEvent(QHideEvent *) -{ - // If the user switches to a different tab, stop the dive site filtering - DiveFilter::instance()->stopFilterDiveSites(); -} diff --git a/desktop-widgets/tab-widgets/TabDiveSite.h b/desktop-widgets/divesitelistview.h similarity index 71% rename from desktop-widgets/tab-widgets/TabDiveSite.h rename to desktop-widgets/divesitelistview.h index d123dc28e..3457ac5e3 100644 --- a/desktop-widgets/tab-widgets/TabDiveSite.h +++ b/desktop-widgets/divesitelistview.h @@ -1,20 +1,18 @@ // SPDX-License-Identifier: GPL-2.0 -#ifndef TAB_DIVE_SITE_H -#define TAB_DIVE_SITE_H +#ifndef DIVE_SITE_LIST_VIEW_H +#define DIVE_SITE_LIST_VIEW_H -#include "TabBase.h" -#include "ui_TabDiveSite.h" +#include "ui_divesitelistview.h" class DiveSiteSortedModel; -class TabDiveSite : public TabBase { +class DiveSiteListView : public QWidget { Q_OBJECT public: - TabDiveSite(QWidget *parent = 0); - void updateData() override; - void clear() override; + DiveSiteListView(QWidget *parent = 0); private slots: void add(); + void done(); void diveSiteAdded(struct dive_site *, int idx); void diveSiteChanged(struct dive_site *ds, int field); void diveSiteClicked(const QModelIndex &); @@ -22,7 +20,7 @@ private slots: void on_filterText_textChanged(const QString &text); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); private: - Ui::TabDiveSite ui; + Ui::DiveSiteListView ui; DiveSiteSortedModel *model; QVector selectedDiveSites(); void hideEvent(QHideEvent *) override; diff --git a/desktop-widgets/tab-widgets/TabDiveSite.ui b/desktop-widgets/divesitelistview.ui similarity index 80% rename from desktop-widgets/tab-widgets/TabDiveSite.ui rename to desktop-widgets/divesitelistview.ui index adb16f598..496c3d103 100644 --- a/desktop-widgets/tab-widgets/TabDiveSite.ui +++ b/desktop-widgets/divesitelistview.ui @@ -1,7 +1,7 @@ - TabDiveSite - + DiveSiteListView + 0 @@ -14,6 +14,16 @@ Dive sites + + + + + 0 + 0 + + + + diff --git a/desktop-widgets/locationinformation.cpp b/desktop-widgets/locationinformation.cpp index 76afaee79..4b061c4d1 100644 --- a/desktop-widgets/locationinformation.cpp +++ b/desktop-widgets/locationinformation.cpp @@ -246,7 +246,6 @@ void LocationInformationWidget::initFields(dive_site *ds) } } - void LocationInformationWidget::on_GPSbutton_clicked() { QFileInfo finfo(system_default_directory()); diff --git a/desktop-widgets/mainwindow.cpp b/desktop-widgets/mainwindow.cpp index 3dc99dab2..c7b171991 100644 --- a/desktop-widgets/mainwindow.cpp +++ b/desktop-widgets/mainwindow.cpp @@ -39,8 +39,9 @@ #include "desktop-widgets/divelistview.h" #include "desktop-widgets/divelogexportdialog.h" #include "desktop-widgets/divelogimportdialog.h" -#include "desktop-widgets/divesiteimportdialog.h" #include "desktop-widgets/diveplanner.h" +#include "desktop-widgets/divesiteimportdialog.h" +#include "desktop-widgets/divesitelistview.h" #include "desktop-widgets/downloadfromdivecomputer.h" #include "desktop-widgets/findmovedimagesdialog.h" #include "desktop-widgets/locationinformation.h" @@ -139,6 +140,7 @@ MainWindow::MainWindow() : #endif plannerWidgets.reset(new PlannerWidgets); statistics.reset(new StatsWidget); + diveSites.reset(new DiveSiteListView); profile.reset(new ProfileWidget); diveSiteEdit.reset(new LocationInformationWidget); @@ -155,6 +157,8 @@ MainWindow::MainWindow() : { diveList.get(), FLAG_NONE }, { &filterWidget, FLAG_NONE } }); registerApplicationState(ApplicationState::Statistics, { true, { statistics.get(), FLAG_NONE }, { nullptr, FLAG_NONE }, { diveList.get(), FLAG_DISABLED }, { &filterWidget, FLAG_NONE } }); + registerApplicationState(ApplicationState::DiveSites, { false, { diveSites.get(), FLAG_NONE }, { profile.get(), FLAG_NONE }, + { diveList.get(), FLAG_NONE }, { mapWidget.get(), FLAG_NONE } }); registerApplicationState(ApplicationState::MapMaximized, { true, { nullptr, FLAG_NONE }, { nullptr, FLAG_NONE }, { nullptr, FLAG_NONE }, { mapWidget.get(), FLAG_NONE } }); registerApplicationState(ApplicationState::ProfileMaximized, { true, { nullptr, FLAG_NONE }, { profile.get(), FLAG_NONE }, @@ -757,6 +761,13 @@ void MainWindow::on_actionViewMap_triggered() setApplicationState(ApplicationState::MapMaximized); } +void MainWindow::on_actionViewDiveSites_triggered() +{ + if (!userMayChangeAppState()) + return; + setApplicationState(ApplicationState::DiveSites); +} + void MainWindow::on_actionViewAll_triggered() { if (!userMayChangeAppState()) @@ -1508,6 +1519,7 @@ void MainWindow::setApplicationState(ApplicationState state) ui.actionViewProfile->setEnabled(allowChange); ui.actionViewInfo->setEnabled(allowChange); ui.actionViewMap->setEnabled(allowChange); + ui.actionViewDiveSites->setEnabled(allowChange); ui.actionFilterTags->setEnabled(allowChange); } diff --git a/desktop-widgets/mainwindow.h b/desktop-widgets/mainwindow.h index 61cf97ac5..31e12694f 100644 --- a/desktop-widgets/mainwindow.h +++ b/desktop-widgets/mainwindow.h @@ -28,6 +28,7 @@ class QSortFilterProxyModel; class DiveTripModel; class QItemSelection; class DiveListView; +class DiveSiteListView; class MainTab; class MapWidget; class QWebView; @@ -59,6 +60,7 @@ public: EditDiveSite, FilterDive, Statistics, + DiveSites, MapMaximized, ProfileMaximized, ListMaximized, @@ -79,6 +81,7 @@ public: std::unique_ptr mainTab; std::unique_ptr plannerWidgets; std::unique_ptr statistics; + std::unique_ptr diveSites; std::unique_ptr diveList; std::unique_ptr profile; std::unique_ptr mapWidget; @@ -112,6 +115,7 @@ slots: void on_actionViewProfile_triggered(); void on_actionViewInfo_triggered(); void on_actionViewMap_triggered(); + void on_actionViewDiveSites_triggered(); void on_actionViewAll_triggered(); void on_actionPreviousDC_triggered(); void on_actionNextDC_triggered(); diff --git a/desktop-widgets/mainwindow.ui b/desktop-widgets/mainwindow.ui index 61541b1ef..921ce9e55 100644 --- a/desktop-widgets/mainwindow.ui +++ b/desktop-widgets/mainwindow.ui @@ -93,6 +93,7 @@ + @@ -343,6 +344,14 @@ Ctrl+5 + + + Dive sites + + + Ctrl+6 + + P&lan dive diff --git a/desktop-widgets/tab-widgets/maintab.cpp b/desktop-widgets/tab-widgets/maintab.cpp index 079902b3f..cd3f5972e 100644 --- a/desktop-widgets/tab-widgets/maintab.cpp +++ b/desktop-widgets/tab-widgets/maintab.cpp @@ -13,7 +13,6 @@ #include "TabDiveNotes.h" #include "TabDivePhotos.h" #include "TabDiveStatistics.h" -#include "TabDiveSite.h" #include "core/selection.h" #include "desktop-widgets/simplewidgets.h" // for isGnome3Session() @@ -44,8 +43,6 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent), addTab(extraWidgets.last(), tr("Media")); extraWidgets << new TabDiveExtraInfo(this); addTab(extraWidgets.last(), tr("Extra Info")); - extraWidgets << new TabDiveSite(this); - addTab(extraWidgets.last(), tr("Dive sites")); // make sure we know if this is a light or dark mode isDark = paletteIsDark(palette()); @@ -107,39 +104,30 @@ void MainTab::updateDiveInfo() if (DivePlannerPointsModel::instance()->isPlanner()) return; - // If there is no current dive, disable all widgets except the last one, - // which is the dive site tab - // TODO: Conceptually, this shouldn't even be a tab here! + // If there is no current dive, disable all widgets. bool enabled = current_dive != nullptr; - for (int i = 0; i < extraWidgets.size() - 1; ++i) - extraWidgets[i]->setEnabled(enabled); + for (TabBase *widget: extraWidgets) + widget->setEnabled(enabled); if (current_dive) { for (TabBase *widget: extraWidgets) widget->updateData(); - - // If we're on the dive-site tab, we don't want to switch tab when entering / exiting - // trip mode. The reason is that - // 1) this disrupts the user-experience and - // 2) the filter is reset, potentially erasing the current trip under our feet. - // TODO: Don't hard code tab location! - bool onDiveSiteTab = currentIndex() == 6; if (single_selected_trip()) { // Remember the tab selected for last dive but only if we're not on the dive site tab - if (lastSelectedDive && !onDiveSiteTab) + if (lastSelectedDive) lastTabSelectedDive = currentIndex(); setTabText(0, tr("Trip notes")); // Recover the tab selected for last dive trip but only if we're not on the dive site tab - if (lastSelectedDive && !onDiveSiteTab) + if (lastSelectedDive) setCurrentIndex(lastTabSelectedDiveTrip); lastSelectedDive = false; } else { // Remember the tab selected for last dive trip but only if we're not on the dive site tab - if (!lastSelectedDive && !onDiveSiteTab) + if (!lastSelectedDive) lastTabSelectedDiveTrip = currentIndex(); setTabText(0, tr("Notes")); // Recover the tab selected for last dive but only if we're not on the dive site tab - if (!lastSelectedDive && !onDiveSiteTab) + if (!lastSelectedDive) setCurrentIndex(lastTabSelectedDive); lastSelectedDive = true; }