mirror of
https://github.com/subsurface/subsurface.git
synced 2025-01-19 22:35:27 +00:00
improve DownloadDialog UI control
* Removes the InterfaceThread which is basically an unecessary proxy between the MainThread and the DownloadThread. * Use a state machine to control the DownloadWidget UI logic. Signed-off-by: Danilo Cesar Lemes de Paula <danilo.eu@gmail.com>
This commit is contained in:
parent
923b4cd9b1
commit
59da382613
2 changed files with 113 additions and 67 deletions
|
@ -10,6 +10,7 @@
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QStringListModel>
|
#include <QStringListModel>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
struct product {
|
struct product {
|
||||||
const char *product;
|
const char *product;
|
||||||
|
@ -42,7 +43,8 @@ DownloadFromDCWidget *DownloadFromDCWidget::instance()
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadFromDCWidget::DownloadFromDCWidget(QWidget* parent, Qt::WindowFlags f) :
|
DownloadFromDCWidget::DownloadFromDCWidget(QWidget* parent, Qt::WindowFlags f) :
|
||||||
QDialog(parent, f), ui(new Ui::DownloadFromDiveComputer), thread(0), downloading(false)
|
QDialog(parent, f), ui(new Ui::DownloadFromDiveComputer), thread(0), timer(new QTimer(this)),
|
||||||
|
currentState(INITIAL)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->progressBar->hide();
|
ui->progressBar->hide();
|
||||||
|
@ -61,21 +63,77 @@ DownloadFromDCWidget::DownloadFromDCWidget(QWidget* parent, Qt::WindowFlags f) :
|
||||||
}
|
}
|
||||||
if (default_dive_computer_device)
|
if (default_dive_computer_device)
|
||||||
ui->device->setText(default_dive_computer_device);
|
ui->device->setText(default_dive_computer_device);
|
||||||
|
|
||||||
|
timer->setInterval(200);
|
||||||
|
connect(timer, SIGNAL(timeout()), this, SLOT(updateProgressBar()));
|
||||||
|
|
||||||
|
updateState(INITIAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadFromDCWidget::runDialog()
|
void DownloadFromDCWidget::runDialog()
|
||||||
{
|
{
|
||||||
// Since the DownloadDialog is only
|
updateState(INITIAL);
|
||||||
// created once, we need to do put some starting code here
|
|
||||||
ui->progressBar->hide();
|
|
||||||
markChildrenAsEnabled();
|
|
||||||
|
|
||||||
exec();
|
exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadFromDCWidget::stoppedDownloading()
|
void DownloadFromDCWidget::updateProgressBar()
|
||||||
{
|
{
|
||||||
downloading = false;
|
ui->progressBar->setValue(progress_bar_fraction *100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadFromDCWidget::updateState(states state)
|
||||||
|
{
|
||||||
|
if (state == currentState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (state == INITIAL) {
|
||||||
|
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)
|
||||||
|
&& state == CANCELLING) {
|
||||||
|
timer->stop();
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
// A cancel 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();
|
||||||
|
accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
// DOWNLOAD is started.
|
||||||
|
else if (state == DOWNLOADING) {
|
||||||
|
timer->start();
|
||||||
|
ui->progressBar->setValue(0);
|
||||||
|
ui->progressBar->show();
|
||||||
|
markChildrenAsDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
// properly updating the widget state
|
||||||
|
currentState = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadFromDCWidget::on_vendor_currentIndexChanged(const QString& vendor)
|
void DownloadFromDCWidget::on_vendor_currentIndexChanged(const QString& vendor)
|
||||||
|
@ -136,28 +194,15 @@ void DownloadFromDCWidget::fill_computer_list()
|
||||||
|
|
||||||
void DownloadFromDCWidget::on_cancel_clicked()
|
void DownloadFromDCWidget::on_cancel_clicked()
|
||||||
{
|
{
|
||||||
import_thread_cancelled = true;
|
updateState(CANCELLING);
|
||||||
if (thread) {
|
|
||||||
thread->wait();
|
|
||||||
thread->deleteLater();
|
|
||||||
thread = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confusing, but if the user press cancel during a download
|
|
||||||
// he probably want to cancel the download, not to close the window.
|
|
||||||
if (!downloading)
|
|
||||||
close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadFromDCWidget::on_ok_clicked()
|
void DownloadFromDCWidget::on_ok_clicked()
|
||||||
{
|
{
|
||||||
if (downloading)
|
updateState(DOWNLOADING);
|
||||||
return;
|
|
||||||
|
|
||||||
markChildrenAsDisabled();
|
|
||||||
ui->progressBar->setValue(0);
|
|
||||||
ui->progressBar->show();
|
|
||||||
|
|
||||||
|
// I don't really think that create/destroy the thread
|
||||||
|
// is really necessary.
|
||||||
if (thread) {
|
if (thread) {
|
||||||
thread->deleteLater();
|
thread->deleteLater();
|
||||||
}
|
}
|
||||||
|
@ -172,14 +217,15 @@ void DownloadFromDCWidget::on_ok_clicked()
|
||||||
set_default_dive_computer(data.vendor, data.product);
|
set_default_dive_computer(data.vendor, data.product);
|
||||||
set_default_dive_computer_device(data.devname);
|
set_default_dive_computer_device(data.devname);
|
||||||
|
|
||||||
thread = new InterfaceThread(this, &data);
|
thread = new DownloadThread(this, &data);
|
||||||
connect(thread, SIGNAL(updateInterface(int)),
|
|
||||||
ui->progressBar, SLOT(setValue(int)), Qt::QueuedConnection); // Qt::QueuedConnection == threadsafe.
|
|
||||||
|
|
||||||
connect(thread, SIGNAL(finished()), this, SLOT(close()));
|
connect(thread, SIGNAL(finished()),
|
||||||
|
this, SLOT(onDownloadThreadFinished()), Qt::QueuedConnection);
|
||||||
|
|
||||||
|
MainWindow *w = mainWindow();
|
||||||
|
connect(thread, SIGNAL(finished()), w, SLOT(refreshDisplay()));
|
||||||
|
|
||||||
thread->start();
|
thread->start();
|
||||||
downloading = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DownloadFromDCWidget::preferDownloaded()
|
bool DownloadFromDCWidget::preferDownloaded()
|
||||||
|
@ -191,10 +237,18 @@ void DownloadFromDCWidget::reject()
|
||||||
{
|
{
|
||||||
// we don't want the download window being able to close
|
// we don't want the download window being able to close
|
||||||
// while we're still downloading.
|
// while we're still downloading.
|
||||||
if (!downloading)
|
if (currentState != DOWNLOADING && currentState != CANCELLING)
|
||||||
QDialog::reject();
|
QDialog::reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DownloadFromDCWidget::onDownloadThreadFinished()
|
||||||
|
{
|
||||||
|
if (currentState == DOWNLOADING)
|
||||||
|
updateState(DONE);
|
||||||
|
else
|
||||||
|
updateState(CANCELLED);
|
||||||
|
}
|
||||||
|
|
||||||
void DownloadFromDCWidget::markChildrenAsDisabled()
|
void DownloadFromDCWidget::markChildrenAsDisabled()
|
||||||
{
|
{
|
||||||
ui->device->setDisabled(true);
|
ui->device->setDisabled(true);
|
||||||
|
@ -214,37 +268,26 @@ void DownloadFromDCWidget::markChildrenAsEnabled()
|
||||||
ui->forceDownload->setDisabled(false);
|
ui->forceDownload->setDisabled(false);
|
||||||
ui->preferDownloaded->setDisabled(false);
|
ui->preferDownloaded->setDisabled(false);
|
||||||
ui->ok->setDisabled(false);
|
ui->ok->setDisabled(false);
|
||||||
|
ui->cancel->setDisabled(false);
|
||||||
ui->search->setDisabled(false);
|
ui->search->setDisabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadThread::DownloadThread(device_data_t* data): data(data)
|
DownloadThread::DownloadThread(QObject* parent, device_data_t* data): QThread(parent),
|
||||||
|
data(data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadThread::run()
|
void DownloadThread::run()
|
||||||
{
|
{
|
||||||
DownloadFromDCWidget *dfdcw = DownloadFromDCWidget::instance();
|
DownloadFromDCWidget *dfdcw = DownloadFromDCWidget::instance();
|
||||||
|
|
||||||
if (!strcmp(data->vendor, "Uemis"))
|
if (!strcmp(data->vendor, "Uemis"))
|
||||||
do_uemis_import(data->devname, data->force_download);
|
do_uemis_import(data->devname, data->force_download);
|
||||||
else
|
else
|
||||||
|
// TODO: implement error handling
|
||||||
do_libdivecomputer_import(data);
|
do_libdivecomputer_import(data);
|
||||||
|
|
||||||
|
// I'm not sure if we should really process_dives even
|
||||||
|
// if there's an error or a cancelation
|
||||||
process_dives(TRUE, dfdcw->preferDownloaded());
|
process_dives(TRUE, dfdcw->preferDownloaded());
|
||||||
dfdcw->stoppedDownloading();
|
|
||||||
}
|
|
||||||
|
|
||||||
InterfaceThread::InterfaceThread(QObject* parent, device_data_t* data): QThread(parent), data(data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void InterfaceThread::run()
|
|
||||||
{
|
|
||||||
DownloadThread *download = new DownloadThread(data);
|
|
||||||
MainWindow *w = mainWindow();
|
|
||||||
connect(download, SIGNAL(finished()), w, SLOT(refreshDisplay()));
|
|
||||||
download->start();
|
|
||||||
while (download->isRunning()) {
|
|
||||||
msleep(200);
|
|
||||||
updateInterface(progress_bar_fraction *100);
|
|
||||||
}
|
|
||||||
updateInterface(100);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,24 +15,12 @@ struct device_data_t;
|
||||||
class DownloadThread : public QThread{
|
class DownloadThread : public QThread{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit DownloadThread(device_data_t* data);
|
explicit DownloadThread(QObject* parent, device_data_t* data);
|
||||||
virtual void run();
|
virtual void run();
|
||||||
private:
|
private:
|
||||||
device_data_t *data;
|
device_data_t *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class InterfaceThread : public QThread{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
InterfaceThread(QObject *parent, device_data_t *data);
|
|
||||||
virtual void run();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void updateInterface(int value);
|
|
||||||
private:
|
|
||||||
device_data_t *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
class QStringListModel;
|
class QStringListModel;
|
||||||
class DownloadFromDCWidget : public QDialog{
|
class DownloadFromDCWidget : public QDialog{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -41,19 +29,29 @@ public:
|
||||||
static DownloadFromDCWidget *instance();
|
static DownloadFromDCWidget *instance();
|
||||||
void reject();
|
void reject();
|
||||||
|
|
||||||
|
enum states {
|
||||||
|
INITIAL,
|
||||||
|
DOWNLOADING,
|
||||||
|
CANCELLING,
|
||||||
|
CANCELLED,
|
||||||
|
DONE,
|
||||||
|
};
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void on_ok_clicked();
|
void on_ok_clicked();
|
||||||
void on_cancel_clicked();
|
void on_cancel_clicked();
|
||||||
void runDialog();
|
|
||||||
void stoppedDownloading();
|
|
||||||
void on_vendor_currentIndexChanged(const QString& vendor);
|
void on_vendor_currentIndexChanged(const QString& vendor);
|
||||||
|
|
||||||
|
void onDownloadThreadFinished();
|
||||||
|
void updateProgressBar();
|
||||||
|
void runDialog();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void markChildrenAsDisabled();
|
void markChildrenAsDisabled();
|
||||||
void markChildrenAsEnabled();
|
void markChildrenAsEnabled();
|
||||||
|
|
||||||
Ui::DownloadFromDiveComputer *ui;
|
Ui::DownloadFromDiveComputer *ui;
|
||||||
InterfaceThread *thread;
|
DownloadThread *thread;
|
||||||
bool downloading;
|
bool downloading;
|
||||||
|
|
||||||
QStringList vendorList;
|
QStringList vendorList;
|
||||||
|
@ -65,8 +63,13 @@ private:
|
||||||
QStringListModel *productModel;
|
QStringListModel *productModel;
|
||||||
void fill_computer_list();
|
void fill_computer_list();
|
||||||
|
|
||||||
|
QTimer *timer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool preferDownloaded();
|
bool preferDownloaded();
|
||||||
|
void updateState(states state);
|
||||||
|
states currentState;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue