Fix various crashes

Task-Number: QTCREATORBUG-6365

Change-Id: I19a200e3c811eef83d591f6eacca3e48eb0fba8f
Reviewed-by: Tobias Hunger <tobias.hunger@nokia.com>
This commit is contained in:
Daniel Teske
2011-10-24 13:10:38 +00:00
parent 2fb8e13529
commit e202e4b8e0
12 changed files with 196 additions and 46 deletions

View File

@@ -89,6 +89,8 @@ struct BuildManagerPrivate {
QString m_currentConfiguration; QString m_currentConfiguration;
// used to decide if we are building a project to decide when to emit buildStateChanged(Project *) // used to decide if we are building a project to decide when to emit buildStateChanged(Project *)
QHash<Project *, int> m_activeBuildSteps; QHash<Project *, int> m_activeBuildSteps;
QHash<Target *, int> m_activeBuildStepsPerTarget;
QHash<ProjectConfiguration *, int> m_activeBuildStepsPerProjectConfiguration;
Project *m_previousBuildStepProject; Project *m_previousBuildStepProject;
// is set to true while canceling, so that nextBuildStep knows that the BuildStep finished because of canceling // is set to true while canceling, so that nextBuildStep knows that the BuildStep finished because of canceling
bool m_canceling; bool m_canceling;
@@ -221,7 +223,7 @@ void BuildManager::cancel()
QTimer::singleShot(0, this, SLOT(emitCancelMessage())); QTimer::singleShot(0, this, SLOT(emitCancelMessage()));
disconnectOutput(d->m_currentBuildStep); disconnectOutput(d->m_currentBuildStep);
decrementActiveBuildSteps(d->m_currentBuildStep->buildConfiguration()->target()->project()); decrementActiveBuildSteps(d->m_currentBuildStep);
d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100, tr("Build canceled")); //TODO NBS fix in qtconcurrent d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100, tr("Build canceled")); //TODO NBS fix in qtconcurrent
clearBuildQueue(); clearBuildQueue();
@@ -256,7 +258,7 @@ void BuildManager::emitCancelMessage()
void BuildManager::clearBuildQueue() void BuildManager::clearBuildQueue()
{ {
foreach (BuildStep *bs, d->m_buildQueue) { foreach (BuildStep *bs, d->m_buildQueue) {
decrementActiveBuildSteps(bs->buildConfiguration()->target()->project()); decrementActiveBuildSteps(bs);
disconnectOutput(bs); disconnectOutput(bs);
} }
@@ -382,7 +384,7 @@ void BuildManager::nextBuildQueue()
disconnectOutput(d->m_currentBuildStep); disconnectOutput(d->m_currentBuildStep);
++d->m_progress; ++d->m_progress;
d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100, msgProgress(d->m_progress, d->m_maxProgress)); d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100, msgProgress(d->m_progress, d->m_maxProgress));
decrementActiveBuildSteps(d->m_currentBuildStep->buildConfiguration()->target()->project()); decrementActiveBuildSteps(d->m_currentBuildStep);
bool result = d->m_watcher.result(); bool result = d->m_watcher.result();
if (!result) { if (!result) {
@@ -491,7 +493,7 @@ bool BuildManager::buildQueueAppend(QList<BuildStep *> steps)
for (i = 0; i < count; ++i) { for (i = 0; i < count; ++i) {
++d->m_maxProgress; ++d->m_maxProgress;
d->m_buildQueue.append(steps.at(i)); d->m_buildQueue.append(steps.at(i));
incrementActiveBuildSteps(steps.at(i)->buildConfiguration()->target()->project()); incrementActiveBuildSteps(steps.at(i));
} }
return true; return true;
} }
@@ -531,14 +533,29 @@ void BuildManager::appendStep(BuildStep *step)
startBuildQueue(); startBuildQueue();
} }
template <class T>
int count(const QHash<T *, int> &hash, T *key)
{
typename QHash<T *, int>::const_iterator it = hash.find(key);
typename QHash<T *, int>::const_iterator end = hash.end();
if (it != end)
return *it;
return 0;
}
bool BuildManager::isBuilding(Project *pro) bool BuildManager::isBuilding(Project *pro)
{ {
QHash<Project *, int>::iterator it = d->m_activeBuildSteps.find(pro); return count(d->m_activeBuildSteps, pro) > 0;
QHash<Project *, int>::iterator end = d->m_activeBuildSteps.end(); }
if (it == end || *it == 0)
return false; bool BuildManager::isBuilding(Target *t)
else {
return true; return count(d->m_activeBuildStepsPerTarget, t) > 0;
}
bool BuildManager::isBuilding(ProjectConfiguration *p)
{
return count(d->m_activeBuildStepsPerProjectConfiguration, p) > 0;
} }
bool BuildManager::isBuilding(BuildStep *step) bool BuildManager::isBuilding(BuildStep *step)
@@ -546,33 +563,51 @@ bool BuildManager::isBuilding(BuildStep *step)
return (d->m_currentBuildStep == step) || d->m_buildQueue.contains(step); return (d->m_currentBuildStep == step) || d->m_buildQueue.contains(step);
} }
void BuildManager::incrementActiveBuildSteps(Project *pro) template <class T> bool increment(QHash<T *, int> &hash, T *key)
{ {
QHash<Project *, int>::iterator it = d->m_activeBuildSteps.find(pro); typename QHash<T *, int>::iterator it = hash.find(key);
QHash<Project *, int>::iterator end = d->m_activeBuildSteps.end(); typename QHash<T *, int>::iterator end = hash.end();
if (it == end) { if (it == end) {
d->m_activeBuildSteps.insert(pro, 1); hash.insert(key, 1);
emit buildStateChanged(pro); return true;
} else if (*it == 0) { } else if (*it == 0) {
++*it; ++*it;
emit buildStateChanged(pro); return true;
} else { } else {
++*it; ++*it;
} }
return false;
} }
void BuildManager::decrementActiveBuildSteps(Project *pro) template <class T> bool decrement(QHash<T *, int> &hash, T *key)
{ {
QHash<Project *, int>::iterator it = d->m_activeBuildSteps.find(pro); typename QHash<T *, int>::iterator it = hash.find(key);
QHash<Project *, int>::iterator end = d->m_activeBuildSteps.end(); typename QHash<T *, int>::iterator end = hash.end();
if (it == end) { if (it == end) {
Q_ASSERT(false && "BuildManager d->m_activeBuildSteps says project is not building, but apparently a build step was still in the queue."); // Can't happen
} else if (*it == 1) { } else if (*it == 1) {
--*it; --*it;
emit buildStateChanged(pro); return true;
} else { } else {
--*it; --*it;
} }
return false;
}
void BuildManager::incrementActiveBuildSteps(BuildStep *bs)
{
increment<ProjectConfiguration>(d->m_activeBuildStepsPerProjectConfiguration, bs->projectConfiguration());
increment<Target>(d->m_activeBuildStepsPerTarget, bs->target());
if (increment<Project>(d->m_activeBuildSteps, bs->project()))
emit buildStateChanged(bs->project());
}
void BuildManager::decrementActiveBuildSteps(BuildStep *bs)
{
decrement<ProjectConfiguration>(d->m_activeBuildStepsPerProjectConfiguration, bs->projectConfiguration());
decrement<Target>(d->m_activeBuildStepsPerTarget, bs->target());
if (decrement<Project>(d->m_activeBuildSteps, bs->project()))
emit buildStateChanged(bs->project());
} }
void BuildManager::disconnectOutput(BuildStep *bs) void BuildManager::disconnectOutput(BuildStep *bs)

