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;
|
||||
QPointer<RunConfiguration> m_delayedRunConfiguration;
|
||||
QList<QPair<RunConfiguration *, ProjectExplorer::RunMode>> m_delayedRunConfigurationForRun;
|
||||
bool m_shouldHaveRunConfiguration;
|
||||
RunMode m_runMode;
|
||||
QString m_projectFilterString;
|
||||
@@ -1753,14 +1754,25 @@ void ProjectExplorerPlugin::buildStateChanged(Project * pro)
|
||||
|
||||
void ProjectExplorerPlugin::executeRunConfiguration(RunConfiguration *runConfiguration, RunMode runMode)
|
||||
{
|
||||
if (!runConfiguration->isConfigured()) {
|
||||
QString errorMessage;
|
||||
if (!runConfiguration->ensureConfigured(&errorMessage)) {
|
||||
RunConfiguration::ConfigurationState state = runConfiguration->ensureConfigured(&errorMessage);
|
||||
|
||||
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)) {
|
||||
emit aboutToExecuteProject(runConfiguration->target()->project(), runMode);
|
||||
|
||||
QString errorMessage;
|
||||
RunControl *control = runControlFactory->create(runConfiguration, runMode, &errorMessage);
|
||||
if (!control) {
|
||||
showRunErrorMessage(errorMessage);
|
||||
@@ -1877,6 +1889,22 @@ void ProjectExplorerPlugin::updateContext()
|
||||
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)
|
||||
{
|
||||
if (debug)
|
||||
|
||||
@@ -232,6 +232,7 @@ private slots:
|
||||
void updateExternalFileWarning();
|
||||
|
||||
void updateContext();
|
||||
void runConfigurationConfigurationFinished();
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
void testAnsiFilterOutputParser_data();
|
||||
|
||||
@@ -273,13 +273,13 @@ bool RunConfiguration::isConfigured() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RunConfiguration::ensureConfigured(QString *errorMessage)
|
||||
RunConfiguration::ConfigurationState RunConfiguration::ensureConfigured(QString *errorMessage)
|
||||
{
|
||||
if (isConfigured())
|
||||
return true;
|
||||
return Configured;
|
||||
if (errorMessage)
|
||||
*errorMessage = tr("Unknown error.");
|
||||
return false;
|
||||
return UnConfigured;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -163,9 +163,12 @@ public:
|
||||
virtual bool isEnabled() const;
|
||||
virtual QString disabledReason() const;
|
||||
virtual QWidget *createConfigurationWidget() = 0;
|
||||
|
||||
virtual bool isConfigured() const;
|
||||
// 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;
|
||||
|
||||
@@ -194,6 +197,7 @@ public:
|
||||
signals:
|
||||
void enabledChanged();
|
||||
void requestRunActionsUpdate();
|
||||
void configurationFinished();
|
||||
|
||||
protected:
|
||||
RunConfiguration(Target *parent, Core::Id id);
|
||||
|
||||
@@ -71,7 +71,8 @@ void CustomExecutableRunConfiguration::ctor()
|
||||
CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *parent) :
|
||||
LocalApplicationRunConfiguration(parent, Core::Id(CUSTOM_EXECUTABLE_ID)),
|
||||
m_workingDirectory(QLatin1String(Constants::DEFAULT_WORKING_DIR)),
|
||||
m_runMode(ProjectExplorer::ApplicationLauncher::Gui)
|
||||
m_runMode(ProjectExplorer::ApplicationLauncher::Gui),
|
||||
m_dialog(0)
|
||||
{
|
||||
addExtraAspect(new LocalEnvironmentAspect(this));
|
||||
|
||||
@@ -86,7 +87,8 @@ CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *paren
|
||||
m_executable(source->m_executable),
|
||||
m_workingDirectory(source->m_workingDirectory),
|
||||
m_cmdArguments(source->m_cmdArguments),
|
||||
m_runMode(source->m_runMode)
|
||||
m_runMode(source->m_runMode),
|
||||
m_dialog(0)
|
||||
{
|
||||
ctor();
|
||||
}
|
||||
@@ -94,6 +96,12 @@ CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *paren
|
||||
// Note: Qt4Project deletes all empty customexecrunconfigs for which isConfigured() == false.
|
||||
CustomExecutableRunConfiguration::~CustomExecutableRunConfiguration()
|
||||
{
|
||||
if (m_dialog) {
|
||||
emit configurationFinished();
|
||||
disconnect(m_dialog, SIGNAL(finished(int)),
|
||||
this, SLOT(configurationDialogFinished()));
|
||||
delete m_dialog;
|
||||
}
|
||||
}
|
||||
|
||||
// Dialog embedding the CustomExecutableConfigurationWidget
|
||||
@@ -150,30 +158,33 @@ void CustomExecutableDialog::accept()
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
bool CustomExecutableRunConfiguration::ensureConfigured(QString *errorMessage)
|
||||
// CustomExecutableRunConfiguration
|
||||
|
||||
RunConfiguration::ConfigurationState CustomExecutableRunConfiguration::ensureConfigured(QString *errorMessage)
|
||||
{
|
||||
if (isConfigured())
|
||||
return validateExecutable(0, errorMessage);
|
||||
CustomExecutableDialog dialog(this, Core::ICore::mainWindow());
|
||||
dialog.setWindowTitle(displayName());
|
||||
const QString oldExecutable = m_executable;
|
||||
const QString oldWorkingDirectory = m_workingDirectory;
|
||||
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();
|
||||
Q_UNUSED(errorMessage)
|
||||
if (m_dialog) {// uhm already shown
|
||||
*errorMessage = QLatin1String(""); // no error dialog
|
||||
m_dialog->activateWindow();
|
||||
m_dialog->raise();
|
||||
return UnConfigured;
|
||||
}
|
||||
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.
|
||||
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
|
||||
QVariantMap toMap() const;
|
||||
|
||||
bool ensureConfigured(QString *errorMessage);
|
||||
ConfigurationState ensureConfigured(QString *errorMessage);
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
@@ -85,6 +85,8 @@ protected:
|
||||
virtual bool fromMap(const QVariantMap &map);
|
||||
QString defaultDisplayName() const;
|
||||
|
||||
private slots:
|
||||
void configurationDialogFinished();
|
||||
private:
|
||||
void ctor();
|
||||
|
||||
@@ -102,6 +104,7 @@ private:
|
||||
QString m_workingDirectory;
|
||||
QString m_cmdArguments;
|
||||
ProjectExplorer::ApplicationLauncher::Mode m_runMode;
|
||||
QWidget *m_dialog;
|
||||
};
|
||||
|
||||
class CustomExecutableRunConfigurationFactory : public ProjectExplorer::IRunConfigurationFactory
|
||||
|
||||
@@ -119,16 +119,17 @@ bool RemoteLinuxCustomRunConfiguration::isConfigured() const
|
||||
return !m_remoteExecutable.isEmpty();
|
||||
}
|
||||
|
||||
bool RemoteLinuxCustomRunConfiguration::ensureConfigured(QString *errorMessage)
|
||||
ProjectExplorer::RunConfiguration::ConfigurationState
|
||||
RemoteLinuxCustomRunConfiguration::ensureConfigured(QString *errorMessage)
|
||||
{
|
||||
if (!isConfigured()) {
|
||||
if (errorMessage) {
|
||||
*errorMessage = tr("The remote executable must be set "
|
||||
"in order to run a custom remote run configuration.");
|
||||
}
|
||||
return false;
|
||||
return UnConfigured;
|
||||
}
|
||||
return true;
|
||||
return Configured;
|
||||
}
|
||||
|
||||
QWidget *RemoteLinuxCustomRunConfiguration::createConfigurationWidget()
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
|
||||
bool isEnabled() const { return true; }
|
||||
bool isConfigured() const;
|
||||
bool ensureConfigured(QString *errorMessage);
|
||||
ConfigurationState ensureConfigured(QString *errorMessage);
|
||||
QWidget *createConfigurationWidget();
|
||||
Utils::OutputFormatter *createOutputFormatter() const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user