Commit fe2dd584 authored by Friedemann Kleint's avatar Friedemann Kleint Committed by Daniel Teske

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: default avatarTobias Hunger <tobias.hunger@digia.com>
Reviewed-by: default avatarDaniel Teske <daniel.teske@digia.com>
parent 10352247
......@@ -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);
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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()
......
......@@ -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;
......
......@@ -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
{
Q_OBJECT
public:
explicit CustomExecutableDialog(CustomExecutableRunConfiguration *rc, QWidget *parent = 0);
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);
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);
}
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 (m_executable != oldExecutable
|| m_workingDirectory != oldWorkingDirectory
|| m_cmdArguments != oldCmdArguments) {
m_executable = oldExecutable;
m_workingDirectory = oldWorkingDirectory;
m_cmdArguments = oldCmdArguments;
emit changed();
}
return false;
}
// Search the executable in the path.
bool CustomExecutableRunConfiguration::validateExecutable(QString *executable, QString *errorMessage) const
{
Utils::Environment env = environment();
QString exec = env.searchInPath(Utils::expandMacros(m_executable, macroExpander()),
QStringList() << workingDirectory());
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());
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);
QString oldExecutable = m_executable;
QString oldWorkingDirectory = m_workingDirectory;
QString oldCmdArguments = m_cmdArguments;
if (dialog.exec() == QDialog::Accepted) {
return executable();
} else {
// 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();
}
return QString();
}
if (executable)
executable->clear();
if (m_executable.isEmpty()) {
if (errorMessage)
*errorMessage = tr("No executable.");
return false;
}
return QDir::cleanPath(exec);
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;
}
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"
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment