mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-28 05:00:20 +00:00
c7a5d0490f
This is the skeleton code for a non-blocking ui-thread It already creates the first-thread ( 'do not block the ui' ) and the second thread ('download from the dive computer') We can in the future merge both in the same place - I didn't want to do that now because the download function is written in the libdivecomputer.c code, and I cant just transform that to a QThread and use signals, so I used two threads for that. Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
534 lines
13 KiB
C++
534 lines
13 KiB
C++
/*
|
|
* mainwindow.cpp
|
|
*
|
|
* classes for the main UI window in Subsurface
|
|
*/
|
|
#include "mainwindow.h"
|
|
#include "ui_mainwindow.h"
|
|
|
|
#include <QVBoxLayout>
|
|
#include <QFileDialog>
|
|
#include <QMessageBox>
|
|
#include <QtDebug>
|
|
#include <QDateTime>
|
|
#include <QSettings>
|
|
#include <QCloseEvent>
|
|
#include <QApplication>
|
|
#include <QFontMetrics>
|
|
|
|
#include "divelistview.h"
|
|
#include "starwidget.h"
|
|
|
|
#include "glib.h"
|
|
#include "../dive.h"
|
|
#include "../divelist.h"
|
|
#include "../pref.h"
|
|
#include "modeldelegates.h"
|
|
#include "models.h"
|
|
#include "downloadfromdivecomputer.h"
|
|
|
|
static MainWindow* instance = 0;
|
|
|
|
MainWindow* mainWindow()
|
|
{
|
|
return instance;
|
|
}
|
|
|
|
MainWindow::MainWindow() : ui(new Ui::MainWindow())
|
|
{
|
|
ui->setupUi(this);
|
|
readSettings();
|
|
setWindowIcon(QIcon(":subsurface-icon"));
|
|
connect(ui->ListWidget, SIGNAL(currentDiveChanged(int)), this, SLOT(current_dive_changed(int)));
|
|
ui->globeMessage->hide();
|
|
ui->globe->setMessageWidget(ui->globeMessage);
|
|
ui->globeMessage->setCloseButtonVisible(false);
|
|
ui->ProfileWidget->setFocusProxy(ui->ListWidget);
|
|
ui->ListWidget->reload();
|
|
ui->ListWidget->setFocus();
|
|
ui->globe->reload();
|
|
instance = this;
|
|
}
|
|
|
|
void MainWindow::current_dive_changed(int divenr)
|
|
{
|
|
select_dive(divenr);
|
|
ui->globe->centerOn(get_dive(selected_dive));
|
|
redrawProfile();
|
|
ui->InfoWidget->updateDiveInfo(divenr);
|
|
}
|
|
|
|
void MainWindow::redrawProfile()
|
|
{
|
|
ui->ProfileWidget->plot(get_dive(selected_dive));
|
|
}
|
|
|
|
void MainWindow::on_actionNew_triggered()
|
|
{
|
|
qDebug("actionNew");
|
|
}
|
|
|
|
void MainWindow::on_actionOpen_triggered()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Open File"), QDir::homePath(), filter());
|
|
if (filename.isEmpty())
|
|
return;
|
|
|
|
// Needed to convert to char*
|
|
QByteArray fileNamePtr = filename.toLocal8Bit();
|
|
|
|
on_actionClose_triggered();
|
|
|
|
GError *error = NULL;
|
|
parse_file(fileNamePtr.data(), &error);
|
|
set_filename(fileNamePtr.data(), TRUE);
|
|
|
|
if (error != NULL) {
|
|
QMessageBox::warning(this, "Error", error->message);
|
|
g_error_free(error);
|
|
error = NULL;
|
|
}
|
|
process_dives(FALSE, FALSE);
|
|
|
|
ui->InfoWidget->reload();
|
|
ui->globe->reload();
|
|
ui->ListWidget->reload();
|
|
ui->ListWidget->setFocus();
|
|
}
|
|
|
|
void MainWindow::on_actionSave_triggered()
|
|
{
|
|
file_save();
|
|
}
|
|
|
|
void MainWindow::on_actionSaveAs_triggered()
|
|
{
|
|
file_save_as();
|
|
}
|
|
void MainWindow::on_actionClose_triggered()
|
|
{
|
|
if (unsaved_changes() && (askSaveChanges() == FALSE))
|
|
return;
|
|
|
|
/* free the dives and trips */
|
|
while (dive_table.nr)
|
|
delete_single_dive(0);
|
|
|
|
/* clear the selection and the statistics */
|
|
selected_dive = -1;
|
|
|
|
//WARNING: Port this to Qt.
|
|
//process_selected_dives();
|
|
|
|
ui->InfoWidget->clearStats();
|
|
ui->InfoWidget->clearInfo();
|
|
ui->InfoWidget->clearEquipment();
|
|
ui->InfoWidget->updateDiveInfo(-1);
|
|
ui->ProfileWidget->clear();
|
|
ui->ListWidget->reload();
|
|
ui->globe->reload();
|
|
|
|
clear_events();
|
|
}
|
|
|
|
void MainWindow::on_actionImport_triggered()
|
|
{
|
|
qDebug("actionImport");
|
|
}
|
|
|
|
void MainWindow::on_actionExportUDDF_triggered()
|
|
{
|
|
qDebug("actionExportUDDF");
|
|
}
|
|
|
|
void MainWindow::on_actionPrint_triggered()
|
|
{
|
|
qDebug("actionPrint");
|
|
}
|
|
|
|
void MainWindow::on_actionPreferences_triggered()
|
|
{
|
|
qDebug("actionPreferences");
|
|
}
|
|
|
|
void MainWindow::on_actionQuit_triggered()
|
|
{
|
|
if (unsaved_changes() && (askSaveChanges() == FALSE))
|
|
return;
|
|
writeSettings();
|
|
QApplication::quit();
|
|
}
|
|
|
|
void MainWindow::on_actionDownloadDC_triggered()
|
|
{
|
|
DownloadFromDCWidget* downloadWidget = new DownloadFromDCWidget();
|
|
downloadWidget->show();
|
|
}
|
|
|
|
void MainWindow::on_actionDownloadWeb_triggered()
|
|
{
|
|
qDebug("actionDownloadWeb");}
|
|
|
|
void MainWindow::on_actionEditDeviceNames_triggered()
|
|
{
|
|
qDebug("actionEditDeviceNames");}
|
|
|
|
void MainWindow::on_actionAddDive_triggered()
|
|
{
|
|
qDebug("actionAddDive");
|
|
}
|
|
|
|
void MainWindow::on_actionRenumber_triggered()
|
|
{
|
|
qDebug("actionRenumber");
|
|
}
|
|
|
|
void MainWindow::on_actionAutoGroup_triggered()
|
|
{
|
|
qDebug("actionAutoGroup");
|
|
}
|
|
|
|
void MainWindow::on_actionToggleZoom_triggered()
|
|
{
|
|
qDebug("actionToggleZoom");
|
|
}
|
|
|
|
void MainWindow::on_actionYearlyStatistics_triggered()
|
|
{
|
|
qDebug("actionYearlyStatistics");
|
|
}
|
|
|
|
void MainWindow::on_actionViewList_triggered()
|
|
{
|
|
ui->InfoWidget->setVisible(false);
|
|
ui->ListWidget->setVisible(true);
|
|
ui->ProfileWidget->setVisible(false);
|
|
}
|
|
|
|
void MainWindow::on_actionViewProfile_triggered()
|
|
{
|
|
ui->InfoWidget->setVisible(false);
|
|
ui->ListWidget->setVisible(false);
|
|
ui->ProfileWidget->setVisible(true);
|
|
}
|
|
|
|
void MainWindow::on_actionViewInfo_triggered()
|
|
{
|
|
ui->InfoWidget->setVisible(true);
|
|
ui->ListWidget->setVisible(false);
|
|
ui->ProfileWidget->setVisible(false);
|
|
}
|
|
|
|
void MainWindow::on_actionViewAll_triggered()
|
|
{
|
|
ui->InfoWidget->setVisible(true);
|
|
ui->ListWidget->setVisible(true);
|
|
ui->ProfileWidget->setVisible(true);
|
|
}
|
|
|
|
void MainWindow::on_actionPreviousDC_triggered()
|
|
{
|
|
dc_number--;
|
|
redrawProfile();
|
|
}
|
|
|
|
void MainWindow::on_actionNextDC_triggered()
|
|
{
|
|
dc_number++;
|
|
redrawProfile();
|
|
}
|
|
|
|
void MainWindow::on_actionSelectEvents_triggered()
|
|
{
|
|
qDebug("actionSelectEvents");
|
|
}
|
|
|
|
void MainWindow::on_actionInputPlan_triggered()
|
|
{
|
|
qDebug("actionInputPlan");
|
|
}
|
|
|
|
void MainWindow::on_actionAboutSubsurface_triggered()
|
|
{
|
|
qDebug("actionAboutSubsurface");
|
|
}
|
|
|
|
void MainWindow::on_actionUserManual_triggered()
|
|
{
|
|
qDebug("actionUserManual");
|
|
}
|
|
|
|
QString MainWindow::filter()
|
|
{
|
|
QString f;
|
|
f += "ALL ( *.xml *.XML *.uddf *.udcf *.UDFC *.jlb *.JLB ";
|
|
#ifdef LIBZIP
|
|
f += "*.sde *.SDE *.dld *.DLD ";
|
|
#endif
|
|
#ifdef SQLITE3
|
|
f += "*.db";
|
|
#endif
|
|
f += ");;";
|
|
|
|
f += "XML (*.xml *.XML);;";
|
|
f += "UDDF (*.uddf);;";
|
|
f += "UDCF (*.udcf *.UDCF);;";
|
|
f += "JLB (*.jlb *.JLB);;";
|
|
|
|
#ifdef LIBZIP
|
|
f += "SDE (*.sde *.SDE);;";
|
|
f += "DLD (*.dld *.DLD);;";
|
|
#endif
|
|
#ifdef SQLITE3
|
|
f += "DB (*.db)";
|
|
#endif
|
|
|
|
return f;
|
|
}
|
|
|
|
bool MainWindow::askSaveChanges()
|
|
{
|
|
QString message;
|
|
QMessageBox::StandardButton response;
|
|
|
|
if (existing_filename)
|
|
message = tr("You have unsaved changes to file: %1\nDo you really want to close the file without saving?").arg(existing_filename);
|
|
else
|
|
message = tr("You have unsaved changes\nDo you really want to close the datafile without saving?");
|
|
|
|
response = QMessageBox::question(this, tr("Save Changes?"), message,
|
|
QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Ok, QMessageBox::Save);
|
|
if (response == QMessageBox::Save) {
|
|
file_save();
|
|
return true;
|
|
} else if (response == QMessageBox::Ok) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#define GET_UNIT(v, name, field, f, t) \
|
|
v = settings.value(QString(name)); \
|
|
if (v.isValid()) \
|
|
prefs.units.field = (v.toInt() == (t)) ? (t) : (f)
|
|
|
|
#define GET_BOOL(v, name, field) \
|
|
v = settings.value(QString(name)); \
|
|
if (v.isValid() && v.toInt()) \
|
|
field = TRUE; \
|
|
else \
|
|
field = FALSE
|
|
|
|
void MainWindow::readSettings()
|
|
{
|
|
int i;
|
|
QVariant v;
|
|
QSettings settings("hohndel.org","subsurface");
|
|
|
|
settings.beginGroup("MainWindow");
|
|
QSize sz = settings.value("size").value<QSize>();
|
|
resize(sz);
|
|
ui->mainSplitter->restoreState(settings.value("mainSplitter").toByteArray());
|
|
ui->infoProfileSplitter->restoreState(settings.value("infoProfileSplitter").toByteArray());
|
|
settings.endGroup();
|
|
|
|
settings.beginGroup("ListWidget");
|
|
/* if no width are set, use the calculated width for each column;
|
|
* for that to work we need to temporarily expand all rows */
|
|
ui->ListWidget->expandAll();
|
|
for (i = TreeItemDT::NR; i < TreeItemDT::COLUMNS; i++) {
|
|
QVariant width = settings.value(QString("colwidth%1").arg(i));
|
|
if (width.isValid())
|
|
ui->ListWidget->setColumnWidth(i, width.toInt());
|
|
else
|
|
ui->ListWidget->resizeColumnToContents(i);
|
|
}
|
|
ui->ListWidget->collapseAll();
|
|
ui->ListWidget->scrollTo(ui->ListWidget->model()->index(0,0), QAbstractItemView::PositionAtCenter);
|
|
|
|
settings.endGroup();
|
|
settings.beginGroup("Units");
|
|
GET_UNIT(v, "feet", length, units::METERS, units::FEET);
|
|
GET_UNIT(v, "psi", pressure, units::BAR, units::PSI);
|
|
GET_UNIT(v, "cuft", volume, units::LITER, units::CUFT);
|
|
GET_UNIT(v, "fahrenheit", temperature, units::CELSIUS, units::FAHRENHEIT);
|
|
GET_UNIT(v, "lbs", weight, units::KG, units::LBS);
|
|
settings.endGroup();
|
|
settings.beginGroup("DisplayListColumns");
|
|
GET_BOOL(v, "CYLINDER", prefs.visible_cols.cylinder);
|
|
GET_BOOL(v, "TEMPERATURE", prefs.visible_cols.temperature);
|
|
GET_BOOL(v, "TOTALWEIGHT", prefs.visible_cols.totalweight);
|
|
GET_BOOL(v, "SUIT", prefs.visible_cols.suit);
|
|
GET_BOOL(v, "NITROX", prefs.visible_cols.nitrox);
|
|
GET_BOOL(v, "OTU", prefs.visible_cols.otu);
|
|
GET_BOOL(v, "MAXCNS", prefs.visible_cols.maxcns);
|
|
GET_BOOL(v, "SAC", prefs.visible_cols.sac);
|
|
GET_BOOL(v, "po2graph", prefs.pp_graphs.po2);
|
|
GET_BOOL(v, "pn2graph", prefs.pp_graphs.pn2);
|
|
GET_BOOL(v, "phegraph", prefs.pp_graphs.phe);
|
|
settings.endGroup();
|
|
settings.beginGroup("TecDetails");
|
|
v = settings.value(QString("po2threshold"));
|
|
if (v.isValid())
|
|
prefs.pp_graphs.po2_threshold = v.toDouble();
|
|
v = settings.value(QString("pn2threshold"));
|
|
if (v.isValid())
|
|
prefs.pp_graphs.pn2_threshold = v.toDouble();
|
|
v = settings.value(QString("phethreshold"));
|
|
if (v.isValid())
|
|
prefs.pp_graphs.phe_threshold = v.toDouble();
|
|
GET_BOOL(v, "mod", prefs.mod);
|
|
v = settings.value(QString("modppO2"));
|
|
if (v.isValid())
|
|
prefs.mod_ppO2 = v.toDouble();
|
|
GET_BOOL(v, "ead", prefs.ead);
|
|
GET_BOOL(v, "redceiling", prefs.profile_red_ceiling);
|
|
GET_BOOL(v, "calcceiling", prefs.profile_calc_ceiling);
|
|
GET_BOOL(v, "calcceiling3m", prefs.calc_ceiling_3m_incr);
|
|
v = settings.value(QString("gflow"));
|
|
if (v.isValid())
|
|
prefs.gflow = v.toInt() / 100.0;
|
|
v = settings.value(QString("gfhigh"));
|
|
if (v.isValid())
|
|
prefs.gfhigh = v.toInt() / 100.0;
|
|
set_gf(prefs.gflow, prefs.gfhigh);
|
|
settings.endGroup();
|
|
|
|
#if ONCE_WE_CAN_SET_FONTS
|
|
settings.beginGroup("Display");
|
|
v = settings.value(QString("divelist_font"));
|
|
if (v.isValid())
|
|
/* I don't think this is right */
|
|
prefs.divelist_font = strdup(v.toString);
|
|
#endif
|
|
|
|
#if ONCE_WE_HAVE_MAPS
|
|
v = settings.value(QString_int("map_provider"));
|
|
if(v.isValid())
|
|
prefs.map_provider = v.toInt();
|
|
#endif
|
|
}
|
|
|
|
#define SAVE_VALUE(name, field) \
|
|
if (prefs.field != default_prefs.field) \
|
|
settings.setValue(name, prefs.field)
|
|
|
|
void MainWindow::writeSettings()
|
|
{
|
|
int i;
|
|
QSettings settings("hohndel.org","subsurface");
|
|
|
|
settings.beginGroup("MainWindow");
|
|
settings.setValue("size",size());
|
|
settings.setValue("mainSplitter", ui->mainSplitter->saveState());
|
|
settings.setValue("infoProfileSplitter", ui->infoProfileSplitter->saveState());
|
|
settings.endGroup();
|
|
|
|
settings.beginGroup("ListWidget");
|
|
for (i = TreeItemDT::NR; i < TreeItemDT::COLUMNS; i++)
|
|
settings.setValue(QString("colwidth%1").arg(i), ui->ListWidget->columnWidth(i));
|
|
settings.endGroup();
|
|
settings.beginGroup("Units");
|
|
SAVE_VALUE("feet", units.length);
|
|
SAVE_VALUE("psi", units.pressure);
|
|
SAVE_VALUE("cuft", units.volume);
|
|
SAVE_VALUE("fahrenheit", units.temperature);
|
|
SAVE_VALUE("lbs", units.weight);
|
|
settings.endGroup();
|
|
settings.beginGroup("DisplayListColumns");
|
|
SAVE_VALUE("TEMPERATURE", visible_cols.temperature);
|
|
SAVE_VALUE("TOTALWEIGHT", visible_cols.totalweight);
|
|
SAVE_VALUE("SUIT", visible_cols.suit);
|
|
SAVE_VALUE("CYLINDER", visible_cols.cylinder);
|
|
SAVE_VALUE("NITROX", visible_cols.nitrox);
|
|
SAVE_VALUE("SAC", visible_cols.sac);
|
|
SAVE_VALUE("OTU", visible_cols.otu);
|
|
SAVE_VALUE("MAXCNS", visible_cols.maxcns);
|
|
settings.endGroup();
|
|
settings.beginGroup("TecDetails");
|
|
SAVE_VALUE("po2graph", pp_graphs.po2);
|
|
SAVE_VALUE("pn2graph", pp_graphs.pn2);
|
|
SAVE_VALUE("phegraph", pp_graphs.phe);
|
|
SAVE_VALUE("po2threshold", pp_graphs.po2_threshold);
|
|
SAVE_VALUE("pn2threshold", pp_graphs.pn2_threshold);
|
|
SAVE_VALUE("phethreshold", pp_graphs.phe_threshold);
|
|
SAVE_VALUE("mod", mod);
|
|
SAVE_VALUE("modppO2", mod_ppO2);
|
|
SAVE_VALUE("ead", ead);
|
|
SAVE_VALUE("redceiling", profile_red_ceiling);
|
|
SAVE_VALUE("calcceiling", profile_calc_ceiling);
|
|
SAVE_VALUE("calcceiling3m", calc_ceiling_3m_incr);
|
|
SAVE_VALUE("gflow", gflow);
|
|
SAVE_VALUE("gfhigh", gfhigh);
|
|
settings.endGroup();
|
|
settings.beginGroup("GeneralSettings");
|
|
SAVE_VALUE("default_filename", default_filename);
|
|
settings.endGroup();
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
if (unsaved_changes() && (askSaveChanges() == FALSE)) {
|
|
event->ignore();
|
|
return;
|
|
}
|
|
event->accept();
|
|
writeSettings();
|
|
}
|
|
|
|
DiveListView* MainWindow::dive_list()
|
|
{
|
|
return ui->ListWidget;
|
|
}
|
|
|
|
GlobeGPS* MainWindow::globe()
|
|
{
|
|
return ui->globe;
|
|
}
|
|
|
|
ProfileGraphicsView* MainWindow::graphics()
|
|
{
|
|
return ui->ProfileWidget;
|
|
}
|
|
|
|
MainTab* MainWindow::information()
|
|
{
|
|
return ui->InfoWidget;
|
|
}
|
|
|
|
void MainWindow::file_save_as(void)
|
|
{
|
|
QString filename;
|
|
const char *default_filename;
|
|
|
|
if (existing_filename)
|
|
default_filename = existing_filename;
|
|
else
|
|
default_filename = prefs.default_filename;
|
|
filename = QFileDialog::getSaveFileName(this, tr("Save File as"), default_filename,
|
|
tr("Subsurface XML files (*.ssrf *.xml *.XML)"));
|
|
if (!filename.isNull() && !filename.isEmpty()) {
|
|
save_dives(filename.toUtf8().data());
|
|
set_filename(filename.toUtf8().data(), TRUE);
|
|
mark_divelist_changed(FALSE);
|
|
}
|
|
}
|
|
|
|
void MainWindow::file_save(void)
|
|
{
|
|
const char *current_default;
|
|
|
|
if (!existing_filename)
|
|
return file_save_as();
|
|
|
|
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());
|
|
}
|
|
save_dives(existing_filename);
|
|
mark_divelist_changed(FALSE);
|
|
}
|