summaryrefslogtreecommitdiffstats
path: root/qt-ui/mainwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qt-ui/mainwindow.cpp')
-rw-r--r--qt-ui/mainwindow.cpp1922
1 files changed, 0 insertions, 1922 deletions
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
deleted file mode 100644
index e0476381f..000000000
--- a/qt-ui/mainwindow.cpp
+++ /dev/null
@@ -1,1922 +0,0 @@
-/*
- * mainwindow.cpp
- *
- * classes for the main UI window in Subsurface
- */
-#include "mainwindow.h"
-
-#include <QFileDialog>
-#include <QMessageBox>
-#include <QDesktopWidget>
-#include <QSettings>
-#include <QShortcut>
-#include <QToolBar>
-#include "version.h"
-#include "divelistview.h"
-#include "downloadfromdivecomputer.h"
-#include "preferences.h"
-#include "subsurfacewebservices.h"
-#include "divecomputermanagementdialog.h"
-#include "about.h"
-#include "updatemanager.h"
-#include "planner.h"
-#include "filtermodels.h"
-#include "profile/profilewidget2.h"
-#include "globe.h"
-#include "divecomputer.h"
-#include "maintab.h"
-#include "diveplanner.h"
-#ifndef NO_PRINTING
-#include <QPrintDialog>
-#include "printdialog.h"
-#endif
-#include "tankinfomodel.h"
-#include "weigthsysteminfomodel.h"
-#include "yearlystatisticsmodel.h"
-#include "diveplannermodel.h"
-#include "divelogimportdialog.h"
-#include "divelogexportdialog.h"
-#include "usersurvey.h"
-#include "divesitehelpers.h"
-#include "windowtitleupdate.h"
-#include "locationinformation.h"
-
-#ifndef NO_USERMANUAL
-#include "usermanual.h"
-#endif
-#include "divepicturemodel.h"
-#include "git-access.h"
-#include <QNetworkProxy>
-#include <QUndoStack>
-#include <qthelper.h>
-#include <QtConcurrentRun>
-
-#if defined(FBSUPPORT)
-#include "socialnetworks.h"
-#endif
-
-QProgressDialog *progressDialog = NULL;
-bool progressDialogCanceled = false;
-
-extern "C" int updateProgress(int percent)
-{
- if (progressDialog)
- progressDialog->setValue(percent);
- return progressDialogCanceled;
-}
-
-MainWindow *MainWindow::m_Instance = NULL;
-
-MainWindow::MainWindow() : QMainWindow(),
- actionNextDive(0),
- actionPreviousDive(0),
- helpView(0),
- state(VIEWALL),
- survey(0)
-{
- Q_ASSERT_X(m_Instance == NULL, "MainWindow", "MainWindow recreated!");
- m_Instance = this;
- ui.setupUi(this);
- read_hashes();
- // Define the States of the Application Here, Currently the states are situations where the different
- // widgets will change on the mainwindow.
-
- // for the "default" mode
- MainTab *mainTab = new MainTab();
- DiveListView *diveListView = new DiveListView();
- ProfileWidget2 *profileWidget = new ProfileWidget2();
-
-#ifndef NO_MARBLE
- GlobeGPS *globeGps = GlobeGPS::instance();
-#else
- QWidget *globeGps = NULL;
-#endif
-
- PlannerSettingsWidget *plannerSettings = new PlannerSettingsWidget();
- DivePlannerWidget *plannerWidget = new DivePlannerWidget();
- PlannerDetails *plannerDetails = new PlannerDetails();
-
- // what is a sane order for those icons? we should have the ones the user is
- // most likely to want towards the top so they are always visible
- // and the ones that someone likely sets and then never touches again towards the bottom
- profileToolbarActions << ui.profCalcCeiling << ui.profCalcAllTissues << // start with various ceilings
- ui.profIncrement3m << ui.profDcCeiling <<
- ui.profPhe << ui.profPn2 << ui.profPO2 << // partial pressure graphs
- ui.profRuler << ui.profScaled << // measuring and scaling
- ui.profTogglePicture << ui.profTankbar <<
- ui.profMod << ui.profNdl_tts << // various values that a user is either interested in or not
- ui.profEad << ui.profSAC <<
- ui.profHR << // very few dive computers support this
- ui.profTissues; // maybe less frequently used
-
- QToolBar *toolBar = new QToolBar();
- Q_FOREACH (QAction *a, profileToolbarActions)
- toolBar->addAction(a);
- toolBar->setOrientation(Qt::Vertical);
- toolBar->setIconSize(QSize(24,24));
- QWidget *profileContainer = new QWidget();
- QHBoxLayout *profLayout = new QHBoxLayout();
- profLayout->setSpacing(0);
- profLayout->setMargin(0);
- profLayout->setContentsMargins(0,0,0,0);
- profLayout->addWidget(toolBar);
- profLayout->addWidget(profileWidget);
- profileContainer->setLayout(profLayout);
-
- LocationInformationWidget * diveSiteEdit = new LocationInformationWidget();
- connect(diveSiteEdit, &LocationInformationWidget::endEditDiveSite,
- this, &MainWindow::setDefaultState);
-
- connect(diveSiteEdit, &LocationInformationWidget::endEditDiveSite,
- mainTab, &MainTab::refreshDiveInfo);
-
- connect(diveSiteEdit, &LocationInformationWidget::endEditDiveSite,
- mainTab, &MainTab::refreshDisplayedDiveSite);
-
- QWidget *diveSitePictures = new QWidget(); // Placeholder
-
- std::pair<QByteArray, QVariant> enabled = std::make_pair("enabled", QVariant(true));
- std::pair<QByteArray, QVariant> disabled = std::make_pair("enabled", QVariant(false));
- PropertyList enabledList;
- PropertyList disabledList;
- enabledList.push_back(enabled);
- disabledList.push_back(disabled);
-
- registerApplicationState("Default", mainTab, profileContainer, diveListView, globeGps );
- registerApplicationState("AddDive", mainTab, profileContainer, diveListView, globeGps );
- registerApplicationState("EditDive", mainTab, profileContainer, diveListView, globeGps );
- registerApplicationState("PlanDive", plannerWidget, profileContainer, plannerSettings, plannerDetails );
- registerApplicationState("EditPlannedDive", plannerWidget, profileContainer, diveListView, globeGps );
- registerApplicationState("EditDiveSite", diveSiteEdit, profileContainer, diveListView, globeGps);
-
- setStateProperties("Default", enabledList, enabledList, enabledList,enabledList);
- setStateProperties("AddDive", enabledList, enabledList, enabledList,enabledList);
- setStateProperties("EditDive", enabledList, enabledList, enabledList,enabledList);
- setStateProperties("PlanDive", enabledList, enabledList, enabledList,enabledList);
- setStateProperties("EditPlannedDive", enabledList, enabledList, enabledList,enabledList);
- setStateProperties("EditDiveSite", enabledList, disabledList, disabledList, enabledList);
-
- setApplicationState("Default");
-
- ui.multiFilter->hide();
-
- setWindowIcon(QIcon(":subsurface-icon"));
- if (!QIcon::hasThemeIcon("window-close")) {
- QIcon::setThemeName("subsurface");
- }
- connect(dive_list(), SIGNAL(currentDiveChanged(int)), this, SLOT(current_dive_changed(int)));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(readSettings()));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), diveListView, SLOT(update()));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), diveListView, SLOT(reloadHeaderActions()));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), information(), SLOT(updateDiveInfo()));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), divePlannerWidget(), SLOT(settingsChanged()));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), divePlannerSettingsWidget(), SLOT(settingsChanged()));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), TankInfoModel::instance(), SLOT(update()));
- connect(ui.actionRecent1, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool)));
- connect(ui.actionRecent2, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool)));
- connect(ui.actionRecent3, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool)));
- connect(ui.actionRecent4, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool)));
- connect(information(), SIGNAL(addDiveFinished()), graphics(), SLOT(setProfileState()));
- connect(DivePlannerPointsModel::instance(), SIGNAL(planCreated()), this, SLOT(planCreated()));
- connect(DivePlannerPointsModel::instance(), SIGNAL(planCanceled()), this, SLOT(planCanceled()));
- connect(plannerDetails->printPlan(), SIGNAL(pressed()), divePlannerWidget(), SLOT(printDecoPlan()));
- connect(this, SIGNAL(startDiveSiteEdit()), this, SLOT(on_actionDiveSiteEdit_triggered()));
-
-#ifndef NO_MARBLE
- connect(information(), SIGNAL(diveSiteChanged(struct dive_site *)), globeGps, SLOT(centerOnDiveSite(struct dive_site *)));
-#endif
- wtu = new WindowTitleUpdate();
- connect(WindowTitleUpdate::instance(), SIGNAL(updateTitle()), this, SLOT(setAutomaticTitle()));
-#ifdef NO_PRINTING
- plannerDetails->printPlan()->hide();
- ui.menuFile->removeAction(ui.actionPrint);
-#endif
-#ifndef USE_LIBGIT23_API
- ui.menuFile->removeAction(ui.actionCloudstorageopen);
- ui.menuFile->removeAction(ui.actionCloudstoragesave);
- qDebug() << "disabled / made invisible the cloud storage stuff";
-#else
- enableDisableCloudActions();
-#endif
-
- ui.mainErrorMessage->hide();
- graphics()->setEmptyState();
- initialUiSetup();
- readSettings();
- diveListView->reload(DiveTripModel::TREE);
- diveListView->reloadHeaderActions();
- diveListView->setFocus();
- GlobeGPS::instance()->reload();
- diveListView->expand(dive_list()->model()->index(0, 0));
- diveListView->scrollTo(dive_list()->model()->index(0, 0), QAbstractItemView::PositionAtCenter);
- divePlannerWidget()->settingsChanged();
- divePlannerSettingsWidget()->settingsChanged();
-#ifdef NO_MARBLE
- ui.menuView->removeAction(ui.actionViewGlobe);
-#endif
-#ifdef NO_USERMANUAL
- ui.menuHelp->removeAction(ui.actionUserManual);
-#endif
- memset(&copyPasteDive, 0, sizeof(copyPasteDive));
- memset(&what, 0, sizeof(what));
-
- updateManager = new UpdateManager(this);
- undoStack = new QUndoStack(this);
- QAction *undoAction = undoStack->createUndoAction(this, tr("&Undo"));
- QAction *redoAction = undoStack->createRedoAction(this, tr("&Redo"));
- undoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Z));
- redoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z));
- QList<QAction*>undoRedoActions;
- undoRedoActions.append(undoAction);
- undoRedoActions.append(redoAction);
- ui.menu_Edit->addActions(undoRedoActions);
-
- ReverseGeoLookupThread *geoLookup = ReverseGeoLookupThread::instance();
- connect(geoLookup, SIGNAL(started()),information(), SLOT(disableGeoLookupEdition()));
- connect(geoLookup, SIGNAL(finished()), information(), SLOT(enableGeoLookupEdition()));
-#ifndef NO_PRINTING
- // copy the bundled print templates to the user path; no overwriting occurs!
- copyPath(getPrintingTemplatePathBundle(), getPrintingTemplatePathUser());
- find_all_templates();
-#endif
-
-#if defined(FBSUPPORT)
- FacebookManager *fb = FacebookManager::instance();
- connect(fb, SIGNAL(justLoggedIn(bool)), ui.actionFacebook, SLOT(setEnabled(bool)));
- connect(fb, SIGNAL(justLoggedOut(bool)), ui.actionFacebook, SLOT(setEnabled(bool)));
- connect(ui.actionFacebook, SIGNAL(triggered(bool)), fb, SLOT(sendDive()));
- ui.actionFacebook->setEnabled(fb->loggedIn());
-#else
- ui.actionFacebook->setEnabled(false);
-#endif
-
-
- ui.menubar->show();
- set_git_update_cb(&updateProgress);
-}
-
-MainWindow::~MainWindow()
-{
- write_hashes();
- m_Instance = NULL;
-}
-
-void MainWindow::setStateProperties(const QByteArray& state, const PropertyList& tl, const PropertyList& tr, const PropertyList& bl, const PropertyList& br)
-{
- stateProperties[state] = PropertiesForQuadrant(tl, tr, bl, br);
-}
-
-void MainWindow::on_actionDiveSiteEdit_triggered() {
- setApplicationState("EditDiveSite");
-}
-
-void MainWindow::enableDisableCloudActions()
-{
-#ifdef USE_LIBGIT23_API
- ui.actionCloudstorageopen->setEnabled(prefs.cloud_verification_status == CS_VERIFIED);
- ui.actionCloudstoragesave->setEnabled(prefs.cloud_verification_status == CS_VERIFIED);
-#endif
-}
-
-PlannerDetails *MainWindow::plannerDetails() const {
- return qobject_cast<PlannerDetails*>(applicationState["PlanDive"].bottomRight);
-}
-
-PlannerSettingsWidget *MainWindow::divePlannerSettingsWidget() {
- return qobject_cast<PlannerSettingsWidget*>(applicationState["PlanDive"].bottomLeft);
-}
-
-void MainWindow::setDefaultState() {
- setApplicationState("Default");
- if (information()->getEditMode() != MainTab::NONE) {
- ui.bottomLeft->currentWidget()->setEnabled(false);
- }
-}
-
-void MainWindow::setLoadedWithFiles(bool f)
-{
- filesAsArguments = f;
-}
-
-bool MainWindow::filesFromCommandLine() const
-{
- return filesAsArguments;
-}
-
-MainWindow *MainWindow::instance()
-{
- return m_Instance;
-}
-
-// this gets called after we download dives from a divecomputer
-void MainWindow::refreshDisplay(bool doRecreateDiveList)
-{
- getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
- information()->reload();
- TankInfoModel::instance()->update();
- GlobeGPS::instance()->reload();
- if (doRecreateDiveList)
- recreateDiveList();
-
- setApplicationState("Default");
- dive_list()->setEnabled(true);
- dive_list()->setFocus();
- WSInfoModel::instance()->updateInfo();
- if (amount_selected == 0)
- cleanUpEmpty();
-}
-
-void MainWindow::recreateDiveList()
-{
- dive_list()->reload(DiveTripModel::CURRENT);
- TagFilterModel::instance()->repopulate();
- BuddyFilterModel::instance()->repopulate();
- LocationFilterModel::instance()->repopulate();
- SuitsFilterModel::instance()->repopulate();
-}
-
-void MainWindow::configureToolbar() {
- if (selected_dive>0) {
- if (current_dive->dc.divemode == FREEDIVE) {
- ui.profCalcCeiling->setDisabled(true);
- ui.profCalcAllTissues ->setDisabled(true);
- ui.profIncrement3m->setDisabled(true);
- ui.profDcCeiling->setDisabled(true);
- ui.profPhe->setDisabled(true);
- ui.profPn2->setDisabled(true); //TODO is the same as scuba?
- ui.profPO2->setDisabled(true); //TODO is the same as scuba?
- ui.profRuler->setDisabled(false);
- ui.profScaled->setDisabled(false); // measuring and scaling
- ui.profTogglePicture->setDisabled(false);
- ui.profTankbar->setDisabled(true);
- ui.profMod->setDisabled(true);
- ui.profNdl_tts->setDisabled(true);
- ui.profEad->setDisabled(true);
- ui.profSAC->setDisabled(true);
- ui.profHR->setDisabled(false);
- ui.profTissues->setDisabled(true);
- } else {
- ui.profCalcCeiling->setDisabled(false);
- ui.profCalcAllTissues ->setDisabled(false);
- ui.profIncrement3m->setDisabled(false);
- ui.profDcCeiling->setDisabled(false);
- ui.profPhe->setDisabled(false);
- ui.profPn2->setDisabled(false);
- ui.profPO2->setDisabled(false); // partial pressure graphs
- ui.profRuler->setDisabled(false);
- ui.profScaled->setDisabled(false); // measuring and scaling
- ui.profTogglePicture->setDisabled(false);
- ui.profTankbar->setDisabled(false);
- ui.profMod->setDisabled(false);
- ui.profNdl_tts->setDisabled(false); // various values that a user is either interested in or not
- ui.profEad->setDisabled(false);
- ui.profSAC->setDisabled(false);
- ui.profHR->setDisabled(false); // very few dive computers support this
- ui.profTissues->setDisabled(false);; // maybe less frequently used
- }
- }
-}
-
-void MainWindow::current_dive_changed(int divenr)
-{
- if (divenr >= 0) {
- select_dive(divenr);
- }
- graphics()->plotDive();
- information()->updateDiveInfo();
- configureToolbar();
- GlobeGPS::instance()->reload();
-}
-
-void MainWindow::on_actionNew_triggered()
-{
- on_actionClose_triggered();
-}
-
-void MainWindow::on_actionOpen_triggered()
-{
- if (!okToClose(tr("Please save or cancel the current dive edit before opening a new file.")))
- return;
-
- // yes, this look wrong to use getSaveFileName() for the open dialog, but we need to be able
- // to enter file names that don't exist in order to use our git syntax /path/to/dir[branch]
- // with is a potentially valid input, but of course won't exist. So getOpenFileName() wouldn't work
- QFileDialog dialog(this, tr("Open file"), lastUsedDir(), filter());
- dialog.setFileMode(QFileDialog::AnyFile);
- dialog.setViewMode(QFileDialog::Detail);
- dialog.setLabelText(QFileDialog::Accept, tr("Open"));
- dialog.setLabelText(QFileDialog::Reject, tr("Cancel"));
- dialog.setAcceptMode(QFileDialog::AcceptOpen);
- QStringList filenames;
- if (dialog.exec())
- filenames = dialog.selectedFiles();
- if (filenames.isEmpty())
- return;
- updateLastUsedDir(QFileInfo(filenames.first()).dir().path());
- closeCurrentFile();
- // some file dialogs decide to add the default extension to a filename without extension
- // so we would get dir[branch].ssrf when trying to select dir[branch].
- // let's detect that and remove the incorrect extension
- QStringList cleanFilenames;
- QRegularExpression reg(".*\\[[^]]+]\\.ssrf", QRegularExpression::CaseInsensitiveOption);
-
- Q_FOREACH (QString filename, filenames) {
- if (reg.match(filename).hasMatch())
- filename.remove(QRegularExpression("\\.ssrf$", QRegularExpression::CaseInsensitiveOption));
- cleanFilenames << filename;
- }
- loadFiles(cleanFilenames);
-}
-
-void MainWindow::on_actionSave_triggered()
-{
- file_save();
-}
-
-void MainWindow::on_actionSaveAs_triggered()
-{
- file_save_as();
-}
-
-void MainWindow::on_actionCloudstorageopen_triggered()
-{
- if (!okToClose(tr("Please save or cancel the current dive edit before opening a new file.")))
- return;
-
- QString filename;
- if (getCloudURL(filename)) {
- getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
- return;
- }
- qDebug() << filename;
-
- closeCurrentFile();
-
- int error;
-
- showProgressBar();
- QByteArray fileNamePtr = QFile::encodeName(filename);
- error = parse_file(fileNamePtr.data());
- if (!error) {
- set_filename(fileNamePtr.data(), true);
- setTitle(MWTF_FILENAME);
- }
- getNotificationWidget()->hideNotification();
- process_dives(false, false);
- hideProgressBar();
- refreshDisplay();
- ui.actionAutoGroup->setChecked(autogroup);
-}
-
-void MainWindow::on_actionCloudstoragesave_triggered()
-{
- QString filename;
- if (getCloudURL(filename)) {
- getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
- return;
- }
- qDebug() << filename;
- if (information()->isEditing())
- information()->acceptChanges();
-
- showProgressBar();
-
- if (save_dives(filename.toUtf8().data())) {
- getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
- return;
- }
-
- hideProgressBar();
-
- getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
- set_filename(filename.toUtf8().data(), true);
- setTitle(MWTF_FILENAME);
- mark_divelist_changed(false);
-}
-
-void learnImageDirs(QStringList dirnames)
-{
- QList<QFuture<void> > futures;
- foreach (QString dir, dirnames) {
- futures << QtConcurrent::run(learnImages, QDir(dir), 10, false);
- }
- DivePictureModel::instance()->updateDivePicturesWhenDone(futures);
-}
-
-void MainWindow::on_actionHash_images_triggered()
-{
- QFuture<void> future;
- QFileDialog dialog(this, tr("Traverse image directories"), lastUsedDir(), filter());
- dialog.setFileMode(QFileDialog::Directory);
- dialog.setViewMode(QFileDialog::Detail);
- dialog.setLabelText(QFileDialog::Accept, tr("Scan"));
- dialog.setLabelText(QFileDialog::Reject, tr("Cancel"));
- QStringList dirnames;
- if (dialog.exec())
- dirnames = dialog.selectedFiles();
- if (dirnames.isEmpty())
- return;
- future = QtConcurrent::run(learnImageDirs,dirnames);
- MainWindow::instance()->getNotificationWidget()->showNotification(tr("Scanning images...(this can take a while)"), KMessageWidget::Information);
- MainWindow::instance()->getNotificationWidget()->setFuture(future);
-
-}
-
-ProfileWidget2 *MainWindow::graphics() const
-{
- return qobject_cast<ProfileWidget2*>(applicationState["Default"].topRight->layout()->itemAt(1)->widget());
-}
-
-void MainWindow::cleanUpEmpty()
-{
- information()->clearStats();
- information()->clearInfo();
- information()->clearEquipment();
- information()->updateDiveInfo(true);
- graphics()->setEmptyState();
- dive_list()->reload(DiveTripModel::TREE);
- GlobeGPS::instance()->reload();
- if (!existing_filename)
- setTitle(MWTF_DEFAULT);
- disableShortcuts();
-}
-
-bool MainWindow::okToClose(QString message)
-{
- if (DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING ||
- information()->isEditing() ) {
- QMessageBox::warning(this, tr("Warning"), message);
- return false;
- }
- if (unsaved_changes() && askSaveChanges() == false)
- return false;
-
- return true;
-}
-
-void MainWindow::closeCurrentFile()
-{
- graphics()->setEmptyState();
- /* free the dives and trips */
- clear_git_id();
- clear_dive_file_data();
- cleanUpEmpty();
- mark_divelist_changed(false);
-
- clear_events();
-
- dcList.dcMap.clear();
-}
-
-void MainWindow::on_actionClose_triggered()
-{
- if (okToClose(tr("Please save or cancel the current dive edit before closing the file."))) {
- closeCurrentFile();
- // hide any pictures and the filter
- DivePictureModel::instance()->updateDivePictures();
- ui.multiFilter->closeFilter();
- recreateDiveList();
- }
-}
-
-QString MainWindow::lastUsedDir()
-{
- QSettings settings;
- QString lastDir = QDir::homePath();
-
- settings.beginGroup("FileDialog");
- if (settings.contains("LastDir"))
- if (QDir::setCurrent(settings.value("LastDir").toString()))
- lastDir = settings.value("LastDir").toString();
- return lastDir;
-}
-
-void MainWindow::updateLastUsedDir(const QString &dir)
-{
- QSettings s;
- s.beginGroup("FileDialog");
- s.setValue("LastDir", dir);
-}
-
-void MainWindow::on_actionPrint_triggered()
-{
-#ifndef NO_PRINTING
- PrintDialog dlg(this);
-
- dlg.exec();
-#endif
-}
-
-void MainWindow::disableShortcuts(bool disablePaste)
-{
- ui.actionPreviousDC->setShortcut(QKeySequence());
- ui.actionNextDC->setShortcut(QKeySequence());
- ui.copy->setShortcut(QKeySequence());
- if (disablePaste)
- ui.paste->setShortcut(QKeySequence());
-}
-
-void MainWindow::enableShortcuts()
-{
- ui.actionPreviousDC->setShortcut(Qt::Key_Left);
- ui.actionNextDC->setShortcut(Qt::Key_Right);
- ui.copy->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
- ui.paste->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_V));
-}
-
-void MainWindow::showProfile()
-{
- enableShortcuts();
- graphics()->setProfileState();
- setApplicationState("Default");
-}
-
-void MainWindow::on_actionPreferences_triggered()
-{
- PreferencesDialog::instance()->show();
- PreferencesDialog::instance()->raise();
-}
-
-void MainWindow::on_actionQuit_triggered()
-{
- if (information()->isEditing()) {
- information()->rejectChanges();
- if (information()->isEditing())
- // didn't discard the edits
- return;
- }
- if (DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING) {
- DivePlannerPointsModel::instance()->cancelPlan();
- if (DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING)
- // The planned dive was not discarded
- return;
- }
-
- if (unsaved_changes() && (askSaveChanges() == false))
- return;
- writeSettings();
- QApplication::quit();
-}
-
-void MainWindow::on_actionDownloadDC_triggered()
-{
- DownloadFromDCWidget dlg(this);
-
- dlg.exec();
-}
-
-void MainWindow::on_actionDownloadWeb_triggered()
-{
- SubsurfaceWebServices dlg(this);
-
- dlg.exec();
-}
-
-void MainWindow::on_actionDivelogs_de_triggered()
-{
- DivelogsDeWebServices::instance()->downloadDives();
-}
-
-void MainWindow::on_actionEditDeviceNames_triggered()
-{
- DiveComputerManagementDialog::instance()->init();
- DiveComputerManagementDialog::instance()->update();
- DiveComputerManagementDialog::instance()->show();
-}
-
-bool MainWindow::plannerStateClean()
-{
- if (DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING ||
- information()->isEditing()) {
- QMessageBox::warning(this, tr("Warning"), tr("Please save or cancel the current dive edit before trying to add a dive."));
- return false;
- }
- return true;
-}
-
-void MainWindow::refreshProfile()
-{
- showProfile();
- configureToolbar();
- graphics()->replot(get_dive(selected_dive));
- DivePictureModel::instance()->updateDivePictures();
-}
-
-void MainWindow::planCanceled()
-{
- // while planning we might have modified the displayed_dive
- // let's refresh what's shown on the profile
- refreshProfile();
- refreshDisplay(false);
-}
-
-void MainWindow::planCreated()
-{
- // get the new dive selected and assign a number if reasonable
- graphics()->setProfileState();
- if (displayed_dive.id == 0) {
- // we might have added a new dive (so displayed_dive was cleared out by clone_dive()
- dive_list()->unselectDives();
- select_dive(dive_table.nr - 1);
- dive_list()->selectDive(selected_dive);
- set_dive_nr_for_current_dive();
- }
- // make sure our UI is in a consistent state
- information()->updateDiveInfo();
- showProfile();
- refreshDisplay();
-}
-
-void MainWindow::setPlanNotes()
-{
- plannerDetails()->divePlanOutput()->setHtml(displayed_dive.notes);
-}
-
-void MainWindow::printPlan()
-{
-#ifndef NO_PRINTING
- QString diveplan = plannerDetails()->divePlanOutput()->toHtml();
- QString withDisclaimer = QString("<img height=50 src=\":subsurface-icon\"> ") + diveplan + QString(disclaimer);
-
- QPrinter printer;
- QPrintDialog *dialog = new QPrintDialog(&printer, this);
- dialog->setWindowTitle(tr("Print runtime table"));
- if (dialog->exec() != QDialog::Accepted)
- return;
-
- plannerDetails()->divePlanOutput()->setHtml(withDisclaimer);
- plannerDetails()->divePlanOutput()->print(&printer);
- plannerDetails()->divePlanOutput()->setHtml(diveplan);
-#endif
-}
-
-void MainWindow::setupForAddAndPlan(const char *model)
-{
- // clean out the dive and give it an id and the correct dc model
- clear_dive(&displayed_dive);
- clear_dive_site(&displayed_dive_site);
- displayed_dive.id = dive_getUniqID(&displayed_dive);
- displayed_dive.when = QDateTime::currentMSecsSinceEpoch() / 1000L + gettimezoneoffset() + 3600;
- displayed_dive.dc.model = model; // don't translate! this is stored in the XML file
- // setup the dive cylinders
- DivePlannerPointsModel::instance()->clear();
- DivePlannerPointsModel::instance()->setupCylinders();
-}
-
-void MainWindow::on_actionReplanDive_triggered()
-{
- if (!plannerStateClean() || !current_dive || !current_dive->dc.model)
- return;
- else if (strcmp(current_dive->dc.model, "planned dive")) {
- if (QMessageBox::warning(this, tr("Warning"), tr("Trying to replan a dive that's not a planned dive."),
- QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
- return;
- }
- // put us in PLAN mode
- DivePlannerPointsModel::instance()->clear();
- DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN);
-
- graphics()->setPlanState();
- graphics()->clearHandlers();
- setApplicationState("PlanDive");
- divePlannerWidget()->setReplanButton(true);
- DivePlannerPointsModel::instance()->loadFromDive(current_dive);
- reset_cylinders(&displayed_dive, true);
-}
-
-void MainWindow::on_actionDivePlanner_triggered()
-{
- if (!plannerStateClean())
- return;
-
- // put us in PLAN mode
- DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN);
- setApplicationState("PlanDive");
-
- graphics()->setPlanState();
-
- // create a simple starting dive, using the first gas from the just copied cylinders
- setupForAddAndPlan("planned dive"); // don't translate, stored in XML file
- DivePlannerPointsModel::instance()->setupStartTime();
- DivePlannerPointsModel::instance()->createSimpleDive();
- DivePictureModel::instance()->updateDivePictures();
- divePlannerWidget()->setReplanButton(false);
-}
-
-DivePlannerWidget* MainWindow::divePlannerWidget() {
- return qobject_cast<DivePlannerWidget*>(applicationState["PlanDive"].topLeft);
-}
-
-void MainWindow::on_actionAddDive_triggered()
-{
- if (!plannerStateClean())
- return;
-
- if (dive_list()->selectedTrips().count() >= 1) {
- dive_list()->rememberSelection();
- dive_list()->clearSelection();
- }
-
- setApplicationState("AddDive");
- DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD);
-
- // 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
- information()->updateDiveInfo();
-
- // show main tab
- information()->setCurrentIndex(0);
-
- information()->addDiveStarted();
-
- graphics()->setAddState();
- DivePlannerPointsModel::instance()->createSimpleDive();
- configureToolbar();
- graphics()->plotDive();
-}
-
-void MainWindow::on_actionEditDive_triggered()
-{
- if (information()->isEditing() || DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING) {
- QMessageBox::warning(this, tr("Warning"), tr("Please, first finish the current edition before trying to do another."));
- return;
- }
-
- const bool isTripEdit = dive_list()->selectedTrips().count() >= 1;
- if (!current_dive || isTripEdit || (current_dive->dc.model && strcmp(current_dive->dc.model, "manually added dive"))) {
- QMessageBox::warning(this, tr("Warning"), tr("Trying to edit a dive that's not a manually added dive."));
- return;
- }
-
- DivePlannerPointsModel::instance()->clear();
- disableShortcuts();
- DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD);
- graphics()->setAddState();
- GlobeGPS::instance()->endGetDiveCoordinates();
- setApplicationState("EditDive");
- DivePlannerPointsModel::instance()->loadFromDive(current_dive);
- information()->enableEdition(MainTab::MANUALLY_ADDED_DIVE);
-}
-
-void MainWindow::on_actionRenumber_triggered()
-{
- RenumberDialog::instance()->renumberOnlySelected(false);
- RenumberDialog::instance()->show();
-}
-
-void MainWindow::on_actionAutoGroup_triggered()
-{
- autogroup = ui.actionAutoGroup->isChecked();
- if (autogroup)
- autogroup_dives();
- else
- remove_autogen_trips();
- refreshDisplay();
- mark_divelist_changed(true);
-}
-
-void MainWindow::on_actionYearlyStatistics_triggered()
-{
- QDialog d;
- QVBoxLayout *l = new QVBoxLayout(&d);
- YearlyStatisticsModel *m = new YearlyStatisticsModel();
- QTreeView *view = new QTreeView();
- view->setModel(m);
- l->addWidget(view);
- d.resize(width() * .8, height() / 2);
- d.move(width() * .1, height() / 4);
- QShortcut *close = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), &d);
- connect(close, SIGNAL(activated()), &d, SLOT(close()));
- QShortcut *quit = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), &d);
- connect(quit, SIGNAL(activated()), this, SLOT(close()));
- d.setWindowFlags(Qt::Window | Qt::CustomizeWindowHint
- | Qt::WindowCloseButtonHint | Qt::WindowTitleHint);
- d.setWindowTitle(tr("Yearly statistics"));
- d.setWindowIcon(QIcon(":/subsurface-icon"));
- d.exec();
-}
-
-#define BEHAVIOR QList<int>()
-
-#define TOGGLE_COLLAPSABLE( X ) \
- ui.mainSplitter->setCollapsible(0, X); \
- ui.mainSplitter->setCollapsible(1, X); \
- ui.topSplitter->setCollapsible(0, X); \
- ui.topSplitter->setCollapsible(1, X); \
- ui.bottomSplitter->setCollapsible(0, X); \
- ui.bottomSplitter->setCollapsible(1, X);
-
-void MainWindow::on_actionViewList_triggered()
-{
- TOGGLE_COLLAPSABLE( true );
- beginChangeState(LIST_MAXIMIZED);
- ui.topSplitter->setSizes(BEHAVIOR << EXPANDED << COLLAPSED);
- ui.mainSplitter->setSizes(BEHAVIOR << COLLAPSED << EXPANDED);
-}
-
-void MainWindow::on_actionViewProfile_triggered()
-{
- TOGGLE_COLLAPSABLE( true );
- beginChangeState(PROFILE_MAXIMIZED);
- ui.topSplitter->setSizes(BEHAVIOR << COLLAPSED << EXPANDED);
- ui.mainSplitter->setSizes(BEHAVIOR << EXPANDED << COLLAPSED);
-}
-
-void MainWindow::on_actionViewInfo_triggered()
-{
- TOGGLE_COLLAPSABLE( true );
- beginChangeState(INFO_MAXIMIZED);
- ui.topSplitter->setSizes(BEHAVIOR << EXPANDED << COLLAPSED);
- ui.mainSplitter->setSizes(BEHAVIOR << EXPANDED << COLLAPSED);
-}
-
-void MainWindow::on_actionViewGlobe_triggered()
-{
- TOGGLE_COLLAPSABLE( true );
- beginChangeState(GLOBE_MAXIMIZED);
- ui.mainSplitter->setSizes(BEHAVIOR << COLLAPSED << EXPANDED);
- ui.bottomSplitter->setSizes(BEHAVIOR << COLLAPSED << EXPANDED);
-}
-#undef BEHAVIOR
-
-void MainWindow::on_actionViewAll_triggered()
-{
- TOGGLE_COLLAPSABLE( false );
- beginChangeState(VIEWALL);
- static QList<int> mainSizes;
- const int appH = qApp->desktop()->size().height();
- const int appW = qApp->desktop()->size().width();
- if (mainSizes.empty()) {
- mainSizes.append(appH * 0.7);
- mainSizes.append(appH * 0.3);
- }
- static QList<int> infoProfileSizes;
- if (infoProfileSizes.empty()) {
- infoProfileSizes.append(appW * 0.3);
- infoProfileSizes.append(appW * 0.7);
- }
-
- static QList<int> listGlobeSizes;
- if (listGlobeSizes.empty()) {
- listGlobeSizes.append(appW * 0.7);
- listGlobeSizes.append(appW * 0.3);
- }
-
- QSettings settings;
- settings.beginGroup("MainWindow");
- if (settings.value("mainSplitter").isValid()) {
- ui.mainSplitter->restoreState(settings.value("mainSplitter").toByteArray());
- ui.topSplitter->restoreState(settings.value("topSplitter").toByteArray());
- ui.bottomSplitter->restoreState(settings.value("bottomSplitter").toByteArray());
- if (ui.mainSplitter->sizes().first() == 0 || ui.mainSplitter->sizes().last() == 0)
- ui.mainSplitter->setSizes(mainSizes);
- if (ui.topSplitter->sizes().first() == 0 || ui.topSplitter->sizes().last() == 0)
- ui.topSplitter->setSizes(infoProfileSizes);
- if (ui.bottomSplitter->sizes().first() == 0 || ui.bottomSplitter->sizes().last() == 0)
- ui.bottomSplitter->setSizes(listGlobeSizes);
-
- } else {
- ui.mainSplitter->setSizes(mainSizes);
- ui.topSplitter->setSizes(infoProfileSizes);
- ui.bottomSplitter->setSizes(listGlobeSizes);
- }
- ui.mainSplitter->setCollapsible(0, false);
- ui.mainSplitter->setCollapsible(1, false);
- ui.topSplitter->setCollapsible(0, false);
- ui.topSplitter->setCollapsible(1, false);
- ui.bottomSplitter->setCollapsible(0,false);
- ui.bottomSplitter->setCollapsible(1,false);
-}
-
-#undef TOGGLE_COLLAPSABLE
-
-void MainWindow::beginChangeState(CurrentState s)
-{
- if (state == VIEWALL && state != s) {
- saveSplitterSizes();
- }
- state = s;
-}
-
-void MainWindow::saveSplitterSizes()
-{
- QSettings settings;
- settings.beginGroup("MainWindow");
- settings.setValue("mainSplitter", ui.mainSplitter->saveState());
- settings.setValue("topSplitter", ui.topSplitter->saveState());
- settings.setValue("bottomSplitter", ui.bottomSplitter->saveState());
-}
-
-void MainWindow::on_actionPreviousDC_triggered()
-{
- unsigned nrdc = number_of_computers(current_dive);
- dc_number = (dc_number + nrdc - 1) % nrdc;
- configureToolbar();
- graphics()->plotDive();
- information()->updateDiveInfo();
-}
-
-void MainWindow::on_actionNextDC_triggered()
-{
- unsigned nrdc = number_of_computers(current_dive);
- dc_number = (dc_number + 1) % nrdc;
- configureToolbar();
- graphics()->plotDive();
- information()->updateDiveInfo();
-}
-
-void MainWindow::on_actionFullScreen_triggered(bool checked)
-{
- if (checked) {
- setWindowState(windowState() | Qt::WindowFullScreen);
- } else {
- setWindowState(windowState() & ~Qt::WindowFullScreen);
- }
-}
-
-void MainWindow::on_actionAboutSubsurface_triggered()
-{
- SubsurfaceAbout dlg(this);
-
- dlg.exec();
-}
-
-void MainWindow::on_action_Check_for_Updates_triggered()
-{
- if (!updateManager)
- updateManager = new UpdateManager(this);
-
- updateManager->checkForUpdates();
-}
-
-void MainWindow::on_actionUserManual_triggered()
-{
-#ifndef NO_USERMANUAL
- if (!helpView) {
- helpView = new UserManual();
- }
- helpView->show();
-#endif
-}
-
-void MainWindow::on_actionUserSurvey_triggered()
-{
- if(!survey) {
- survey = new UserSurvey(this);
- }
- survey->show();
-}
-
-QString MainWindow::filter()
-{
- QString f;
- f += "Dive log files ( *.ssrf ";
- f += "*.can *.CAN ";
- f += "*.db *.DB " ;
- f += "*.sql *.SQL " ;
- f += "*.dld *.DLD ";
- f += "*.jlb *.JLB ";
- f += "*.lvd *.LVD ";
- f += "*.sde *.SDE ";
- f += "*.udcf *.UDCF ";
- f += "*.uddf *.UDDF ";
- f += "*.xml *.XML ";
- f += "*.dlf *.DLF ";
- f += ");;";
-
- f += "Subsurface (*.ssrf);;";
- f += "Cochran (*.can *.CAN);;";
- f += "DiveLogs.de (*.dld *.DLD);;";
- f += "JDiveLog (*.jlb *.JLB);;";
- f += "Liquivision (*.lvd *.LVD);;";
- f += "Suunto (*.sde *.SDE *.db *.DB);;";
- f += "UDCF (*.udcf *.UDCF);;";
- f += "UDDF (*.uddf *.UDDF);;";
- f += "XML (*.xml *.XML)";
- f += "Divesoft (*.dlf *.DLF)";
- f += "Datatrak/WLog Files (*.log *.LOG)";
-
- return f;
-}
-
-bool MainWindow::askSaveChanges()
-{
- QString message;
- QMessageBox response(this);
-
- if (existing_filename)
- message = tr("Do you want to save the changes that you made in the file %1?")
- .arg(displayedFilename(existing_filename));
- else
- message = tr("Do you want to save the changes that you made in the data file?");
-
- response.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
- response.setDefaultButton(QMessageBox::Save);
- response.setText(message);
- response.setWindowTitle(tr("Save changes?")); // Not displayed on MacOSX as described in Qt API
- response.setInformativeText(tr("Changes will be lost if you don't save them."));
- response.setIcon(QMessageBox::Warning);
- response.setWindowModality(Qt::WindowModal);
- int ret = response.exec();
-
- switch (ret) {
- case QMessageBox::Save:
- file_save();
- return true;
- case QMessageBox::Discard:
- return true;
- }
- return false;
-}
-
-void MainWindow::initialUiSetup()
-{
- QSettings settings;
- settings.beginGroup("MainWindow");
- if (settings.value("maximized", isMaximized()).value<bool>()) {
- showMaximized();
- } else {
- restoreGeometry(settings.value("geometry").toByteArray());
- restoreState(settings.value("windowState", 0).toByteArray());
- }
-
- state = (CurrentState)settings.value("lastState", 0).toInt();
- switch (state) {
- case VIEWALL:
- on_actionViewAll_triggered();
- break;
- case GLOBE_MAXIMIZED:
- on_actionViewGlobe_triggered();
- break;
- case INFO_MAXIMIZED:
- on_actionViewInfo_triggered();
- break;
- case LIST_MAXIMIZED:
- on_actionViewList_triggered();
- break;
- case PROFILE_MAXIMIZED:
- on_actionViewProfile_triggered();
- break;
- }
- settings.endGroup();
- show();
-}
-
-const char *getSetting(QSettings &s, QString name)
-{
- QVariant v;
- v = s.value(name);
- if (v.isValid()) {
- return strdup(v.toString().toUtf8().data());
- }
- return NULL;
-}
-
-#define TOOLBOX_PREF_BUTTON(pref, setting, button) \
- prefs.pref = s.value(#setting).toBool(); \
- ui.button->setChecked(prefs.pref);
-
-void MainWindow::readSettings()
-{
- static bool firstRun = true;
- QSettings s;
- // the static object for preferences already reads in the settings
- // and sets up the font, so just get what we need for the toolbox and other widgets here
-
- s.beginGroup("TecDetails");
- TOOLBOX_PREF_BUTTON(calcalltissues, calcalltissues, profCalcAllTissues);
- TOOLBOX_PREF_BUTTON(calcceiling, calcceiling, profCalcCeiling);
- TOOLBOX_PREF_BUTTON(dcceiling, dcceiling, profDcCeiling);
- TOOLBOX_PREF_BUTTON(ead, ead, profEad);
- TOOLBOX_PREF_BUTTON(calcceiling3m, calcceiling3m, profIncrement3m);
- TOOLBOX_PREF_BUTTON(mod, mod, profMod);
- TOOLBOX_PREF_BUTTON(calcndltts, calcndltts, profNdl_tts);
- TOOLBOX_PREF_BUTTON(pp_graphs.phe, phegraph, profPhe);
- TOOLBOX_PREF_BUTTON(pp_graphs.pn2, pn2graph, profPn2);
- TOOLBOX_PREF_BUTTON(pp_graphs.po2, po2graph, profPO2);
- TOOLBOX_PREF_BUTTON(hrgraph, hrgraph, profHR);
- TOOLBOX_PREF_BUTTON(rulergraph, rulergraph, profRuler);
- TOOLBOX_PREF_BUTTON(show_sac, show_sac, profSAC);
- TOOLBOX_PREF_BUTTON(show_pictures_in_profile, show_pictures_in_profile, profTogglePicture);
- TOOLBOX_PREF_BUTTON(tankbar, tankbar, profTankbar);
- TOOLBOX_PREF_BUTTON(percentagegraph, percentagegraph, profTissues);
- TOOLBOX_PREF_BUTTON(zoomed_plot, zoomed_plot, profScaled);
- s.endGroup(); // note: why doesn't the list of 17 buttons match the order in the gui?
- s.beginGroup("DiveComputer");
- default_dive_computer_vendor = getSetting(s, "dive_computer_vendor");
- default_dive_computer_product = getSetting(s, "dive_computer_product");
- default_dive_computer_device = getSetting(s, "dive_computer_device");
- default_dive_computer_download_mode = s.value("dive_computer_download_mode").toInt();
- s.endGroup();
- QNetworkProxy proxy;
- proxy.setType(QNetworkProxy::ProxyType(prefs.proxy_type));
- proxy.setHostName(prefs.proxy_host);
- proxy.setPort(prefs.proxy_port);
- if (prefs.proxy_auth) {
- proxy.setUser(prefs.proxy_user);
- proxy.setPassword(prefs.proxy_pass);
- }
- QNetworkProxy::setApplicationProxy(proxy);
-
-#if !defined(SUBSURFACE_MOBILE)
- loadRecentFiles(&s);
- if (firstRun) {
- checkSurvey(&s);
- firstRun = false;
- }
-#endif
-}
-
-#undef TOOLBOX_PREF_BUTTON
-
-void MainWindow::checkSurvey(QSettings *s)
-{
- s->beginGroup("UserSurvey");
- if (!s->contains("FirstUse42")) {
- QVariant value = QDate().currentDate();
- s->setValue("FirstUse42", value);
- }
- // wait a week for production versions, but not at all for non-tagged builds
- QString ver(subsurface_version());
- int waitTime = 7;
- QDate firstUse42 = s->value("FirstUse42").toDate();
- if (run_survey || (firstUse42.daysTo(QDate().currentDate()) > waitTime && !s->contains("SurveyDone"))) {
- if (!survey)
- survey = new UserSurvey(this);
- survey->show();
- }
- s->endGroup();
-}
-
-void MainWindow::writeSettings()
-{
- QSettings settings;
-
- settings.beginGroup("MainWindow");
- settings.setValue("geometry", saveGeometry());
- settings.setValue("windowState", saveState());
- settings.setValue("maximized", isMaximized());
- settings.setValue("lastState", (int)state);
- if (state == VIEWALL)
- saveSplitterSizes();
- settings.endGroup();
-}
-
-void MainWindow::closeEvent(QCloseEvent *event)
-{
- if (DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING ||
- information()->isEditing()) {
- on_actionQuit_triggered();
- event->ignore();
- return;
- }
-
-#ifndef NO_USERMANUAL
- if (helpView && helpView->isVisible()) {
- helpView->close();
- helpView->deleteLater();
- }
-#endif
-
- if (survey && survey->isVisible()) {
- survey->close();
- survey->deleteLater();
- }
-
- if (unsaved_changes() && (askSaveChanges() == false)) {
- event->ignore();
- return;
- }
- event->accept();
- writeSettings();
- QApplication::closeAllWindows();
-}
-
-DiveListView *MainWindow::dive_list()
-{
- return qobject_cast<DiveListView*>(applicationState["Default"].bottomLeft);
-}
-
-MainTab *MainWindow::information()
-{
- return qobject_cast<MainTab*>(applicationState["Default"].topLeft);
-}
-
-void MainWindow::loadRecentFiles(QSettings *s)
-{
- QStringList files;
- bool modified = false;
-
- s->beginGroup("Recent_Files");
- for (int c = 1; c <= 4; c++) {
- QString key = QString("File_%1").arg(c);
- if (s->contains(key)) {
- QString file = s->value(key).toString();
-
- if (QFile::exists(file)) {
- files.append(file);
- } else {
- modified = true;
- }
- } else {
- break;
- }
- }
-
- if (modified) {
- for (int c = 0; c < 4; c++) {
- QString key = QString("File_%1").arg(c + 1);
-
- if (files.count() > c) {
- s->setValue(key, files.at(c));
- } else {
- if (s->contains(key)) {
- s->remove(key);
- }
- }
- }
-
- s->sync();
- }
- s->endGroup();
-
- for (int c = 0; c < 4; c++) {
- QAction *action = this->findChild<QAction *>(QString("actionRecent%1").arg(c + 1));
-
- if (files.count() > c) {
- QFileInfo fi(files.at(c));
- action->setText(fi.fileName());
- action->setToolTip(fi.absoluteFilePath());
- action->setVisible(true);
- } else {
- action->setVisible(false);
- }
- }
-}
-
-void MainWindow::addRecentFile(const QStringList &newFiles)
-{
- QStringList files;
- QSettings s;
-
- if (newFiles.isEmpty())
- return;
-
- s.beginGroup("Recent_Files");
-
- for (int c = 1; c <= 4; c++) {
- QString key = QString("File_%1").arg(c);
- if (s.contains(key)) {
- QString file = s.value(key).toString();
-
- files.append(file);
- } else {
- break;
- }
- }
-
- foreach (const QString &file, newFiles) {
- int index = files.indexOf(QDir::toNativeSeparators(file));
-
- if (index >= 0) {
- files.removeAt(index);
- }
- }
-
- foreach (const QString &file, newFiles) {
- if (QFile::exists(file)) {
- files.prepend(QDir::toNativeSeparators(file));
- }
- }
-
- while (files.count() > 4) {
- files.removeLast();
- }
-
- for (int c = 1; c <= 4; c++) {
- QString key = QString("File_%1").arg(c);
-
- if (files.count() >= c) {
- s.setValue(key, files.at(c - 1));
- } else {
- if (s.contains(key)) {
- s.remove(key);
- }
- }
- }
- s.endGroup();
- s.sync();
-
- loadRecentFiles(&s);
-}
-
-void MainWindow::removeRecentFile(QStringList failedFiles)
-{
- QStringList files;
- QSettings s;
-
- if (failedFiles.isEmpty())
- return;
-
- s.beginGroup("Recent_Files");
-
- for (int c = 1; c <= 4; c++) {
- QString key = QString("File_%1").arg(c);
-
- if (s.contains(key)) {
- QString file = s.value(key).toString();
- files.append(file);
- } else {
- break;
- }
- }
-
- foreach (const QString &file, failedFiles)
- files.removeAll(file);
-
- for (int c = 1; c <= 4; c++) {
- QString key = QString("File_%1").arg(c);
-
- if (files.count() >= c)
- s.setValue(key, files.at(c - 1));
- else if (s.contains(key))
- s.remove(key);
- }
-
- s.endGroup();
- s.sync();
-
- loadRecentFiles(&s);
-}
-
-void MainWindow::recentFileTriggered(bool checked)
-{
- Q_UNUSED(checked);
-
- if (!okToClose(tr("Please save or cancel the current dive edit before opening a new file.")))
- return;
-
- QAction *actionRecent = (QAction *)sender();
-
- const QString &filename = actionRecent->toolTip();
-
- updateLastUsedDir(QFileInfo(filename).dir().path());
- closeCurrentFile();
- loadFiles(QStringList() << filename);
-}
-
-int MainWindow::file_save_as(void)
-{
- QString filename;
- const char *default_filename = existing_filename;
-
- // if the default is to save to cloud storage, pick something that will work as local file:
- // simply extract the branch name which should be the users email address
- if (default_filename && strstr(default_filename, prefs.cloud_git_url)) {
- QString filename(default_filename);
- filename.remove(prefs.cloud_git_url);
- filename.remove(0, filename.indexOf("[") + 1);
- filename.replace("]", ".ssrf");
- default_filename = strdup(qPrintable(filename));
- }
- // create a file dialog that allows us to save to a new file
- QFileDialog selection_dialog(this, tr("Save file as"), default_filename,
- tr("Subsurface XML files (*.ssrf *.xml *.XML)"));
- selection_dialog.setAcceptMode(QFileDialog::AcceptSave);
- selection_dialog.setFileMode(QFileDialog::AnyFile);
- selection_dialog.setDefaultSuffix("");
- if (same_string(default_filename, "")) {
- QFileInfo defaultFile(system_default_filename());
- selection_dialog.setDirectory(qPrintable(defaultFile.absolutePath()));
- }
- /* if the exit/cancel button is pressed return */
- if (!selection_dialog.exec())
- return 0;
-
- /* get the first selected file */
- filename = selection_dialog.selectedFiles().at(0);
-
- /* now for reasons I don't understand we appear to add a .ssrf to
- * git style filenames <path>/directory[branch]
- * so let's remove that */
- QRegularExpression reg(".*\\[[^]]+]\\.ssrf", QRegularExpression::CaseInsensitiveOption);
- if (reg.match(filename).hasMatch())
- filename.remove(QRegularExpression("\\.ssrf$", QRegularExpression::CaseInsensitiveOption));
- if (filename.isNull() || filename.isEmpty())
- return report_error("No filename to save into");
-
- if (information()->isEditing())
- information()->acceptChanges();
-
- if (save_dives(filename.toUtf8().data())) {
- getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
- return -1;
- }
-
- getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
- set_filename(filename.toUtf8().data(), true);
- setTitle(MWTF_FILENAME);
- mark_divelist_changed(false);
- addRecentFile(QStringList() << filename);
- return 0;
-}
-
-int MainWindow::file_save(void)
-{
- const char *current_default;
- bool is_cloud = false;
-
- if (!existing_filename)
- return file_save_as();
-
- is_cloud = (strncmp(existing_filename, "http", 4) == 0);
-
- if (information()->isEditing())
- information()->acceptChanges();
-
- current_default = prefs.default_filename;
- if (strcmp(existing_filename, current_default) == 0) {
- /* if we are using the default filename the directory
- * that we are creating the file in may not exist */
- QDir current_def_dir = QFileInfo(current_default).absoluteDir();
- if (!current_def_dir.exists())
- current_def_dir.mkpath(current_def_dir.absolutePath());
- }
- if (is_cloud)
- showProgressBar();
- if (save_dives(existing_filename)) {
- getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
- if (is_cloud)
- hideProgressBar();
- return -1;
- }
- if (is_cloud)
- hideProgressBar();
- getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
- mark_divelist_changed(false);
- addRecentFile(QStringList() << QString(existing_filename));
- return 0;
-}
-
-NotificationWidget *MainWindow::getNotificationWidget()
-{
- return ui.mainErrorMessage;
-}
-
-void MainWindow::showError()
-{
- getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
-}
-
-QString MainWindow::displayedFilename(QString fullFilename)
-{
- QFile f(fullFilename);
- QFileInfo fileInfo(f);
- QString fileName(fileInfo.fileName());
-
- if (fullFilename.contains(prefs.cloud_git_url))
- return tr("[cloud storage for] %1").arg(fileName.left(fileName.indexOf('[')));
- else
- return fileName;
-}
-
-void MainWindow::setAutomaticTitle()
-{
- setTitle();
-}
-
-void MainWindow::setTitle(enum MainWindowTitleFormat format)
-{
- switch (format) {
- case MWTF_DEFAULT:
- setWindowTitle("Subsurface");
- break;
- case MWTF_FILENAME:
- if (!existing_filename) {
- setTitle(MWTF_DEFAULT);
- return;
- }
- QString unsaved = (unsaved_changes() ? " *" : "");
- setWindowTitle("Subsurface: " + displayedFilename(existing_filename) + unsaved);
- break;
- }
-}
-
-void MainWindow::importFiles(const QStringList fileNames)
-{
- if (fileNames.isEmpty())
- return;
-
- QByteArray fileNamePtr;
-
- for (int i = 0; i < fileNames.size(); ++i) {
- fileNamePtr = QFile::encodeName(fileNames.at(i));
- parse_file(fileNamePtr.data());
- }
- process_dives(true, false);
- refreshDisplay();
-}
-
-void MainWindow::importTxtFiles(const QStringList fileNames)
-{
- if (fileNames.isEmpty())
- return;
-
- QByteArray fileNamePtr, csv;
-
- for (int i = 0; i < fileNames.size(); ++i) {
- fileNamePtr = QFile::encodeName(fileNames.at(i));
- csv = fileNamePtr.data();
- csv.replace(strlen(csv.data()) - 3, 3, "csv");
- parse_txt_file(fileNamePtr.data(), csv);
- }
- process_dives(true, false);
- refreshDisplay();
-}
-
-void MainWindow::loadFiles(const QStringList fileNames)
-{
- bool showWarning = false;
- if (fileNames.isEmpty()) {
- refreshDisplay();
- return;
- }
- QByteArray fileNamePtr;
- QStringList failedParses;
-
- showProgressBar();
- for (int i = 0; i < fileNames.size(); ++i) {
- int error;
-
- fileNamePtr = QFile::encodeName(fileNames.at(i));
- error = parse_file(fileNamePtr.data());
- if (!error) {
- set_filename(fileNamePtr.data(), true);
- setTitle(MWTF_FILENAME);
- // if there were any messages, show them
- QString warning = get_error_string();
- if (!warning.isEmpty()) {
- showWarning = true;
- getNotificationWidget()->showNotification(warning , KMessageWidget::Information);
- }
- } else {
- failedParses.append(fileNames.at(i));
- }
- }
- hideProgressBar();
- if (!showWarning)
- getNotificationWidget()->hideNotification();
- process_dives(false, false);
- addRecentFile(fileNames);
- removeRecentFile(failedParses);
-
- refreshDisplay();
- ui.actionAutoGroup->setChecked(autogroup);
-
- int min_datafile_version = get_min_datafile_version();
- if (min_datafile_version >0 && min_datafile_version < DATAFORMAT_VERSION) {
- QMessageBox::warning(this, tr("Opening datafile from older version"),
- tr("You opened a data file from an older version of Subsurface. We recommend "
- "you read the manual to learn about the changes in the new version, especially "
- "about dive site management which has changed significantly.\n"
- "Subsurface has already tried to pre-populate the data but it might be worth "
- "while taking a look at the new dive site management system and to make "
- "sure that everything looks correct."));
- }
-}
-
-void MainWindow::on_actionImportDiveLog_triggered()
-{
- QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open dive log file"), lastUsedDir(),
- tr("Dive log files (*.ssrf *.can *.csv *.db *.sql *.dld *.jlb *.lvd *.sde *.udcf *.uddf *.xml *.txt *.dlf *.apd"
- "*.SSRF *.CAN *.CSV *.DB *.SQL *.DLD *.JLB *.LVD *.SDE *.UDCF *.UDDF *.xml *.TXT *.DLF *.APD);;"
- "Cochran files (*.can *.CAN);;"
- "CSV files (*.csv *.CSV);;"
- "DiveLog.de files (*.dld *.DLD);;"
- "JDiveLog files (*.jlb *.JLB);;"
- "Liquivision files (*.lvd *.LVD);;"
- "MkVI files (*.txt *.TXT);;"
- "Suunto files (*.sde *.db *.SDE *.DB);;"
- "Divesoft files (*.dlf *.DLF);;"
- "UDDF/UDCF files (*.uddf *.udcf *.UDDF *.UDCF);;"
- "XML files (*.xml *.XML);;"
- "APD log viewer (*.apd *.APD);;"
- "Datatrak/WLog Files (*.log *.LOG);;"
- "OSTCtools Files (*.dive *.DIVE);;"
- "All files (*)"));
-
- if (fileNames.isEmpty())
- return;
- updateLastUsedDir(QFileInfo(fileNames[0]).dir().path());
-
- QStringList logFiles = fileNames.filter(QRegExp("^.*\\.(?!(csv|txt|apd))", Qt::CaseInsensitive));
- QStringList csvFiles = fileNames.filter(".csv", Qt::CaseInsensitive);
- csvFiles += fileNames.filter(".apd", Qt::CaseInsensitive);
- QStringList txtFiles = fileNames.filter(".txt", Qt::CaseInsensitive);
-
- if (logFiles.size()) {
- importFiles(logFiles);
- }
-
- if (csvFiles.size()) {
- DiveLogImportDialog *diveLogImport = new DiveLogImportDialog(csvFiles, this);
- diveLogImport->show();
- process_dives(true, false);
- refreshDisplay();
- }
-
- if (txtFiles.size()) {
- importTxtFiles(txtFiles);
- }
-}
-
-void MainWindow::editCurrentDive()
-{
- if (information()->isEditing() || DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING) {
- QMessageBox::warning(this, tr("Warning"), tr("Please, first finish the current edition before trying to do another."));
- return;
- }
-
- struct dive *d = current_dive;
- QString defaultDC(d->dc.model);
- DivePlannerPointsModel::instance()->clear();
- if (defaultDC == "manually added dive") {
- disableShortcuts();
- DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD);
- graphics()->setAddState();
- setApplicationState("EditDive");
- DivePlannerPointsModel::instance()->loadFromDive(d);
- information()->enableEdition(MainTab::MANUALLY_ADDED_DIVE);
- } else if (defaultDC == "planned dive") {
- disableShortcuts();
- DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN);
- setApplicationState("EditPlannedDive");
- DivePlannerPointsModel::instance()->loadFromDive(d);
- information()->enableEdition(MainTab::MANUALLY_ADDED_DIVE);
- }
-}
-
-#define PREF_PROFILE(QT_PREFS) \
- QSettings s; \
- s.beginGroup("TecDetails"); \
- s.setValue(#QT_PREFS, triggered); \
- PreferencesDialog::instance()->emitSettingsChanged();
-
-#define TOOLBOX_PREF_PROFILE(METHOD, INTERNAL_PREFS, QT_PREFS) \
- void MainWindow::on_##METHOD##_triggered(bool triggered) \
- { \
- prefs.INTERNAL_PREFS = triggered; \
- PREF_PROFILE(QT_PREFS); \
- }
-
-// note: why doesn't the list of 17 buttons match the order in the gui? or the order above? (line 1136)
-TOOLBOX_PREF_PROFILE(profCalcAllTissues, calcalltissues, calcalltissues);
-TOOLBOX_PREF_PROFILE(profCalcCeiling, calcceiling, calcceiling);
-TOOLBOX_PREF_PROFILE(profDcCeiling, dcceiling, dcceiling);
-TOOLBOX_PREF_PROFILE(profEad, ead, ead);
-TOOLBOX_PREF_PROFILE(profIncrement3m, calcceiling3m, calcceiling3m);
-TOOLBOX_PREF_PROFILE(profMod, mod, mod);
-TOOLBOX_PREF_PROFILE(profNdl_tts, calcndltts, calcndltts);
-TOOLBOX_PREF_PROFILE(profPhe, pp_graphs.phe, phegraph);
-TOOLBOX_PREF_PROFILE(profPn2, pp_graphs.pn2, pn2graph);
-TOOLBOX_PREF_PROFILE(profPO2, pp_graphs.po2, po2graph);
-TOOLBOX_PREF_PROFILE(profHR, hrgraph, hrgraph);
-TOOLBOX_PREF_PROFILE(profRuler, rulergraph, rulergraph);
-TOOLBOX_PREF_PROFILE(profSAC, show_sac, show_sac);
-TOOLBOX_PREF_PROFILE(profScaled, zoomed_plot, zoomed_plot);
-TOOLBOX_PREF_PROFILE(profTogglePicture, show_pictures_in_profile, show_pictures_in_profile);
-TOOLBOX_PREF_PROFILE(profTankbar, tankbar, tankbar);
-TOOLBOX_PREF_PROFILE(profTissues, percentagegraph, percentagegraph);
-// couldn't the args to TOOLBOX_PREF_PROFILE be made to go in the same sequence as TOOLBOX_PREF_BUTTON?
-
-void MainWindow::turnOffNdlTts()
-{
- const bool triggered = false;
- prefs.calcndltts = triggered;
- PREF_PROFILE(calcndltts);
-}
-
-#undef TOOLBOX_PREF_PROFILE
-#undef PERF_PROFILE
-
-void MainWindow::on_actionExport_triggered()
-{
- DiveLogExportDialog diveLogExport;
- diveLogExport.exec();
-}
-
-void MainWindow::on_actionConfigure_Dive_Computer_triggered()
-{
- ConfigureDiveComputerDialog *dcConfig = new ConfigureDiveComputerDialog(this);
- dcConfig->show();
-}
-
-void MainWindow::setEnabledToolbar(bool arg1)
-{
- Q_FOREACH (QAction *b, profileToolbarActions)
- b->setEnabled(arg1);
-}
-
-void MainWindow::on_copy_triggered()
-{
- // open dialog to select what gets copied
- // copy the displayed dive
- DiveComponentSelection dialog(this, &copyPasteDive, &what);
- dialog.exec();
-}
-
-void MainWindow::on_paste_triggered()
-{
- // take the data in our copyPasteDive and apply it to selected dives
- selective_copy_dive(&copyPasteDive, &displayed_dive, what, false);
- information()->showAndTriggerEditSelective(what);
-}
-
-void MainWindow::on_actionFilterTags_triggered()
-{
- if (ui.multiFilter->isVisible())
- ui.multiFilter->closeFilter();
- else
- ui.multiFilter->setVisible(true);
-}
-
-void MainWindow::registerApplicationState(const QByteArray& state, QWidget *topLeft, QWidget *topRight, QWidget *bottomLeft, QWidget *bottomRight)
-{
- applicationState[state] = WidgetForQuadrant(topLeft, topRight, bottomLeft, bottomRight);
- if (ui.topLeft->indexOf(topLeft) == -1 && topLeft) {
- ui.topLeft->addWidget(topLeft);
- }
- if (ui.topRight->indexOf(topRight) == -1 && topRight) {
- ui.topRight->addWidget(topRight);
- }
- if (ui.bottomLeft->indexOf(bottomLeft) == -1 && bottomLeft) {
- ui.bottomLeft->addWidget(bottomLeft);
- }
- if(ui.bottomRight->indexOf(bottomRight) == -1 && bottomRight) {
- ui.bottomRight->addWidget(bottomRight);
- }
-}
-
-void MainWindow::setApplicationState(const QByteArray& state) {
- if (!applicationState.keys().contains(state))
- return;
-
- if (getCurrentAppState() == state)
- return;
-
- setCurrentAppState(state);
-
-#define SET_CURRENT_INDEX( X ) \
- if (applicationState[state].X) { \
- ui.X->setCurrentWidget( applicationState[state].X); \
- ui.X->show(); \
- } else { \
- ui.X->hide(); \
- }
-
- SET_CURRENT_INDEX( topLeft )
- Q_FOREACH(const WidgetProperty& p, stateProperties[state].topLeft) {
- ui.topLeft->currentWidget()->setProperty( p.first.data(), p.second);
- }
- SET_CURRENT_INDEX( topRight )
- Q_FOREACH(const WidgetProperty& p, stateProperties[state].topRight) {
- ui.topRight->currentWidget()->setProperty( p.first.data(), p.second);
- }
- SET_CURRENT_INDEX( bottomLeft )
- Q_FOREACH(const WidgetProperty& p, stateProperties[state].bottomLeft) {
- ui.bottomLeft->currentWidget()->setProperty( p.first.data(), p.second);
- }
- SET_CURRENT_INDEX( bottomRight )
- Q_FOREACH(const WidgetProperty& p, stateProperties[state].bottomRight) {
- ui.bottomRight->currentWidget()->setProperty( p.first.data(), p.second);
- }
-#undef SET_CURRENT_INDEX
-}
-
-void MainWindow::showProgressBar()
-{
- if (progressDialog)
- delete progressDialog;
-
- progressDialog = new QProgressDialog(tr("Contacting cloud service..."), tr("Cancel"), 0, 100, this);
- progressDialog->setWindowModality(Qt::WindowModal);
- progressDialog->setMinimumDuration(200);
- progressDialogCanceled = false;
- connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelCloudStorageOperation()));
-}
-
-void MainWindow::cancelCloudStorageOperation()
-{
- progressDialogCanceled = true;
-}
-
-void MainWindow::hideProgressBar()
-{
- if (progressDialog) {
- progressDialog->setValue(100);
- progressDialog->deleteLater();
- progressDialog = NULL;
- }
-}