View File

@@ -63,6 +63,8 @@ public:
bool buildLists(QList<BuildStepList *> bsls); bool buildLists(QList<BuildStepList *> bsls);
bool buildList(BuildStepList *bsl); bool buildList(BuildStepList *bsl);
bool isBuilding(Project *p); bool isBuilding(Project *p);
bool isBuilding(Target *t);
bool isBuilding(ProjectConfiguration *p);
bool isBuilding(BuildStep *step); bool isBuilding(BuildStep *step);
// Append any build step to the list of build steps (currently only used to add the QMakeStep) // Append any build step to the list of build steps (currently only used to add the QMakeStep)
@@ -102,8 +104,8 @@ private:
void nextStep(); void nextStep();
void clearBuildQueue(); void clearBuildQueue();
bool buildQueueAppend(QList<BuildStep *> steps); bool buildQueueAppend(QList<BuildStep *> steps);
void incrementActiveBuildSteps(Project *pro); void incrementActiveBuildSteps(BuildStep *bs);
void decrementActiveBuildSteps(Project *pro); void decrementActiveBuildSteps(BuildStep *bs);
void disconnectOutput(BuildStep *bs); void disconnectOutput(BuildStep *bs);
BuildManagerPrivate *d; BuildManagerPrivate *d;

View File

