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.cpp548
1 files changed, 370 insertions, 178 deletions
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 82eaaac57..a06a2c227 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -11,7 +11,8 @@
#include <QSettings>
#include <QShortcut>
#include <QToolBar>
-#include "ssrf-version.h"
+#include "version.h"
+#include "divelistview.h"
#include "downloadfromdivecomputer.h"
#include "preferences.h"
#include "subsurfacewebservices.h"
@@ -20,6 +21,10 @@
#include "updatemanager.h"
#include "planner.h"
#include "filtermodels.h"
+#include "profile/profilewidget2.h"
+#include "globe.h"
+#include "maintab.h"
+#include "diveplanner.h"
#ifndef NO_PRINTING
#include <QPrintDialog>
#include "printdialog.h"
@@ -27,10 +32,15 @@
#include "divelogimportdialog.h"
#include "divelogexportdialog.h"
#include "usersurvey.h"
+#include "divesitehelpers.h"
+#include "locationinformation.h"
#ifndef NO_USERMANUAL
#include "usermanual.h"
#endif
#include <QNetworkProxy>
+#include <QUndoStack>
+#include <qthelper.h>
+#include <QtConcurrentRun>
MainWindow *MainWindow::m_Instance = NULL;
@@ -44,7 +54,26 @@ MainWindow::MainWindow() : QMainWindow(),
Q_ASSERT_X(m_Instance == NULL, "MainWindow", "MainWindow recreated!");
m_Instance = this;
ui.setupUi(this);
- ui.multiFilter->hide();
+ 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 = new GlobeGPS();
+#else
+ QWidget *globeGps = NULL;
+#endif
+
+ PlannerSettingsWidget *plannerSettings = new PlannerSettingsWidget();
+ DivePlannerWidget *plannerWidget = new DivePlannerWidget();
+ PlannerDetails *plannerDetails = new PlannerDetails();
+ LocationInformationWidget *locationInformation = new LocationInformationWidget();
+
// 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
@@ -57,69 +86,82 @@ MainWindow::MainWindow() : QMainWindow(),
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->addWidget(toolBar);
+ profLayout->addWidget(profileWidget);
+ profileContainer->setLayout(profLayout);
+
+ 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",locationInformation, profileContainer, diveListView, globeGps );
+
+ setApplicationState("Default");
+
+ ui.multiFilter->hide();
+
setWindowIcon(QIcon(":subsurface-icon"));
if (!QIcon::hasThemeIcon("window-close")) {
QIcon::setThemeName("subsurface");
}
- connect(ui.ListWidget, SIGNAL(currentDiveChanged(int)), this, SLOT(current_dive_changed(int)));
+ 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()), ui.ListWidget, SLOT(update()));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), ui.ListWidget, SLOT(reloadHeaderActions()));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), ui.InfoWidget, SLOT(updateDiveInfo()));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), ui.divePlannerWidget, SLOT(settingsChanged()));
- connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), ui.plannerSettingsWidget, SLOT(settingsChanged()));
+ 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()), ui.newProfile, SLOT(setProfileState()));
+ connect(information(), SIGNAL(addDiveFinished()), graphics(), SLOT(setProfileState()));
connect(DivePlannerPointsModel::instance(), SIGNAL(planCreated()), this, SLOT(planCreated()));
connect(DivePlannerPointsModel::instance(), SIGNAL(planCanceled()), this, SLOT(planCanceled()));
- connect(ui.printPlan, SIGNAL(pressed()), ui.divePlannerWidget, SLOT(printDecoPlan()));
+ connect(plannerDetails->printPlan(), SIGNAL(pressed()), divePlannerWidget(), SLOT(printDecoPlan()));
+ connect(mainTab, SIGNAL(requestDiveSiteEdit(uint32_t)), this, SLOT(enableDiveSiteEdit(uint32_t)));
+ connect(locationInformation, SIGNAL(informationManagementEnded()), this, SLOT(setDefaultState()));
+ connect(locationInformation, SIGNAL(informationManagementEnded()), information(), SLOT(showLocation()));
+
#ifdef NO_PRINTING
- ui.printPlan->hide();
+ plannerDetails->printPlan()->hide();
+ ui.menuFile->removeAction(ui.actionPrint);
#endif
ui.mainErrorMessage->hide();
- ui.newProfile->setEmptyState();
+ graphics()->setEmptyState();
initialUiSetup();
readSettings();
- ui.ListWidget->reload(DiveTripModel::TREE);
- ui.ListWidget->reloadHeaderActions();
- ui.ListWidget->setFocus();
- ui.globe->reload();
- ui.ListWidget->expand(ui.ListWidget->model()->index(0, 0));
- ui.ListWidget->scrollTo(ui.ListWidget->model()->index(0, 0), QAbstractItemView::PositionAtCenter);
- ui.divePlannerWidget->settingsChanged();
- ui.plannerSettingsWidget->settingsChanged();
+ diveListView->reload(DiveTripModel::TREE);
+ diveListView->reloadHeaderActions();
+ diveListView->setFocus();
+ globe()->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.globePane->hide();
ui.menuView->removeAction(ui.actionViewGlobe);
#else
- connect(ui.globe, SIGNAL(coordinatesChanged()), ui.InfoWidget, SLOT(updateGpsCoordinates()));
+ connect(globe(), SIGNAL(coordinatesChanged()), locationInformation, SLOT(updateGpsCoordinates()));
#endif
#ifdef NO_USERMANUAL
ui.menuHelp->removeAction(ui.actionUserManual);
#endif
-#ifdef NO_PRINTING
- ui.menuFile->removeAction(ui.actionPrint);
-#endif
memset(&copyPasteDive, 0, sizeof(copyPasteDive));
memset(&what, 0, sizeof(what));
- QToolBar *toolBar = new QToolBar();
- Q_FOREACH (QAction *a, profileToolbarActions)
- toolBar->addAction(a);
- toolBar->setOrientation(Qt::Vertical);
- toolBar->setIconSize(QSize(24,24));
- // since I'm adding the toolBar by hand, because designer
- // has no concept of "toolbar" for a non-mainwindow widget (...)
- // I need to take the current item that's in the toolbar Position
- // and reposition it alongside the grid layout.
- QLayoutItem *p = ui.profileInnerLayout->takeAt(0);
- ui.profileInnerLayout->addWidget(toolBar, 0, 0);
- ui.profileInnerLayout->addItem(p, 0, 1);
// and now for some layout hackery
// this gets us consistent margins everywhere and a much more balanced look
@@ -146,19 +188,52 @@ MainWindow::MainWindow() : QMainWindow(),
else
layout->setContentsMargins(margins);
}
- margins = QMargins(0, 5, 5, 5);
- ui.profileInnerLayout->setContentsMargins(margins);
- ui.profileInnerLayout->setSpacing(0);
toolBar->setContentsMargins(zeroMargins);
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);
+
+ ReverseGeoLoockupThread *geoLoockup = ReverseGeoLoockupThread::instance();
+ connect(geoLoockup, SIGNAL(started()),information(), SLOT(disableGeoLoockupEdition()));
+ connect(geoLoockup, SIGNAL(finished()), information(), SLOT(enableGeoLoockupEdition()));
}
MainWindow::~MainWindow()
{
+ write_hashes();
m_Instance = NULL;
}
+PlannerDetails *MainWindow::plannerDetails() const {
+ return qobject_cast<PlannerDetails*>(applicationState["PlanDive"].bottomRight);
+}
+
+PlannerSettingsWidget *MainWindow::divePlannerSettingsWidget() {
+ return qobject_cast<PlannerSettingsWidget*>(applicationState["PlanDive"].bottomLeft);
+}
+
+LocationInformationWidget *MainWindow::locationInformationWidget() {
+ return qobject_cast<LocationInformationWidget*>(applicationState["EditDiveSite"].topLeft);
+}
+
+void MainWindow::enableDiveSiteEdit(uint32_t id) {
+ locationInformationWidget()->setLocationId(displayed_dive.dive_site_uuid);
+ setApplicationState("EditDiveSite");
+}
+
+void MainWindow::setDefaultState() {
+ setApplicationState("Default");
+}
+
void MainWindow::setLoadedWithFiles(bool f)
{
filesAsArguments = f;
@@ -177,19 +252,16 @@ MainWindow *MainWindow::instance()
// this gets called after we download dives from a divecomputer
void MainWindow::refreshDisplay(bool doRecreateDiveList)
{
- showError(get_error_string());
- ui.InfoWidget->reload();
+ getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
+ information()->reload();
TankInfoModel::instance()->update();
- ui.globe->reload();
+ globe()->reload();
if (doRecreateDiveList)
recreateDiveList();
- ui.diveListPane->setCurrentIndex(0); // switch to the dive list
-#ifdef NO_MARBLE
- ui.globePane->hide();
-#endif
- ui.globePane->setCurrentIndex(0);
- ui.ListWidget->setEnabled(true);
- ui.ListWidget->setFocus();
+
+ setApplicationState("Default");
+ dive_list()->setEnabled(true);
+ dive_list()->setFocus();
WSInfoModel::instance()->updateInfo();
if (amount_selected == 0)
cleanUpEmpty();
@@ -197,7 +269,7 @@ void MainWindow::refreshDisplay(bool doRecreateDiveList)
void MainWindow::recreateDiveList()
{
- ui.ListWidget->reload(DiveTripModel::CURRENT);
+ dive_list()->reload(DiveTripModel::CURRENT);
TagFilterModel::instance()->repopulate();
BuddyFilterModel::instance()->repopulate();
LocationFilterModel::instance()->repopulate();
@@ -208,10 +280,11 @@ void MainWindow::current_dive_changed(int divenr)
{
if (divenr >= 0) {
select_dive(divenr);
- ui.globe->centerOnCurrentDive();
+ globe()->centerOnCurrentDive();
}
- ui.newProfile->plotDive();
- ui.InfoWidget->updateDiveInfo();
+ graphics()->plotDive();
+ information()->updateDiveInfo();
+ locationInformationWidget()->setLocationId(displayed_dive.dive_site_uuid);
}
void MainWindow::on_actionNew_triggered()
@@ -252,20 +325,49 @@ void MainWindow::on_actionSaveAs_triggered()
file_save_as();
}
+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 ui.newProfile;
+ return qobject_cast<ProfileWidget2*>(applicationState["Default"].topRight->layout()->itemAt(1)->widget());
}
void MainWindow::cleanUpEmpty()
{
- ui.InfoWidget->clearStats();
- ui.InfoWidget->clearInfo();
- ui.InfoWidget->clearEquipment();
- ui.InfoWidget->updateDiveInfo(true);
- ui.newProfile->setEmptyState();
- ui.ListWidget->reload(DiveTripModel::TREE);
- ui.globe->reload();
+ information()->clearStats();
+ information()->clearInfo();
+ information()->clearEquipment();
+ information()->updateDiveInfo(true);
+ graphics()->setEmptyState();
+ dive_list()->reload(DiveTripModel::TREE);
+ locationInformationWidget()->setLocationId(0);
+ globe()->reload();
if (!existing_filename)
setTitle(MWTF_DEFAULT);
disableShortcuts();
@@ -274,7 +376,8 @@ void MainWindow::cleanUpEmpty()
bool MainWindow::okToClose(QString message)
{
if (DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING ||
- ui.InfoWidget->isEditing()) {
+ information()->isEditing() ||
+ currentApplicationState == "EditDiveSite") {
QMessageBox::warning(this, tr("Warning"), message);
return false;
}
@@ -286,11 +389,13 @@ bool MainWindow::okToClose(QString message)
void MainWindow::closeCurrentFile()
{
- ui.newProfile->setEmptyState();
+ graphics()->setEmptyState();
/* free the dives and trips */
clear_git_id();
while (dive_table.nr)
delete_single_dive(0);
+ while (dive_site_table.nr)
+ delete_dive_site(get_dive_site(0)->uuid);
free((void *)existing_filename);
existing_filename = NULL;
@@ -362,8 +467,8 @@ void MainWindow::enableShortcuts()
void MainWindow::showProfile()
{
enableShortcuts();
- ui.newProfile->setProfileState();
- ui.infoPane->setCurrentIndex(MAINTAB);
+ graphics()->setProfileState();
+ setApplicationState("Default");
}
void MainWindow::on_actionPreferences_triggered()
@@ -373,9 +478,9 @@ void MainWindow::on_actionPreferences_triggered()
void MainWindow::on_actionQuit_triggered()
{
- if (ui.InfoWidget->isEditing()) {
- ui.InfoWidget->rejectChanges();
- if (ui.InfoWidget->isEditing())
+ if (information()->isEditing()) {
+ information()->rejectChanges();
+ if (information()->isEditing())
// didn't discard the edits
return;
}
@@ -421,7 +526,7 @@ void MainWindow::on_actionEditDeviceNames_triggered()
bool MainWindow::plannerStateClean()
{
if (DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING ||
- ui.InfoWidget->isEditing()) {
+ information()->isEditing()) {
QMessageBox::warning(this, tr("Warning"), tr("Please save or cancel the current dive edit before trying to add a dive."));
return false;
}
@@ -433,16 +538,16 @@ void MainWindow::planCanceled()
// while planning we might have modified the displayed_dive
// let's refresh what's shown on the profile
showProfile();
- ui.newProfile->replot();
+ graphics()->replot();
refreshDisplay(false);
- ui.newProfile->plotDive(get_dive(selected_dive));
+ graphics()->plotDive(get_dive(selected_dive));
DivePictureModel::instance()->updateDivePictures();
}
void MainWindow::planCreated()
{
// get the new dive selected and assign a number if reasonable
- ui.newProfile->setProfileState();
+ 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();
@@ -451,20 +556,20 @@ void MainWindow::planCreated()
set_dive_nr_for_current_dive();
}
// make sure our UI is in a consistent state
- ui.InfoWidget->updateDiveInfo();
+ information()->updateDiveInfo();
showProfile();
refreshDisplay();
}
void MainWindow::setPlanNotes(const char *notes)
{
- ui.divePlanOutput->setHtml(notes);
+ plannerDetails()->divePlanOutput()->setHtml(notes);
}
void MainWindow::printPlan()
{
#ifndef NO_PRINTING
- QString diveplan = ui.divePlanOutput->toHtml();
+ QString diveplan = plannerDetails()->divePlanOutput()->toHtml();
QString withDisclaimer = QString("<img height=50 src=\":subsurface-icon\"> ") + diveplan + QString(disclaimer);
QPrinter printer;
@@ -473,9 +578,9 @@ void MainWindow::printPlan()
if (dialog->exec() != QDialog::Accepted)
return;
- ui.divePlanOutput->setHtml(withDisclaimer);
- ui.divePlanOutput->print(&printer);
- ui.divePlanOutput->setHtml(diveplan);
+ plannerDetails()->divePlanOutput()->setHtml(withDisclaimer);
+ plannerDetails()->divePlanOutput()->print(&printer);
+ plannerDetails()->divePlanOutput()->setHtml(diveplan);
#endif
}
@@ -489,31 +594,28 @@ void MainWindow::setupForAddAndPlan(const char *model)
// setup the dive cylinders
DivePlannerPointsModel::instance()->clear();
DivePlannerPointsModel::instance()->setupCylinders();
+ locationInformationWidget()->setLocationId(0);
}
void MainWindow::on_actionReplanDive_triggered()
{
- if (!plannerStateClean())
- return;
- if (!current_dive || !current_dive->dc.model || strcmp(current_dive->dc.model, "planned dive")) {
- qDebug() << "trying to replan a dive that's not a planned dive:" << current_dive->dc.model;
+ 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);
- ui.newProfile->setPlanState();
- ui.newProfile->clearHandlers();
- ui.infoPane->setCurrentIndex(PLANNERWIDGET);
- ui.divePlannerWidget->setReplanButton(true);
+ graphics()->setPlanState();
+ graphics()->clearHandlers();
+ setApplicationState("PlanDive");
+ divePlannerWidget()->setReplanButton(true);
DivePlannerPointsModel::instance()->loadFromDive(current_dive);
reset_cylinders(&displayed_dive, true);
- ui.diveListPane->setCurrentIndex(1); // switch to the plan output
- ui.globePane->setCurrentIndex(1);
-#ifdef NO_MARBLE
- ui.globePane->show();
-#endif
}
void MainWindow::on_actionDivePlanner_triggered()
@@ -523,22 +625,20 @@ void MainWindow::on_actionDivePlanner_triggered()
// put us in PLAN mode
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN);
+ setApplicationState("PlanDive");
- ui.newProfile->setPlanState();
- ui.infoPane->setCurrentIndex(PLANNERWIDGET);
+ graphics()->setPlanState();
- // create a simple starting dive, using the first gas from the just copied cylidners
+ // 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();
- ui.divePlannerWidget->setReplanButton(false);
+ divePlannerWidget()->setReplanButton(false);
+}
- ui.diveListPane->setCurrentIndex(1); // switch to the plan output
- ui.globePane->setCurrentIndex(1);
-#ifdef NO_MARBLE
- ui.globePane->show();
-#endif
+DivePlannerWidget* MainWindow::divePlannerWidget() {
+ return qobject_cast<DivePlannerWidget*>(applicationState["PlanDive"].topLeft);
}
void MainWindow::on_actionAddDive_triggered()
@@ -551,23 +651,45 @@ void MainWindow::on_actionAddDive_triggered()
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
- ui.InfoWidget->updateDiveInfo();
+ information()->updateDiveInfo();
// show main tab
- ui.InfoWidget->setCurrentIndex(0);
+ information()->setCurrentIndex(0);
- ui.InfoWidget->addDiveStarted();
- ui.infoPane->setCurrentIndex(MAINTAB);
+ information()->addDiveStarted();
- ui.newProfile->setAddState();
+ graphics()->setAddState();
DivePlannerPointsModel::instance()->createSimpleDive();
- ui.newProfile->plotDive();
+ 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 || 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();
+ setApplicationState("EditDive");
+ DivePlannerPointsModel::instance()->loadFromDive(current_dive);
+ information()->enableEdition(MainTab::MANUALLY_ADDED_DIVE);
}
void MainWindow::on_actionRenumber_triggered()
@@ -612,16 +734,16 @@ void MainWindow::on_actionYearlyStatistics_triggered()
#define TOGGLE_COLLAPSABLE( X ) \
ui.mainSplitter->setCollapsible(0, X); \
ui.mainSplitter->setCollapsible(1, X); \
- ui.infoProfileSplitter->setCollapsible(0, X); \
- ui.infoProfileSplitter->setCollapsible(1, X); \
- ui.listGlobeSplitter->setCollapsible(0, X); \
- ui.listGlobeSplitter->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.listGlobeSplitter->setSizes(BEHAVIOR << EXPANDED << COLLAPSED);
+ ui.topSplitter->setSizes(BEHAVIOR << EXPANDED << COLLAPSED);
ui.mainSplitter->setSizes(BEHAVIOR << COLLAPSED << EXPANDED);
}
@@ -629,7 +751,7 @@ void MainWindow::on_actionViewProfile_triggered()
{
TOGGLE_COLLAPSABLE( true );
beginChangeState(PROFILE_MAXIMIZED);
- ui.infoProfileSplitter->setSizes(BEHAVIOR << COLLAPSED << EXPANDED);
+ ui.topSplitter->setSizes(BEHAVIOR << COLLAPSED << EXPANDED);
ui.mainSplitter->setSizes(BEHAVIOR << EXPANDED << COLLAPSED);
}
@@ -637,7 +759,7 @@ void MainWindow::on_actionViewInfo_triggered()
{
TOGGLE_COLLAPSABLE( true );
beginChangeState(INFO_MAXIMIZED);
- ui.infoProfileSplitter->setSizes(BEHAVIOR << EXPANDED << COLLAPSED);
+ ui.topSplitter->setSizes(BEHAVIOR << EXPANDED << COLLAPSED);
ui.mainSplitter->setSizes(BEHAVIOR << EXPANDED << COLLAPSED);
}
@@ -646,7 +768,7 @@ void MainWindow::on_actionViewGlobe_triggered()
TOGGLE_COLLAPSABLE( true );
beginChangeState(GLOBE_MAXIMIZED);
ui.mainSplitter->setSizes(BEHAVIOR << COLLAPSED << EXPANDED);
- ui.listGlobeSplitter->setSizes(BEHAVIOR << COLLAPSED << EXPANDED);
+ ui.bottomSplitter->setSizes(BEHAVIOR << COLLAPSED << EXPANDED);
}
#undef BEHAVIOR
@@ -677,26 +799,26 @@ void MainWindow::on_actionViewAll_triggered()
settings.beginGroup("MainWindow");
if (settings.value("mainSplitter").isValid()) {
ui.mainSplitter->restoreState(settings.value("mainSplitter").toByteArray());
- ui.infoProfileSplitter->restoreState(settings.value("infoProfileSplitter").toByteArray());
- ui.listGlobeSplitter->restoreState(settings.value("listGlobeSplitter").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.infoProfileSplitter->sizes().first() == 0 || ui.infoProfileSplitter->sizes().last() == 0)
- ui.infoProfileSplitter->setSizes(infoProfileSizes);
- if (ui.listGlobeSplitter->sizes().first() == 0 || ui.listGlobeSplitter->sizes().last() == 0)
- ui.listGlobeSplitter->setSizes(listGlobeSizes);
+ 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.infoProfileSplitter->setSizes(infoProfileSizes);
- ui.listGlobeSplitter->setSizes(listGlobeSizes);
+ ui.topSplitter->setSizes(infoProfileSizes);
+ ui.bottomSplitter->setSizes(listGlobeSizes);
}
ui.mainSplitter->setCollapsible(0, false);
ui.mainSplitter->setCollapsible(1, false);
- ui.infoProfileSplitter->setCollapsible(0, false);
- ui.infoProfileSplitter->setCollapsible(1, false);
- ui.listGlobeSplitter->setCollapsible(0,false);
- ui.listGlobeSplitter->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
@@ -714,24 +836,24 @@ void MainWindow::saveSplitterSizes()
QSettings settings;
settings.beginGroup("MainWindow");
settings.setValue("mainSplitter", ui.mainSplitter->saveState());
- settings.setValue("infoProfileSplitter", ui.infoProfileSplitter->saveState());
- settings.setValue("listGlobeSplitter", ui.listGlobeSplitter->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;
- ui.newProfile->plotDive();
- ui.InfoWidget->updateDiveInfo();
+ graphics()->plotDive();
+ information()->updateDiveInfo();
}
void MainWindow::on_actionNextDC_triggered()
{
unsigned nrdc = number_of_computers(current_dive);
dc_number = (dc_number + 1) % nrdc;
- ui.newProfile->plotDive();
- ui.InfoWidget->updateDiveInfo();
+ graphics()->plotDive();
+ information()->updateDiveInfo();
}
void MainWindow::on_actionFullScreen_triggered(bool checked)
@@ -802,6 +924,7 @@ QString MainWindow::filter()
f += "UDDF (*.uddf *.UDDF);;";
f += "XML (*.xml *.XML)";
f += "Divesoft (*.dlf *.DLF)";
+ f += "Datatrak/WLog Files (*.log *.LOG)";
return f;
}
@@ -937,7 +1060,7 @@ void MainWindow::checkSurvey(QSettings *s)
s->setValue("FirstUse42", value);
}
// wait a week for production versions, but not at all for non-tagged builds
- QString ver(VERSION_STRING);
+ QString ver(subsurface_version());
int waitTime = 7;
QDate firstUse42 = s->value("FirstUse42").toDate();
if (run_survey || (firstUse42.daysTo(QDate().currentDate()) > waitTime && !s->contains("SurveyDone"))) {
@@ -965,7 +1088,7 @@ void MainWindow::writeSettings()
void MainWindow::closeEvent(QCloseEvent *event)
{
if (DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING ||
- ui.InfoWidget->isEditing()) {
+ information()->isEditing()) {
on_actionQuit_triggered();
event->ignore();
return;
@@ -994,17 +1117,17 @@ void MainWindow::closeEvent(QCloseEvent *event)
DiveListView *MainWindow::dive_list()
{
- return ui.ListWidget;
+ return qobject_cast<DiveListView*>(applicationState["Default"].bottomLeft);
}
GlobeGPS *MainWindow::globe()
{
- return ui.globe;
+ return qobject_cast<GlobeGPS*>(applicationState["Default"].bottomRight);
}
MainTab *MainWindow::information()
{
- return ui.InfoWidget;
+ return qobject_cast<MainTab*>(applicationState["Default"].topLeft);
}
void MainWindow::loadRecentFiles(QSettings *s)
@@ -1174,20 +1297,31 @@ int MainWindow::file_save_as(void)
{
QString filename;
const char *default_filename = existing_filename;
- filename = QFileDialog::getSaveFileName(this, tr("Save file as"), default_filename,
- tr("Subsurface XML files (*.ssrf *.xml *.XML)"));
+
+ // 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);
+
+ /* 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);
if (filename.isNull() || filename.isEmpty())
return report_error("No filename to save into");
- if (ui.InfoWidget->isEditing())
- ui.InfoWidget->acceptChanges();
+ if (information()->isEditing())
+ information()->acceptChanges();
if (save_dives(filename.toUtf8().data())) {
- showError(get_error_string());
+ getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
return -1;
}
- showError(get_error_string());
+ getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
set_filename(filename.toUtf8().data(), true);
setTitle(MWTF_FILENAME);
mark_divelist_changed(false);
@@ -1202,8 +1336,8 @@ int MainWindow::file_save(void)
if (!existing_filename)
return file_save_as();
- if (ui.InfoWidget->isEditing())
- ui.InfoWidget->acceptChanges();
+ if (information()->isEditing())
+ information()->acceptChanges();
current_default = prefs.default_filename;
if (strcmp(existing_filename, current_default) == 0) {
@@ -1214,23 +1348,18 @@ int MainWindow::file_save(void)
current_def_dir.mkpath(current_def_dir.absolutePath());
}
if (save_dives(existing_filename)) {
- showError(get_error_string());
+ getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
return -1;
}
- showError(get_error_string());
+ getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
mark_divelist_changed(false);
addRecentFile(QStringList() << QString(existing_filename));
return 0;
}
-void MainWindow::showError(QString message)
+NotificationWidget *MainWindow::getNotificationWidget()
{
- if (message.isEmpty())
- return;
- ui.mainErrorMessage->setText(message);
- ui.mainErrorMessage->setCloseButtonVisible(true);
- ui.mainErrorMessage->setMessageType(KMessageWidget::Error);
- ui.mainErrorMessage->animatedShow();
+ return ui.mainErrorMessage;
}
void MainWindow::setTitle(enum MainWindowTitleFormat format)
@@ -1284,6 +1413,18 @@ void MainWindow::importTxtFiles(const QStringList fileNames)
refreshDisplay();
}
+void MainWindow::showV2Dialog()
+{
+ // here we need to ask the user if / how they want to do the reverse geo coding
+ // for now this is just a warning that things could take a long time
+ QMessageBox d(QMessageBox::Information,
+ tr("Welcom to Subsurface %1").arg(subsurface_version()),
+ tr("Importing data files from earlier versions of Subsurface can take a significant amount of time"),
+ QMessageBox::Ok,
+ this);
+ d.exec();
+}
+
void MainWindow::loadFiles(const QStringList fileNames)
{
if (fileNames.isEmpty())
@@ -1301,14 +1442,26 @@ void MainWindow::loadFiles(const QStringList fileNames)
set_filename(fileNamePtr.data(), true);
setTitle(MWTF_FILENAME);
} else {
+ if (!v2_question_shown && abort_read_of_old_file) {
+ v2_question_shown = true;
+ abort_read_of_old_file = false;
+ showV2Dialog();
+ getNotificationWidget()->showNotification(tr("Please Wait, Importing your files..."), KMessageWidget::Information);
+ i--; // so we re-try this file
+ continue;
+ }
failedParses.append(fileNames.at(i));
}
}
-
+ getNotificationWidget()->hideNotification();
process_dives(false, false);
addRecentFile(fileNames);
removeRecentFile(failedParses);
+ // searches for geo lookup information in a thread so it doesn`t
+ // freezes the ui.
+ ReverseGeoLoockupThread::instance()->start();
+
refreshDisplay();
ui.actionAutoGroup->setChecked(autogroup);
}
@@ -1316,18 +1469,21 @@ void MainWindow::loadFiles(const QStringList fileNames)
void MainWindow::on_actionImportDiveLog_triggered()
{
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open dive log file"), lastUsedDir(),
- tr("Dive log files (*.ssrf *.can *.csv *.db *.dld *.jlb *.lvd *.sde *.udcf *.uddf *.xml *.txt *.dlf *.apd);;"
- "Cochran files (*.can);;"
- "CSV files (*.csv);;"
- "DiveLog.de files (*.dld);;"
- "JDiveLog files (*.jlb);;"
- "Liquivision files (*.lvd);;"
- "MkVI files (*.txt);;"
- "Suunto files (*.sde *.db);;"
- "Divesoft files (*.dlf);;"
- "UDDF/UDCF files (*.uddf *.udcf);;"
- "XML files (*.xml);;"
- "APD log viewer (*.apd);;"
+ tr("Dive log files (*.ssrf *.can *.csv *.db *.dld *.jlb *.lvd *.sde *.udcf *.uddf *.xml *.txt *.dlf *.apd"
+ "*.SSRF *.CAN *.CSV *.DB *.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())
@@ -1368,20 +1524,16 @@ void MainWindow::editCurrentDive()
if (defaultDC == "manually added dive") {
disableShortcuts();
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD);
- ui.newProfile->setAddState();
- ui.infoPane->setCurrentIndex(MAINTAB);
+ graphics()->setAddState();
+ setApplicationState("EditDive");
DivePlannerPointsModel::instance()->loadFromDive(d);
- ui.InfoWidget->enableEdition(MainTab::MANUALLY_ADDED_DIVE);
+ information()->enableEdition(MainTab::MANUALLY_ADDED_DIVE);
} else if (defaultDC == "planned dive") {
disableShortcuts();
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN);
- //TODO: I BROKE THIS BY COMMENTING THE LINE BELOW
- // and I'm sleepy now, so I think I should not try to fix right away.
- // we don't setCurrentIndex anymore, we ->setPlanState() or ->setAddState() on the ProfileView.
- //ui.stackedWidget->setCurrentIndex(PLANNERPROFILE); // Planner.
- ui.infoPane->setCurrentIndex(PLANNERWIDGET);
+ setApplicationState("EditPlannedDive");
DivePlannerPointsModel::instance()->loadFromDive(d);
- ui.InfoWidget->enableEdition(MainTab::MANUALLY_ADDED_DIVE);
+ information()->enableEdition(MainTab::MANUALLY_ADDED_DIVE);
}
}
@@ -1456,7 +1608,7 @@ 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);
- ui.InfoWidget->showAndTriggerEditSelective(what);
+ information()->showAndTriggerEditSelective(what);
}
void MainWindow::on_actionFilterTags_triggered()
@@ -1466,3 +1618,43 @@ void MainWindow::on_actionFilterTags_triggered()
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 (currentApplicationState == state)
+ return;
+
+ currentApplicationState = 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 )
+ SET_CURRENT_INDEX( topRight )
+ SET_CURRENT_INDEX( bottomLeft )
+ SET_CURRENT_INDEX( bottomRight )
+#undef SET_CURRENT_INDEX
+}