From bd064d50e625bb7e9efa0346ed899897f40bb678 Mon Sep 17 00:00:00 2001
From: David Kaspar <dkaspar@blackberry.com>
Date: Fri, 26 Jul 2013 16:55:12 +0200
Subject: [PATCH] Qnx: Fixing UI freeze when canceling SSH-keys generation

The UI freeze happens when an user cancels 'Add BlackBerry Device' wizard
while SSH-keys are being generated.

Removing a need for terminate() and wait() calls in
BlackBerryDeviceConfigurationWizardSshKeyPage dtor by invoking a new
thread each time a Generate button is pressed. Such a thread can delete
itself later when the calculation is finished.
The only drawback is that the calculation is still happening even when the
wizard is closed. Just the calculation results are not used anywhere.

Task-number: QTCREATORBUG-9888

Change-Id: Ibc5e98d08e129d7f76620a5dea9ed5190932243b
Reviewed-by: Mehdi Fekari <mfekari@blackberry.com>
Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
---
 ...ackberrydeviceconfigurationwizardpages.cpp | 44 +++++++++----------
 ...blackberrydeviceconfigurationwizardpages.h |  9 ++--
 .../qnx/blackberrysshkeysgenerator.cpp        | 21 ++++-----
 src/plugins/qnx/blackberrysshkeysgenerator.h  |  8 ++--
 4 files changed, 36 insertions(+), 46 deletions(-)

diff --git a/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.cpp b/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.cpp
index 3b13e95071c..6d7eeec3a44 100644
--- a/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.cpp
+++ b/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.cpp
@@ -162,7 +162,6 @@ void BlackBerryDeviceConfigurationWizardSetupPage::requestDebugToken()
 BlackBerryDeviceConfigurationWizardSshKeyPage::BlackBerryDeviceConfigurationWizardSshKeyPage(QWidget *parent)
     : QWizardPage(parent)
     , m_ui(new Ui::BlackBerryDeviceConfigurationWizardSshKeyPage)
-    , m_sshKeysGenerator(new BlackBerrySshKeysGenerator(this))
 {
     m_ui->setupUi(this);
 
@@ -180,15 +179,10 @@ BlackBerryDeviceConfigurationWizardSshKeyPage::BlackBerryDeviceConfigurationWiza
     connect(m_ui->privateKey, SIGNAL(changed(QString)), this, SLOT(findMatchingPublicKey(QString)));
     connect(m_ui->privateKey, SIGNAL(changed(QString)), this, SIGNAL(completeChanged()));
     connect(m_ui->generate, SIGNAL(clicked()), this, SLOT(generateSshKeys()));
-    connect(m_sshKeysGenerator, SIGNAL(sshKeysGenerationFinished(bool)), this, SLOT(processSshKeys(bool)));
 }
 
 BlackBerryDeviceConfigurationWizardSshKeyPage::~BlackBerryDeviceConfigurationWizardSshKeyPage()
 {
-    // Make sure the m_sshKeysGenerator thread is terminated before it's destroyed
-    m_sshKeysGenerator->terminate();
-    m_sshKeysGenerator->wait();
-
     delete m_ui;
     m_ui = 0;
 }
@@ -224,42 +218,43 @@ void BlackBerryDeviceConfigurationWizardSshKeyPage::findMatchingPublicKey(const
         m_ui->publicKey->clear();
 }
 
-void BlackBerryDeviceConfigurationWizardSshKeyPage::processSshKeys(bool success)
+void BlackBerryDeviceConfigurationWizardSshKeyPage::sshKeysGenerationFailed(const QString &error)
 {
     setBusy(false);
+    QMessageBox::critical(this, tr("Key Generation Failed"), error);
+}
 