@@ -42,6 +42,8 @@
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/buildmanager.h>
#include <QtCore/QMargins> #include <QtCore/QMargins>
#include <QtCore/QTimer> #include <QtCore/QTimer>
@@ -370,6 +372,29 @@ void BuildSettingsWidget::deleteConfiguration(BuildConfiguration *deleteConfigur
m_target->buildConfigurations().size() <= 1) m_target->buildConfigurations().size() <= 1)
return; return;
ProjectExplorer::BuildManager *bm = ProjectExplorerPlugin::instance()->buildManager();
if (bm->isBuilding(deleteConfiguration)) {
QMessageBox box;
QPushButton *closeAnyway = box.addButton(tr("Cancel Build && Remove Build Configuration"), QMessageBox::AcceptRole);
QPushButton *cancelClose = box.addButton(tr("Do Not Remove"), QMessageBox::RejectRole);
box.setDefaultButton(cancelClose);
box.setWindowTitle(tr("Remove Build Configuration %1?").arg(deleteConfiguration->displayName()));
box.setText(tr("The build configuration <b>%1</b> is currently being built.").arg(deleteConfiguration->displayName()));
box.setInformativeText(tr("Do you want to cancel the build process and remove the Build Configuration anyway?"));
box.exec();
if (box.clickedButton() != closeAnyway)
return;
bm->cancel();
} else {
QMessageBox msgBox(QMessageBox::Question, tr("Remove Build Configuration?"),
tr("Do you really want to delete build configuration <b>%1</b>?").arg(deleteConfiguration->displayName()),
QMessageBox::Yes|QMessageBox::No, this);
msgBox.setDefaultButton(QMessageBox::No);
msgBox.setEscapeButton(QMessageBox::No);
if (msgBox.exec() == QMessageBox::No)
return;
}
m_target->removeBuildConfiguration(deleteConfiguration); m_target->removeBuildConfiguration(deleteConfiguration);
updateBuildSettings(); updateBuildSettings();

View File

