Commit e202e4b8 authored by Daniel Teske's avatar Daniel Teske

Fix various crashes

Task-Number: QTCREATORBUG-6365

Change-Id: I19a200e3c811eef83d591f6eacca3e48eb0fba8f
Reviewed-by: default avatarTobias Hunger <tobias.hunger@nokia.com>
parent 2fb8e135
......@@ -89,6 +89,8 @@ struct BuildManagerPrivate {
QString m_currentConfiguration;
// used to decide if we are building a project to decide when to emit buildStateChanged(Project *)
QHash<Project *, int> m_activeBuildSteps;
QHash<Target *, int> m_activeBuildStepsPerTarget;
QHash<ProjectConfiguration *, int> m_activeBuildStepsPerProjectConfiguration;
Project *m_previousBuildStepProject;
// is set to true while canceling, so that nextBuildStep knows that the BuildStep finished because of canceling
bool m_canceling;
......@@ -221,7 +223,7 @@ void BuildManager::cancel()
QTimer::singleShot(0, this, SLOT(emitCancelMessage()));
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
clearBuildQueue();
......@@ -256,7 +258,7 @@ void BuildManager::emitCancelMessage()
void BuildManager::clearBuildQueue()
{
foreach (BuildStep *bs, d->m_buildQueue) {
decrementActiveBuildSteps(bs->buildConfiguration()->target()->project());
decrementActiveBuildSteps(bs);
disconnectOutput(bs);
}
......@@ -382,7 +384,7 @@ void BuildManager::nextBuildQueue()
disconnectOutput(d->m_currentBuildStep);
++d->m_progress;
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();
if (!result) {
......@@ -491,7 +493,7 @@ bool BuildManager::buildQueueAppend(QList<BuildStep *> steps)
for (i = 0; i < count; ++i) {
++d->m_maxProgress;
d->m_buildQueue.append(steps.at(i));
incrementActiveBuildSteps(steps.at(i)->buildConfiguration()->target()->project());
incrementActiveBuildSteps(steps.at(i));
}
return true;
}
......@@ -531,14 +533,29 @@ void BuildManager::appendStep(BuildStep *step)
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)
{
QHash<Project *, int>::iterator it = d->m_activeBuildSteps.find(pro);
QHash<Project *, int>::iterator end = d->m_activeBuildSteps.end();
if (it == end || *it == 0)
return false;
else
return true;
return count(d->m_activeBuildSteps, pro) > 0;
}
bool BuildManager::isBuilding(Target *t)
{
return count(d->m_activeBuildStepsPerTarget, t) > 0;
}
bool BuildManager::isBuilding(ProjectConfiguration *p)
{
return count(d->m_activeBuildStepsPerProjectConfiguration, p) > 0;
}
bool BuildManager::isBuilding(BuildStep *step)
......@@ -546,33 +563,51 @@ bool BuildManager::isBuilding(BuildStep *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);
QHash<Project *, int>::iterator end = d->m_activeBuildSteps.end();
typename QHash<T *, int>::iterator it = hash.find(key);
typename QHash<T *, int>::iterator end = hash.end();
if (it == end) {
d->m_activeBuildSteps.insert(pro, 1);
emit buildStateChanged(pro);
hash.insert(key, 1);
return true;
} else if (*it == 0) {
++*it;
emit buildStateChanged(pro);
return true;
} else {
++*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);
QHash<Project *, int>::iterator end = d->m_activeBuildSteps.end();
typename QHash<T *, int>::iterator it = hash.find(key);
typename QHash<T *, int>::iterator end = hash.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) {
--*it;
emit buildStateChanged(pro);
return true;
} else {
--*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)
......
......@@ -63,6 +63,8 @@ public:
bool buildLists(QList<BuildStepList *> bsls);
bool buildList(BuildStepList *bsl);
bool isBuilding(Project *p);
bool isBuilding(Target *t);
bool isBuilding(ProjectConfiguration *p);
bool isBuilding(BuildStep *step);
// 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 clearBuildQueue();
bool buildQueueAppend(QList<BuildStep *> steps);
void incrementActiveBuildSteps(Project *pro);
void decrementActiveBuildSteps(Project *pro);
void incrementActiveBuildSteps(BuildStep *bs);
void decrementActiveBuildSteps(BuildStep *bs);
void disconnectOutput(BuildStep *bs);
BuildManagerPrivate *d;
......
......@@ -42,6 +42,8 @@
#include <coreplugin/coreconstants.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/qtcassert.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/buildmanager.h>
#include <QtCore/QMargins>
#include <QtCore/QTimer>
......@@ -370,6 +372,29 @@ void BuildSettingsWidget::deleteConfiguration(BuildConfiguration *deleteConfigur
m_target->buildConfigurations().size() <= 1)
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);
updateBuildSettings();
......
......@@ -156,11 +156,21 @@ DeployConfiguration *BuildStep::deployConfiguration() const
return dc;
}
ProjectConfiguration *BuildStep::projectConfiguration() const
{
return static_cast<ProjectConfiguration *>(parent()->parent());
}
Target *BuildStep::target() const
{
return qobject_cast<Target *>(parent()->parent()->parent());
}
Project *BuildStep::project() const
{
return target()->project();
}
bool BuildStep::immutable() const
{
return false;
......
......@@ -72,7 +72,9 @@ public:
BuildConfiguration *buildConfiguration() const;
DeployConfiguration *deployConfiguration() const;
ProjectConfiguration *projectConfiguration() const;
Target *target() const;
Project *project() const;
enum OutputFormat { NormalOutput, ErrorOutput, MessageOutput, ErrorMessageOutput };
enum OutputNewlineSetting { DoAppendNewline, DontAppendNewline };
......
......@@ -43,6 +43,7 @@
#include <coreplugin/ifile.h>
#include <coreplugin/icontext.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/buildmanager.h>
#include <limits>
#include <utils/qtcassert.h>
......@@ -166,9 +167,15 @@ void Project::addTarget(Target *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);
......
......@@ -83,7 +83,7 @@ public:
// Target:
void addTarget(Target *target);
void removeTarget(Target *target);
bool removeTarget(Target *target);
QList<Target *> targets() const;
// Note: activeTarget can be 0 (if no targets are defined).
......
......@@ -1031,6 +1031,20 @@ void ProjectExplorerPlugin::unloadProject()
if (debug)
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();
if (!fi || fi->fileName().isEmpty()) //nothing to save?
......
......@@ -42,6 +42,8 @@
#include <coreplugin/coreconstants.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/buildmanager.h>
#include <utils/qtcassert.h>
#include <QtCore/QPair>
......@@ -389,15 +391,31 @@ void RunSettingsWidget::addDeployConfiguration()
void RunSettingsWidget::removeDeployConfiguration()
{
DeployConfiguration *dc = m_target->activeDeployConfiguration();
QMessageBox msgBox(QMessageBox::Question, tr("Remove Deploy Configuration?"),
tr("Do you really want to delete deploy configuration <b>%1</b>?").arg(dc->displayName()),
QMessageBox::Yes|QMessageBox::No, this);
msgBox.setDefaultButton(QMessageBox::No);
msgBox.setEscapeButton(QMessageBox::No);
if (msgBox.exec() == QMessageBox::No)
return;
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?"),
tr("Do you really want to delete deploy configuration <b>%1</b>?").arg(dc->displayName()),
QMessageBox::Yes|QMessageBox::No, this);
msgBox.setDefaultButton(QMessageBox::No);
msgBox.setEscapeButton(QMessageBox::No);
if (msgBox.exec() == QMessageBox::No)
return;
}
m_target->removeDeployConfiguration(dc);
m_removeDeployToolButton->setEnabled(m_target->deployConfigurations().size() > 1);
}
......
......@@ -42,6 +42,8 @@
#include <limits>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <utils/qtcassert.h>
#include <QtGui/QIcon>
......@@ -174,11 +176,16 @@ void Target::addBuildConfiguration(BuildConfiguration *configuration)
setActiveBuildConfiguration(configuration);
}
void Target::removeBuildConfiguration(BuildConfiguration *configuration)
bool Target::removeBuildConfiguration(BuildConfiguration *configuration)
{
//todo: this might be error prone
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);
......@@ -192,6 +199,7 @@ void Target::removeBuildConfiguration(BuildConfiguration *configuration)
}
delete configuration;
return true;
}
QList<BuildConfiguration *> Target::buildConfigurations() const
......@@ -242,11 +250,16 @@ void Target::addDeployConfiguration(DeployConfiguration *dc)
Q_ASSERT(activeDeployConfiguration());
}
void Target::removeDeployConfiguration(DeployConfiguration *dc)
bool Target::removeDeployConfiguration(DeployConfiguration *dc)
{
//todo: this might be error prone
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);
......@@ -260,6 +273,7 @@ void Target::removeDeployConfiguration(DeployConfiguration *dc)
}
delete dc;
return true;
}
QList<DeployConfiguration *> Target::deployConfigurations() const
......
......@@ -67,7 +67,7 @@ public:
// Build configuration
void addBuildConfiguration(BuildConfiguration *configuration);
void removeBuildConfiguration(BuildConfiguration *configuration);
bool removeBuildConfiguration(BuildConfiguration *configuration);
QList<BuildConfiguration *> buildConfigurations() const;
virtual BuildConfiguration *activeBuildConfiguration() const;
......@@ -77,7 +77,7 @@ public:
// DeployConfiguration
void addDeployConfiguration(DeployConfiguration *dc);
void removeDeployConfiguration(DeployConfiguration *dc);
bool removeDeployConfiguration(DeployConfiguration *dc);
QList<DeployConfiguration *> deployConfigurations() const;
virtual DeployConfiguration *activeDeployConfiguration() const;
......
......@@ -40,6 +40,8 @@
#include "targetsettingswidget.h"
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/buildmanager.h>
#include <QtCore/QCoreApplication>
#include <QtGui/QLabel>
......@@ -47,6 +49,7 @@
#include <QtGui/QMessageBox>
#include <QtGui/QVBoxLayout>
#include <QtGui/QStackedWidget>
#include <QtGui/QPushButton>
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;
......@@ -230,13 +233,33 @@ void TargetSettingsPanelWidget::removeTarget()
{
int index = m_selector->currentIndex();
Target *t = m_targets.at(index);
int ret = QMessageBox::warning(this, tr("Qt Creator"),
tr("Do you really want to remove the\n"
"\"%1\" target?").arg(t->displayName()),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);
if (ret == QMessageBox::Yes)
m_project->removeTarget(t);
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"),
tr("Do you really want to remove the\n"
"\"%1\" target?").arg(t->displayName()),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);
if (ret != QMessageBox::Yes)
return;
}
m_project->removeTarget(t);
}
void TargetSettingsPanelWidget::targetAdded(ProjectExplorer::Target *target)
......
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