-    if (!success) {
-        QMessageBox::critical(this, tr("Key Generation Failed"), m_sshKeysGenerator->error());
-        return;
-    }
+void BlackBerryDeviceConfigurationWizardSshKeyPage::processSshKeys(const QString &privateKeyPath, const QByteArray &privateKey, const QByteArray &publicKey)
+{
+    setBusy(false);
 
-    const QString publicKeyPath = m_generatedPrivateKeyPath + QLatin1String(".pub");
+    const QString publicKeyPath = privateKeyPath + QLatin1String(".pub");
 
-    if (!saveKeys(m_generatedPrivateKeyPath, publicKeyPath)) // saveKeys(..) will show an error message if necessary
+    if (!saveKeys(privateKey, publicKey, privateKeyPath, publicKeyPath)) // saveKeys(..) will show an error message if necessary
         return;
 
-    m_ui->privateKey->setFileName(Utils::FileName::fromString(m_generatedPrivateKeyPath));
+    m_ui->privateKey->setFileName(Utils::FileName::fromString(privateKeyPath));
     m_ui->publicKey->setText(QDir::toNativeSeparators(publicKeyPath));
 
     emit completeChanged();
 }
 
-bool BlackBerryDeviceConfigurationWizardSshKeyPage::saveKeys(const QString &privateKeyFile, const QString &publicKeyFile)
+bool BlackBerryDeviceConfigurationWizardSshKeyPage::saveKeys(const QByteArray &privateKey, const QByteArray &publicKey, const QString &privateKeyPath, const QString &publicKeyPath)
 {
-    Utils::FileSaver privSaver(privateKeyFile);
-    privSaver.write(m_sshKeysGenerator->keyGenerator()->privateKey());
+    Utils::FileSaver privSaver(privateKeyPath);
+    privSaver.write(privateKey);
     if (!privSaver.finalize(this))
         return false; // finalize shows an error message if necessary
-    QFile::setPermissions(privateKeyFile, QFile::ReadOwner | QFile::WriteOwner);
+    QFile::setPermissions(privateKeyPath, QFile::ReadOwner | QFile::WriteOwner);
 
-    Utils::FileSaver pubSaver(publicKeyFile);
+    Utils::FileSaver pubSaver(publicKeyPath);
 
     // blackberry-connect requires an @ character to be included in the RSA comment
     const QString atHost = QLatin1Char('@') + QHostInfo::localHostName();
-    QByteArray pubKeyContent = m_sshKeysGenerator->keyGenerator()->publicKey();
+    QByteArray pubKeyContent = publicKey;
     pubKeyContent.append(atHost.toLocal8Bit());
 
-    pubSaver.write(pubKeyContent);
+    pubSaver.write(publicKey);
     if (!pubSaver.finalize(this))
         return false;
 
@@ -276,10 +271,11 @@ void BlackBerryDeviceConfigurationWizardSshKeyPage::generateSshKeys()
     if (privateKeyPath.isEmpty())
         return;
 
-    m_generatedPrivateKeyPath = privateKeyPath;
-
     setBusy(true);
-    m_sshKeysGenerator->start();
+    BlackBerrySshKeysGenerator *sshKeysGenerator = new BlackBerrySshKeysGenerator(privateKeyPath);
+    connect(sshKeysGenerator, SIGNAL(sshKeysGenerationFailed(QString)), this, SLOT(sshKeysGenerationFailed(QString)), Qt::QueuedConnection);
+    connect(sshKeysGenerator, SIGNAL(sshKeysGenerationFinished(QString,QByteArray,QByteArray)), this, SLOT(processSshKeys(QString,QByteArray,QByteArray)), Qt::QueuedConnection);
+    sshKeysGenerator->start();
 }
 
 void BlackBerryDeviceConfigurationWizardSshKeyPage::setBusy(bool busy)
diff --git a/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.h b/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.h
index c9354cd30da..0fd4106f783 100644
--- a/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.h
+++ b/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.h
@@ -87,17 +87,16 @@ public:
 
 private slots:
     void findMatchingPublicKey(const QString &privateKeyPath);
