diff options
Diffstat (limited to 'qt-ui/mainwindow.cpp')
-rw-r--r-- | qt-ui/mainwindow.cpp | 1922 |
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(©PasteDive, 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, ©PasteDive, &what); - dialog.exec(); -} - -void MainWindow::on_paste_triggered() -{ - // take the data in our copyPasteDive and apply it to selected dives - selective_copy_dive(©PasteDive, &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; - } -} |