diff --git a/desktop-widgets/CMakeLists.txt b/desktop-widgets/CMakeLists.txt index 2b482ba97..82ca26aa6 100644 --- a/desktop-widgets/CMakeLists.txt +++ b/desktop-widgets/CMakeLists.txt @@ -52,6 +52,7 @@ set (SUBSURFACE_UI urldialog.ui webservices.ui tab-widgets/maintab.ui + tab-widgets/TabDiveNotes.ui tab-widgets/TabDiveStatistics.ui tab-widgets/TabDiveInformation.ui tab-widgets/TabDivePhotos.ui @@ -116,6 +117,8 @@ set(SUBSURFACE_INTERFACE subsurfacewebservices.h tab-widgets/TabBase.cpp tab-widgets/TabBase.h + tab-widgets/TabDiveNotes.cpp + tab-widgets/TabDiveNotes.h tab-widgets/TabDiveExtraInfo.cpp tab-widgets/TabDiveExtraInfo.h tab-widgets/TabDiveEquipment.cpp diff --git a/desktop-widgets/tab-widgets/TabBase.cpp b/desktop-widgets/tab-widgets/TabBase.cpp index fa0a88f06..53d467492 100644 --- a/desktop-widgets/tab-widgets/TabBase.cpp +++ b/desktop-widgets/tab-widgets/TabBase.cpp @@ -9,3 +9,11 @@ void TabBase::updateUi(QString titleColor) { Q_UNUSED(titleColor) } + +void TabBase::enterEditMode() +{ +} + +void TabBase::exitEditMode() +{ +} diff --git a/desktop-widgets/tab-widgets/TabBase.h b/desktop-widgets/tab-widgets/TabBase.h index 928de633f..a9ee13545 100644 --- a/desktop-widgets/tab-widgets/TabBase.h +++ b/desktop-widgets/tab-widgets/TabBase.h @@ -14,6 +14,8 @@ public: virtual void updateData() = 0; virtual void clear() = 0; virtual void updateUi(QString titleColor); + virtual void enterEditMode(); + virtual void exitEditMode(); }; #endif diff --git a/desktop-widgets/tab-widgets/TabDiveNotes.cpp b/desktop-widgets/tab-widgets/TabDiveNotes.cpp new file mode 100644 index 000000000..fe5b67535 --- /dev/null +++ b/desktop-widgets/tab-widgets/TabDiveNotes.cpp @@ -0,0 +1,419 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "TabDiveNotes.h" +#include "core/divesite.h" +#include "core/qthelper.h" +#include "core/selection.h" +#include "core/subsurface-string.h" +#include "core/trip.h" +#include "desktop-widgets/mainwindow.h" +#include "desktop-widgets/mapwidget.h" +#include "desktop-widgets/simplewidgets.h" +#include "qt-models/diveplannermodel.h" +#include "commands/command.h" + +#include +#include + +struct Completers { + QCompleter *diveguide; + QCompleter *buddy; + QCompleter *tags; +}; + +TabDiveNotes::TabDiveNotes(QWidget *parent) : TabBase(parent), + ignoreInput(false), + currentTrip(0) +{ + ui.setupUi(this); + + updateDateTimeFields(); + + connect(&diveListNotifier, &DiveListNotifier::divesChanged, this, &TabDiveNotes::divesChanged); + connect(&diveListNotifier, &DiveListNotifier::tripChanged, this, &TabDiveNotes::tripChanged); + connect(&diveListNotifier, &DiveListNotifier::diveSiteChanged, this, &TabDiveNotes::diveSiteEdited); + connect(&diveListNotifier, &DiveListNotifier::commandExecuted, this, &TabDiveNotes::closeWarning); + + connect(ui.editDiveSiteButton, &QToolButton::clicked, MainWindow::instance(), &MainWindow::startDiveSiteEdit); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + connect(ui.location, &DiveLocationLineEdit::entered, MapWidget::instance(), &MapWidget::centerOnIndex); + connect(ui.location, &DiveLocationLineEdit::currentChanged, MapWidget::instance(), &MapWidget::centerOnIndex); +#endif + connect(ui.location, &DiveLocationLineEdit::editingFinished, this, &TabDiveNotes::on_location_diveSiteSelected); + + // One might think that we could listen to the precise property-changed signals of the preferences system. + // Alas, this is not the case. When the user switches to system-format, the preferences sends the according + // signal. However, the correct date and time format is set by the preferences dialog later. This should be fixed. + connect(&diveListNotifier, &DiveListNotifier::settingsChanged, this, &TabDiveNotes::updateDateTimeFields); + + QAction *action = new QAction(tr("OK"), this); + connect(action, &QAction::triggered, this, &TabDiveNotes::closeWarning); + ui.multiDiveWarningMessage->addAction(action); + + action = new QAction(tr("Undo"), this); + connect(action, &QAction::triggered, Command::undoAction(this), &QAction::trigger); + connect(action, &QAction::triggered, this, &TabDiveNotes::closeWarning); + ui.multiDiveWarningMessage->addAction(action); + + Completers completers; + completers.buddy = new QCompleter(&buddyModel, ui.buddy); + completers.diveguide = new QCompleter(&diveGuideModel, ui.diveguide); + completers.tags = new QCompleter(&tagModel, ui.tagWidget); + completers.buddy->setCaseSensitivity(Qt::CaseInsensitive); + completers.diveguide->setCaseSensitivity(Qt::CaseInsensitive); + completers.tags->setCaseSensitivity(Qt::CaseInsensitive); + ui.buddy->setCompleter(completers.buddy); + ui.diveguide->setCompleter(completers.diveguide); + ui.tagWidget->setCompleter(completers.tags); + ui.multiDiveWarningMessage->hide(); + ui.depth->hide(); + ui.depthLabel->hide(); + ui.duration->hide(); + ui.durationLabel->hide(); + setMinimumHeight(0); + setMinimumWidth(0); + + connect(ui.multiDiveWarningMessage, &KMessageWidget::showAnimationFinished, + ui.location, &DiveLocationLineEdit::fixPopupPosition); + + // enable URL clickability in notes: + new TextHyperlinkEventFilter(ui.notes); //destroyed when ui.notes is destroyed + + ui.diveTripLocation->hide(); +} + +void TabDiveNotes::updateDateTimeFields() +{ + ui.dateEdit->setDisplayFormat(prefs.date_format); + ui.timeEdit->setDisplayFormat(prefs.time_format); +} + +void TabDiveNotes::closeWarning() +{ + ui.multiDiveWarningMessage->hide(); +} + +// This function gets called if a field gets updated by an undo command. +// Refresh the corresponding UI field. +void TabDiveNotes::divesChanged(const QVector &dives, DiveField field) +{ + // If the current dive is not in list of changed dives, do nothing + if (!current_dive || !dives.contains(current_dive)) + return; + + if (field.duration) + ui.duration->setText(render_seconds_to_string(current_dive->duration.seconds)); + if (field.depth) + ui.depth->setText(get_depth_string(current_dive->maxdepth, true)); + if (field.rating) + ui.rating->setCurrentStars(current_dive->rating); + if (field.notes) + updateNotes(current_dive); + if (field.datetime) { + updateDateTime(current_dive); + DivePlannerPointsModel::instance()->getDiveplan().when = current_dive->when; + } + if (field.divesite) + updateDiveSite(current_dive); + if (field.tags) + ui.tagWidget->setText(get_taglist_string(current_dive->tag_list)); + if (field.buddy) + ui.buddy->setText(current_dive->buddy); + if (field.diveguide) + ui.diveguide->setText(current_dive->diveguide); +} + +void TabDiveNotes::diveSiteEdited(dive_site *ds, int) +{ + if (current_dive && current_dive->dive_site == ds) + updateDiveSite(current_dive); +} + +// This function gets called if a trip-field gets updated by an undo command. +// Refresh the corresponding UI field. +void TabDiveNotes::tripChanged(dive_trip *trip, TripField field) +{ + // If the current dive is not in list of changed dives, do nothing + if (currentTrip != trip) + return; + + if (field.notes) + ui.notes->setText(currentTrip->notes); + if (field.location) + ui.diveTripLocation->setText(currentTrip->location); +} + +static bool isHtml(const QString &s) +{ + return s.contains("notes); + if (isHtml(tmp)) { + ui.notes->setHtml(tmp); + } else { + ui.notes->setPlainText(tmp); + } +} + +void TabDiveNotes::updateDateTime(const struct dive *d) +{ + QDateTime localTime = timestampToDateTime(d->when); + ui.dateEdit->setDate(localTime.date()); + ui.timeEdit->setTime(localTime.time()); +} + +void TabDiveNotes::updateTripDate(const struct dive_trip *t) +{ + QDateTime localTime = timestampToDateTime(trip_date(t)); + ui.dateEdit->setDate(localTime.date()); +} + +void TabDiveNotes::updateDiveSite(struct dive *d) +{ + struct dive_site *ds = d->dive_site; + ui.location->setCurrentDiveSite(d); + if (ds) { + ui.locationTags->setText(constructLocationTags(&ds->taxonomy, true)); + + if (ui.locationTags->text().isEmpty() && has_location(&ds->location)) + ui.locationTags->setText(printGPSCoords(&ds->location)); + ui.editDiveSiteButton->setEnabled(true); + } else { + ui.locationTags->clear(); + ui.editDiveSiteButton->setEnabled(false); + } + + if (ui.locationTags->text().isEmpty()) + ui.locationTags->hide(); + else + ui.locationTags->show(); +} + +void TabDiveNotes::updateData() +{ + ui.location->refreshDiveSiteCache(); + + ignoreInput = true; // don't trigger on changes to the widgets + + currentTrip = single_selected_trip(); + if (currentTrip) { + // only use trip relevant fields + ui.diveguide->setVisible(false); + ui.DiveguideLabel->setVisible(false); + ui.buddy->setVisible(false); + ui.BuddyLabel->setVisible(false); + ui.rating->setVisible(false); + ui.RatingLabel->setVisible(false); + ui.tagWidget->setVisible(false); + ui.TagLabel->setVisible(false); + ui.dateEdit->setReadOnly(true); + ui.timeLabel->setVisible(false); + ui.timeEdit->setVisible(false); + ui.diveTripLocation->show(); + ui.location->hide(); + ui.locationPopupButton->hide(); + ui.editDiveSiteButton->hide(); + // rename the remaining fields and fill data from selected trip + ui.LocationLabel->setText(tr("Trip location")); + ui.diveTripLocation->setText(currentTrip->location); + updateTripDate(currentTrip); + ui.locationTags->clear(); + //TODO: Fix this. + //ui.location->setText(currentTrip->location); + ui.NotesLabel->setText(tr("Trip notes")); + ui.notes->setText(currentTrip->notes); + ui.depth->setVisible(false); + ui.depthLabel->setVisible(false); + ui.duration->setVisible(false); + ui.durationLabel->setVisible(false); + } else { + // make all the fields visible writeable + ui.diveTripLocation->hide(); + ui.location->show(); + ui.locationPopupButton->show(); + ui.editDiveSiteButton->show(); + ui.diveguide->setVisible(true); + ui.buddy->setVisible(true); + ui.rating->setVisible(true); + ui.RatingLabel->setVisible(true); + ui.BuddyLabel->setVisible(true); + ui.DiveguideLabel->setVisible(true); + ui.TagLabel->setVisible(true); + ui.tagWidget->setVisible(true); + ui.dateEdit->setReadOnly(false); + ui.timeLabel->setVisible(true); + ui.timeEdit->setVisible(true); + /* and fill them from the dive */ + ui.rating->setCurrentStars(current_dive->rating); + // reset labels in case we last displayed trip notes + ui.LocationLabel->setText(tr("Location")); + ui.NotesLabel->setText(tr("Notes")); + ui.tagWidget->setText(get_taglist_string(current_dive->tag_list)); + bool isManual = same_string(current_dive->dc.model, "manually added dive"); + ui.depth->setVisible(isManual); + ui.depthLabel->setVisible(isManual); + ui.duration->setVisible(isManual); + ui.durationLabel->setVisible(isManual); + + updateNotes(current_dive); + updateDiveSite(current_dive); + updateDateTime(current_dive); + ui.diveguide->setText(current_dive->diveguide); + ui.buddy->setText(current_dive->buddy); + } + ui.duration->setText(render_seconds_to_string(current_dive->duration.seconds)); + ui.depth->setText(get_depth_string(current_dive->maxdepth, true)); + + ui.editDiveSiteButton->setEnabled(!ui.location->text().isEmpty()); + /* unset the special value text for date and time, just in case someone dove at midnight */ + ui.dateEdit->setSpecialValueText(QString()); + ui.timeEdit->setSpecialValueText(QString()); + + ignoreInput = false; +} + +void TabDiveNotes::clear() +{ + ui.rating->setCurrentStars(0); + ui.location->clear(); + ui.diveguide->clear(); + ui.buddy->clear(); + ui.notes->clear(); + /* set date and time to minimums which triggers showing the special value text */ + ui.dateEdit->setSpecialValueText(QString("-")); + ui.dateEdit->setMinimumDate(QDate(1, 1, 1)); + ui.dateEdit->setDate(QDate(1, 1, 1)); + ui.timeEdit->setSpecialValueText(QString("-")); + ui.timeEdit->setMinimumTime(QTime(0, 0, 0, 0)); + ui.timeEdit->setTime(QTime(0, 0, 0, 0)); + ui.tagWidget->clear(); +} + +void TabDiveNotes::divesEdited(int i) +{ + // No warning if only one dive was edited + if (i <= 1) + return; + ui.multiDiveWarningMessage->setCloseButtonVisible(false); + ui.multiDiveWarningMessage->setText(tr("Warning: edited %1 dives").arg(i)); + ui.multiDiveWarningMessage->show(); +} + +void TabDiveNotes::on_buddy_editingFinished() +{ + if (ignoreInput || !current_dive) + return; + + divesEdited(Command::editBuddies(stringToList(ui.buddy->toPlainText()), false)); +} + +void TabDiveNotes::on_diveguide_editingFinished() +{ + if (ignoreInput || !current_dive) + return; + + divesEdited(Command::editDiveGuide(stringToList(ui.diveguide->toPlainText()), false)); +} + +void TabDiveNotes::on_duration_editingFinished() +{ + if (ignoreInput || !current_dive) + return; + + // Duration editing is special: we only edit the current dive. + divesEdited(Command::editDuration(parseDurationToSeconds(ui.duration->text()), true)); +} + +void TabDiveNotes::on_depth_editingFinished() +{ + if (ignoreInput || !current_dive) + return; + + // Depth editing is special: we only edit the current dive. + divesEdited(Command::editDepth(parseLengthToMm(ui.depth->text()), true)); +} + +// Editing of the dive time is different. If multiple dives are edited, +// all dives are shifted by an offset. +static void shiftTime(QDateTime &dateTime) +{ + timestamp_t when = dateTimeToTimestamp(dateTime); + if (current_dive && current_dive->when != when) { + timestamp_t offset = when - current_dive->when; + Command::shiftTime(getDiveSelection(), (int)offset); + } +} + +void TabDiveNotes::on_dateEdit_editingFinished() +{ + if (ignoreInput || !current_dive) + return; + QDateTime dateTime = timestampToDateTime(current_dive->when); + dateTime.setDate(ui.dateEdit->date()); + shiftTime(dateTime); +} + +void TabDiveNotes::on_timeEdit_editingFinished() +{ + if (ignoreInput || !current_dive) + return; + QDateTime dateTime = timestampToDateTime(current_dive->when); + dateTime.setTime(ui.timeEdit->time()); + shiftTime(dateTime); +} + +void TabDiveNotes::on_tagWidget_editingFinished() +{ + if (ignoreInput || !current_dive) + return; + + divesEdited(Command::editTags(ui.tagWidget->getBlockStringList(), false)); +} + +void TabDiveNotes::on_location_diveSiteSelected() +{ + if (ignoreInput || !current_dive) + return; + + struct dive_site *newDs = ui.location->currDiveSite(); + if (newDs == RECENTLY_ADDED_DIVESITE) + divesEdited(Command::editDiveSiteNew(ui.location->text(), false)); + else + divesEdited(Command::editDiveSite(newDs, false)); +} + +void TabDiveNotes::on_locationPopupButton_clicked() +{ + ui.location->showAllSites(); +} + +void TabDiveNotes::on_diveTripLocation_editingFinished() +{ + if (!currentTrip) + return; + Command::editTripLocation(currentTrip, ui.diveTripLocation->text()); +} + +void TabDiveNotes::on_notes_editingFinished() +{ + if (!currentTrip && !current_dive) + return; + + QString html = ui.notes->toHtml(); + QString notes = isHtml(html) ? html : ui.notes->toPlainText(); + + if (currentTrip) + Command::editTripNotes(currentTrip, notes); + else + divesEdited(Command::editNotes(notes, false)); +} + +void TabDiveNotes::on_rating_valueChanged(int value) +{ + if (ignoreInput || !current_dive) + return; + + divesEdited(Command::editRating(value, false)); +} diff --git a/desktop-widgets/tab-widgets/TabDiveNotes.h b/desktop-widgets/tab-widgets/TabDiveNotes.h new file mode 100644 index 000000000..a0fe5490c --- /dev/null +++ b/desktop-widgets/tab-widgets/TabDiveNotes.h @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +// The notes tab. +#ifndef NOTESTAB_H +#define NOTESTAB_H + +#include "TabBase.h" +#include "ui_TabDiveNotes.h" +#include "qt-models/completionmodels.h" +#include "qt-models/divelocationmodel.h" +#include "core/dive.h" +#include "core/subsurface-qt/divelistnotifier.h" + +class ExtraDataModel; +class DivePictureModel; + +class TabDiveNotes : public TabBase { + Q_OBJECT +public: + TabDiveNotes(QWidget *parent = 0); + void updateData() override; + void clear() override; + void closeWarning(); + +public +slots: + void divesChanged(const QVector &dives, DiveField field); + void diveSiteEdited(dive_site *ds, int field); + void tripChanged(dive_trip *trip, TripField field); + void updateNotes(const struct dive *d); + void updateDateTime(const struct dive *d); + void updateTripDate(const struct dive_trip *t); + void updateDiveSite(struct dive *d); + void on_location_diveSiteSelected(); + void on_locationPopupButton_clicked(); + void on_diveguide_editingFinished(); + void on_buddy_editingFinished(); + void on_diveTripLocation_editingFinished(); + void on_notes_editingFinished(); + void on_duration_editingFinished(); + void on_depth_editingFinished(); + void on_dateEdit_editingFinished(); + void on_timeEdit_editingFinished(); + void on_rating_valueChanged(int value); + void on_tagWidget_editingFinished(); + void updateDateTimeFields(); +private: + Ui::TabDiveNotes ui; + bool ignoreInput; // When computionally editing fields, we have to ignore changed-signals + dive_trip *currentTrip; + BuddyCompletionModel buddyModel; + DiveGuideCompletionModel diveGuideModel; + TagCompletionModel tagModel; + void divesEdited(int num); // Opens a warning window if more than one dive was edited +}; + +#endif // TABDIVENOTES_H diff --git a/desktop-widgets/tab-widgets/TabDiveNotes.ui b/desktop-widgets/tab-widgets/TabDiveNotes.ui new file mode 100644 index 000000000..60984cfb0 --- /dev/null +++ b/desktop-widgets/tab-widgets/TabDiveNotes.ui @@ -0,0 +1,519 @@ + + + TabDiveNotes + + + Notes + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + true + + + + + 0 + 0 + 523 + 739 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 8 + + + 0 + + + + + Date + + + true + + + + + 1 + 0 + + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + Time + + + true + + + + 1 + 0 + + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + + 2 + 0 + + + + + + + + + 1 + 0 + + + + Depth + + + true + + + + + + + + 1 + 0 + + + + Duration (h:mm) + + + true + + + + + + + true + + + Qt::UTC + + + + 1 + 0 + + + + + + + + + 1 + 0 + + + + Qt::UTC + + + + + + + + + + + 2 + 0 + + + + + + + + + 1 + 0 + + + + + + + + + 1 + 0 + + + + + + + + + + 0 + + + 0 + + + 0 + + + + + + + Location + + + true + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + Qt::RichText + + + + + + + + + 2 + + + + + + + + ... + + + + + + + Edit dive site + + + ... + + + + :geotag-icon:geotag-icon + + + + + + + + + + + + + + 0 + + + 0 + + + 5 + + + 0 + + + + + Diveguide + + + true + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + Buddy + + + true + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + false + + + + + + + false + + + + + + + + + 5 + + + + + 5 + + + + + Tags + + + true + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QPlainTextEdit::NoWrap + + + + + + + + + 5 + + + + + + 0 + 0 + + + + Rating + + + true + + + + + + + + 0 + 0 + + + + Qt::StrongFocus + + + + + + + + + + + 0 + + + + + Notes + + + true + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + 0 + + + + + false + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + + + KMessageWidget + QFrame +
desktop-widgets/kmessagewidget.h
+ 1 +
+ + StarWidget + QWidget +
desktop-widgets/starwidget.h
+ 1 +
+ + TagWidget + QPlainTextEdit +
desktop-widgets/tagwidget.h
+
+ + DiveLocationLineEdit + QLineEdit +
desktop-widgets/locationinformation.h
+
+ + TextEdit + QTextEdit +
desktop-widgets/textedit.h
+
+
+ + + + +
diff --git a/desktop-widgets/tab-widgets/maintab.cpp b/desktop-widgets/tab-widgets/maintab.cpp index 71c6d2e02..3df2218bb 100644 --- a/desktop-widgets/tab-widgets/maintab.cpp +++ b/desktop-widgets/tab-widgets/maintab.cpp @@ -2,42 +2,24 @@ /* * maintab.cpp * - * classes for the "notebook" area of the main window of Subsurface + * "notebook" area of the main window of Subsurface * */ -#include "desktop-widgets/tab-widgets/maintab.h" -#include "desktop-widgets/mainwindow.h" -#include "desktop-widgets/mapwidget.h" -#include "core/qthelper.h" -#include "core/trip.h" -#include "qt-models/diveplannermodel.h" -#include "core/selection.h" -#include "qt-models/divecomputerextradatamodel.h" -#include "qt-models/divelocationmodel.h" -#include "qt-models/filtermodels.h" -#include "core/divesite.h" -#include "core/errorhelper.h" -#include "core/subsurface-string.h" -#include "core/gettextfromc.h" -#include "desktop-widgets/locationinformation.h" -#include "desktop-widgets/simplewidgets.h" -#include "commands/command.h" +#include "maintab.h" #include "TabDiveEquipment.h" #include "TabDiveExtraInfo.h" #include "TabDiveInformation.h" +#include "TabDiveNotes.h" #include "TabDivePhotos.h" #include "TabDiveStatistics.h" #include "TabDiveSite.h" -#include -#include +#include "core/selection.h" +#include "desktop-widgets/simplewidgets.h" // for isGnome3Session() +#include "qt-models/diveplannermodel.h" -struct Completers { - QCompleter *diveguide; - QCompleter *buddy; - QCompleter *tags; -}; +#include static bool paletteIsDark(const QPalette &p) { @@ -46,14 +28,14 @@ static bool paletteIsDark(const QPalette &p) } MainTab::MainTab(QWidget *parent) : QTabWidget(parent), - ignoreInput(false), lastSelectedDive(true), lastTabSelectedDive(0), - lastTabSelectedDiveTrip(0), - currentTrip(0) + lastTabSelectedDiveTrip(0) { ui.setupUi(this); + extraWidgets << new TabDiveNotes(this); + ui.tabWidget->addTab(extraWidgets.last(), tr("Notes")); extraWidgets << new TabDiveEquipment(this); ui.tabWidget->addTab(extraWidgets.last(), tr("Equipment")); extraWidgets << new TabDiveInformation(this); @@ -73,35 +55,8 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent), // call colorsChanged() for the initial setup now that the extraWidgets are loaded colorsChanged(); - updateDateTimeFields(); - - connect(&diveListNotifier, &DiveListNotifier::divesChanged, this, &MainTab::divesChanged); - connect(&diveListNotifier, &DiveListNotifier::tripChanged, this, &MainTab::tripChanged); - connect(&diveListNotifier, &DiveListNotifier::diveSiteChanged, this, &MainTab::diveSiteEdited); - connect(&diveListNotifier, &DiveListNotifier::commandExecuted, this, &MainTab::closeWarning); connect(&diveListNotifier, &DiveListNotifier::settingsChanged, this, &MainTab::updateDiveInfo); - connect(ui.editDiveSiteButton, &QToolButton::clicked, MainWindow::instance(), &MainWindow::startDiveSiteEdit); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - connect(ui.location, &DiveLocationLineEdit::entered, MapWidget::instance(), &MapWidget::centerOnIndex); - connect(ui.location, &DiveLocationLineEdit::currentChanged, MapWidget::instance(), &MapWidget::centerOnIndex); -#endif - connect(ui.location, &DiveLocationLineEdit::editingFinished, this, &MainTab::on_location_diveSiteSelected); - - // One might think that we could listen to the precise property-changed signals of the preferences system. - // Alas, this is not the case. When the user switches to system-format, the preferences sends the according - // signal. However, the correct date and time format is set by the preferences dialog later. This should be fixed. - connect(&diveListNotifier, &DiveListNotifier::settingsChanged, this, &MainTab::updateDateTimeFields); - - QAction *action = new QAction(tr("OK"), this); - connect(action, &QAction::triggered, this, &MainTab::closeWarning); - ui.multiDiveWarningMessage->addAction(action); - - action = new QAction(tr("Undo"), this); - connect(action, &QAction::triggered, Command::undoAction(this), &QAction::trigger); - connect(action, &QAction::triggered, this, &MainTab::closeWarning); - ui.multiDiveWarningMessage->addAction(action); - QShortcut *closeKey = new QShortcut(QKeySequence(Qt::Key_Escape), this); connect(closeKey, &QShortcut::activated, this, &MainTab::escDetected); @@ -110,34 +65,13 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent), else setDocumentMode(false); - // we start out with the fields read-only; once things are - // filled from a dive, they are made writeable - setEnabled(false); - - Completers completers; - completers.buddy = new QCompleter(&buddyModel, ui.buddy); - completers.diveguide = new QCompleter(&diveGuideModel, ui.diveguide); - completers.tags = new QCompleter(&tagModel, ui.tagWidget); - completers.buddy->setCaseSensitivity(Qt::CaseInsensitive); - completers.diveguide->setCaseSensitivity(Qt::CaseInsensitive); - completers.tags->setCaseSensitivity(Qt::CaseInsensitive); - ui.buddy->setCompleter(completers.buddy); - ui.diveguide->setCompleter(completers.diveguide); - ui.tagWidget->setCompleter(completers.tags); - ui.multiDiveWarningMessage->hide(); - ui.depth->hide(); - ui.depthLabel->hide(); - ui.duration->hide(); - ui.durationLabel->hide(); - setMinimumHeight(0); - setMinimumWidth(0); - // Current display of things on Gnome3 looks like shit, so // let's fix that. if (isGnome3Session()) { - QPalette p; - p.setColor(QPalette::Window, QColor(Qt::white)); - ui.scrollArea->viewport()->setPalette(p); + // TODO: Either do this for all scroll areas or none + //QPalette p; + //p.setColor(QPalette::Window, QColor(Qt::white)); + //ui.scrollArea->viewport()->setPalette(p); // GroupBoxes in Gnome3 looks like I'v drawn them... static const QString gnomeCss = QStringLiteral( @@ -155,84 +89,13 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent), "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1," "stop: 0 #E0E0E0, stop: 1 #FFFFFF);" "}"); - Q_FOREACH (QGroupBox *box, findChildren()) { + for (QGroupBox *box: findChildren()) box->setStyleSheet(gnomeCss); - } } // QLineEdit and QLabels should have minimal margin on the left and right but not waste vertical space QMargins margins(3, 2, 1, 0); - Q_FOREACH (QLabel *label, findChildren()) { + for (QLabel *label: findChildren()) label->setContentsMargins(margins); - } - - connect(ui.multiDiveWarningMessage, &KMessageWidget::showAnimationFinished, - ui.location, &DiveLocationLineEdit::fixPopupPosition); - - // enable URL clickability in notes: - new TextHyperlinkEventFilter(ui.notes);//destroyed when ui.notes is destroyed - - ui.diveTripLocation->hide(); -} - -void MainTab::updateDateTimeFields() -{ - ui.dateEdit->setDisplayFormat(prefs.date_format); - ui.timeEdit->setDisplayFormat(prefs.time_format); -} - -void MainTab::closeWarning() -{ - ui.multiDiveWarningMessage->hide(); -} - -// This function gets called if a field gets updated by an undo command. -// Refresh the corresponding UI field. -void MainTab::divesChanged(const QVector &dives, DiveField field) -{ - // If the current dive is not in list of changed dives, do nothing - if (!current_dive || !dives.contains(current_dive)) - return; - - if (field.duration) - ui.duration->setText(render_seconds_to_string(current_dive->duration.seconds)); - if (field.depth) - ui.depth->setText(get_depth_string(current_dive->maxdepth, true)); - if (field.rating) - ui.rating->setCurrentStars(current_dive->rating); - if (field.notes && !Command::placingCommand()) - updateNotes(current_dive); - if (field.datetime) { - updateDateTime(current_dive); - DivePlannerPointsModel::instance()->getDiveplan().when = current_dive->when; - } - if (field.divesite) - updateDiveSite(current_dive); - if (field.tags) - ui.tagWidget->setText(get_taglist_string(current_dive->tag_list)); - if (field.buddy) - ui.buddy->setText(current_dive->buddy); - if (field.diveguide) - ui.diveguide->setText(current_dive->diveguide); -} - -void MainTab::diveSiteEdited(dive_site *ds, int) -{ - if (current_dive && current_dive->dive_site == ds) - updateDiveSite(current_dive); -} - -// This function gets called if a trip-field gets updated by an undo command. -// Refresh the corresponding UI field. -void MainTab::tripChanged(dive_trip *trip, TripField field) -{ - // If the current dive is not in list of changed dives, do nothing - if (currentTrip != trip) - return; - - if (field.notes) - ui.notes->setText(currentTrip->notes); - if (field.location) - ui.diveTripLocation->setText(currentTrip->location); } void MainTab::nextInputField(QKeyEvent *event) @@ -240,57 +103,8 @@ void MainTab::nextInputField(QKeyEvent *event) keyPressEvent(event); } -static bool isHtml(const QString &s) -{ - return s.contains("notes); - if (isHtml(tmp)) - ui.notes->setHtml(tmp); - else - ui.notes->setPlainText(tmp); -} - -void MainTab::updateDateTime(const struct dive *d) -{ - QDateTime localTime = timestampToDateTime(d->when); - ui.dateEdit->setDate(localTime.date()); - ui.timeEdit->setTime(localTime.time()); -} - -void MainTab::updateTripDate(const struct dive_trip *t) -{ - QDateTime localTime = timestampToDateTime(trip_date(t)); - ui.dateEdit->setDate(localTime.date()); -} - -void MainTab::updateDiveSite(struct dive *d) -{ - struct dive_site *ds = d->dive_site; - ui.location->setCurrentDiveSite(d); - if (ds) { - ui.locationTags->setText(constructLocationTags(&ds->taxonomy, true)); - - if (ui.locationTags->text().isEmpty() && has_location(&ds->location)) - ui.locationTags->setText(printGPSCoords(&ds->location)); - ui.editDiveSiteButton->setEnabled(true); - } else { - ui.locationTags->clear(); - ui.editDiveSiteButton->setEnabled(false); - } - - if (ui.locationTags->text().isEmpty()) - ui.locationTags->hide(); - else - ui.locationTags->show(); -} - void MainTab::updateDiveInfo() { - ui.location->refreshDiveSiteCache(); // don't execute this while planning a dive if (DivePlannerPointsModel::instance()->isPlanner()) return; @@ -299,12 +113,9 @@ void MainTab::updateDiveInfo() // which are the dive site tab and the dive computer tabs. // TODO: Conceptually, these two shouldn't even be a tabs here! bool enabled = current_dive != nullptr; - ui.notesTab->setEnabled(enabled); for (int i = 0; i < extraWidgets.size() - 2; ++i) extraWidgets[i]->setEnabled(enabled); - ignoreInput = true; // don't trigger on changes to the widgets - if (current_dive) { for (TabBase *widget: extraWidgets) widget->updateData(); @@ -315,8 +126,7 @@ void MainTab::updateDiveInfo() // 2) the filter is reset, potentially erasing the current trip under our feet. // TODO: Don't hard code tab location! bool onDiveSiteTab = ui.tabWidget->currentIndex() == 6; - currentTrip = single_selected_trip(); - if (currentTrip) { + 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) lastTabSelectedDive = ui.tabWidget->currentIndex(); @@ -325,35 +135,6 @@ void MainTab::updateDiveInfo() if (lastSelectedDive && !onDiveSiteTab) ui.tabWidget->setCurrentIndex(lastTabSelectedDiveTrip); lastSelectedDive = false; - // only use trip relevant fields - ui.diveguide->setVisible(false); - ui.DiveguideLabel->setVisible(false); - ui.buddy->setVisible(false); - ui.BuddyLabel->setVisible(false); - ui.rating->setVisible(false); - ui.RatingLabel->setVisible(false); - ui.tagWidget->setVisible(false); - ui.TagLabel->setVisible(false); - ui.dateEdit->setReadOnly(true); - ui.timeLabel->setVisible(false); - ui.timeEdit->setVisible(false); - ui.diveTripLocation->show(); - ui.location->hide(); - ui.locationPopupButton->hide(); - ui.editDiveSiteButton->hide(); - // rename the remaining fields and fill data from selected trip - ui.LocationLabel->setText(tr("Trip location")); - ui.diveTripLocation->setText(currentTrip->location); - updateTripDate(currentTrip); - ui.locationTags->clear(); - //TODO: Fix this. - //ui.location->setText(currentTrip->location); - ui.NotesLabel->setText(tr("Trip notes")); - ui.notes->setText(currentTrip->notes); - ui.depth->setVisible(false); - ui.depthLabel->setVisible(false); - ui.duration->setVisible(false); - ui.durationLabel->setVisible(false); } else { // Remember the tab selected for last dive trip but only if we're not on the dive site tab if (!lastSelectedDive && !onDiveSiteTab) @@ -363,195 +144,10 @@ void MainTab::updateDiveInfo() if (!lastSelectedDive && !onDiveSiteTab) ui.tabWidget->setCurrentIndex(lastTabSelectedDive); lastSelectedDive = true; - // make all the fields visible writeable - ui.diveTripLocation->hide(); - ui.location->show(); - ui.locationPopupButton->show(); - ui.editDiveSiteButton->show(); - ui.diveguide->setVisible(true); - ui.buddy->setVisible(true); - ui.rating->setVisible(true); - ui.RatingLabel->setVisible(true); - ui.BuddyLabel->setVisible(true); - ui.DiveguideLabel->setVisible(true); - ui.TagLabel->setVisible(true); - ui.tagWidget->setVisible(true); - ui.dateEdit->setReadOnly(false); - ui.timeLabel->setVisible(true); - ui.timeEdit->setVisible(true); - /* and fill them from the dive */ - ui.rating->setCurrentStars(current_dive->rating); - // reset labels in case we last displayed trip notes - ui.LocationLabel->setText(tr("Location")); - ui.NotesLabel->setText(tr("Notes")); - ui.tagWidget->setText(get_taglist_string(current_dive->tag_list)); - bool isManual = same_string(current_dive->dc.model, "manually added dive"); - ui.depth->setVisible(isManual); - ui.depthLabel->setVisible(isManual); - ui.duration->setVisible(isManual); - ui.durationLabel->setVisible(isManual); - - updateNotes(current_dive); - updateDiveSite(current_dive); - updateDateTime(current_dive); - ui.diveguide->setText(current_dive->diveguide); - ui.buddy->setText(current_dive->buddy); } - ui.duration->setText(render_seconds_to_string(current_dive->duration.seconds)); - ui.depth->setText(get_depth_string(current_dive->maxdepth, true)); - - ui.editDiveSiteButton->setEnabled(!ui.location->text().isEmpty()); - /* unset the special value text for date and time, just in case someone dove at midnight */ - ui.dateEdit->setSpecialValueText(QString()); - ui.timeEdit->setSpecialValueText(QString()); } else { - /* clear the fields */ clearTabs(); - ui.rating->setCurrentStars(0); - ui.location->clear(); - ui.diveguide->clear(); - ui.buddy->clear(); - ui.notes->clear(); - /* set date and time to minimums which triggers showing the special value text */ - ui.dateEdit->setSpecialValueText(QString("-")); - ui.dateEdit->setMinimumDate(QDate(1, 1, 1)); - ui.dateEdit->setDate(QDate(1, 1, 1)); - ui.timeEdit->setSpecialValueText(QString("-")); - ui.timeEdit->setMinimumTime(QTime(0, 0, 0, 0)); - ui.timeEdit->setTime(QTime(0, 0, 0, 0)); - ui.tagWidget->clear(); } - ignoreInput = false; - - if (verbose && current_dive && current_dive->dive_site) - qDebug() << "Set the current dive site:" << current_dive->dive_site->uuid; -} - -void MainTab::divesEdited(int i) -{ - // No warning if only one dive was edited - if (i <= 1) - return; - ui.multiDiveWarningMessage->setCloseButtonVisible(false); - ui.multiDiveWarningMessage->setText(tr("Warning: edited %1 dives").arg(i)); - ui.multiDiveWarningMessage->show(); -} - -void MainTab::on_buddy_editingFinished() -{ - if (ignoreInput || !current_dive) - return; - - divesEdited(Command::editBuddies(stringToList(ui.buddy->toPlainText()), false)); -} - -void MainTab::on_diveguide_editingFinished() -{ - if (ignoreInput || !current_dive) - return; - - divesEdited(Command::editDiveGuide(stringToList(ui.diveguide->toPlainText()), false)); -} - -void MainTab::on_duration_editingFinished() -{ - if (ignoreInput || !current_dive) - return; - - // Duration editing is special: we only edit the current dive. - divesEdited(Command::editDuration(parseDurationToSeconds(ui.duration->text()), true)); -} - -void MainTab::on_depth_editingFinished() -{ - if (ignoreInput || !current_dive) - return; - - // Depth editing is special: we only edit the current dive. - divesEdited(Command::editDepth(parseLengthToMm(ui.depth->text()), true)); -} - -// Editing of the dive time is different. If multiple dives are edited, -// all dives are shifted by an offset. -static void shiftTime(QDateTime &dateTime) -{ - timestamp_t when = dateTimeToTimestamp(dateTime); - if (current_dive && current_dive->when != when) { - timestamp_t offset = when - current_dive->when; - Command::shiftTime(getDiveSelection(), (int)offset); - } -} - -void MainTab::on_dateEdit_editingFinished() -{ - if (ignoreInput || !current_dive) - return; - QDateTime dateTime = timestampToDateTime(current_dive->when); - dateTime.setDate(ui.dateEdit->date()); - shiftTime(dateTime); -} - -void MainTab::on_timeEdit_editingFinished() -{ - if (ignoreInput || !current_dive) - return; - QDateTime dateTime = timestampToDateTime(current_dive->when); - dateTime.setTime(ui.timeEdit->time()); - shiftTime(dateTime); -} - -void MainTab::on_tagWidget_editingFinished() -{ - if (ignoreInput || !current_dive) - return; - - divesEdited(Command::editTags(ui.tagWidget->getBlockStringList(), false)); -} - -void MainTab::on_location_diveSiteSelected() -{ - if (ignoreInput || !current_dive) - return; - - struct dive_site *newDs = ui.location->currDiveSite(); - if (newDs == RECENTLY_ADDED_DIVESITE) - divesEdited(Command::editDiveSiteNew(ui.location->text(), false)); - else - divesEdited(Command::editDiveSite(newDs, false)); -} - -void MainTab::on_locationPopupButton_clicked() -{ - ui.location->showAllSites(); -} - -void MainTab::on_diveTripLocation_editingFinished() -{ - if (!currentTrip) - return; - Command::editTripLocation(currentTrip, ui.diveTripLocation->text()); -} - -void MainTab::on_notes_editingFinished() -{ - if (!currentTrip && !current_dive) - return; - - QString html = ui.notes->toHtml(); - QString notes = isHtml(html) ? html : ui.notes->toPlainText(); - - if (currentTrip) - Command::editTripNotes(currentTrip, notes); - else - divesEdited(Command::editNotes(notes, false)); -} - -void MainTab::on_rating_valueChanged(int value) -{ - if (ignoreInput || !current_dive) - return; - - divesEdited(Command::editRating(value, false)); } // Remove focus from any active field to update the corresponding value in the dive. diff --git a/desktop-widgets/tab-widgets/maintab.h b/desktop-widgets/tab-widgets/maintab.h index 903b9ff1d..95fe00c76 100644 --- a/desktop-widgets/tab-widgets/maintab.h +++ b/desktop-widgets/tab-widgets/maintab.h @@ -11,14 +11,9 @@ #include #include "ui_maintab.h" -#include "qt-models/completionmodels.h" -#include "qt-models/divelocationmodel.h" #include "core/dive.h" #include "core/subsurface-qt/divelistnotifier.h" -class ExtraDataModel; -class DivePictureModel; - class TabBase; class MainTab : public QTabWidget { Q_OBJECT @@ -30,42 +25,15 @@ public: public slots: - void divesChanged(const QVector &dives, DiveField field); - void diveSiteEdited(dive_site *ds, int field); - void tripChanged(dive_trip *trip, TripField field); void updateDiveInfo(); - void updateNotes(const struct dive *d); - void updateDateTime(const struct dive *d); - void updateTripDate(const struct dive_trip *t); - void updateDiveSite(struct dive *d); - void on_location_diveSiteSelected(); - void on_locationPopupButton_clicked(); - void on_diveguide_editingFinished(); - void on_buddy_editingFinished(); - void on_diveTripLocation_editingFinished(); - void on_notes_editingFinished(); - void on_duration_editingFinished(); - void on_depth_editingFinished(); - void on_dateEdit_editingFinished(); - void on_timeEdit_editingFinished(); - void on_rating_valueChanged(int value); - void on_tagWidget_editingFinished(); - void closeWarning(); - void escDetected(void); - void updateDateTimeFields(); + void escDetected(); void colorsChanged(); private: Ui::MainTab ui; - bool ignoreInput; // When computionally editing fields, we have to ignore changed-signals - BuddyCompletionModel buddyModel; - DiveGuideCompletionModel diveGuideModel; - TagCompletionModel tagModel; bool lastSelectedDive; int lastTabSelectedDive; int lastTabSelectedDiveTrip; - dive_trip *currentTrip; QList extraWidgets; - void divesEdited(int num); // Opens a warning window if more than one dive was edited void changeEvent(QEvent *ev) override; bool isDark; }; diff --git a/desktop-widgets/tab-widgets/maintab.ui b/desktop-widgets/tab-widgets/maintab.ui index 1bf05619b..f020a4668 100644 --- a/desktop-widgets/tab-widgets/maintab.ui +++ b/desktop-widgets/tab-widgets/maintab.ui @@ -14,526 +14,15 @@ Form - - - 0 - - - Notes - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - true - - - - - 0 - 0 - 523 - 739 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - 8 - - - 0 - - - - - Date - - - true - - - - - 1 - 0 - - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - Time - - - true - - - - 1 - 0 - - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - - - - - 2 - 0 - - - - - - - - - 1 - 0 - - - - Depth - - - true - - - - - - - - 1 - 0 - - - - Duration (h:mm) - - - true - - - - - - - true - - - Qt::UTC - - - - 1 - 0 - - - - - - - - - 1 - 0 - - - - Qt::UTC - - - - - - - - - - - 2 - 0 - - - - - - - - - 1 - 0 - - - - - - - - - 1 - 0 - - - - - - - - - - 0 - - - 0 - - - 0 - - - - - - - Location - - - true - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - - - - Qt::RichText - - - - - - - - - 2 - - - - - - - - ... - - - - - - - Edit dive site - - - ... - - - - :geotag-icon:geotag-icon - - - - - - - - - - - - - - 0 - - - 0 - - - 5 - - - 0 - - - - - Dive guide - - - true - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - Buddy - - - true - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - false - - - - - - - false - - - - - - - - - 5 - - - - - 5 - - - - - Tags - - - true - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - QPlainTextEdit::NoWrap - - - - - - - - - 5 - - - - - - 0 - 0 - - - - Rating - - - true - - - - - - - - 0 - 0 - - - - Qt::StrongFocus - - - - - - - - - - - 0 - - - - - Notes - - - true - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - 0 - - - - - false - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - KMessageWidget - QFrame -
desktop-widgets/kmessagewidget.h
- 1 -
- - StarWidget - QWidget -
desktop-widgets/starwidget.h
- 1 -
- - TagWidget - QPlainTextEdit -
desktop-widgets/tagwidget.h
-
- - DiveLocationLineEdit - QLineEdit -
desktop-widgets/locationinformation.h
-
- - TextEdit - QTextEdit -
desktop-widgets/textedit.h
-
-