Fix error handling for custom executables.

Prevent dialog showing "No executable" when canceling the
prompt for the executable when pressing 'Run' / 'Debug'
on a library project. Introduce new
LocalApplicationRunControl::ensureConfigured() to ensure
the configuration is complete and detect cancel via
empty/non-null strings.

Change-Id: I9bd4a296e7c995d26d6ad265519e7ebd3f98d6fe
Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
Reviewed-by: Daniel Teske <daniel.teske@digia.com>
This commit is contained in:
Friedemann Kleint
2012-09-13 11:27:15 +02:00
committed by Daniel Teske
parent 1035224774
commit fe2dd584fc
7 changed files with 127 additions and 49 deletions

View File

@@ -478,6 +478,8 @@ static DebuggerStartParameters localStartParameters(RunConfiguration *runConfigu
LocalApplicationRunConfiguration *rc =
qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
QTC_ASSERT(rc, return sp);
if (!rc->ensureConfigured(errorMessage))
return sp;
Target *target = runConfiguration->target();
Kit *kit = target ? target->kit() : KitManager::instance()->defaultKit();
@@ -541,7 +543,6 @@ static DebuggerStartParameters localStartParameters(RunConfiguration *runConfigu
RunControl *DebuggerRunControlFactory::create
(RunConfiguration *runConfiguration, RunMode mode, QString *errorMessage)
{
Q_UNUSED(errorMessage)
QTC_ASSERT(mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain, return 0);
DebuggerStartParameters sp = localStartParameters(runConfiguration, errorMessage);
if (sp.startMode == NoStartMode)
@@ -621,6 +622,9 @@ DebuggerRunControl *DebuggerRunControlFactory::createAndScheduleRun
(const DebuggerStartParameters &sp, RunConfiguration *runConfiguration)
{
QString errorMessage;
if (runConfiguration && !runConfiguration->ensureConfigured(&errorMessage))
ProjectExplorer::ProjectExplorerPlugin::showRunErrorMessage(errorMessage);
DebuggerRunControl *rc = doCreate(sp, runConfiguration, &errorMessage);
if (!rc) {
ProjectExplorer::ProjectExplorerPlugin::showRunErrorMessage(errorMessage);

View File

@@ -66,11 +66,8 @@ RunControl *LocalApplicationRunControlFactory::create(RunConfiguration *runConfi
QTC_ASSERT(canRun(runConfiguration, mode), return 0);
LocalApplicationRunConfiguration *localRunConfiguration = qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
// Force the dialog about executables at this point and fail if there is none
if (localRunConfiguration->executable().isEmpty()) {
if (errorMessage)
*errorMessage = tr("No executable");
if (!localRunConfiguration->ensureConfigured(errorMessage))
return 0;
}
return new LocalApplicationRunControl(localRunConfiguration, mode);
}

View File

@@ -1565,10 +1565,14 @@ void ProjectExplorerPlugin::buildStateChanged(Project * pro)
void ProjectExplorerPlugin::executeRunConfiguration(RunConfiguration *runConfiguration, RunMode runMode)
{
QString errorMessage;
if (!runConfiguration->ensureConfigured(&errorMessage)) {
showRunErrorMessage(errorMessage);
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);

View File

@@ -322,6 +322,16 @@ bool RunConfiguration::isConfigured() const
return true;
}
bool RunConfiguration::ensureConfigured(QString *errorMessage)
{
if (isConfigured())
return true;
if (errorMessage)
*errorMessage = tr("Unknown error.");
return false;
}
/*!
\fn virtual QWidget *ProjectExplorer::RunConfiguration::createConfigurationWidget()

View File

@@ -151,6 +151,8 @@ public:
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);
Target *target() const;

View File

@@ -45,6 +45,7 @@
#include <QDialog>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>
@@ -119,51 +120,106 @@ void CustomExecutableRunConfiguration::activeBuildConfigurationChanged()
}
}
QString CustomExecutableRunConfiguration::executable() const
// Dialog embedding the CustomExecutableConfigurationWidget
// prompting the user to complete the configuration.
class CustomExecutableDialog : public QDialog
{
Utils::Environment env = environment();
QString exec = env.searchInPath(Utils::expandMacros(m_executable, macroExpander()),
QStringList() << workingDirectory());
Q_OBJECT
public:
explicit CustomExecutableDialog(CustomExecutableRunConfiguration *rc, QWidget *parent = 0);
if (exec.isEmpty() || !QFileInfo(exec).exists()) {
// Oh the executable doesn't exists, ask the user.
CustomExecutableRunConfiguration *that = const_cast<CustomExecutableRunConfiguration *>(this);
QWidget *confWidget = that->createConfigurationWidget();
confWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
QDialog dialog(Core::ICore::mainWindow());
dialog.setWindowTitle(displayName());
dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
dialog.setLayout(new QVBoxLayout());
private slots:
void changed()
{
setOkButtonEnabled(m_runConfiguration->isConfigured());
}
private:
inline void setOkButtonEnabled(bool e)
{
m_dialogButtonBox->button(QDialogButtonBox::Ok)->setEnabled(e);
}
QDialogButtonBox *m_dialogButtonBox;
CustomExecutableRunConfiguration *m_runConfiguration;
};
CustomExecutableDialog::CustomExecutableDialog(CustomExecutableRunConfiguration *rc, QWidget *parent)
: QDialog(parent)
, m_dialogButtonBox(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel))
, m_runConfiguration(rc)
{
connect(rc, SIGNAL(changed()), this, SLOT(changed()));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
QVBoxLayout *layout = new QVBoxLayout(this);
QLabel *label = new QLabel(tr("Could not find the executable, please specify one."));
label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
dialog.layout()->addWidget(label);
dialog.layout()->addWidget(confWidget);
QDialogButtonBox *dbb = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(dbb, SIGNAL(accepted()), &dialog, SLOT(accept()));
connect(dbb, SIGNAL(rejected()), &dialog, SLOT(reject()));
dialog.layout()->addWidget(dbb);
dialog.layout()->setSizeConstraint(QLayout::SetMinAndMaxSize);
layout->addWidget(label);
QWidget *configWidget = rc->createConfigurationWidget();
configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
layout->addWidget(configWidget);
setOkButtonEnabled(false);
connect(m_dialogButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(m_dialogButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
layout->addWidget(m_dialogButtonBox);
layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
}
QString oldExecutable = m_executable;
QString oldWorkingDirectory = m_workingDirectory;
QString oldCmdArguments = m_cmdArguments;
if (dialog.exec() == QDialog::Accepted) {
return executable();
} else {
bool 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 (that->m_executable != oldExecutable
|| that->m_workingDirectory != oldWorkingDirectory
|| that->m_cmdArguments != oldCmdArguments) {
that->m_executable = oldExecutable;
that->m_workingDirectory = oldWorkingDirectory;
that->m_cmdArguments = oldCmdArguments;
emit that->changed();
if (m_executable != oldExecutable
|| m_workingDirectory != oldWorkingDirectory
|| m_cmdArguments != oldCmdArguments) {
m_executable = oldExecutable;
m_workingDirectory = oldWorkingDirectory;
m_cmdArguments = oldCmdArguments;
emit changed();
}
return QString();
return false;
}
// Search the executable in the path.
bool CustomExecutableRunConfiguration::validateExecutable(QString *executable, QString *errorMessage) const
{
if (executable)
executable->clear();
if (m_executable.isEmpty()) {
if (errorMessage)
*errorMessage = tr("No executable.");
return false;
}
const Utils::Environment env = environment();
const QString exec = env.searchInPath(Utils::expandMacros(m_executable, macroExpander()),
QStringList(workingDirectory()));
if (exec.isEmpty()) {
if (errorMessage)
*errorMessage = tr("The executable\n%1\ncannot be found in the path.").
arg(QDir::toNativeSeparators(m_executable));
return false;
}
return QDir::cleanPath(exec);
if (executable)
*executable = QDir::cleanPath(exec);
return true;
}
QString CustomExecutableRunConfiguration::executable() const
{
QString result;
validateExecutable(&result);
return result;
}
QString CustomExecutableRunConfiguration::rawExecutable() const
@@ -426,3 +482,5 @@ QString CustomExecutableRunConfigurationFactory::displayNameForId(const Core::Id
return tr("Custom Executable");
return QString();
}
#include "customexecutablerunconfiguration.moc"

View File

@@ -80,6 +80,8 @@ public:
QVariantMap toMap() const;
bool ensureConfigured(QString *errorMessage);
signals:
void changed();
@@ -116,6 +118,7 @@ private:
QString baseWorkingDirectory() const;
void setUserName(const QString &name);
void setRunMode(ProjectExplorer::LocalApplicationRunConfiguration::RunMode runMode);
bool validateExecutable(QString *executable = 0, QString *errorMessage = 0) const;
QString m_executable;
QString m_workingDirectory;