From d749c1dc7186e87ffc4e729898ce8c6bc004c02c Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Thu, 29 Oct 2009 12:48:12 +0100 Subject: [PATCH] S60: Provide a message box prompting to start TRK ... with cancel, similar to the Bluetooth connect box. Reviewed-by: Robert Loehning <robert.loehning@nokia.com> --- .../qt-s60/s60devicerunconfiguration.cpp | 67 +++++++++++-- .../qt-s60/s60devicerunconfiguration.h | 11 ++- .../s60devicerunconfigurationwidget.cpp | 97 ++++++++++--------- .../qt-s60/s60devicerunconfigurationwidget.h | 9 +- .../qt4projectmanager/qt-s60/s60manager.cpp | 3 +- .../qt4projectmanager/qt-s60/s60manager.h | 10 +- src/shared/trk/launcher.cpp | 61 +++++++++--- src/shared/trk/launcher.h | 14 +++ 8 files changed, 203 insertions(+), 69 deletions(-) diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp index 0804a9fe258..181fe4d1926 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp @@ -50,6 +50,9 @@ #include <debugger/debuggermanager.h> +#include <QtGui/QMessageBox> +#include <QtGui/QMainWindow> + using namespace ProjectExplorer; using namespace Qt4ProjectManager::Internal; @@ -446,6 +449,11 @@ S60DeviceRunControlBase::~S60DeviceRunControlBase() void S60DeviceRunControlBase::start() { emit started(); + if (m_serialPortName.isEmpty()) { + error(this, tr("There is no device plugged in.")); + emit finished(); + return; + } emit addToOutputWindow(this, tr("Creating %1.sisx ...").arg(QDir::toNativeSeparators(m_baseFileName))); emit addToOutputWindow(this, tr("Executable file: %1").arg(m_executableFileName)); @@ -472,10 +480,23 @@ void S60DeviceRunControlBase::start() m_makesis->start(m_makesisTool, QStringList(m_packageFile), QIODevice::ReadOnly); } +static inline void stopProcess(QProcess *p) +{ + const int timeOutMS = 200; + if (p->state() != QProcess::Running) + return; + p->terminate(); + if (p->waitForFinished(timeOutMS)) + return; + p->kill(); +} + void S60DeviceRunControlBase::stop() { - m_makesis->kill(); - m_signsis->kill(); + if (m_makesis) + stopProcess(m_makesis); + if (m_signsis) + stopProcess(m_signsis); if (m_launcher) m_launcher->terminate(); } @@ -529,6 +550,7 @@ void S60DeviceRunControlBase::makesisProcessFinished() { if (m_makesis->exitCode() != 0) { error(this, tr("An error occurred while creating the package.")); + stop(); emit finished(); return; } @@ -557,6 +579,7 @@ void S60DeviceRunControlBase::signsisProcessFinished() { if (m_signsis->exitCode() != 0) { error(this, tr("An error occurred while creating the package.")); + stop(); emit finished(); return; } @@ -570,6 +593,7 @@ void S60DeviceRunControlBase::signsisProcessFinished() connect(m_launcher, SIGNAL(installingStarted()), this, SLOT(printInstallingNotice())); connect(m_launcher, SIGNAL(canNotInstall(QString,QString)), this, SLOT(printInstallFailed(QString,QString))); connect(m_launcher, SIGNAL(copyProgress(int)), this, SLOT(printCopyProgress(int))); + connect(m_launcher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int))); //TODO sisx destination and file path user definable m_launcher->setTrkServerName(m_serialPortName); @@ -593,18 +617,17 @@ void S60DeviceRunControlBase::signsisProcessFinished() break; case trk::PromptStartCommunicationCanceled: case trk::PromptStartCommunicationError: - delete m_launcher; - m_launcher = 0; error(this, errorMessage); + stop(); emit finished(); return; }; if (!m_launcher->startServer(&errorMessage)) { - delete m_launcher; - m_launcher = 0; + error(this, tr("Could not connect to phone on port '%1': %2\n" "Check if the phone is connected and the TRK application is running.").arg(m_serialPortName, errorMessage)); + stop(); emit finished(); } } @@ -657,6 +680,37 @@ void S60DeviceRunControlBase::launcherFinished() handleLauncherFinished(); } +QMessageBox *S60DeviceRunControlBase::createTrkWaitingMessageBox(const QString &port, QWidget *parent) +{ + const QString title = QCoreApplication::translate("Qt4ProjectManager::Internal::S60DeviceRunControlBase", + "Waiting for TRK"); + const QString text = QCoreApplication::translate("Qt4ProjectManager::Internal::S60DeviceRunControlBase", + "Please start TRK on %1.").arg(port); + QMessageBox *rc = new QMessageBox(QMessageBox::Information, title, text, + QMessageBox::Cancel, parent); + return rc; +} + +void S60DeviceRunControlBase::slotLauncherStateChanged(int s) +{ + if (s == trk::Launcher::WaitingForTrk) { + QMessageBox *mb = S60DeviceRunControlBase::createTrkWaitingMessageBox(m_launcher->trkServerName(), + Core::ICore::instance()->mainWindow()); + connect(m_launcher, SIGNAL(stateChanged(int)), mb, SLOT(close())); + connect(mb, SIGNAL(finished(int)), this, SLOT(slotWaitingForTrkClosed())); + mb->open(); + } +} + +void S60DeviceRunControlBase::slotWaitingForTrkClosed() +{ + if (m_launcher && m_launcher->state() == trk::Launcher::WaitingForTrk) { + stop(); + error(this, tr("Canceled.")); + emit finished(); + } +} + void S60DeviceRunControlBase::processFailed(const QString &program, QProcess::ProcessError errorCode) { QString errorString; @@ -671,6 +725,7 @@ void S60DeviceRunControlBase::processFailed(const QString &program, QProcess::Pr errorString = tr("An error has occurred while running %1."); } error(this, errorString.arg(program)); + stop(); emit finished(); } diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h index 444e8855f65..fa7651a2fb7 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h @@ -37,6 +37,11 @@ #include <QtCore/QProcess> +QT_BEGIN_NAMESPACE +class QMessageBox; +class QWidget; +QT_END_NAMESPACE + namespace Debugger { class DebuggerStartParameters; } @@ -134,6 +139,8 @@ public: virtual void stop(); virtual bool isRunning() const; + static QMessageBox *createTrkWaitingMessageBox(const QString &port, QWidget *parent = 0); + protected: virtual void initLauncher(const QString &executable, trk::Launcher *) = 0; virtual void handleLauncherFinished() = 0; @@ -162,8 +169,10 @@ private slots: void printInstallingNotice(); void printInstallFailed(const QString &filename, const QString &errorMessage); void launcherFinished(); + void slotLauncherStateChanged(int); + void slotWaitingForTrkClosed(); -private: +private: bool createPackageFileFromTemplate(QString *errorMessage); QString m_serialPortName; diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp index a80c4200c98..7fbbf9f7fc6 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp @@ -54,6 +54,8 @@ #include <QtGui/QStyle> #include <QtGui/QApplication> #include <QtGui/QSpacerItem> +#include <QtGui/QMainWindow> +#include <QtGui/QMessageBox> Q_DECLARE_METATYPE(Qt4ProjectManager::Internal::CommunicationDevice) @@ -196,6 +198,7 @@ void S60DeviceRunConfigurationWidget::updateSerialDevices() if (newPortName != previousRunConfigurationPortName) m_runConfiguration->setSerialPortName(newPortName); } + updateSummary(); } CommunicationDevice S60DeviceRunConfigurationWidget::device(int i) const @@ -288,66 +291,72 @@ void S60DeviceRunConfigurationWidget::setDeviceInfoLabel(const QString &message, m_deviceInfoLabel->adjustSize(); } -void S60DeviceRunConfigurationWidget::updateDeviceInfo() +void S60DeviceRunConfigurationWidget::slotLauncherStateChanged(int s) { - QString message; - setDeviceInfoLabel(tr("Connecting...")); - const bool ok = getDeviceInfo(&message); - setDeviceInfoLabel(message, !ok); + switch (s) { + case trk::Launcher::WaitingForTrk: { + // Entered trk wait state..open message box + QMessageBox *mb = S60DeviceRunControlBase::createTrkWaitingMessageBox(m_infoLauncher->trkServerName(), this); + connect(m_infoLauncher, SIGNAL(stateChanged(int)), mb, SLOT(close())); + connect(mb, SIGNAL(finished(int)), this, SLOT(slotWaitingForTrkClosed())); + mb->open(); + } + break; + case trk::Launcher::DeviceDescriptionReceived: // All ok, done + setDeviceInfoLabel(m_infoLauncher->deviceDescription()); + m_deviceInfoButton->setEnabled(true); + m_infoLauncher->deleteLater(); + break; + } } -bool S60DeviceRunConfigurationWidget::getDeviceInfo(QString *message) +void S60DeviceRunConfigurationWidget::slotWaitingForTrkClosed() { - message->clear(); - // Do a launcher run with the ping protocol. Instantiate launcher on heap - // as not to introduce delays when destructing a device with timeout - trk::Launcher *launcher = new trk::Launcher(trk::Launcher::ActionPingOnly, QSharedPointer<trk::TrkDevice>(), this); + if (m_infoLauncher && m_infoLauncher->state() == trk::Launcher::WaitingForTrk) { + m_infoLauncher->deleteLater(); + clearDeviceInfo(); + m_deviceInfoButton->setEnabled(true); + } +} + +void S60DeviceRunConfigurationWidget::updateDeviceInfo() +{ + QTC_ASSERT(!m_infoLauncher, return) + setDeviceInfoLabel(tr("Connecting...")); + // Do a launcher run with the ping protocol. Prompt to connect and + // go asynchronous afterwards to pop up launch trk box if a timeout occurs. + m_infoLauncher = new trk::Launcher(trk::Launcher::ActionPingOnly, QSharedPointer<trk::TrkDevice>(), this); + connect(m_infoLauncher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int))); const CommunicationDevice commDev = currentDevice(); - launcher->setSerialFrame(commDev.type == SerialPortCommunication); - launcher->setTrkServerName(commDev.portName); + m_infoLauncher->setSerialFrame(commDev.type == SerialPortCommunication); + m_infoLauncher->setTrkServerName(commDev.portName); // Prompt user + QString message; const trk::PromptStartCommunicationResult src = - S60RunConfigBluetoothStarter::startCommunication(launcher->trkDevice(), + S60RunConfigBluetoothStarter::startCommunication(m_infoLauncher->trkDevice(), commDev.portName, commDev.type, this, - message); + &message); switch (src) { case trk::PromptStartCommunicationConnected: break; case trk::PromptStartCommunicationCanceled: - launcher->deleteLater(); - return true; + clearDeviceInfo(); + m_infoLauncher->deleteLater(); + return; case trk::PromptStartCommunicationError: - launcher->deleteLater(); - return false; + setDeviceInfoLabel(message, true); + m_infoLauncher->deleteLater(); + return; }; - if (!launcher->startServer(message)) { - launcher->deleteLater(); - return false; - } - // Set up event loop in the foreground with a timer to quit in case of timeout. - QEventLoop eventLoop; - if (!m_infoTimeOutTimer) { - m_infoTimeOutTimer = new QTimer(this); - m_infoTimeOutTimer->setInterval(3000); - m_infoTimeOutTimer->setSingleShot(true); - } - connect(m_infoTimeOutTimer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); - connect(launcher, SIGNAL(finished()), &eventLoop, SLOT(quit())); - // Go! - QApplication::setOverrideCursor(Qt::BusyCursor); - m_infoTimeOutTimer->start(); - eventLoop.exec(QEventLoop::ExcludeUserInputEvents); - m_infoTimeOutTimer->disconnect(); - QApplication::restoreOverrideCursor(); - // Anything received? - *message = launcher->deviceDescription(); - launcher->deleteLater(); - if (message->isEmpty()) { - *message = tr("A timeout occurred while querying the device. Check whether Trk is running"); - return false; + if (!m_infoLauncher->startServer(&message)) { + setDeviceInfoLabel(message, true); + m_infoLauncher->deleteLater(); + return; } - return true; + // Wait for either timeout or results + m_deviceInfoButton->setEnabled(false); + return; } } // namespace Internal diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.h b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.h index 1863f5d5e5e..18f736da736 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.h @@ -31,6 +31,7 @@ #define S60DEVICERUNCONFIGURATIONWIDGET_H #include <QtGui/QWidget> +#include <QtCore/QPointer> QT_BEGIN_NAMESPACE class QLabel; @@ -44,6 +45,10 @@ namespace Utils { class DetailsWidget; } +namespace trk { + class Launcher; +} + namespace Qt4ProjectManager { namespace Internal { @@ -72,12 +77,13 @@ private slots: void updateSummary(); void updateDeviceInfo(); void clearDeviceInfo(); + void slotLauncherStateChanged(int); + void slotWaitingForTrkClosed(); private: inline CommunicationDevice device(int i) const; inline CommunicationDevice currentDevice() const; - bool getDeviceInfo(QString *message); void setDeviceInfoLabel(const QString &message, bool isError = false); S60DeviceRunConfiguration *m_runConfiguration; @@ -89,6 +95,7 @@ private: QLabel *m_deviceInfoDescriptionLabel; QLabel *m_deviceInfoLabel; QTimer *m_infoTimeOutTimer; + QPointer<trk::Launcher> m_infoLauncher; }; } // namespace Internal diff --git a/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp b/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp index 0c9084c88dd..c2fe7ac6177 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp @@ -29,8 +29,8 @@ #include "s60manager.h" -#include "s60devices.h" #include "s60devicespreferencepane.h" +#include "serialdevicelister.h" #include "winscwtoolchain.h" #include "gccetoolchain.h" #include "rvcttoolchain.h" @@ -40,6 +40,7 @@ #include <coreplugin/icore.h> #include <extensionsystem/pluginmanager.h> #include <projectexplorer/projectexplorerconstants.h> +#include <projectexplorer/toolchain.h> #include <debugger/debuggermanager.h> #include <utils/qtcassert.h> diff --git a/src/plugins/qt4projectmanager/qt-s60/s60manager.h b/src/plugins/qt4projectmanager/qt-s60/s60manager.h index fe4078583d8..77e93be3a93 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60manager.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60manager.h @@ -31,17 +31,19 @@ #define S60MANAGER_H #include "qtversionmanager.h" -#include "serialdevicelister.h" #include "s60devices.h" -#include <extensionsystem/iplugin.h> -#include <projectexplorer/toolchain.h> - #include <QtCore/QObject> +namespace ProjectExplorer { +class ToolChain; +} + namespace Qt4ProjectManager { namespace Internal { +class SerialDeviceLister; + class S60Manager : public QObject { Q_OBJECT diff --git a/src/shared/trk/launcher.cpp b/src/shared/trk/launcher.cpp index f066ab4864f..a554269f0ef 100644 --- a/src/shared/trk/launcher.cpp +++ b/src/shared/trk/launcher.cpp @@ -56,6 +56,7 @@ struct LauncherPrivate { TrkDevicePtr m_device; QString m_trkServerName; QByteArray m_trkReadBuffer; + Launcher::State m_state; void logMessage(const QString &msg); // Debuggee state @@ -66,14 +67,13 @@ struct LauncherPrivate { QString m_installFileName; int m_verbose; Launcher::Actions m_startupActions; - bool m_connected; bool m_closeDevice; }; LauncherPrivate::LauncherPrivate(const TrkDevicePtr &d) : m_device(d), + m_state(Launcher::Disconnected), m_verbose(0), - m_connected(false), m_closeDevice(true) { if (m_device.isNull()) @@ -97,6 +97,19 @@ Launcher::~Launcher() delete d; } +Launcher::State Launcher::state() const +{ + return d->m_state; +} + +void Launcher::setState(State s) +{ + if (s != d->m_state) { + d->m_state = s; + emit stateChanged(s); + } +} + void Launcher::addStartupActions(trk::Launcher::Actions startupActions) { d->m_startupActions = Actions(d->m_startupActions | startupActions); @@ -186,7 +199,9 @@ bool Launcher::startServer(QString *errorMessage) } else { disconnect(this, SIGNAL(finished()), d->m_device.data(), 0); } - + setState(Connecting); + // Set up the temporary 'waiting' state if we do not get immediate connection + QTimer::singleShot(200, this, SLOT(slotWaitingForTrk())); d->m_device->sendTrkInitialPing(); d->m_device->sendTrkMessage(TrkDisconnect); // Disconnect, as trk might be still connected d->m_device->sendTrkMessage(TrkSupported, TrkCallback(this, &Launcher::handleSupportMask)); @@ -197,13 +212,20 @@ bool Launcher::startServer(QString *errorMessage) return true; } +void Launcher::slotWaitingForTrk() +{ + // Set temporary state if we are still in connected state + if (state() == Connecting) + setState(WaitingForTrk); +} + void Launcher::handleConnect(const TrkResult &result) { if (result.errorCode()) { emit canNotConnect(result.errorString()); return; } - d->m_connected = true; + setState(Connected); if (d->m_startupActions & ActionCopy) copyFileToRemote(); else if (d->m_startupActions & ActionInstall) @@ -226,17 +248,27 @@ void Launcher::logMessage(const QString &msg) void Launcher::terminate() { - if (d->m_session.pid) { - QByteArray ba; - appendShort(&ba, 0x0000, TargetByteOrder); - appendInt(&ba, d->m_session.pid, TargetByteOrder); - d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleRemoteProcessKilled), ba); - } else if (d->m_connected) { + switch (state()) { + case DeviceDescriptionReceived: + case Connected: + if (d->m_session.pid) { + QByteArray ba; + appendShort(&ba, 0x0000, TargetByteOrder); + appendInt(&ba, d->m_session.pid, TargetByteOrder); + d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleRemoteProcessKilled), ba); + return; + } if (d->m_copyState.copyFileHandle) closeRemoteFile(true); disconnectTrk(); - } else { + break; + case Disconnected: + break; + case Connecting: + case WaitingForTrk: + setState(Disconnected); emit finished(); + break; } } @@ -364,17 +396,21 @@ QString Launcher::deviceDescription(unsigned verbose) const void Launcher::handleTrkVersion(const TrkResult &result) { if (result.errorCode() || result.data.size() < 5) { - if (d->m_startupActions == ActionPingOnly) + if (d->m_startupActions == ActionPingOnly) { + setState(Disconnected); emit finished(); + } return; } d->m_session.trkAppVersion.trkMajor = result.data.at(1); d->m_session.trkAppVersion.trkMinor = result.data.at(2); d->m_session.trkAppVersion.protocolMajor = result.data.at(3); d->m_session.trkAppVersion.protocolMinor = result.data.at(4); + setState(DeviceDescriptionReceived); // Ping mode: Log & Terminate if (d->m_startupActions == ActionPingOnly) { qWarning("%s", qPrintable(deviceDescription())); + setState(Disconnected); emit finished(); } } @@ -501,6 +537,7 @@ void Launcher::handleCreateProcess(const TrkResult &result) void Launcher::handleWaitForFinished(const TrkResult &result) { logMessage(" FINISHED: " + stringFromArray(result.data)); + setState(Disconnected); emit finished(); } diff --git a/src/shared/trk/launcher.h b/src/shared/trk/launcher.h index 2c4881de6d1..538d367e742 100644 --- a/src/shared/trk/launcher.h +++ b/src/shared/trk/launcher.h @@ -61,10 +61,21 @@ public: ActionCopyInstallRun = ActionCopy | ActionInstall | ActionRun }; + enum State { Disconnected, Connecting, Connected, + WaitingForTrk, // This occurs only if the initial ping times out after + // a reasonable timeout, indicating that Trk is not + // running. Note that this will never happen with + // Bluetooth as communication immediately starts + // after connecting. + DeviceDescriptionReceived }; + explicit Launcher(trk::Launcher::Actions startupActions = trk::Launcher::ActionPingOnly, const TrkDevicePtr &trkDevice = TrkDevicePtr(), QObject *parent = 0); ~Launcher(); + + State state() const; + void addStartupActions(trk::Launcher::Actions startupActions); void setTrkServerName(const QString &name); QString trkServerName() const; @@ -98,12 +109,14 @@ signals: void finished(); void applicationOutputReceived(const QString &output); void copyProgress(int percent); + void stateChanged(int); public slots: void terminate(); private slots: void handleResult(const trk::TrkResult &data); + void slotWaitingForTrk(); private: // kill process and breakpoints @@ -130,6 +143,7 @@ private: void startInferiorIfNeeded(); void logMessage(const QString &msg); + void setState(State s); LauncherPrivate *d; }; -- GitLab