diff options
-rw-r--r-- | src/plugins/projectexplorer/buildmanager.cpp | 44 | ||||
-rw-r--r-- | src/plugins/projectexplorer/buildmanager.h | 1 | ||||
-rw-r--r-- | src/plugins/projectexplorer/buildstep.cpp | 30 | ||||
-rw-r--r-- | src/plugins/projectexplorer/buildstep.h | 4 |
4 files changed, 75 insertions, 4 deletions
diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp index d729439ad6..13f54b1c63 100644 --- a/src/plugins/projectexplorer/buildmanager.cpp +++ b/src/plugins/projectexplorer/buildmanager.cpp @@ -84,6 +84,7 @@ struct BuildManagerPrivate { ProjectExplorerPlugin *m_projectExplorerPlugin; bool m_running; QFutureWatcher<bool> m_watcher; + QFutureInterface<bool> m_futureInterfaceForAysnc; BuildStep *m_currentBuildStep; QString m_currentConfiguration; // used to decide if we are building a project to decide when to emit buildStateChanged(Project *) @@ -91,6 +92,8 @@ struct BuildManagerPrivate { Project *m_previousBuildStepProject; // is set to true while canceling, so that nextBuildStep knows that the BuildStep finished because of canceling bool m_canceling; + bool m_doNotEnterEventLoop; + QEventLoop *m_eventLoop; // Progress reporting to the progress manager int m_progress; @@ -103,6 +106,8 @@ BuildManagerPrivate::BuildManagerPrivate() : m_running(false) , m_previousBuildStepProject(0) , m_canceling(false) + , m_doNotEnterEventLoop(false) + , m_eventLoop(0) , m_maxProgress(0) , m_progressFutureInterface(0) { @@ -190,7 +195,20 @@ void BuildManager::cancel() if (d->m_running) { d->m_canceling = true; d->m_watcher.cancel(); - d->m_watcher.waitForFinished(); + if (d->m_currentBuildStep->runInGuiThread()) { + // This is evil. A nested event loop. + d->m_currentBuildStep->cancel(); + if (d->m_doNotEnterEventLoop) { + d->m_doNotEnterEventLoop = false; + } else { + d->m_eventLoop = new QEventLoop; + d->m_eventLoop->exec(); + delete d->m_eventLoop; + d->m_eventLoop = 0; + } + } else { + d->m_watcher.waitForFinished(); + } // The cancel message is added to the output window via a single shot timer // since the canceling is likely to have generated new addToOutputWindow signals @@ -332,6 +350,21 @@ void BuildManager::addToOutputWindow(const QString &string, BuildStep::OutputFor d->m_outputWindow->appendText(stringToWrite, format); } +void BuildManager::buildStepFinishedAsync() +{ + disconnect(d->m_currentBuildStep, SIGNAL(finished()), + this, SLOT(buildStepFinishedAsync())); + d->m_futureInterfaceForAysnc = QFutureInterface<bool>(); + if (d->m_canceling) { + if (d->m_eventLoop) + d->m_eventLoop->exit(); + else + d->m_doNotEnterEventLoop = true; + } else { + nextBuildQueue(); + } +} + void BuildManager::nextBuildQueue() { if (d->m_canceling) @@ -393,7 +426,14 @@ void BuildManager::nextStep() .arg(projectName), BuildStep::MessageOutput); d->m_previousBuildStepProject = d->m_currentBuildStep->buildConfiguration()->target()->project(); } - d->m_watcher.setFuture(QtConcurrent::run(&BuildStep::run, d->m_currentBuildStep)); + if (d->m_currentBuildStep->runInGuiThread()) { + connect (d->m_currentBuildStep, SIGNAL(finished()), + this, SLOT(buildStepFinishedAsync())); + d->m_watcher.setFuture(d->m_futureInterfaceForAysnc.future()); + d->m_currentBuildStep->run(d->m_futureInterfaceForAysnc); + } else { + d->m_watcher.setFuture(QtConcurrent::run(&BuildStep::run, d->m_currentBuildStep)); + } } else { d->m_running = false; d->m_previousBuildStepProject = 0; diff --git a/src/plugins/projectexplorer/buildmanager.h b/src/plugins/projectexplorer/buildmanager.h index 574a2cc77a..1933cacdc4 100644 --- a/src/plugins/projectexplorer/buildmanager.h +++ b/src/plugins/projectexplorer/buildmanager.h @@ -87,6 +87,7 @@ private slots: void addToOutputWindow(const QString &string, ProjectExplorer::BuildStep::OutputFormat, ProjectExplorer::BuildStep::OutputNewlineSetting = BuildStep::DoAppendNewline); + void buildStepFinishedAsync(); void nextBuildQueue(); void progressChanged(); void progressTextChanged(); diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index e4c397a362..2a5ddaa961 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -69,13 +69,18 @@ \fn void ProjectExplorer::BuildStep::run(QFutureInterface<bool> &fi) Reimplement this. This function is called when the target is build. - This function is NOT run in the gui thread. It runs in its own thread - If you need an event loop, you need to create one. + By default this function is NOT run in the gui thread. It runs in its + own thread. If you need an event loop, you need to create one. + This function should block until the task is done The absolute minimal implementation is: \code fi.reportResult(true); \endcode + + By returning true from \sa runInGuiThread() this function is called in the + gui thread. Then the function should not block and instead the + finished() signal should be emitted. */ /*! @@ -106,6 +111,17 @@ It should be in plain text, with the format in the parameter. */ +/*! + \fn void ProjectExplorer::BuildStep::cancel() const + + This function needs to be reimplemented only for BuildSteps that return false from \sa runInGuiThread. +*/ + +/*! + \fn void ProjectExplorer::BuildStep::finished() + \brief This signal needs to be emitted if the BuildStep runs in the gui thread. +*/ + using namespace ProjectExplorer; BuildStep::BuildStep(BuildStepList *bsl, const QString &id) : @@ -150,6 +166,16 @@ bool BuildStep::immutable() const return false; } +bool BuildStep::runInGuiThread() const +{ + return false; +} + +void BuildStep::cancel() +{ + // Do nothing +} + IBuildStepFactory::IBuildStepFactory(QObject *parent) : QObject(parent) { } diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h index b4b3d116eb..886f6c048f 100644 --- a/src/plugins/projectexplorer/buildstep.h +++ b/src/plugins/projectexplorer/buildstep.h @@ -68,6 +68,8 @@ public: virtual BuildStepConfigWidget *createConfigWidget() = 0; virtual bool immutable() const; + virtual bool runInGuiThread() const; + virtual void cancel(); BuildConfiguration *buildConfiguration() const; DeployConfiguration *deployConfiguration() const; @@ -81,6 +83,8 @@ signals: void addOutput(const QString &string, ProjectExplorer::BuildStep::OutputFormat format, ProjectExplorer::BuildStep::OutputNewlineSetting newlineSetting = DoAppendNewline) const; + + void finished(); }; class PROJECTEXPLORER_EXPORT IBuildStepFactory : |