@@ -156,11 +156,21 @@ DeployConfiguration *BuildStep::deployConfiguration() const
return dc; return dc;
} }
ProjectConfiguration *BuildStep::projectConfiguration() const
{
return static_cast<ProjectConfiguration *>(parent()->parent());
}
Target *BuildStep::target() const Target *BuildStep::target() const
{ {
return qobject_cast<Target *>(parent()->parent()->parent()); return qobject_cast<Target *>(parent()->parent()->parent());
} }
Project *BuildStep::project() const
{
return target()->project();
}
bool BuildStep::immutable() const bool BuildStep::immutable() const
{ {
return false; return false;

View File

@@ -72,7 +72,9 @@ public:
BuildConfiguration *buildConfiguration() const; BuildConfiguration *buildConfiguration() const;
DeployConfiguration *deployConfiguration() const; DeployConfiguration *deployConfiguration() const;
ProjectConfiguration *projectConfiguration() const;
Target *target() const; Target *target() const;
Project *project() const;
enum OutputFormat { NormalOutput, ErrorOutput, MessageOutput, ErrorMessageOutput }; enum OutputFormat { NormalOutput, ErrorOutput, MessageOutput, ErrorMessageOutput };
enum OutputNewlineSetting { DoAppendNewline, DontAppendNewline }; enum OutputNewlineSetting { DoAppendNewline, DontAppendNewline };

View File

@@ -43,6 +43,7 @@
#include <coreplugin/ifile.h> #include <coreplugin/ifile.h>
#include <coreplugin/icontext.h> #include <coreplugin/icontext.h>
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <projectexplorer/buildmanager.h>
#include <limits> #include <limits>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -166,9 +167,15 @@ void Project::addTarget(Target *t)
setActiveTarget(t); setActiveTarget(t);
} }
void Project::removeTarget(Target *target) bool Project::removeTarget(Target *target)
{ {
QTC_ASSERT(target && d->m_targets.contains(target), return); if (!target || !d->m_targets.contains(target))
return false;
ProjectExplorer::BuildManager *bm =
ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager();
if (bm->isBuilding(target))
return false;
emit aboutToRemoveTarget(target); emit aboutToRemoveTarget(target);

View File

@@ -83,7 +83,7 @@ public:
// Target: // Target:
void addTarget(Target *target); void addTarget(Target *target);
void removeTarget(Target *target); bool removeTarget(Target *target);
QList<Target *> targets() const; QList<Target *> targets() const;
// Note: activeTarget can be 0 (if no targets are defined). // Note: activeTarget can be 0 (if no targets are defined).

View File

@@ -1031,6 +1031,20 @@ void ProjectExplorerPlugin::unloadProject()
if (debug) if (debug)
qDebug() << "ProjectExplorerPlugin::unloadProject"; qDebug() << "ProjectExplorerPlugin::unloadProject";
if (buildManager()->isBuilding(d->m_currentProject)) {
QMessageBox box;
QPushButton *closeAnyway = box.addButton(tr("Cancel Build && Unload"), QMessageBox::AcceptRole);
QPushButton *cancelClose = box.addButton(tr("Do Not Unload"), QMessageBox::RejectRole);
box.setDefaultButton(cancelClose);
box.setWindowTitle(tr("Unload Project %1?").arg(d->m_currentProject->displayName()));
box.setText(tr("The project %1 is currently being built.").arg(d->m_currentProject->displayName()));
box.setInformativeText(tr("Do you want to cancel the build process and unload the project anyway?"));
box.exec();
if (box.clickedButton() != closeAnyway)
return;
buildManager()->cancel();
}
Core::IFile *fi = d->m_currentProject->file(); Core::IFile *fi = d->m_currentProject->file();
if (!fi || fi->fileName().isEmpty()) //nothing to save? if (!fi || fi->fileName().isEmpty()) //nothing to save?

View File

@@ -42,6 +42,8 @@
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/buildmanager.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QtCore/QPair> #include <QtCore/QPair>
@@ -389,6 +391,20 @@ void RunSettingsWidget::addDeployConfiguration()
void RunSettingsWidget::removeDeployConfiguration() void RunSettingsWidget::removeDeployConfiguration()
{ {
DeployConfiguration *dc = m_target->activeDeployConfiguration(); DeployConfiguration *dc = m_target->activeDeployConfiguration();
ProjectExplorer::BuildManager *bm = ProjectExplorerPlugin::instance()->buildManager();
if (bm->isBuilding(dc)) {
QMessageBox box;
QPushButton *closeAnyway = box.addButton(tr("Cancel Build && Remove Deploy Configuration"), QMessageBox::AcceptRole);
QPushButton *cancelClose = box.addButton(tr("Do Not Remove"), QMessageBox::RejectRole);
box.setDefaultButton(cancelClose);
box.setWindowTitle(tr("Remove Deploy Configuration %1?").arg(dc->displayName()));
box.setText(tr("The deploy configuration <b>%1</b> is currently being built.").arg(dc->displayName()));
box.setInformativeText(tr("Do you want to cancel the build process and remove the Deploy Configuration anyway?"));
box.exec();
if (box.clickedButton() != closeAnyway)
return;
bm->cancel();
} else {
QMessageBox msgBox(QMessageBox::Question, tr("Remove Deploy Configuration?"), QMessageBox msgBox(QMessageBox::Question, tr("Remove Deploy Configuration?"),
tr("Do you really want to delete deploy configuration <b>%1</b>?").arg(dc->displayName()), tr("Do you really want to delete deploy configuration <b>%1</b>?").arg(dc->displayName()),
QMessageBox::Yes|QMessageBox::No, this); QMessageBox::Yes|QMessageBox::No, this);
@@ -396,8 +412,10 @@ void RunSettingsWidget::removeDeployConfiguration()
msgBox.setEscapeButton(QMessageBox::No); msgBox.setEscapeButton(QMessageBox::No);
if (msgBox.exec() == QMessageBox::No) if (msgBox.exec() == QMessageBox::No)
return; return;
}
m_target->removeDeployConfiguration(dc); m_target->removeDeployConfiguration(dc);
m_removeDeployToolButton->setEnabled(m_target->deployConfigurations().size() > 1); m_removeDeployToolButton->setEnabled(m_target->deployConfigurations().size() > 1);
} }

View File

@@ -42,6 +42,8 @@
#include <limits> #include <limits>
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QtGui/QIcon> #include <QtGui/QIcon>
@@ -174,11 +176,16 @@ void Target::addBuildConfiguration(BuildConfiguration *configuration)
setActiveBuildConfiguration(configuration); setActiveBuildConfiguration(configuration);
} }
void Target::removeBuildConfiguration(BuildConfiguration *configuration) bool Target::removeBuildConfiguration(BuildConfiguration *configuration)
{ {
//todo: this might be error prone //todo: this might be error prone
if (!d->m_buildConfigurations.contains(configuration)) if (!d->m_buildConfigurations.contains(configuration))
return; return false;
ProjectExplorer::BuildManager *bm =
ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager();
if (bm->isBuilding(configuration))
return false;
d->m_buildConfigurations.removeOne(configuration); d->m_buildConfigurations.removeOne(configuration);
@@ -192,6 +199,7 @@ void Target::removeBuildConfiguration(BuildConfiguration *configuration)
} }
delete configuration; delete configuration;
return true;
} }
QList<BuildConfiguration *> Target::buildConfigurations() const QList<BuildConfiguration *> Target::buildConfigurations() const
@@ -242,11 +250,16 @@ void Target::addDeployConfiguration(DeployConfiguration *dc)
Q_ASSERT(activeDeployConfiguration()); Q_ASSERT(activeDeployConfiguration());
} }
void Target::removeDeployConfiguration(DeployConfiguration *dc) bool Target::removeDeployConfiguration(DeployConfiguration *dc)
{ {
//todo: this might be error prone //todo: this might be error prone
if (!d->m_deployConfigurations.contains(dc)) if (!d->m_deployConfigurations.contains(dc))
return; return false;
ProjectExplorer::BuildManager *bm =
ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager();
if (bm->isBuilding(dc))
return false;
d->m_deployConfigurations.removeOne(dc); d->m_deployConfigurations.removeOne(dc);
@@ -260,6 +273,7 @@ void Target::removeDeployConfiguration(DeployConfiguration *dc)
} }
delete dc; delete dc;
return true;
} }
QList<DeployConfiguration *> Target::deployConfigurations() const QList<DeployConfiguration *> Target::deployConfigurations() const

