forked from qt-creator/qt-creator
CustomExecutableRunConfiguration: Remove nested event loop
Nested event loops are dangerous and in this case lead to a crash. So change the api of ensureConfigured to not use a nested event loop. The CustomExecutableRunConfiguration then has to manage the dialog more explicitly. Also this makes the dialog non modal, since it should then cope with every situation. Task-number: QTCREATORBUG-11416 Change-Id: I2af782915c148f8dff1b0df54fdb64aa83f684d2 Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
This commit is contained in:
@@ -248,6 +248,7 @@ struct ProjectExplorerPluginPrivate {
|
|||||||
|
|
||||||
QString m_lastOpenDirectory;
|
QString m_lastOpenDirectory;
|
||||||
QPointer<RunConfiguration> m_delayedRunConfiguration;
|
QPointer<RunConfiguration> m_delayedRunConfiguration;
|
||||||
|
QList<QPair<RunConfiguration *, ProjectExplorer::RunMode>> m_delayedRunConfigurationForRun;
|
||||||
bool m_shouldHaveRunConfiguration;
|
bool m_shouldHaveRunConfiguration;
|
||||||
RunMode m_runMode;
|
RunMode m_runMode;
|
||||||
QString m_projectFilterString;
|
QString m_projectFilterString;
|
||||||
@@ -1753,14 +1754,25 @@ void ProjectExplorerPlugin::buildStateChanged(Project * pro)
|
|||||||
|
|
||||||
void ProjectExplorerPlugin::executeRunConfiguration(RunConfiguration *runConfiguration, RunMode runMode)
|
void ProjectExplorerPlugin::executeRunConfiguration(RunConfiguration *runConfiguration, RunMode runMode)
|
||||||
{
|
{
|
||||||
QString errorMessage;
|
if (!runConfiguration->isConfigured()) {
|
||||||
if (!runConfiguration->ensureConfigured(&errorMessage)) {
|
QString errorMessage;
|
||||||
showRunErrorMessage(errorMessage);
|
RunConfiguration::ConfigurationState state = runConfiguration->ensureConfigured(&errorMessage);
|
||||||
return;
|
|
||||||
|
if (state == RunConfiguration::UnConfigured) {
|
||||||
|
showRunErrorMessage(errorMessage);
|
||||||
|
return;
|
||||||
|
} else if (state == RunConfiguration::Waiting) {
|
||||||
|
connect(runConfiguration, SIGNAL(configurationFinished()),
|
||||||
|
this, SLOT(runConfigurationConfigurationFinished()));
|
||||||
|
d->m_delayedRunConfigurationForRun.append(qMakePair(runConfiguration, runMode));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IRunControlFactory *runControlFactory = findRunControlFactory(runConfiguration, runMode)) {
|
if (IRunControlFactory *runControlFactory = findRunControlFactory(runConfiguration, runMode)) {
|
||||||
emit aboutToExecuteProject(runConfiguration->target()->project(), runMode);
|
emit aboutToExecuteProject(runConfiguration->target()->project(), runMode);
|
||||||
|
|
||||||
|
QString errorMessage;
|
||||||
RunControl *control = runControlFactory->create(runConfiguration, runMode, &errorMessage);
|
RunControl *control = runControlFactory->create(runConfiguration, runMode, &errorMessage);
|
||||||
if (!control) {
|
if (!control) {
|
||||||
showRunErrorMessage(errorMessage);
|
showRunErrorMessage(errorMessage);
|
||||||
@@ -1877,6 +1889,22 @@ void ProjectExplorerPlugin::updateContext()
|
|||||||
ICore::updateAdditionalContexts(oldContext, newContext);
|
ICore::updateAdditionalContexts(oldContext, newContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProjectExplorerPlugin::runConfigurationConfigurationFinished()
|
||||||
|
{
|
||||||
|
RunConfiguration *rc = qobject_cast<RunConfiguration *>(sender());
|
||||||
|
ProjectExplorer::RunMode runMode = ProjectExplorer::NoRunMode;
|
||||||
|
for (int i = 0; i < d->m_delayedRunConfigurationForRun.size(); ++i) {
|
||||||
|
if (d->m_delayedRunConfigurationForRun.at(i).first == rc) {
|
||||||
|
runMode = d->m_delayedRunConfigurationForRun.at(i).second;
|
||||||
|
d->m_delayedRunConfigurationForRun.removeAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (runMode != ProjectExplorer::NoRunMode
|
||||||
|
&& rc->isConfigured())
|
||||||
|
executeRunConfiguration(rc, runMode);
|
||||||
|
}
|
||||||
|
|
||||||
void ProjectExplorerPlugin::setCurrent(Project *project, QString filePath, Node *node)
|
void ProjectExplorerPlugin::setCurrent(Project *project, QString filePath, Node *node)
|
||||||
{
|
{
|
||||||
if (debug)
|
if (debug)
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ private slots:
|
|||||||
void updateExternalFileWarning();
|
void updateExternalFileWarning();
|
||||||
|
|
||||||
void updateContext();
|
void updateContext();
|
||||||
|
void runConfigurationConfigurationFinished();
|
||||||
|
|
||||||
#ifdef WITH_TESTS
|
#ifdef WITH_TESTS
|
||||||
void testAnsiFilterOutputParser_data();
|
void testAnsiFilterOutputParser_data();
|
||||||
|
|||||||
@@ -273,13 +273,13 @@ bool RunConfiguration::isConfigured() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RunConfiguration::ensureConfigured(QString *errorMessage)
|
RunConfiguration::ConfigurationState RunConfiguration::ensureConfigured(QString *errorMessage)
|
||||||
{
|
{
|
||||||
if (isConfigured())
|
if (isConfigured())
|
||||||
return true;
|
return Configured;
|
||||||
if (errorMessage)
|
if (errorMessage)
|
||||||
*errorMessage = tr("Unknown error.");
|
*errorMessage = tr("Unknown error.");
|
||||||
return false;
|
return UnConfigured;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -163,9 +163,12 @@ public:
|
|||||||
virtual bool isEnabled() const;
|
virtual bool isEnabled() const;
|
||||||
virtual QString disabledReason() const;
|
virtual QString disabledReason() const;
|
||||||
virtual QWidget *createConfigurationWidget() = 0;
|
virtual QWidget *createConfigurationWidget() = 0;
|
||||||
|
|
||||||
virtual bool isConfigured() const;
|
virtual bool isConfigured() const;
|
||||||
// Pop up configuration dialog in case for example the executable is missing.
|
// Pop up configuration dialog in case for example the executable is missing.
|
||||||
virtual bool ensureConfigured(QString *errorMessage = 0);
|
enum ConfigurationState { Configured, UnConfigured, Waiting };
|
||||||
|
// TODO rename function
|
||||||
|
virtual ConfigurationState ensureConfigured(QString *errorMessage = 0);
|
||||||
|
|
||||||
Target *target() const;
|
Target *target() const;
|
||||||
|
|
||||||
@@ -194,6 +197,7 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void enabledChanged();
|
void enabledChanged();
|
||||||
void requestRunActionsUpdate();
|
void requestRunActionsUpdate();
|
||||||
|
void configurationFinished();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RunConfiguration(Target *parent, Core::Id id);
|
RunConfiguration(Target *parent, Core::Id id);
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ void CustomExecutableRunConfiguration::ctor()
|
|||||||
CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *parent) :
|
CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *parent) :
|
||||||
LocalApplicationRunConfiguration(parent, Core::Id(CUSTOM_EXECUTABLE_ID)),
|
LocalApplicationRunConfiguration(parent, Core::Id(CUSTOM_EXECUTABLE_ID)),
|
||||||
m_workingDirectory(QLatin1String(Constants::DEFAULT_WORKING_DIR)),
|
m_workingDirectory(QLatin1String(Constants::DEFAULT_WORKING_DIR)),
|
||||||
m_runMode(ProjectExplorer::ApplicationLauncher::Gui)
|
m_runMode(ProjectExplorer::ApplicationLauncher::Gui),
|
||||||
|
m_dialog(0)
|
||||||
{
|
{
|
||||||
addExtraAspect(new LocalEnvironmentAspect(this));
|
addExtraAspect(new LocalEnvironmentAspect(this));
|
||||||
|
|
||||||
@@ -86,7 +87,8 @@ CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *paren
|
|||||||
m_executable(source->m_executable),
|
m_executable(source->m_executable),
|
||||||
m_workingDirectory(source->m_workingDirectory),
|
m_workingDirectory(source->m_workingDirectory),
|
||||||
m_cmdArguments(source->m_cmdArguments),
|
m_cmdArguments(source->m_cmdArguments),
|
||||||
m_runMode(source->m_runMode)
|
m_runMode(source->m_runMode),
|
||||||
|
m_dialog(0)
|
||||||
{
|
{
|
||||||
ctor();
|
ctor();
|
||||||
}
|
}
|
||||||
@@ -94,6 +96,12 @@ CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *paren
|
|||||||
// Note: Qt4Project deletes all empty customexecrunconfigs for which isConfigured() == false.
|
// Note: Qt4Project deletes all empty customexecrunconfigs for which isConfigured() == false.
|
||||||
CustomExecutableRunConfiguration::~CustomExecutableRunConfiguration()
|
CustomExecutableRunConfiguration::~CustomExecutableRunConfiguration()
|
||||||
{
|
{
|
||||||
|
if (m_dialog) {
|
||||||
|
emit configurationFinished();
|
||||||
|
disconnect(m_dialog, SIGNAL(finished(int)),
|
||||||
|
this, SLOT(configurationDialogFinished()));
|
||||||
|
delete m_dialog;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dialog embedding the CustomExecutableConfigurationWidget
|
// Dialog embedding the CustomExecutableConfigurationWidget
|
||||||
@@ -150,30 +158,33 @@ void CustomExecutableDialog::accept()
|
|||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CustomExecutableRunConfiguration::ensureConfigured(QString *errorMessage)
|
// CustomExecutableRunConfiguration
|
||||||
|
|
||||||
|
RunConfiguration::ConfigurationState CustomExecutableRunConfiguration::ensureConfigured(QString *errorMessage)
|
||||||
{
|
{
|
||||||
if (isConfigured())
|
Q_UNUSED(errorMessage)
|
||||||
return validateExecutable(0, errorMessage);
|
if (m_dialog) {// uhm already shown
|
||||||
CustomExecutableDialog dialog(this, Core::ICore::mainWindow());
|
*errorMessage = QLatin1String(""); // no error dialog
|
||||||
dialog.setWindowTitle(displayName());
|
m_dialog->activateWindow();
|
||||||
const QString oldExecutable = m_executable;
|
m_dialog->raise();
|
||||||
const QString oldWorkingDirectory = m_workingDirectory;
|
return UnConfigured;
|
||||||
const QString oldCmdArguments = m_cmdArguments;
|
|
||||||
if (dialog.exec() == QDialog::Accepted)
|
|
||||||
return validateExecutable(0, errorMessage);
|
|
||||||
// User canceled: Hack: Silence the error dialog.
|
|
||||||
if (errorMessage)
|
|
||||||
*errorMessage = QLatin1String("");
|
|
||||||
// Restore values changed by the configuration widget.
|
|
||||||
if (m_executable != oldExecutable
|
|
||||||
|| m_workingDirectory != oldWorkingDirectory
|
|
||||||
|| m_cmdArguments != oldCmdArguments) {
|
|
||||||
m_executable = oldExecutable;
|
|
||||||
m_workingDirectory = oldWorkingDirectory;
|
|
||||||
m_cmdArguments = oldCmdArguments;
|
|
||||||
emit changed();
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
m_dialog = new CustomExecutableDialog(this, Core::ICore::mainWindow());
|
||||||
|
connect(m_dialog, SIGNAL(finished(int)),
|
||||||
|
this, SLOT(configurationDialogFinished()));
|
||||||
|
m_dialog->setWindowTitle(displayName()); // pretty pointless
|
||||||
|
m_dialog->show();
|
||||||
|
return Waiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomExecutableRunConfiguration::configurationDialogFinished()
|
||||||
|
{
|
||||||
|
disconnect(m_dialog, SIGNAL(finished(int)),
|
||||||
|
this, SLOT(configurationDialogFinished()));
|
||||||
|
m_dialog->deleteLater();
|
||||||
|
m_dialog = 0;
|
||||||
|
emit configurationFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search the executable in the path.
|
// Search the executable in the path.
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public:
|
|||||||
|
|
||||||
QVariantMap toMap() const;
|
QVariantMap toMap() const;
|
||||||
|
|
||||||
bool ensureConfigured(QString *errorMessage);
|
ConfigurationState ensureConfigured(QString *errorMessage);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void changed();
|
void changed();
|
||||||
@@ -85,6 +85,8 @@ protected:
|
|||||||
virtual bool fromMap(const QVariantMap &map);
|
virtual bool fromMap(const QVariantMap &map);
|
||||||
QString defaultDisplayName() const;
|
QString defaultDisplayName() const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void configurationDialogFinished();
|
||||||
private:
|
private:
|
||||||
void ctor();
|
void ctor();
|
||||||
|
|
||||||
@@ -102,6 +104,7 @@ private:
|
|||||||
QString m_workingDirectory;
|
QString m_workingDirectory;
|
||||||
QString m_cmdArguments;
|
QString m_cmdArguments;
|
||||||
ProjectExplorer::ApplicationLauncher::Mode m_runMode;
|
ProjectExplorer::ApplicationLauncher::Mode m_runMode;
|
||||||
|
QWidget *m_dialog;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CustomExecutableRunConfigurationFactory : public ProjectExplorer::IRunConfigurationFactory
|
class CustomExecutableRunConfigurationFactory : public ProjectExplorer::IRunConfigurationFactory
|
||||||
|
|||||||
@@ -119,16 +119,17 @@ bool RemoteLinuxCustomRunConfiguration::isConfigured() const
|
|||||||
return !m_remoteExecutable.isEmpty();
|
return !m_remoteExecutable.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemoteLinuxCustomRunConfiguration::ensureConfigured(QString *errorMessage)
|
ProjectExplorer::RunConfiguration::ConfigurationState
|
||||||
|
RemoteLinuxCustomRunConfiguration::ensureConfigured(QString *errorMessage)
|
||||||
{
|
{
|
||||||
if (!isConfigured()) {
|
if (!isConfigured()) {
|
||||||
if (errorMessage) {
|
if (errorMessage) {
|
||||||
*errorMessage = tr("The remote executable must be set "
|
*errorMessage = tr("The remote executable must be set "
|
||||||
"in order to run a custom remote run configuration.");
|
"in order to run a custom remote run configuration.");
|
||||||
}
|
}
|
||||||
return false;
|
return UnConfigured;
|
||||||
}
|
}
|
||||||
return true;
|
return Configured;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *RemoteLinuxCustomRunConfiguration::createConfigurationWidget()
|
QWidget *RemoteLinuxCustomRunConfiguration::createConfigurationWidget()
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public:
|
|||||||
|
|
||||||
bool isEnabled() const { return true; }
|
bool isEnabled() const { return true; }
|
||||||
bool isConfigured() const;
|
bool isConfigured() const;
|
||||||
bool ensureConfigured(QString *errorMessage);
|
ConfigurationState ensureConfigured(QString *errorMessage);
|
||||||
QWidget *createConfigurationWidget();
|
QWidget *createConfigurationWidget();
|
||||||
Utils::OutputFormatter *createOutputFormatter() const;
|
Utils::OutputFormatter *createOutputFormatter() const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user