2017-04-27 18:26:05 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "desktop-widgets/downloadfromdivecomputer.h"
|
2019-11-13 14:08:40 +00:00
|
|
|
#include "commands/command.h"
|
2018-07-26 01:40:19 +00:00
|
|
|
#include "core/qthelper.h"
|
2019-07-15 21:44:39 +00:00
|
|
|
#include "core/divelist.h"
|
2018-08-15 09:56:17 +00:00
|
|
|
#include "core/settings/qPrefDiveComputer.h"
|
2022-08-30 16:13:13 +00:00
|
|
|
#include "core/subsurface-float.h"
|
2018-05-11 15:25:41 +00:00
|
|
|
#include "core/subsurface-string.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "core/uemis.h"
|
2019-09-25 18:49:13 +00:00
|
|
|
#include "core/downloadfromdcthread.h"
|
2018-07-26 01:40:19 +00:00
|
|
|
#include "desktop-widgets/divelistview.h"
|
|
|
|
#include "desktop-widgets/mainwindow.h"
|
2017-04-18 15:32:10 +00:00
|
|
|
#include "qt-models/diveimportedmodel.h"
|
2018-07-26 01:40:19 +00:00
|
|
|
#include "qt-models/models.h"
|
2015-02-09 21:51:31 +00:00
|
|
|
|
2013-12-25 00:26:00 +00:00
|
|
|
#include <QFileDialog>
|
2013-09-01 14:14:54 +00:00
|
|
|
#include <QMessageBox>
|
2014-04-25 17:44:23 +00:00
|
|
|
#include <QShortcut>
|
2018-07-26 01:40:19 +00:00
|
|
|
#include <QTimer>
|
2018-07-21 19:29:49 +00:00
|
|
|
#include <QUndoStack>
|
2013-05-20 20:58:06 +00:00
|
|
|
|
2020-10-25 21:27:39 +00:00
|
|
|
DownloadFromDCWidget::DownloadFromDCWidget(QWidget *parent) : QDialog(parent, QFlag(0)),
|
2014-02-09 18:38:26 +00:00
|
|
|
downloading(false),
|
|
|
|
previousLast(0),
|
|
|
|
timer(new QTimer(this)),
|
|
|
|
dumpWarningShown(false),
|
2018-09-25 00:31:33 +00:00
|
|
|
#if defined (BT_SUPPORT)
|
|
|
|
btd(nullptr),
|
|
|
|
#endif
|
2014-12-29 23:25:54 +00:00
|
|
|
currentState(INITIAL)
|
2013-05-20 19:43:33 +00:00
|
|
|
{
|
2017-04-18 17:14:03 +00:00
|
|
|
diveImportedModel = new DiveImportedModel(this);
|
2017-11-11 18:40:47 +00:00
|
|
|
vendorModel.setStringList(vendorList);
|
2022-02-08 19:24:53 +00:00
|
|
|
QShortcut *close = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), this);
|
|
|
|
QShortcut *quit = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this);
|
2017-04-18 17:14:03 +00:00
|
|
|
|
|
|
|
int startingWidth = defaultModelFont().pointSize();
|
|
|
|
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.setupUi(this);
|
|
|
|
ui.progressBar->hide();
|
|
|
|
ui.progressBar->setMinimum(0);
|
|
|
|
ui.progressBar->setMaximum(100);
|
2015-01-08 13:29:28 +00:00
|
|
|
ui.downloadedView->setModel(diveImportedModel);
|
2015-01-08 19:19:01 +00:00
|
|
|
ui.downloadedView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
|
|
ui.downloadedView->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
|
|
ui.downloadedView->setColumnWidth(0, startingWidth * 20);
|
2015-01-13 08:20:32 +00:00
|
|
|
ui.downloadedView->setColumnWidth(1, startingWidth * 10);
|
2015-01-08 19:19:01 +00:00
|
|
|
ui.downloadedView->setColumnWidth(2, startingWidth * 10);
|
2017-04-18 17:14:03 +00:00
|
|
|
ui.chooseDumpFile->setEnabled(ui.dumpToFile->isChecked());
|
|
|
|
ui.chooseLogFile->setEnabled(ui.logToFile->isChecked());
|
|
|
|
ui.selectAllButton->setEnabled(false);
|
|
|
|
ui.unselectAllButton->setEnabled(false);
|
2017-11-11 18:40:47 +00:00
|
|
|
ui.vendor->setModel(&vendorModel);
|
|
|
|
ui.product->setModel(&productModel);
|
2013-09-16 21:04:42 +00:00
|
|
|
|
2014-02-26 16:37:13 +00:00
|
|
|
progress_bar_text = "";
|
|
|
|
|
2017-04-18 17:14:03 +00:00
|
|
|
timer->setInterval(200);
|
2013-05-20 20:58:06 +00:00
|
|
|
|
2017-04-18 17:14:03 +00:00
|
|
|
connect(ui.downloadedView, SIGNAL(clicked(QModelIndex)), diveImportedModel, SLOT(changeSelected(QModelIndex)));
|
2013-12-25 00:26:00 +00:00
|
|
|
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)));
|
2015-01-08 20:54:53 +00:00
|
|
|
connect(ui.selectAllButton, SIGNAL(clicked()), diveImportedModel, SLOT(selectAll()));
|
|
|
|
connect(ui.unselectAllButton, SIGNAL(clicked()), diveImportedModel, SLOT(selectNone()));
|
2017-04-18 17:14:03 +00:00
|
|
|
connect(timer, SIGNAL(timeout()), this, SLOT(updateProgressBar()));
|
|
|
|
connect(close, SIGNAL(activated()), this, SLOT(close()));
|
|
|
|
connect(quit, SIGNAL(activated()), parent, SLOT(close()));
|
2016-08-10 21:10:15 +00:00
|
|
|
|
2019-09-25 18:49:13 +00:00
|
|
|
connect(diveImportedModel, &DiveImportedModel::downloadFinished, this, &DownloadFromDCWidget::onDownloadThreadFinished);
|
2017-10-16 11:29:21 +00:00
|
|
|
|
2018-08-15 09:56:17 +00:00
|
|
|
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()));
|
2013-05-23 06:24:33 +00:00
|
|
|
}
|
2013-08-25 22:02:30 +00:00
|
|
|
|
2018-09-20 21:19:03 +00:00
|
|
|
// now lets set the four shortcuts for previously used dive computers
|
2018-09-21 22:41:28 +00:00
|
|
|
showRememberedDCs();
|
2018-09-20 21:19:03 +00:00
|
|
|
|
2013-08-25 22:02:30 +00:00
|
|
|
updateState(INITIAL);
|
2015-01-08 17:39:47 +00:00
|
|
|
ui.ok->setEnabled(false);
|
2015-01-09 23:01:48 +00:00
|
|
|
ui.downloadCancelRetryButton->setEnabled(true);
|
|
|
|
ui.downloadCancelRetryButton->setText(tr("Download"));
|
2015-07-06 13:35:13 +00:00
|
|
|
|
2018-08-15 09:56:17 +00:00
|
|
|
QString deviceText = qPrefDiveComputer::device();
|
2018-04-17 01:14:59 +00:00
|
|
|
#if defined(BT_SUPPORT)
|
2015-09-04 22:25:35 +00:00
|
|
|
ui.bluetoothMode->setText(tr("Choose Bluetooth download mode"));
|
2018-10-15 11:40:26 +00:00
|
|
|
ui.bluetoothMode->setChecked(isBluetoothAddress(qPrefDiveComputer::device()));
|
2015-07-06 13:35:13 +00:00
|
|
|
btDeviceSelectionDialog = 0;
|
2017-05-28 10:29:26 +00:00
|
|
|
connect(ui.bluetoothMode, SIGNAL(stateChanged(int)), this, SLOT(enableBluetoothMode(int)));
|
|
|
|
connect(ui.chooseBluetoothDevice, SIGNAL(clicked()), this, SLOT(selectRemoteBluetoothDevice()));
|
2015-07-06 13:18:06 +00:00
|
|
|
ui.chooseBluetoothDevice->setEnabled(ui.bluetoothMode->isChecked());
|
2017-11-12 11:33:20 +00:00
|
|
|
if (ui.bluetoothMode->isChecked())
|
2018-08-15 09:56:17 +00:00
|
|
|
deviceText = BtDeviceSelectionDialog::formatDeviceText(qPrefDiveComputer::device(), qPrefDiveComputer::device_name());
|
2015-07-20 16:35:00 +00:00
|
|
|
#else
|
|
|
|
ui.bluetoothMode->hide();
|
|
|
|
ui.chooseBluetoothDevice->hide();
|
|
|
|
#endif
|
2017-11-12 11:33:20 +00:00
|
|
|
if (!deviceText.isEmpty())
|
|
|
|
ui.device->setEditText(deviceText);
|
2013-05-20 20:58:06 +00:00
|
|
|
}
|
|
|
|
|
2018-09-21 22:41:28 +00:00
|
|
|
#define SETUPDC(num) \
|
|
|
|
if (!qPrefDiveComputer::vendor##num().isEmpty()) { \
|
|
|
|
ui.DC##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); \
|
|
|
|
} else { \
|
|
|
|
ui.DC##num->setVisible(false); \
|
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadFromDCWidget::showRememberedDCs()
|
|
|
|
{
|
|
|
|
SETUPDC(1)
|
|
|
|
SETUPDC(2)
|
|
|
|
SETUPDC(3)
|
|
|
|
SETUPDC(4)
|
|
|
|
}
|
|
|
|
|
2018-09-24 14:04:21 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-09-21 19:16:42 +00:00
|
|
|
// DC button slots
|
2019-07-04 04:49:37 +00:00
|
|
|
// 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.bluetoothMode->setChecked(isBluetoothAddress(qPrefDiveComputer::device##num())); \
|
|
|
|
if (ui.device->currentIndex() == -1) \
|
|
|
|
ui.device->setCurrentIndex(deviceIndex(qPrefDiveComputer::device##num())); \
|
|
|
|
if (QSysInfo::kernelType() == "darwin") { \
|
|
|
|
/* it makes no sense that this would be needed on macOS but not Linux */ \
|
|
|
|
QCoreApplication::processEvents(); \
|
|
|
|
ui.vendor->update(); \
|
|
|
|
ui.product->update(); \
|
|
|
|
ui.device->update(); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
#else
|
2018-09-21 19:16:42 +00:00
|
|
|
#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())); \
|
2018-09-24 14:04:21 +00:00
|
|
|
ui.device->setCurrentIndex(deviceIndex(qPrefDiveComputer::device##num())); \
|
2018-09-21 19:16:42 +00:00
|
|
|
if (QSysInfo::kernelType() == "darwin") { \
|
|
|
|
/* it makes no sense that this would be needed on macOS but not Linux */ \
|
|
|
|
QCoreApplication::processEvents(); \
|
|
|
|
ui.vendor->update(); \
|
|
|
|
ui.product->update(); \
|
|
|
|
ui.device->update(); \
|
|
|
|
} \
|
|
|
|
}
|
2019-07-04 04:49:37 +00:00
|
|
|
#endif
|
|
|
|
|
2018-09-21 19:16:42 +00:00
|
|
|
DCBUTTON(1)
|
|
|
|
DCBUTTON(2)
|
|
|
|
DCBUTTON(3)
|
|
|
|
DCBUTTON(4)
|
|
|
|
|
2013-08-25 22:02:30 +00:00
|
|
|
void DownloadFromDCWidget::updateProgressBar()
|
2013-05-30 09:21:08 +00:00
|
|
|
{
|
2017-04-22 20:49:03 +00:00
|
|
|
static char *last_text = NULL;
|
|
|
|
|
2018-01-07 10:12:48 +00:00
|
|
|
if (empty_string(last_text)) {
|
2017-04-22 20:49:03 +00:00
|
|
|
// if we get the first actual text after the download is finished
|
|
|
|
// (which happens for example on the OSTC), then don't bother
|
2022-08-30 15:55:43 +00:00
|
|
|
if (!empty_string(progress_bar_text) && nearly_equal(progress_bar_fraction, 1.0))
|
2017-07-28 19:32:47 +00:00
|
|
|
progress_bar_text = "";
|
2017-04-22 20:49:03 +00:00
|
|
|
}
|
2018-01-07 10:12:48 +00:00
|
|
|
if (!empty_string(progress_bar_text)) {
|
2018-09-26 03:34:25 +00:00
|
|
|
// once the progress bar text is set, setup the maximum so the user sees actual progress
|
2014-01-27 20:47:40 +00:00
|
|
|
ui.progressBar->setFormat(progress_bar_text);
|
2018-09-26 03:34:25 +00:00
|
|
|
ui.progressBar->setMaximum(100);
|
2017-09-17 22:04:14 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
// on mac the progress bar doesn't show its text
|
|
|
|
ui.progressText->setText(progress_bar_text);
|
|
|
|
#endif
|
2014-01-27 20:47:40 +00:00
|
|
|
} else {
|
2022-08-30 15:47:31 +00:00
|
|
|
if (nearly_0(progress_bar_fraction)) {
|
2018-09-26 03:34:25 +00:00
|
|
|
// while we are waiting to connect, set the maximum to 0 so we get a busy indication
|
|
|
|
ui.progressBar->setMaximum(0);
|
2017-09-17 22:02:11 +00:00
|
|
|
ui.progressBar->setFormat(tr("Connecting to dive computer"));
|
2017-09-17 22:04:14 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
2018-07-26 01:40:19 +00:00
|
|
|
// on mac the progress bar doesn't show its text
|
|
|
|
ui.progressText->setText(tr("Connecting to dive computer"));
|
2017-09-17 22:04:14 +00:00
|
|
|
#endif
|
|
|
|
} else {
|
2018-09-26 03:34:25 +00:00
|
|
|
// we have some progress - reset the maximum so the user sees actual progress
|
|
|
|
ui.progressBar->setMaximum(100);
|
2017-09-17 22:02:11 +00:00
|
|
|
ui.progressBar->setFormat("%p%");
|
2017-09-17 22:04:14 +00:00
|
|
|
#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
|
|
|
|
}
|
2014-01-27 20:47:40 +00:00
|
|
|
}
|
2017-03-23 01:13:49 +00:00
|
|
|
ui.progressBar->setValue(lrint(progress_bar_fraction * 100));
|
2017-04-22 20:49:03 +00:00
|
|
|
free(last_text);
|
|
|
|
last_text = strdup(progress_bar_text);
|
2013-08-25 22:02:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadFromDCWidget::updateState(states state)
|
|
|
|
{
|
|
|
|
if (state == currentState)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (state == INITIAL) {
|
2018-08-27 17:32:14 +00:00
|
|
|
fill_device_list(~0);
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.progressBar->hide();
|
2013-08-25 22:02:30 +00:00
|
|
|
markChildrenAsEnabled();
|
|
|
|
timer->stop();
|
2017-04-22 20:49:03 +00:00
|
|
|
progress_bar_text = "";
|
2017-09-17 22:04:14 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
// on mac we show the text in a label
|
|
|
|
ui.progressText->setText(progress_bar_text);
|
|
|
|
#endif
|
2013-08-25 22:02:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// tries to cancel an on going download
|
|
|
|
else if (currentState == DOWNLOADING && state == CANCELLING) {
|
|
|
|
import_thread_cancelled = true;
|
2015-01-09 23:01:48 +00:00
|
|
|
ui.downloadCancelRetryButton->setEnabled(false);
|
2013-08-25 22:02:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// user pressed cancel but the application isn't doing anything.
|
|
|
|
// means close the window
|
2019-08-28 09:21:24 +00:00
|
|
|
else if ((currentState == INITIAL || currentState == DONE || currentState == ERRORED) && state == CANCELLING) {
|
2013-08-25 22:02:30 +00:00
|
|
|
timer->stop();
|
|
|
|
reject();
|
|
|
|
}
|
|
|
|
|
2013-09-01 14:14:54 +00:00
|
|
|
// the cancelation process is finished
|
2015-01-09 23:01:48 +00:00
|
|
|
else if (currentState == CANCELLING && state == DONE) {
|
2013-08-25 22:02:30 +00:00
|
|
|
timer->stop();
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.progressBar->setValue(0);
|
|
|
|
ui.progressBar->hide();
|
2013-08-25 22:02:30 +00:00
|
|
|
markChildrenAsEnabled();
|
2017-04-22 20:49:03 +00:00
|
|
|
progress_bar_text = "";
|
2017-09-17 22:04:14 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
// on mac we show the text in a label
|
|
|
|
ui.progressText->setText(progress_bar_text);
|
|
|
|
#endif
|
2013-08-25 22:02:30 +00:00
|
|
|
}
|
|
|
|
|
2014-01-27 20:47:40 +00:00
|
|
|
// DOWNLOAD is finally done, but we don't know if there was an error as libdivecomputer doesn't pass
|
2015-01-08 17:29:57 +00:00
|
|
|
// that information on to us.
|
|
|
|
// If we find an error, offer to retry, otherwise continue the interaction to pick the dives the user wants
|
2013-08-25 22:02:30 +00:00
|
|
|
else if (currentState == DOWNLOADING && state == DONE) {
|
|
|
|
timer->stop();
|
2014-01-27 20:47:40 +00:00
|
|
|
if (QString(progress_bar_text).contains("error", Qt::CaseInsensitive)) {
|
|
|
|
updateProgressBar();
|
|
|
|
markChildrenAsEnabled();
|
|
|
|
progress_bar_text = "";
|
|
|
|
} else {
|
2019-09-22 19:00:15 +00:00
|
|
|
if (diveImportedModel->numDives() != 0)
|
2017-09-17 21:49:37 +00:00
|
|
|
progress_bar_text = "";
|
2014-01-27 20:47:40 +00:00
|
|
|
ui.progressBar->setValue(100);
|
|
|
|
markChildrenAsEnabled();
|
|
|
|
}
|
2017-09-17 22:04:14 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
// on mac we show the text in a label
|
|
|
|
ui.progressText->setText(progress_bar_text);
|
|
|
|
#endif
|
2013-08-25 22:02:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DOWNLOAD is started.
|
|
|
|
else if (state == DOWNLOADING) {
|
|
|
|
timer->start();
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.progressBar->setValue(0);
|
2017-04-22 20:55:43 +00:00
|
|
|
progress_bar_fraction = 0.0;
|
2014-01-27 20:47:40 +00:00
|
|
|
updateProgressBar();
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.progressBar->show();
|
2013-08-25 22:02:30 +00:00
|
|
|
markChildrenAsDisabled();
|
|
|
|
}
|
|
|
|
|
2013-09-01 14:14:54 +00:00
|
|
|
// got an error
|
2019-08-28 09:21:24 +00:00
|
|
|
else if (state == ERRORED) {
|
2017-04-22 20:46:27 +00:00
|
|
|
timer->stop();
|
2017-10-31 20:28:59 +00:00
|
|
|
|
2019-09-25 18:49:13 +00:00
|
|
|
QMessageBox::critical(this, TITLE_OR_TEXT(tr("Error"), diveImportedModel->thread.error), QMessageBox::Ok);
|
2013-09-01 14:14:54 +00:00
|
|
|
markChildrenAsEnabled();
|
2017-04-22 20:49:03 +00:00
|
|
|
progress_bar_text = "";
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.progressBar->hide();
|
2017-09-17 22:04:14 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
// on mac we show the text in a label
|
|
|
|
ui.progressText->setText(progress_bar_text);
|
|
|
|
#endif
|
2013-09-01 14:14:54 +00:00
|
|
|
}
|
|
|
|
|
2013-08-25 22:02:30 +00:00
|
|
|
// properly updating the widget state
|
|
|
|
currentState = state;
|
2013-05-30 09:21:08 +00:00
|
|
|
}
|
|
|
|
|
2022-02-10 01:25:00 +00:00
|
|
|
void DownloadFromDCWidget::on_vendor_currentTextChanged(const QString &vendor)
|
2013-05-20 20:58:06 +00:00
|
|
|
{
|
2018-08-27 17:32:14 +00:00
|
|
|
unsigned int transport;
|
|
|
|
dc_descriptor_t *descriptor;
|
2017-11-11 18:40:47 +00:00
|
|
|
productModel.setStringList(productList[vendor]);
|
|
|
|
ui.product->setCurrentIndex(0);
|
2013-05-20 20:58:06 +00:00
|
|
|
|
2020-05-14 19:15:24 +00:00
|
|
|
descriptor = descriptorLookup.value(ui.vendor->currentText().toLower() + ui.product->currentText().toLower());
|
2018-08-27 17:32:14 +00:00
|
|
|
transport = dc_descriptor_get_transports(descriptor);
|
|
|
|
fill_device_list(transport);
|
2013-05-20 20:58:06 +00:00
|
|
|
}
|
|
|
|
|
2022-02-10 01:25:00 +00:00
|
|
|
void DownloadFromDCWidget::on_product_currentTextChanged(const QString &)
|
2013-12-27 10:50:13 +00:00
|
|
|
{
|
2017-11-01 07:01:23 +00:00
|
|
|
updateDeviceEnabled();
|
2013-12-27 10:50:13 +00:00
|
|
|
}
|
|
|
|
|
2018-09-25 00:31:33 +00:00
|
|
|
void DownloadFromDCWidget::on_device_currentTextChanged(const QString &device)
|
|
|
|
{
|
|
|
|
#if defined(Q_OS_MACOS)
|
|
|
|
if (isBluetoothAddress(device)) {
|
|
|
|
// ensure we have a discovery running
|
|
|
|
if (btd == nullptr)
|
|
|
|
btd = BTDiscovery::instance();
|
2018-09-26 03:04:02 +00:00
|
|
|
btd->discoverAddress(device);
|
2018-09-25 00:31:33 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
Q_UNUSED(device)
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-02-19 01:20:35 +00:00
|
|
|
void DownloadFromDCWidget::on_search_clicked()
|
|
|
|
{
|
2018-09-02 00:46:19 +00:00
|
|
|
if (ui.vendor->currentText() == "Uemis" || ui.vendor->currentText() == "Garmin") {
|
|
|
|
QString dialogTitle = ui.vendor->currentText() == "Uemis" ?
|
|
|
|
tr("Find Uemis dive computer") : tr("Find Garmin dive computer");
|
2014-02-19 01:20:35 +00:00
|
|
|
QString dirName = QFileDialog::getExistingDirectory(this,
|
2018-09-02 00:46:19 +00:00
|
|
|
dialogTitle,
|
2014-02-28 04:09:57 +00:00
|
|
|
QDir::homePath(),
|
|
|
|
QFileDialog::ShowDirsOnly);
|
2014-02-19 01:20:35 +00:00
|
|
|
if (ui.device->findText(dirName) == -1)
|
|
|
|
ui.device->addItem(dirName);
|
|
|
|
ui.device->setEditText(dirName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-09 23:01:48 +00:00
|
|
|
void DownloadFromDCWidget::on_downloadCancelRetryButton_clicked()
|
2013-05-20 19:43:33 +00:00
|
|
|
{
|
2015-01-09 23:01:48 +00:00
|
|
|
if (currentState == DOWNLOADING) {
|
|
|
|
updateState(CANCELLING);
|
|
|
|
return;
|
|
|
|
}
|
2015-01-11 15:46:21 +00:00
|
|
|
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();
|
|
|
|
}
|
2013-08-25 22:02:30 +00:00
|
|
|
updateState(DOWNLOADING);
|
2013-05-20 19:43:33 +00:00
|
|
|
|
2015-01-09 23:01:48 +00:00
|
|
|
// you cannot cancel the dialog, just the download
|
|
|
|
ui.cancel->setEnabled(false);
|
2017-04-23 07:51:44 +00:00
|
|
|
ui.downloadCancelRetryButton->setText(tr("Cancel download"));
|
2015-01-09 23:01:48 +00:00
|
|
|
|
2019-09-25 18:49:13 +00:00
|
|
|
auto data = diveImportedModel->thread.data();
|
2017-05-26 14:40:50 +00:00
|
|
|
data->setVendor(ui.vendor->currentText());
|
|
|
|
data->setProduct(ui.product->currentText());
|
2015-07-20 16:35:00 +00:00
|
|
|
#if defined(BT_SUPPORT)
|
2017-05-26 14:40:50 +00:00
|
|
|
data->setBluetoothMode(ui.bluetoothMode->isChecked());
|
2017-12-31 10:44:29 +00:00
|
|
|
if (data->bluetoothMode()) {
|
2018-10-15 10:53:00 +00:00
|
|
|
// Get the selected device address
|
2017-12-31 10:44:29 +00:00
|
|
|
if (btDeviceSelectionDialog != NULL) {
|
|
|
|
data->setDevName(btDeviceSelectionDialog->getSelectedDeviceAddress());
|
|
|
|
data->setDevBluetoothName(btDeviceSelectionDialog->getSelectedDeviceName());
|
|
|
|
} else {
|
2018-09-27 14:08:57 +00:00
|
|
|
QString name, address;
|
|
|
|
address = extractBluetoothNameAddress(ui.device->currentText(), name);
|
|
|
|
data->setDevName(address);
|
|
|
|
data->setDevBluetoothName(name);
|
2017-12-31 10:44:29 +00:00
|
|
|
}
|
2015-07-20 16:35:00 +00:00
|
|
|
} else
|
|
|
|
// this breaks an "else if" across lines... not happy...
|
|
|
|
#endif
|
2017-05-26 14:40:50 +00:00
|
|
|
if (data->vendor() == "Uemis") {
|
2015-04-30 23:35:46 +00:00
|
|
|
char *colon;
|
2018-02-28 22:37:09 +00:00
|
|
|
char *devname = copy_qstring(ui.device->currentText());
|
2013-08-25 13:01:59 +00:00
|
|
|
|
2015-04-30 23:35:46 +00:00
|
|
|
if ((colon = strstr(devname, ":\\ (UEMISSDA)")) != NULL) {
|
|
|
|
*(colon + 2) = '\0';
|
2017-05-19 09:23:11 +00:00
|
|
|
fprintf(stderr, "shortened devname to \"%s\"", devname);
|
2015-04-30 23:35:46 +00:00
|
|
|
}
|
2017-05-26 14:40:50 +00:00
|
|
|
data->setDevName(devname);
|
2015-04-30 23:35:46 +00:00
|
|
|
} else {
|
2017-05-26 14:40:50 +00:00
|
|
|
data->setDevName(ui.device->currentText());
|
2015-04-30 23:35:46 +00:00
|
|
|
}
|
2017-05-26 14:40:50 +00:00
|
|
|
|
|
|
|
data->setForceDownload(ui.forceDownload->isChecked());
|
2017-06-15 09:24:48 +00:00
|
|
|
data->setSaveLog(ui.logToFile->isChecked());
|
|
|
|
data->setSaveDump(ui.dumpToFile->isChecked());
|
2016-08-10 21:10:15 +00:00
|
|
|
|
2018-08-15 09:56:17 +00:00
|
|
|
qPrefDiveComputer::set_vendor(data->vendor());
|
|
|
|
qPrefDiveComputer::set_product(data->product());
|
|
|
|
qPrefDiveComputer::set_device(data->devName());
|
2017-05-19 09:23:11 +00:00
|
|
|
|
2013-12-08 05:33:46 +00:00
|
|
|
// before we start, remember where the dive_table ended
|
|
|
|
previousLast = dive_table.nr;
|
2019-09-25 18:49:13 +00:00
|
|
|
diveImportedModel->startDownload();
|
2014-12-27 16:31:51 +00:00
|
|
|
|
2017-01-08 13:04:11 +00:00
|
|
|
// 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.
|
2014-12-28 15:37:11 +00:00
|
|
|
QString product(ui.product->currentText());
|
2017-04-24 16:29:33 +00:00
|
|
|
//
|
|
|
|
// We shouldn't do this for memory dumps.
|
2018-03-03 14:04:49 +00:00
|
|
|
if ((product == "OSTC 3" || product == "OSTC 3+" || product == "OSTC cR" ||
|
2018-08-27 19:09:40 +00:00
|
|
|
product == "OSTC Sport" || product == "OSTC 4" || product == "OSTC Plus") &&
|
2018-07-26 01:40:19 +00:00
|
|
|
!data->saveDump()) {
|
2019-03-18 14:58:07 +00:00
|
|
|
ostcFirmwareCheck.reset(new OstcFirmwareCheck(product));
|
2018-03-03 14:04:49 +00:00
|
|
|
}
|
2013-05-20 19:43:33 +00:00
|
|
|
}
|
|
|
|
|
2013-05-30 08:58:59 +00:00
|
|
|
bool DownloadFromDCWidget::preferDownloaded()
|
|
|
|
{
|
2013-10-03 18:54:25 +00:00
|
|
|
return ui.preferDownloaded->isChecked();
|
2013-05-30 08:58:59 +00:00
|
|
|
}
|
|
|
|
|
2013-12-25 00:26:00 +00:00
|
|
|
void DownloadFromDCWidget::checkLogFile(int state)
|
|
|
|
{
|
|
|
|
ui.chooseLogFile->setEnabled(state == Qt::Checked);
|
2017-05-19 09:23:11 +00:00
|
|
|
// TODO: Verify the Thread.
|
2017-05-19 09:29:03 +00:00
|
|
|
if (state == Qt::Checked) {
|
2013-12-25 00:26:00 +00:00
|
|
|
pickLogFile();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadFromDCWidget::pickLogFile()
|
|
|
|
{
|
2014-02-28 04:09:57 +00:00
|
|
|
QString filename = existing_filename ?: prefs.default_filename;
|
2013-12-25 00:26:00 +00:00
|
|
|
QFileInfo fi(filename);
|
|
|
|
filename = fi.absolutePath().append(QDir::separator()).append("subsurface.log");
|
2017-05-19 09:29:03 +00:00
|
|
|
QString logFile = QFileDialog::getSaveFileName(this, tr("Choose file for dive computer download logfile"),
|
2018-07-26 01:40:19 +00:00
|
|
|
filename, tr("Log files") + " (*.log)");
|
2014-01-07 14:41:21 +00:00
|
|
|
if (!logFile.isEmpty()) {
|
2014-05-12 17:58:15 +00:00
|
|
|
free(logfile_name);
|
2018-02-28 22:37:09 +00:00
|
|
|
logfile_name = copy_qstring(logFile);
|
2014-01-07 14:41:21 +00:00
|
|
|
}
|
2013-12-25 00:26:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadFromDCWidget::checkDumpFile(int state)
|
|
|
|
{
|
|
|
|
ui.chooseDumpFile->setEnabled(state == Qt::Checked);
|
2013-12-26 17:18:57 +00:00
|
|
|
if (state == Qt::Checked) {
|
2017-05-19 09:29:03 +00:00
|
|
|
pickDumpFile();
|
2013-12-26 17:18:57 +00:00
|
|
|
if (!dumpWarningShown) {
|
|
|
|
QMessageBox::warning(this, tr("Warning"),
|
|
|
|
tr("Saving the libdivecomputer dump will NOT download dives to the dive list."));
|
|
|
|
dumpWarningShown = true;
|
|
|
|
}
|
2013-12-25 00:26:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadFromDCWidget::pickDumpFile()
|
|
|
|
{
|
2014-02-28 04:09:57 +00:00
|
|
|
QString filename = existing_filename ?: prefs.default_filename;
|
2013-12-25 00:26:00 +00:00
|
|
|
QFileInfo fi(filename);
|
|
|
|
filename = fi.absolutePath().append(QDir::separator()).append("subsurface.bin");
|
2017-05-19 09:29:03 +00:00
|
|
|
QString dumpFile = QFileDialog::getSaveFileName(this, tr("Choose file for dive computer binary dump file"),
|
2018-07-26 01:40:19 +00:00
|
|
|
filename, tr("Dump files") + " (*.bin)");
|
2014-01-07 14:41:21 +00:00
|
|
|
if (!dumpFile.isEmpty()) {
|
2014-05-12 17:58:15 +00:00
|
|
|
free(dumpfile_name);
|
2018-02-28 22:37:09 +00:00
|
|
|
dumpfile_name = copy_qstring(dumpFile);
|
2014-01-07 14:41:21 +00:00
|
|
|
}
|
2013-12-25 00:26:00 +00:00
|
|
|
}
|
|
|
|
|
2013-08-25 13:01:59 +00:00
|
|
|
void DownloadFromDCWidget::reject()
|
|
|
|
{
|
|
|
|
// we don't want the download window being able to close
|
|
|
|
// while we're still downloading.
|
2013-08-25 22:02:30 +00:00
|
|
|
if (currentState != DOWNLOADING && currentState != CANCELLING)
|
2013-08-25 13:01:59 +00:00
|
|
|
QDialog::reject();
|
|
|
|
}
|
|
|
|
|
2013-10-15 17:25:53 +00:00
|
|
|
void DownloadFromDCWidget::onDownloadThreadFinished()
|
2013-08-25 22:02:30 +00:00
|
|
|
{
|
2018-09-21 22:41:28 +00:00
|
|
|
// let's update the remembered DCs
|
|
|
|
showRememberedDCs();
|
|
|
|
|
2013-09-01 14:14:54 +00:00
|
|
|
if (currentState == DOWNLOADING) {
|
2019-09-25 18:49:13 +00:00
|
|
|
if (diveImportedModel->thread.error.isEmpty())
|
2013-09-01 14:14:54 +00:00
|
|
|
updateState(DONE);
|
|
|
|
else
|
2019-08-28 09:21:24 +00:00
|
|
|
updateState(ERRORED);
|
2015-01-09 22:44:38 +00:00
|
|
|
} else if (currentState == CANCELLING) {
|
|
|
|
updateState(DONE);
|
|
|
|
}
|
2017-04-23 07:51:44 +00:00
|
|
|
ui.downloadCancelRetryButton->setText(tr("Retry download"));
|
2015-01-09 23:01:48 +00:00
|
|
|
ui.downloadCancelRetryButton->setEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadFromDCWidget::on_cancel_clicked()
|
|
|
|
{
|
|
|
|
if (currentState == DOWNLOADING || currentState == CANCELLING)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// now discard all the dives
|
2019-09-22 18:35:38 +00:00
|
|
|
diveImportedModel->clearTable();
|
2015-01-09 23:01:48 +00:00
|
|
|
done(-1);
|
2013-08-25 22:02:30 +00:00
|
|
|
}
|
2015-01-08 13:31:05 +00:00
|
|
|
|
|
|
|
void DownloadFromDCWidget::on_ok_clicked()
|
|
|
|
{
|
2019-08-28 09:21:24 +00:00
|
|
|
if (currentState != DONE && currentState != ERRORED)
|
2015-01-08 13:56:00 +00:00
|
|
|
return;
|
|
|
|
|
2019-11-16 21:24:06 +00:00
|
|
|
int flags = IMPORT_IS_DOWNLOADED;
|
|
|
|
if (preferDownloaded())
|
|
|
|
flags |= IMPORT_PREFER_IMPORTED;
|
|
|
|
if (ui.createNewTrip->isChecked())
|
|
|
|
flags |= IMPORT_ADD_TO_NEW_TRIP;
|
|
|
|
|
|
|
|
diveImportedModel->recordDives(flags);
|
2015-01-08 13:53:16 +00:00
|
|
|
|
2018-12-23 22:45:12 +00:00
|
|
|
if (ostcFirmwareCheck && currentState == DONE)
|
2019-09-25 18:49:13 +00:00
|
|
|
ostcFirmwareCheck->checkLatest(this, diveImportedModel->thread.data()->internalData());
|
2015-01-08 17:59:01 +00:00
|
|
|
accept();
|
2015-01-08 13:31:05 +00:00
|
|
|
}
|
2013-08-25 22:02:30 +00:00
|
|
|
|
2017-11-01 07:01:23 +00:00
|
|
|
void DownloadFromDCWidget::updateDeviceEnabled()
|
|
|
|
{
|
|
|
|
// Set up the DC descriptor
|
|
|
|
dc_descriptor_t *descriptor = NULL;
|
2020-05-14 19:15:24 +00:00
|
|
|
descriptor = descriptorLookup.value(ui.vendor->currentText().toLower() + ui.product->currentText().toLower());
|
2017-11-01 07:01:23 +00:00
|
|
|
|
|
|
|
// call dc_descriptor_get_transport to see if the dc_transport_t is DC_TRANSPORT_SERIAL
|
2018-08-27 17:32:14 +00:00
|
|
|
if (dc_descriptor_get_transports(descriptor) & (DC_TRANSPORT_SERIAL | DC_TRANSPORT_USBSTORAGE)) {
|
2017-11-01 07:01:23 +00:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-25 13:01:59 +00:00
|
|
|
void DownloadFromDCWidget::markChildrenAsDisabled()
|
|
|
|
{
|
2015-01-08 20:56:17 +00:00
|
|
|
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);
|
2015-07-06 13:18:06 +00:00
|
|
|
ui.bluetoothMode->setEnabled(false);
|
|
|
|
ui.chooseBluetoothDevice->setEnabled(false);
|
2013-08-25 13:01:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadFromDCWidget::markChildrenAsEnabled()
|
|
|
|
{
|
2017-11-01 07:01:23 +00:00
|
|
|
updateDeviceEnabled();
|
2015-01-08 20:56:17 +00:00
|
|
|
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);
|
2015-07-20 16:35:00 +00:00
|
|
|
#if defined(BT_SUPPORT)
|
2015-07-06 13:18:06 +00:00
|
|
|
ui.bluetoothMode->setEnabled(true);
|
|
|
|
ui.chooseBluetoothDevice->setEnabled(true);
|
2015-07-20 16:35:00 +00:00
|
|
|
#endif
|
2015-07-06 13:18:06 +00:00
|
|
|
}
|
|
|
|
|
2015-07-20 16:35:00 +00:00
|
|
|
#if defined(BT_SUPPORT)
|
2015-07-06 13:18:06 +00:00
|
|
|
void DownloadFromDCWidget::selectRemoteBluetoothDevice()
|
|
|
|
{
|
2015-07-06 13:35:13 +00:00
|
|
|
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 */
|
2017-11-12 11:33:20 +00:00
|
|
|
ui.device->setEditText(btDeviceSelectionDialog->getSelectedDeviceText());
|
2018-07-26 01:40:19 +00:00
|
|
|
} else if (result == QDialog::Rejected) {
|
2015-07-06 13:35:13 +00:00
|
|
|
/* Disable Bluetooth download mode */
|
|
|
|
ui.bluetoothMode->setChecked(false);
|
|
|
|
}
|
2015-07-06 13:18:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadFromDCWidget::enableBluetoothMode(int state)
|
|
|
|
{
|
|
|
|
ui.chooseBluetoothDevice->setEnabled(state == Qt::Checked);
|
2015-09-06 21:12:00 +00:00
|
|
|
|
2015-07-06 13:18:06 +00:00
|
|
|
if (state == Qt::Checked)
|
|
|
|
selectRemoteBluetoothDevice();
|
2015-09-06 21:12:00 +00:00
|
|
|
else
|
|
|
|
ui.device->setCurrentIndex(-1);
|
2013-08-25 13:01:59 +00:00
|
|
|
}
|
2015-07-20 16:35:00 +00:00
|
|
|
#endif
|
2013-08-25 13:01:59 +00:00
|
|
|
|
2013-09-16 21:04:42 +00:00
|
|
|
static void fillDeviceList(const char *name, void *data)
|
|
|
|
{
|
|
|
|
QComboBox *comboBox = (QComboBox *)data;
|
|
|
|
comboBox->addItem(name);
|
|
|
|
}
|
|
|
|
|
2018-08-27 17:32:14 +00:00
|
|
|
void DownloadFromDCWidget::fill_device_list(unsigned int transport)
|
2013-09-16 21:04:42 +00:00
|
|
|
{
|
|
|
|
int deviceIndex;
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.device->clear();
|
2018-08-27 17:32:14 +00:00
|
|
|
deviceIndex = enumerate_devices(fillDeviceList, ui.device, transport);
|
2013-09-16 21:04:42 +00:00
|
|
|
if (deviceIndex >= 0)
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.device->setCurrentIndex(deviceIndex);
|
2013-09-16 21:04:42 +00:00
|
|
|
}
|