subsurface/qt-ui/downloadfromdivecomputer.cpp
Dirk Hohndel 1646517d28 After done with the DC download dialog, ensure it's in its original state
So in case the OK button was relabeled to 'Retry', relabel it back to OK.
Also, 'Retry' should be capitalized.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-11-09 15:58:57 +09:00

333 lines
8.5 KiB
C++

#include "downloadfromdivecomputer.h"
#include "../libdivecomputer.h"
#include "../helpers.h"
#include "../display.h"
#include "../divelist.h"
#include "mainwindow.h"
#include <cstdlib>
#include <QThread>
#include <QDebug>
#include <QStringListModel>
#include <QTimer>
#include <QMessageBox>
struct product {
const char *product;
dc_descriptor_t *descriptor;
struct product *next;
};
struct vendor {
const char *vendor;
struct product *productlist;
struct vendor *next;
};
struct mydescriptor {
const char *vendor;
const char *product;
dc_family_t type;
unsigned int model;
};
namespace DownloadFromDcGlobal{
const char *err_string;
};
DownloadFromDCWidget *DownloadFromDCWidget::instance()
{
static DownloadFromDCWidget *dialog = new DownloadFromDCWidget();
dialog->setAttribute(Qt::WA_QuitOnClose, false);
return dialog;
}
DownloadFromDCWidget::DownloadFromDCWidget(QWidget* parent, Qt::WindowFlags f) :
QDialog(parent, f), thread(0), timer(new QTimer(this)),
currentState(INITIAL)
{
ui.setupUi(this);
ui.progressBar->hide();
ui.progressBar->setMinimum(0);
ui.progressBar->setMaximum(100);
fill_device_list();
fill_computer_list();
vendorModel = new QStringListModel(vendorList);
ui.vendor->setModel(vendorModel);
if (default_dive_computer_vendor) {
ui.vendor->setCurrentIndex(ui.vendor->findText(default_dive_computer_vendor));
productModel = new QStringListModel(productList[default_dive_computer_vendor]);
ui.product->setModel(productModel);
if (default_dive_computer_product)
ui.product->setCurrentIndex(ui.product->findText(default_dive_computer_product));
}
if (default_dive_computer_device)
ui.device->setEditText(default_dive_computer_device);
timer->setInterval(200);
connect(timer, SIGNAL(timeout()), this, SLOT(updateProgressBar()));
updateState(INITIAL);
}
void DownloadFromDCWidget::runDialog()
{
updateState(INITIAL);
exec();
}
void DownloadFromDCWidget::updateProgressBar()
{
ui.progressBar->setValue(progress_bar_fraction *100);
}
void DownloadFromDCWidget::updateState(states state)
{
if (state == currentState)
return;
if (state == INITIAL) {
fill_device_list();
ui.progressBar->hide();
markChildrenAsEnabled();
timer->stop();
}
// tries to cancel an on going download
else if (currentState == DOWNLOADING && state == CANCELLING) {
import_thread_cancelled = true;
ui.cancel->setEnabled(false);
}
// user pressed cancel but the application isn't doing anything.
// means close the window
else if ((currentState == INITIAL || currentState == CANCELLED || currentState == DONE || currentState == ERROR)
&& state == CANCELLING) {
timer->stop();
reject();
ui.ok->setText(tr("OK"));
}
// the cancelation process is finished
else if (currentState == CANCELLING && (state == DONE || state == CANCELLED)) {
timer->stop();
state = CANCELLED;
ui.progressBar->setValue(0);
ui.progressBar->hide();
markChildrenAsEnabled();
}
// DOWNLOAD is finally done, close the dialog and go back to the main window
else if (currentState == DOWNLOADING && state == DONE) {
timer->stop();
ui.progressBar->setValue(100);
markChildrenAsEnabled();
ui.ok->setText(tr("OK"));
accept();
}
// DOWNLOAD is started.
else if (state == DOWNLOADING) {
timer->start();
ui.progressBar->setValue(0);
ui.progressBar->show();
markChildrenAsDisabled();
}
// got an error
else if (state == ERROR) {
QMessageBox::critical(this, tr("Error"), this->thread->error, QMessageBox::Ok);
markChildrenAsEnabled();
ui.progressBar->hide();
ui.ok->setText(tr("Retry"));
}
// properly updating the widget state
currentState = state;
}
void DownloadFromDCWidget::on_vendor_currentIndexChanged(const QString& vendor)
{
QAbstractItemModel *currentModel = ui.product->model();
if (!currentModel)
return;
productModel = new QStringListModel(productList[vendor]);
ui.product->setModel(productModel);
// Memleak - but deleting gives me a crash.
//currentModel->deleteLater();
}
void DownloadFromDCWidget::fill_computer_list()
{
dc_iterator_t *iterator = NULL;
dc_descriptor_t *descriptor = NULL;
struct mydescriptor *mydescriptor;
QStringList computer;
dc_descriptor_iterator(&iterator);
while (dc_iterator_next (iterator, &descriptor) == DC_STATUS_SUCCESS) {
const char *vendor = dc_descriptor_get_vendor(descriptor);
const char *product = dc_descriptor_get_product(descriptor);
if (!vendorList.contains(vendor))
vendorList.append(vendor);
if (!productList[vendor].contains(product))
productList[vendor].push_back(product);
descriptorLookup[QString(vendor) + QString(product)] = descriptor;
}
dc_iterator_free(iterator);
/* and add the Uemis Zurich which we are handling internally
THIS IS A HACK as we magically have a data structure here that
happens to match a data structure that is internal to libdivecomputer;
this WILL BREAK if libdivecomputer changes the dc_descriptor struct...
eventually the UEMIS code needs to move into libdivecomputer, I guess */
mydescriptor = (struct mydescriptor*) malloc(sizeof(struct mydescriptor));
mydescriptor->vendor = "Uemis";
mydescriptor->product = "Zurich";
mydescriptor->type = DC_FAMILY_NULL;
mydescriptor->model = 0;
if (!vendorList.contains("Uemis"))
vendorList.append("Uemis");
if (!productList["Uemis"].contains("Zurich"))
productList["Uemis"].push_back("Zurich");
descriptorLookup[QString("UemisZurich")] = (dc_descriptor_t *)mydescriptor;
}
void DownloadFromDCWidget::on_cancel_clicked()
{
updateState(CANCELLING);
}
void DownloadFromDCWidget::on_ok_clicked()
{
updateState(DOWNLOADING);
// I don't really think that create/destroy the thread
// is really necessary.
if (thread) {
thread->deleteLater();
}
data.devname = strdup(ui.device->currentText().toUtf8().data());
data.vendor = strdup(ui.vendor->currentText().toUtf8().data());
data.product = strdup(ui.product->currentText().toUtf8().data());
data.descriptor = descriptorLookup[ui.vendor->currentText() + ui.product->currentText()];
data.force_download = ui.forceDownload->isChecked();
data.deviceid = data.diveid = 0;
set_default_dive_computer(data.vendor, data.product);
set_default_dive_computer_device(data.devname);
thread = new DownloadThread(this, &data);
connect(thread, SIGNAL(finished()),
this, SLOT(onDownloadThreadFinished()), Qt::QueuedConnection);
MainWindow *w = mainWindow();
connect(thread, SIGNAL(finished()), w, SLOT(refreshDisplay()));
thread->start();
}
bool DownloadFromDCWidget::preferDownloaded()
{
return ui.preferDownloaded->isChecked();
}
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()
{
if (currentState == DOWNLOADING) {
if (thread->error.isEmpty())
updateState(DONE);
else
updateState(ERROR);
// I'm not sure if we should really call process_dives even
// if there's an error or a cancelation
process_dives(TRUE, preferDownloaded());
} else
updateState(CANCELLED);
}
void DownloadFromDCWidget::markChildrenAsDisabled()
{
ui.device->setDisabled(true);
ui.vendor->setDisabled(true);
ui.product->setDisabled(true);
ui.forceDownload->setDisabled(true);
ui.preferDownloaded->setDisabled(true);
ui.ok->setDisabled(true);
ui.search->setDisabled(true);
}
void DownloadFromDCWidget::markChildrenAsEnabled()
{
ui.device->setDisabled(false);
ui.vendor->setDisabled(false);
ui.product->setDisabled(false);
ui.forceDownload->setDisabled(false);
ui.preferDownloaded->setDisabled(false);
ui.ok->setDisabled(false);
ui.cancel->setDisabled(false);
ui.search->setDisabled(false);
}
static void fillDeviceList(const char *name, void *data)
{
QComboBox *comboBox = (QComboBox *)data;
comboBox->addItem(name);
}
void DownloadFromDCWidget::fill_device_list()
{
int deviceIndex;
ui.device->clear();
deviceIndex = enumerate_devices(fillDeviceList, ui.device);
if (deviceIndex >= 0)
ui.device->setCurrentIndex(deviceIndex);
}
DownloadThread::DownloadThread(QObject* parent, device_data_t* data): QThread(parent),
data(data)
{
}
static QString str_error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
const QString str = QString().vsprintf( fmt, args );
va_end(args);
return str;
}
void DownloadThread::run()
{
const char *error;
if (!strcmp(data->vendor, "Uemis"))
error = do_uemis_import(data->devname, data->force_download);
else
error = do_libdivecomputer_import(data);
if (error)
this->error = str_error(error, data->devname, data->vendor, data->product);
}