View File

@@ -67,7 +67,7 @@ public:
// Build configuration // Build configuration
void addBuildConfiguration(BuildConfiguration *configuration); void addBuildConfiguration(BuildConfiguration *configuration);
void removeBuildConfiguration(BuildConfiguration *configuration); bool removeBuildConfiguration(BuildConfiguration *configuration);
QList<BuildConfiguration *> buildConfigurations() const; QList<BuildConfiguration *> buildConfigurations() const;
virtual BuildConfiguration *activeBuildConfiguration() const; virtual BuildConfiguration *activeBuildConfiguration() const;
@@ -77,7 +77,7 @@ public:
// DeployConfiguration // DeployConfiguration
void addDeployConfiguration(DeployConfiguration *dc); void addDeployConfiguration(DeployConfiguration *dc);
void removeDeployConfiguration(DeployConfiguration *dc); bool removeDeployConfiguration(DeployConfiguration *dc);
QList<DeployConfiguration *> deployConfigurations() const; QList<DeployConfiguration *> deployConfigurations() const;
virtual DeployConfiguration *activeDeployConfiguration() const; virtual DeployConfiguration *activeDeployConfiguration() const;

View File

@@ -40,6 +40,8 @@
#include "targetsettingswidget.h" #include "targetsettingswidget.h"
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/buildmanager.h>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtGui/QLabel> #include <QtGui/QLabel>
@@ -47,6 +49,7 @@
#include <QtGui/QMessageBox> #include <QtGui/QMessageBox>
#include <QtGui/QVBoxLayout> #include <QtGui/QVBoxLayout>
#include <QtGui/QStackedWidget> #include <QtGui/QStackedWidget>
#include <QtGui/QPushButton>
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal; using namespace ProjectExplorer::Internal;
@@ -230,13 +233,33 @@ void TargetSettingsPanelWidget::removeTarget()
{ {
int index = m_selector->currentIndex(); int index = m_selector->currentIndex();
Target *t = m_targets.at(index); Target *t = m_targets.at(index);
ProjectExplorer::BuildManager *bm = ProjectExplorerPlugin::instance()->buildManager();
if (bm->isBuilding(t)) {
QMessageBox box;
QPushButton *closeAnyway = box.addButton(tr("Cancel Build && Remove Target"), QMessageBox::AcceptRole);
QPushButton *cancelClose = box.addButton(tr("Do Not Remove"), QMessageBox::RejectRole);
box.setDefaultButton(cancelClose);
box.setWindowTitle(tr("Remove Target %1?").arg(t->displayName()));
box.setText(tr("The target <b>%1</b> is currently being built.").arg(t->displayName()));
box.setInformativeText(tr("Do you want to cancel the build process and remove the Target anyway?"));
box.exec();
if (box.clickedButton() != closeAnyway)
return;
bm->cancel();
} else {
// We don't show the generic message box on removing the target, if we showed the still building one
int ret = QMessageBox::warning(this, tr("Qt Creator"), int ret = QMessageBox::warning(this, tr("Qt Creator"),
tr("Do you really want to remove the\n" tr("Do you really want to remove the\n"
"\"%1\" target?").arg(t->displayName()), "\"%1\" target?").arg(t->displayName()),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes | QMessageBox::No,
QMessageBox::No); QMessageBox::No);
if (ret == QMessageBox::Yes) if (ret != QMessageBox::Yes)
return;
}
m_project->removeTarget(t); m_project->removeTarget(t);
} }
void TargetSettingsPanelWidget::targetAdded(ProjectExplorer::Target *target) void TargetSettingsPanelWidget::targetAdded(ProjectExplorer::Target *target)