-    void processSshKeys(bool success);
+
+    void sshKeysGenerationFailed(const QString &error);
+    void processSshKeys(const QString &privateKeyPath, const QByteArray &privateKey, const QByteArray &publicKey);
     void generateSshKeys();
 
 private:
-    bool saveKeys(const QString &privateKeyFile, const QString &publicKeyFile);
+    bool saveKeys(const QByteArray &privateKey, const QByteArray &publicKey, const QString &privateKeyPath, const QString &publicKeyPath);
     void setBusy(bool busy);
 
     Ui::BlackBerryDeviceConfigurationWizardSshKeyPage *m_ui;
-
-    BlackBerrySshKeysGenerator *m_sshKeysGenerator;
-    QString m_generatedPrivateKeyPath;
 };
 
 class BlackBerryDeviceConfigurationWizardFinalPage : public QWizardPage
diff --git a/src/plugins/qnx/blackberrysshkeysgenerator.cpp b/src/plugins/qnx/blackberrysshkeysgenerator.cpp
index d8f6dd0b7c7..3be7a6eea52 100644
--- a/src/plugins/qnx/blackberrysshkeysgenerator.cpp
+++ b/src/plugins/qnx/blackberrysshkeysgenerator.cpp
@@ -34,10 +34,12 @@
 
 using namespace Qnx::Internal;
 
-BlackBerrySshKeysGenerator::BlackBerrySshKeysGenerator(QObject *parent)
-    : QThread(parent)
+BlackBerrySshKeysGenerator::BlackBerrySshKeysGenerator(const QString &privateKeyPath)
+    : QThread(0)
     , m_keyGen(new QSsh::SshKeyGenerator)
+    , m_privateKeyPath(privateKeyPath)
 {
+    connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
 }
 
 BlackBerrySshKeysGenerator::~BlackBerrySshKeysGenerator()
@@ -51,15 +53,8 @@ void BlackBerrySshKeysGenerator::run()
     const bool success = m_keyGen->generateKeys(QSsh::SshKeyGenerator::Rsa,
                                                 QSsh::SshKeyGenerator::Mixed, 4096,
                                                 QSsh::SshKeyGenerator::DoNotOfferEncryption);
-    emit sshKeysGenerationFinished(success);
-}
-
-QSsh::SshKeyGenerator *BlackBerrySshKeysGenerator::keyGenerator() const
-{
-    return m_keyGen;
-}
-
-QString BlackBerrySshKeysGenerator::error() const
-{
-    return m_keyGen->error();
+    if (success)
+        emit sshKeysGenerationFinished(m_privateKeyPath, m_keyGen->privateKey(), m_keyGen->publicKey());
+    else
+        emit sshKeysGenerationFailed(m_keyGen->error());
 }
diff --git a/src/plugins/qnx/blackberrysshkeysgenerator.h b/src/plugins/qnx/blackberrysshkeysgenerator.h
index 459a9e205f7..e732d5575ca 100644
--- a/src/plugins/qnx/blackberrysshkeysgenerator.h
+++ b/src/plugins/qnx/blackberrysshkeysgenerator.h
@@ -44,16 +44,16 @@ class BlackBerrySshKeysGenerator : public QThread
 {
     Q_OBJECT
 public:
-    BlackBerrySshKeysGenerator(QObject *parent = 0);
+    BlackBerrySshKeysGenerator(const QString &privateKeyPath);
     ~BlackBerrySshKeysGenerator();
-    QSsh::SshKeyGenerator *keyGenerator() const;
-    QString error() const;
 
 signals:
-    void sshKeysGenerationFinished(bool success);
+    void sshKeysGenerationFailed(const QString &error);
+    void sshKeysGenerationFinished(const QString &privateKeyPath, const QByteArray &privateKey, const QByteArray &publicKey);
 
 private:
       QSsh::SshKeyGenerator *m_keyGen;
+      const QString m_privateKeyPath;
       void run();
 };
 
-- 
GitLab