mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-28 05:00:20 +00:00
01306224ff
It was never clear what was a pointer to a static string from libdivecomputer and what was allocated. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
699 lines
23 KiB
C++
699 lines
23 KiB
C++
// SPDX-License-Identifier: GPL-2.0
|
|
#include "desktop-widgets/downloadfromdivecomputer.h"
|
|
#include "commands/command.h"
|
|
#include "core/qthelper.h"
|
|
#include "core/device.h"
|
|
#include "core/divelist.h"
|
|
#include "core/divelog.h"
|
|
#include "core/errorhelper.h"
|
|
#include "core/settings/qPrefDiveComputer.h"
|
|
#include "core/subsurface-float.h"
|
|
#include "core/subsurface-string.h"
|
|
#include "core/downloadfromdcthread.h"
|
|
#include "desktop-widgets/divelistview.h"
|
|
#include "desktop-widgets/mainwindow.h"
|
|
#include "qt-models/diveimportedmodel.h"
|
|
#include "qt-models/models.h"
|
|
|
|
#include <QFileDialog>
|
|
#include <QMessageBox>
|
|
#include <QShortcut>
|
|
#include <QTimer>
|
|
#include <QUndoStack>
|
|
|
|
static bool is_vendor_searchable(QString vendor)
|
|
{
|
|
return vendor == "Uemis" || vendor == "Garmin" || vendor == "FIT";
|
|
}
|
|
|
|
DownloadFromDCWidget::DownloadFromDCWidget(const QString &filename, QWidget *parent) : QDialog(parent, QFlag(0)),
|
|
filename(filename),
|
|
downloading(false),
|
|
previousLast(0),
|
|
timer(new QTimer(this)),
|
|
dumpWarningShown(false),
|
|
#if defined (BT_SUPPORT)
|
|
btd(nullptr),
|
|
#endif
|
|
currentState(INITIAL)
|
|
{
|
|
diveImportedModel = new DiveImportedModel(this);
|
|
vendorModel.setStringList(vendorList);
|
|
QShortcut *close = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), this);
|
|
QShortcut *quit = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this);
|
|
|
|
int startingWidth = defaultModelFont().pointSize();
|
|
|
|
ui.setupUi(this);
|
|
ui.progressBar->hide();
|
|
ui.progressBar->setMinimum(0);
|
|
ui.progressBar->setMaximum(100);
|
|
ui.downloadedView->setModel(diveImportedModel);
|
|
ui.downloadedView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
ui.downloadedView->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
ui.downloadedView->setColumnWidth(0, startingWidth * 20);
|
|
ui.downloadedView->setColumnWidth(1, startingWidth * 10);
|
|
ui.downloadedView->setColumnWidth(2, startingWidth * 10);
|
|
ui.chooseDumpFile->setEnabled(ui.dumpToFile->isChecked());
|
|
ui.chooseLogFile->setEnabled(ui.logToFile->isChecked());
|
|
ui.selectAllButton->setEnabled(false);
|
|
ui.unselectAllButton->setEnabled(false);
|
|
ui.vendor->setModel(&vendorModel);
|
|
ui.search->setEnabled(is_vendor_searchable(ui.vendor->currentText()));
|
|
ui.product->setModel(&productModel);
|
|
ui.syncDiveComputerTime->setChecked(prefs.sync_dc_time);
|
|
|
|
progress_bar_text = "";
|
|
|
|
timer->setInterval(200);
|
|
|
|
connect(ui.downloadedView, SIGNAL(clicked(QModelIndex)), diveImportedModel, SLOT(changeSelected(QModelIndex)));
|
|
connect(ui.chooseDumpFile, SIGNAL(clicked()), this, SLOT(pickDumpFile()));
|
|
connect(ui.dumpToFile, SIGNAL(stateChanged(int)), this, SLOT(checkDumpFile(int)));
|
|
connect(ui.chooseLogFile, SIGNAL(clicked()), this, SLOT(pickLogFile()));
|
|
connect(ui.logToFile, SIGNAL(stateChanged(int)), this, SLOT(checkLogFile(int)));
|
|
connect(ui.selectAllButton, SIGNAL(clicked()), diveImportedModel, SLOT(selectAll()));
|
|
connect(ui.unselectAllButton, SIGNAL(clicked()), diveImportedModel, SLOT(selectNone()));
|
|
connect(ui.syncDiveComputerTime, &QAbstractButton::toggled, qPrefDiveComputer::instance(), &qPrefDiveComputer::set_sync_dc_time);
|
|
connect(timer, SIGNAL(timeout()), this, SLOT(updateProgressBar()));
|
|
connect(close, SIGNAL(activated()), this, SLOT(close()));
|
|
connect(quit, SIGNAL(activated()), parent, SLOT(close()));
|
|
|
|
connect(diveImportedModel, &DiveImportedModel::downloadFinished, this, &DownloadFromDCWidget::onDownloadThreadFinished);
|
|
|
|
if (!qPrefDiveComputer::vendor().isEmpty()) {
|
|
ui.vendor->setCurrentIndex(ui.vendor->findText(qPrefDiveComputer::vendor()));
|
|
productModel.setStringList(productList[qPrefDiveComputer::vendor()]);
|
|
if (!qPrefDiveComputer::product().isEmpty())
|
|
ui.product->setCurrentIndex(ui.product->findText(qPrefDiveComputer::product()));
|
|
}
|
|
|
|
// now lets set the four shortcuts for previously used dive computers
|
|
showRememberedDCs();
|
|
|
|
updateState(INITIAL);
|
|
ui.ok->setEnabled(false);
|
|
ui.downloadCancelRetryButton->setEnabled(true);
|
|
ui.downloadCancelRetryButton->setText(tr("Download"));
|
|
|
|
QString deviceText = qPrefDiveComputer::device();
|
|
#if defined(BT_SUPPORT)
|
|
ui.bluetoothMode->setText(tr("Choose Bluetooth download mode"));
|
|
ui.bluetoothMode->setChecked(isBluetoothAddress(qPrefDiveComputer::device()));
|
|
btDeviceSelectionDialog = 0;
|
|
connect(ui.bluetoothMode, SIGNAL(stateChanged(int)), this, SLOT(enableBluetoothMode(int)));
|
|
connect(ui.chooseBluetoothDevice, SIGNAL(clicked()), this, SLOT(selectRemoteBluetoothDevice()));
|
|
ui.chooseBluetoothDevice->setEnabled(ui.bluetoothMode->isChecked());
|
|
if (ui.bluetoothMode->isChecked())
|
|
deviceText = BtDeviceSelectionDialog::formatDeviceText(qPrefDiveComputer::device(), qPrefDiveComputer::device_name());
|
|
#else
|
|
ui.bluetoothMode->hide();
|
|
ui.chooseBluetoothDevice->hide();
|
|
#endif
|
|
if (!deviceText.isEmpty())
|
|
ui.device->setEditText(deviceText);
|
|
}
|
|
|
|
#define SETUPDC(num) \
|
|
if (!qPrefDiveComputer::vendor##num().isEmpty()) { \
|
|
ui.DC##num->setVisible(true); \
|
|
ui.DCFrame##num->setVisible(true); \
|
|
ui.DeleteDC##num->setVisible(true); \
|
|
ui.DC##num->setText(qPrefDiveComputer::vendor##num() + " - " + qPrefDiveComputer::product##num()); \
|
|
connect(ui.DC##num, &QPushButton::clicked, this, &DownloadFromDCWidget::DC##num##Clicked, Qt::UniqueConnection); \
|
|
connect(ui.DeleteDC##num, &QPushButton::clicked, this, &DownloadFromDCWidget::DeleteDC##num##Clicked, Qt::UniqueConnection); \
|
|
} else { \
|
|
ui.DC##num->setVisible(false); \
|
|
ui.DCFrame##num->setVisible(false); \
|
|
ui.DeleteDC##num->setVisible(false); \
|
|
}
|
|
|
|
void DownloadFromDCWidget::showRememberedDCs()
|
|
{
|
|
SETUPDC(1)
|
|
SETUPDC(2)
|
|
SETUPDC(3)
|
|
SETUPDC(4)
|
|
}
|
|
|
|
int DownloadFromDCWidget::deviceIndex(QString deviceText)
|
|
{
|
|
int rv = ui.device->findText(deviceText);
|
|
if (rv == -1) {
|
|
// we need to insert the device text into the model
|
|
ui.device->addItem(deviceText);
|
|
rv = ui.device->findText(deviceText);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
// DC button slots
|
|
// we need two versions as one of the helper functions used is only available if
|
|
// Bluetooth support is enabled
|
|
#ifdef BT_SUPPORT
|
|
#define DCBUTTON(num) \
|
|
void DownloadFromDCWidget::DC##num##Clicked() \
|
|
{ \
|
|
ui.vendor->setCurrentIndex(ui.vendor->findText(qPrefDiveComputer::vendor##num())); \
|
|
productModel.setStringList(productList[qPrefDiveComputer::vendor##num()]); \
|
|
ui.product->setCurrentIndex(ui.product->findText(qPrefDiveComputer::product##num())); \
|
|
ui.device->setCurrentIndex(deviceIndex(qPrefDiveComputer::device##num())); \
|
|
ui.bluetoothMode->setChecked(isBluetoothAddress(qPrefDiveComputer::device##num())); \
|
|
}
|
|
#else
|
|
#define DCBUTTON(num) \
|
|
void DownloadFromDCWidget::DC##num##Clicked() \
|
|
{ \
|
|
ui.vendor->setCurrentIndex(ui.vendor->findText(qPrefDiveComputer::vendor##num())); \
|
|
productModel.setStringList(productList[qPrefDiveComputer::vendor##num()]); \
|
|
ui.product->setCurrentIndex(ui.product->findText(qPrefDiveComputer::product##num())); \
|
|
ui.device->setCurrentIndex(deviceIndex(qPrefDiveComputer::device##num())); \
|
|
}
|
|
#endif
|
|
|
|
DCBUTTON(1)
|
|
DCBUTTON(2)
|
|
DCBUTTON(3)
|
|
DCBUTTON(4)
|
|
|
|
// Delete DC button slots
|
|
#define DELETEDCBUTTON(num) \
|
|
void DownloadFromDCWidget::DeleteDC##num##Clicked() \
|
|
{ \
|
|
ui.DC##num->setVisible(false); \
|
|
ui.DeleteDC##num->setVisible(false); \
|
|
int dc = num; \
|
|
switch (dc) { \
|
|
case 1: \
|
|
qPrefDiveComputer::set_vendor1(qPrefDiveComputer::vendor2()); \
|
|
qPrefDiveComputer::set_product1(qPrefDiveComputer::product2()); \
|
|
qPrefDiveComputer::set_device1(qPrefDiveComputer::device2()); \
|
|
case 2: \
|
|
qPrefDiveComputer::set_vendor2(qPrefDiveComputer::vendor3()); \
|
|
qPrefDiveComputer::set_product2(qPrefDiveComputer::product3()); \
|
|
qPrefDiveComputer::set_device2(qPrefDiveComputer::device3()); \
|
|
case 3: \
|
|
qPrefDiveComputer::set_vendor3(qPrefDiveComputer::vendor4()); \
|
|
qPrefDiveComputer::set_product3(qPrefDiveComputer::product4()); \
|
|
qPrefDiveComputer::set_device3(qPrefDiveComputer::device4()); \
|
|
case 4: \
|
|
qPrefDiveComputer::set_vendor4(QString()); \
|
|
qPrefDiveComputer::set_product4(QString()); \
|
|
qPrefDiveComputer::set_device4(QString()); \
|
|
} \
|
|
DownloadFromDCWidget::showRememberedDCs(); \
|
|
}
|
|
|
|
DELETEDCBUTTON(1)
|
|
DELETEDCBUTTON(2)
|
|
DELETEDCBUTTON(3)
|
|
DELETEDCBUTTON(4)
|
|
|
|
void DownloadFromDCWidget::updateProgressBar()
|
|
{
|
|
static char *last_text = NULL;
|
|
|
|
if (empty_string(last_text)) {
|
|
// if we get the first actual text after the download is finished
|
|
// (which happens for example on the OSTC), then don't bother
|
|
if (!empty_string(progress_bar_text) && nearly_equal(progress_bar_fraction, 1.0))
|
|
progress_bar_text = "";
|
|
}
|
|
if (!empty_string(progress_bar_text)) {
|
|
// once the progress bar text is set, setup the maximum so the user sees actual progress
|
|
ui.progressBar->setFormat(progress_bar_text);
|
|
ui.progressBar->setMaximum(100);
|
|
#if defined(Q_OS_MAC)
|
|
// on mac the progress bar doesn't show its text
|
|
ui.progressText->setText(progress_bar_text);
|
|
#endif
|
|
} else {
|
|
if (nearly_0(progress_bar_fraction)) {
|
|
// while we are waiting to connect, set the maximum to 0 so we get a busy indication
|
|
ui.progressBar->setMaximum(0);
|
|
ui.progressBar->setFormat(tr("Connecting to dive computer"));
|
|
#if defined(Q_OS_MAC)
|
|
// on mac the progress bar doesn't show its text
|
|
ui.progressText->setText(tr("Connecting to dive computer"));
|
|
#endif
|
|
} else {
|
|
// we have some progress - reset the maximum so the user sees actual progress
|
|
ui.progressBar->setMaximum(100);
|
|
ui.progressBar->setFormat("%p%");
|
|
#if defined(Q_OS_MAC)
|
|
// on mac the progress bar doesn't show its text
|
|
ui.progressText->setText(QString("%1%").arg(lrint(progress_bar_fraction * 100)));
|
|
#endif
|
|
}
|
|
}
|
|
ui.progressBar->setValue(lrint(progress_bar_fraction * 100));
|
|
free(last_text);
|
|
last_text = strdup(progress_bar_text);
|
|
}
|
|
|
|
void DownloadFromDCWidget::updateState(states state)
|
|
{
|
|
if (state == currentState)
|
|
return;
|
|
|
|
if (state == INITIAL) {
|
|
fill_device_list(~0);
|
|
ui.progressBar->hide();
|
|
markChildrenAsEnabled();
|
|
timer->stop();
|
|
progress_bar_text = "";
|
|
#if defined(Q_OS_MAC)
|
|
// on mac we show the text in a label
|
|
ui.progressText->setText(progress_bar_text);
|
|
#endif
|
|
}
|
|
|
|
// tries to cancel an on going download
|
|
else if (currentState == DOWNLOADING && state == CANCELLING) {
|
|
import_thread_cancelled = true;
|
|
ui.downloadCancelRetryButton->setEnabled(false);
|
|
}
|
|
|
|
// user pressed cancel but the application isn't doing anything.
|
|
// means close the window
|
|
else if ((currentState == INITIAL || currentState == DONE || currentState == ERRORED) && state == CANCELLING) {
|
|
timer->stop();
|
|
reject();
|
|
}
|
|
|
|
// the cancelation process is finished
|
|
else if (currentState == CANCELLING && state == DONE) {
|
|
timer->stop();
|
|
ui.progressBar->setValue(0);
|
|
ui.progressBar->hide();
|
|
markChildrenAsEnabled();
|
|
progress_bar_text = "";
|
|
#if defined(Q_OS_MAC)
|
|
// on mac we show the text in a label
|
|
ui.progressText->setText(progress_bar_text);
|
|
#endif
|
|
}
|
|
|
|
// DOWNLOAD is finally done, but we don't know if there was an error as libdivecomputer doesn't pass
|
|
// that information on to us.
|
|
// If we find an error, offer to retry, otherwise continue the interaction to pick the dives the user wants
|
|
else if (currentState == DOWNLOADING && state == DONE) {
|
|
timer->stop();
|
|
if (QString(progress_bar_text).contains("error", Qt::CaseInsensitive)) {
|
|
updateProgressBar();
|
|
markChildrenAsEnabled();
|
|
progress_bar_text = "";
|
|
} else {
|
|
if (diveImportedModel->numDives() != 0)
|
|
progress_bar_text = "";
|
|
ui.progressBar->setValue(100);
|
|
markChildrenAsEnabled();
|
|
}
|
|
#if defined(Q_OS_MAC)
|
|
// on mac we show the text in a label
|
|
ui.progressText->setText(progress_bar_text);
|
|
#endif
|
|
}
|
|
|
|
// DOWNLOAD is started.
|
|
else if (state == DOWNLOADING) {
|
|
timer->start();
|
|
ui.progressBar->setValue(0);
|
|
progress_bar_fraction = 0.0;
|
|
updateProgressBar();
|
|
ui.progressBar->show();
|
|
markChildrenAsDisabled();
|
|
}
|
|
|
|
// got an error
|
|
else if (state == ERRORED) {
|
|
timer->stop();
|
|
|
|
QMessageBox::critical(this, TITLE_OR_TEXT(tr("Error"),
|
|
QString::fromStdString(diveImportedModel->thread.error)), QMessageBox::Ok);
|
|
markChildrenAsEnabled();
|
|
progress_bar_text = "";
|
|
ui.progressBar->hide();
|
|
#if defined(Q_OS_MAC)
|
|
// on mac we show the text in a label
|
|
ui.progressText->setText(progress_bar_text);
|
|
#endif
|
|
}
|
|
|
|
// properly updating the widget state
|
|
currentState = state;
|
|
}
|
|
|
|
void DownloadFromDCWidget::on_vendor_currentTextChanged(const QString &vendor)
|
|
{
|
|
unsigned int transport;
|
|
dc_descriptor_t *descriptor;
|
|
productModel.setStringList(productList[vendor]);
|
|
ui.product->setCurrentIndex(0);
|
|
|
|
descriptor = descriptorLookup.value(ui.vendor->currentText().toLower() + ui.product->currentText().toLower());
|
|
transport = dc_descriptor_get_transports(descriptor);
|
|
fill_device_list(transport);
|
|
ui.search->setEnabled(is_vendor_searchable(vendor));
|
|
}
|
|
|
|
void DownloadFromDCWidget::on_product_currentTextChanged(const QString &)
|
|
{
|
|
updateDeviceEnabled();
|
|
}
|
|
|
|
void DownloadFromDCWidget::on_device_currentTextChanged(const QString &device)
|
|
{
|
|
#if defined(BT_SUPPORT) && defined(Q_OS_MACOS)
|
|
if (isBluetoothAddress(device)) {
|
|
// ensure we have a discovery running
|
|
if (btd == nullptr)
|
|
btd = BTDiscovery::instance();
|
|
btd->discoverAddress(device);
|
|
}
|
|
#else
|
|
Q_UNUSED(device)
|
|
#endif
|
|
}
|
|
|
|
void DownloadFromDCWidget::on_search_clicked()
|
|
{
|
|
if (is_vendor_searchable(ui.vendor->currentText())) {
|
|
QString dialogTitle;
|
|
if (ui.vendor->currentText() == "Uemis")
|
|
dialogTitle = tr("Find Uemis dive computer");
|
|
else if (ui.vendor->currentText() == "Garmin")
|
|
dialogTitle = tr("Find Garmin dive computer");
|
|
else if (ui.vendor->currentText() == "FIT")
|
|
dialogTitle = tr("Select diretory to import .fit files from");
|
|
QString dirName = QFileDialog::getExistingDirectory(this,
|
|
dialogTitle,
|
|
QDir::homePath(),
|
|
QFileDialog::ShowDirsOnly);
|
|
if (ui.device->findText(dirName) == -1)
|
|
ui.device->addItem(dirName);
|
|
ui.device->setEditText(dirName);
|
|
}
|
|
}
|
|
|
|
void DownloadFromDCWidget::on_downloadCancelRetryButton_clicked()
|
|
{
|
|
if (currentState == DOWNLOADING) {
|
|
updateState(CANCELLING);
|
|
return;
|
|
}
|
|
if (currentState == DONE) {
|
|
// this means we are retrying - so we better clean out the partial
|
|
// list of downloaded dives from the last attempt
|
|
diveImportedModel->clearTable();
|
|
}
|
|
updateState(DOWNLOADING);
|
|
|
|
// you cannot cancel the dialog, just the download
|
|
ui.cancel->setEnabled(false);
|
|
ui.downloadCancelRetryButton->setText(tr("Cancel download"));
|
|
|
|
auto data = diveImportedModel->thread.data();
|
|
data->setVendor(ui.vendor->currentText());
|
|
data->setProduct(ui.product->currentText());
|
|
#if defined(BT_SUPPORT)
|
|
data->setBluetoothMode(ui.bluetoothMode->isChecked());
|
|
if (data->bluetoothMode()) {
|
|
// Get the selected device address
|
|
if (btDeviceSelectionDialog != NULL) {
|
|
data->setDevName(btDeviceSelectionDialog->getSelectedDeviceAddress());
|
|
data->setDevBluetoothName(btDeviceSelectionDialog->getSelectedDeviceName());
|
|
} else {
|
|
auto [address, name] = extractBluetoothNameAddress(ui.device->currentText());
|
|
data->setDevName(address);
|
|
data->setDevBluetoothName(name);
|
|
}
|
|
if (btd) {
|
|
// btd should only be active for mac os.
|
|
// Need to ensure that any scan is shut down BEFORE starting the download
|
|
// because internally (as of 5.15.13) the QT discovery agent uses a QTimer
|
|
// that can only be shut off from the same thread it was started from.
|
|
QString devAddr = data->devName().startsWith("LE:")
|
|
? data->devName().right(data->devName().size()-3)
|
|
: data->devName();
|
|
getBtDeviceInfo(devAddr);
|
|
}
|
|
} else
|
|
// this breaks an "else if" across lines... not happy...
|
|
#endif
|
|
if (data->vendor() == "Uemis") {
|
|
char *colon;
|
|
char *devname = copy_qstring(ui.device->currentText());
|
|
|
|
if ((colon = strstr(devname, ":\\ (UEMISSDA)")) != NULL) {
|
|
*(colon + 2) = '\0';
|
|
report_info("shortened devname to \"%s\"", devname);
|
|
}
|
|
data->setDevName(devname);
|
|
} else {
|
|
data->setDevName(ui.device->currentText());
|
|
}
|
|
|
|
data->setForceDownload(ui.forceDownload->isChecked());
|
|
data->setSaveLog(ui.logToFile->isChecked());
|
|
data->setSaveDump(ui.dumpToFile->isChecked());
|
|
data->setSyncTime(ui.syncDiveComputerTime->isChecked());
|
|
|
|
qPrefDiveComputer::set_vendor(data->vendor());
|
|
qPrefDiveComputer::set_product(data->product());
|
|
qPrefDiveComputer::set_device(data->devName());
|
|
|
|
// before we start, remember where the dive_table ended
|
|
previousLast = divelog.dives->nr;
|
|
diveImportedModel->startDownload();
|
|
|
|
// FIXME: We should get the _actual_ device info instead of whatever
|
|
// the user entered in the dropdown.
|
|
// You can enter "OSTC 3" and download just fine from a "OSTC Sport", but
|
|
// this check will compair apples and oranges, firmware wise, then.
|
|
QString product(ui.product->currentText());
|
|
//
|
|
// We shouldn't do this for memory dumps.
|
|
if ((product == "OSTC 3" || product == "OSTC 3+" || product == "OSTC cR" ||
|
|
product == "OSTC Sport" || product == "OSTC 4" || product == "OSTC Plus") &&
|
|
!data->saveDump()) {
|
|
ostcFirmwareCheck.reset(new OstcFirmwareCheck(product));
|
|
}
|
|
}
|
|
|
|
bool DownloadFromDCWidget::preferDownloaded()
|
|
{
|
|
return ui.preferDownloaded->isChecked();
|
|
}
|
|
|
|
void DownloadFromDCWidget::checkLogFile(int state)
|
|
{
|
|
ui.chooseLogFile->setEnabled(state == Qt::Checked);
|
|
// TODO: Verify the Thread.
|
|
if (state == Qt::Checked) {
|
|
pickLogFile();
|
|
}
|
|
}
|
|
|
|
void DownloadFromDCWidget::pickLogFile()
|
|
{
|
|
QFileInfo fi(filename);
|
|
QString logfilename = fi.absolutePath().append(QDir::separator()).append("subsurface.log");
|
|
QString logFile = QFileDialog::getSaveFileName(this, tr("Choose file for dive computer download logfile"),
|
|
logfilename, tr("Log files") + " (*.log)");
|
|
if (!logFile.isEmpty())
|
|
logfile_name = logFile.toStdString();
|
|
}
|
|
|
|
void DownloadFromDCWidget::checkDumpFile(int state)
|
|
{
|
|
ui.chooseDumpFile->setEnabled(state == Qt::Checked);
|
|
if (state == Qt::Checked) {
|
|
pickDumpFile();
|
|
if (!dumpWarningShown) {
|
|
QMessageBox::warning(this, tr("Warning"),
|
|
tr("Saving the libdivecomputer dump will NOT download dives to the dive list."));
|
|
dumpWarningShown = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DownloadFromDCWidget::pickDumpFile()
|
|
{
|
|
QFileInfo fi(filename);
|
|
QString dumpfilename = fi.absolutePath().append(QDir::separator()).append("subsurface.bin");
|
|
QString dumpFile = QFileDialog::getSaveFileName(this, tr("Choose file for dive computer binary dump file"),
|
|
dumpfilename, tr("Dump files") + " (*.bin)");
|
|
if (!dumpFile.isEmpty())
|
|
dumpfile_name = dumpFile.toStdString();
|
|
}
|
|
|
|
void DownloadFromDCWidget::reject()
|
|
{
|
|
// we don't want the download window being able to close
|
|
// while we're still downloading.
|
|
if (currentState != DOWNLOADING && currentState != CANCELLING)
|
|
QDialog::reject();
|
|
}
|
|
|
|
void DownloadFromDCWidget::onDownloadThreadFinished()
|
|
{
|
|
// let's update the remembered DCs
|
|
showRememberedDCs();
|
|
|
|
if (currentState == DOWNLOADING) {
|
|
if (diveImportedModel->thread.error.empty())
|
|
updateState(DONE);
|
|
else
|
|
updateState(ERRORED);
|
|
} else if (currentState == CANCELLING) {
|
|
updateState(DONE);
|
|
}
|
|
ui.downloadCancelRetryButton->setText(tr("Retry download"));
|
|
ui.downloadCancelRetryButton->setEnabled(true);
|
|
}
|
|
|
|
void DownloadFromDCWidget::on_cancel_clicked()
|
|
{
|
|
if (currentState == DOWNLOADING || currentState == CANCELLING)
|
|
return;
|
|
|
|
// now discard all the dives
|
|
diveImportedModel->clearTable();
|
|
done(-1);
|
|
}
|
|
|
|
void DownloadFromDCWidget::on_ok_clicked()
|
|
{
|
|
if (currentState != DONE && currentState != ERRORED)
|
|
return;
|
|
|
|
int flags = IMPORT_IS_DOWNLOADED;
|
|
if (preferDownloaded())
|
|
flags |= IMPORT_PREFER_IMPORTED;
|
|
if (ui.createNewTrip->isChecked())
|
|
flags |= IMPORT_ADD_TO_NEW_TRIP;
|
|
|
|
diveImportedModel->recordDives(flags);
|
|
|
|
if (ostcFirmwareCheck && currentState == DONE)
|
|
ostcFirmwareCheck->checkLatest(this, diveImportedModel->thread.data()->internalData(), filename);
|
|
accept();
|
|
}
|
|
|
|
void DownloadFromDCWidget::updateDeviceEnabled()
|
|
{
|
|
// Set up the DC descriptor
|
|
dc_descriptor_t *descriptor = NULL;
|
|
descriptor = descriptorLookup.value(ui.vendor->currentText().toLower() + ui.product->currentText().toLower());
|
|
|
|
// call dc_descriptor_get_transport to see if the dc_transport_t is DC_TRANSPORT_SERIAL
|
|
if (dc_descriptor_get_transports(descriptor) & (DC_TRANSPORT_SERIAL | DC_TRANSPORT_USBSTORAGE)) {
|
|
// if the dc_transport_t is DC_TRANSPORT_SERIAL, then enable the device node box.
|
|
ui.device->setEnabled(true);
|
|
} else {
|
|
// otherwise disable the device node box
|
|
ui.device->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
void DownloadFromDCWidget::markChildrenAsDisabled()
|
|
{
|
|
ui.device->setEnabled(false);
|
|
ui.vendor->setEnabled(false);
|
|
ui.product->setEnabled(false);
|
|
ui.forceDownload->setEnabled(false);
|
|
ui.createNewTrip->setEnabled(false);
|
|
ui.preferDownloaded->setEnabled(false);
|
|
ui.ok->setEnabled(false);
|
|
ui.search->setEnabled(false);
|
|
ui.logToFile->setEnabled(false);
|
|
ui.dumpToFile->setEnabled(false);
|
|
ui.chooseLogFile->setEnabled(false);
|
|
ui.chooseDumpFile->setEnabled(false);
|
|
ui.selectAllButton->setEnabled(false);
|
|
ui.unselectAllButton->setEnabled(false);
|
|
ui.bluetoothMode->setEnabled(false);
|
|
ui.chooseBluetoothDevice->setEnabled(false);
|
|
ui.syncDiveComputerTime->setEnabled(false);
|
|
}
|
|
|
|
void DownloadFromDCWidget::markChildrenAsEnabled()
|
|
{
|
|
updateDeviceEnabled();
|
|
ui.vendor->setEnabled(true);
|
|
ui.product->setEnabled(true);
|
|
ui.forceDownload->setEnabled(true);
|
|
ui.createNewTrip->setEnabled(true);
|
|
ui.preferDownloaded->setEnabled(true);
|
|
ui.ok->setEnabled(true);
|
|
ui.cancel->setEnabled(true);
|
|
ui.search->setEnabled(true);
|
|
ui.logToFile->setEnabled(true);
|
|
ui.dumpToFile->setEnabled(true);
|
|
ui.chooseLogFile->setEnabled(true);
|
|
ui.chooseDumpFile->setEnabled(true);
|
|
ui.selectAllButton->setEnabled(true);
|
|
ui.unselectAllButton->setEnabled(true);
|
|
#if defined(BT_SUPPORT)
|
|
ui.bluetoothMode->setEnabled(true);
|
|
ui.chooseBluetoothDevice->setEnabled(true);
|
|
#endif
|
|
ui.syncDiveComputerTime->setEnabled(true);
|
|
}
|
|
|
|
#if defined(BT_SUPPORT)
|
|
void DownloadFromDCWidget::selectRemoteBluetoothDevice()
|
|
{
|
|
if (!btDeviceSelectionDialog) {
|
|
btDeviceSelectionDialog = new BtDeviceSelectionDialog(this);
|
|
connect(btDeviceSelectionDialog, SIGNAL(finished(int)),
|
|
this, SLOT(bluetoothSelectionDialogIsFinished(int)));
|
|
}
|
|
|
|
btDeviceSelectionDialog->show();
|
|
}
|
|
|
|
void DownloadFromDCWidget::bluetoothSelectionDialogIsFinished(int result)
|
|
{
|
|
if (result == QDialog::Accepted) {
|
|
/* Make the selected Bluetooth device default */
|
|
ui.device->setEditText(btDeviceSelectionDialog->getSelectedDeviceText());
|
|
} else if (result == QDialog::Rejected) {
|
|
/* Disable Bluetooth download mode */
|
|
ui.bluetoothMode->setChecked(false);
|
|
}
|
|
}
|
|
|
|
void DownloadFromDCWidget::enableBluetoothMode(int state)
|
|
{
|
|
ui.chooseBluetoothDevice->setEnabled(state == Qt::Checked);
|
|
|
|
/* This is convoluted enough to warrant explanation:
|
|
1. If Bluetooth is enabled, but no Bluetooth address then scan.
|
|
2. If Bluetooth is enabled and we have a Bluetooth address, skip scan.
|
|
3. If Bluetooth is not enabled, but it's a Bluetooth address, clear it. */
|
|
if (state == Qt::Checked) {
|
|
if (!isBluetoothAddress(ui.device->currentText()))
|
|
selectRemoteBluetoothDevice();
|
|
} else
|
|
if (isBluetoothAddress(ui.device->currentText()))
|
|
ui.device->setCurrentIndex(-1);
|
|
}
|
|
#endif
|
|
|
|
static void fillDeviceList(const char *name, void *data)
|
|
{
|
|
QComboBox *comboBox = (QComboBox *)data;
|
|
comboBox->addItem(name);
|
|
}
|
|
|
|
void DownloadFromDCWidget::fill_device_list(unsigned int transport)
|
|
{
|
|
int deviceIndex;
|
|
ui.device->clear();
|
|
deviceIndex = enumerate_devices(fillDeviceList, ui.device, transport);
|
|
if (deviceIndex >= 0)
|
|
ui.device->setCurrentIndex(deviceIndex);
|
|
}
|