Commit 6840c1d1 authored by Friedemann Kleint's avatar Friedemann Kleint

Debugger: Refactor run control termination.

Fix breakage introduced by the new asynchronous stop() methods
of the debugger run controls. Allow for RunControl::stop() to
be asynchronous by introducing a return enumeration indicating
that. Introduce additional method aboutToStop() asking user
to quit (tie that to the RunControl instead of having to hack
the behaviour elsewhere).
If asynchronous stop is detected, terminate the ProjectExplorer
asynchronously.
This makes the behaviour consistent across switching sessions/
closing outputwindow tabs and quitting Qt Creator.

Reviewed-by: dt
Rubber-stamped-by: hjk
parent fa68a545
......@@ -454,21 +454,6 @@ public:
}
};
///////////////////////////////////////////////////////////////////////
//
// DebuggerListener: Close the debugging session if running.
//
///////////////////////////////////////////////////////////////////////
class DebuggerListener : public Core::ICoreListener
{
public:
DebuggerListener() {}
virtual bool coreAboutToClose();
};
///////////////////////////////////////////////////////////////////////
//
// LocationMark
......@@ -1554,7 +1539,6 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *er
m_plugin->addAutoReleasedObject(op);
m_plugin->addAutoReleasedObject(new DebuggingHelperOptionPage);
m_plugin->addAutoReleasedObject(new DebuggerListener);
m_locationMark = 0;
//setSimpleDockWidgetArrangement(LANG_CPP);
......@@ -2597,23 +2581,13 @@ void DebuggerPlugin::clearCppCodeModelSnapshot()
ExtensionSystem::IPlugin::ShutdownFlag DebuggerPlugin::aboutToShutdown()
{
disconnect(sessionManager(), SIGNAL(startupProjectChanged(ProjectExplorer::Project*)), d, 0);
writeSettings();
if (d->m_uiSwitcher)
d->m_uiSwitcher->aboutToShutdown();
//if (d->m_engine)
// d->m_engine->shutdown();
// FIXME: Notify all engines instead.
QTimer::singleShot(0, this, SLOT(emitShutdownFinished()));
return AsynchronousShutdown;
return SynchronousShutdown;
}
void DebuggerPlugin::emitShutdownFinished()
{
emit asynchronousShutdownFinished();
}
void DebuggerPlugin::showMessage(const QString &msg, int channel, int timeout)
{
//qDebug() << "PLUGIN OUTPUT: " << channel << msg;
......@@ -2760,63 +2734,35 @@ bool DebuggerPlugin::isRegisterViewVisible() const
return d->m_registerDock->toggleViewAction()->isChecked();
}
bool DebuggerPlugin::coreAboutToClose()
static inline bool canShutDown(DebuggerState s)
{
// FIXME: Iterate over all running debuggers.
// Ask to terminate the session.
bool cleanTermination = false;
switch (d->state()) {
case DebuggerNotReady:
case DebuggerFinished:
case InferiorUnrunnable:
switch (s) {
case DebuggerNotReady:
case DebuggerFinished:
case InferiorUnrunnable:
return true;
case EngineSetupRequested:
case EngineSetupOk:
case EngineSetupFailed:
case InferiorSetupRequested:
case InferiorSetupFailed:
case EngineRunRequested:
case InferiorRunRequested:
case InferiorRunOk:
case InferiorStopRequested:
case InferiorStopOk:
case InferiorShutdownRequested:
case EngineShutdownRequested:
case InferiorShutdownOk:
case InferiorShutdownFailed:
case InferiorStopFailed:
case EngineRunFailed:
case InferiorRunFailed:
case EngineShutdownOk:
case EngineShutdownFailed:
return false;
}
const QString question = cleanTermination ?
QCoreApplication::translate("Debugger::Internal::DebuggerListener",
"A debugging session is still in progress.\n"
"Would you like to terminate it?") :
QCoreApplication::translate("Debugger::Internal::DebuggerListener",
"A debugging session is still in progress. "
"Terminating the session in the current"
" state (%1) can leave the target in an inconsistent state."
" Would you still like to terminate it?")
.arg(_(DebuggerEngine::stateName(d->state())));
const QString title
= QCoreApplication::translate("Debugger::Internal::DebuggerListener",
"Close Debugging Session");
QMessageBox::StandardButton answer =
QMessageBox::question(DebuggerUISwitcher::instance()->mainWindow(),
title, question,
QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
if (answer != QMessageBox::Yes)
return false;
d->exitDebugger();
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
return true;
case EngineSetupRequested:
case EngineSetupOk:
case EngineSetupFailed:
case EngineRunRequested:
case InferiorSetupFailed:
case InferiorShutdownOk:
case InferiorShutdownFailed:
case EngineShutdownRequested:
case EngineRunFailed:
case EngineShutdownOk:
case EngineShutdownFailed:
case InferiorSetupRequested:
case InferiorRunRequested:
case InferiorRunOk:
case InferiorStopRequested:
case InferiorStopOk:
case InferiorStopFailed:
case InferiorShutdownRequested:
case InferiorRunFailed:
break;
}
return false;
}
//////////////////////////////////////////////////////////////////////
......@@ -2836,12 +2782,6 @@ void DebuggerPlugin::runTest(const QString &fileName)
}
*/
bool DebuggerListener::coreAboutToClose()
{
DebuggerPlugin *plugin = DebuggerPlugin::instance();
return plugin && plugin->coreAboutToClose();
}
} // namespace Debugger
#include "debuggerplugin.moc"
......
......@@ -97,13 +97,9 @@ public slots:
private:
friend class Internal::DebuggerEngine;
friend class Internal::DebuggerListener;
friend class DebuggerPluginPrivate;
friend class DebuggerRunControl;
bool coreAboutToClose();
void resetLocation();
void gotoLocation(const QString &fileName, int lineNumber, bool setMarker);
void activatePreviousMode();
......@@ -122,7 +118,6 @@ private:
QMessageBox *showMessageBox(int icon, const QString &title,
const QString &text, int buttons = 0);
Q_SLOT void emitShutdownFinished();
bool initialize(const QStringList &arguments, QString *errorMessage);
ShutdownFlag aboutToShutdown();
void extensionsInitialized();
......
......@@ -34,6 +34,7 @@
#include "debuggerengine.h"
#include "debuggerplugin.h"
#include "debuggerstringutils.h"
#include "debuggeruiswitcher.h"
#ifdef Q_OS_WIN
# include "peutils.h"
......@@ -48,6 +49,7 @@
#include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*
#include <utils/qtcassert.h>
#include <utils/fancymainwindow.h>
#include <coreplugin/icore.h>
#include <QtCore/QDebug>
......@@ -59,6 +61,7 @@
#include <QtGui/QAbstractItemView>
#include <QtGui/QTextDocument>
#include <QtGui/QTreeWidget>
#include <QtGui/QMessageBox>
using namespace ProjectExplorer;
using namespace Debugger::Internal;
......@@ -509,11 +512,27 @@ void DebuggerRunControl::showMessage(const QString &msg, int channel)
}
}
void DebuggerRunControl::stop()
bool DebuggerRunControl::aboutToStop() const
{
m_running = false;
QTC_ASSERT(m_engine, return);
QTC_ASSERT(isRunning(), return true;)
const QString question = tr("A debugging session are still in progress. "
"Terminating the session in the current"
" state can leave the target in an inconsistent state."
" Would you still like to terminate it?");
const QMessageBox::StandardButton answer =
QMessageBox::question(DebuggerUISwitcher::instance()->mainWindow(),
tr("Close Debugging Session"), question,
QMessageBox::Yes|QMessageBox::No);
return answer == QMessageBox::Yes;
}
RunControl::StopResult DebuggerRunControl::stop()
{
QTC_ASSERT(m_engine, return StoppedSynchronously);
m_engine->quitDebugger();
return AsynchronousStop;
}
void DebuggerRunControl::debuggingFinished()
......
......@@ -93,7 +93,8 @@ public:
// ProjectExplorer::RunControl
virtual void start();
virtual void stop();
virtual bool aboutToStop() const;
virtual StopResult stop();
virtual bool isRunning() const;
QString displayName() const;
......
......@@ -123,9 +123,10 @@ void LocalApplicationRunControl::start()
emit appendMessage(this, tr("Starting %1...").arg(QDir::toNativeSeparators(m_executable)), false);
}
void LocalApplicationRunControl::stop()
LocalApplicationRunControl::StopResult LocalApplicationRunControl::stop()
{
m_applicationLauncher.stop();
return StoppedSynchronously;
}
bool LocalApplicationRunControl::isRunning() const
......
......@@ -84,7 +84,7 @@ public:
LocalApplicationRunControl(LocalApplicationRunConfiguration *runConfiguration, QString mode);
virtual ~LocalApplicationRunControl();
virtual void start();
virtual void stop();
virtual StopResult stop();
virtual bool isRunning() const;
private slots:
void processExited(int exitCode);
......
......@@ -28,33 +28,18 @@
**************************************************************************/
#include "corelistenercheckingforrunningbuild.h"
#include "buildmanager.h"
#include <QtGui/QMessageBox>
#include <QtGui/QPushButton>
#include "projectexplorer.h"
namespace ProjectExplorer {
namespace Internal {
CoreListenerCheckingForRunningBuild::CoreListenerCheckingForRunningBuild(BuildManager *manager)
: Core::ICoreListener(0), m_manager(manager)
CoreListener::CoreListener()
{
}
bool CoreListenerCheckingForRunningBuild::coreAboutToClose()
bool CoreListener::coreAboutToClose()
{
if (m_manager->isBuilding()) {
QMessageBox box;
QPushButton *closeAnyway = box.addButton(tr("Cancel Build && Close"), QMessageBox::AcceptRole);
QPushButton *cancelClose = box.addButton(tr("Do not Close"), QMessageBox::RejectRole);
box.setDefaultButton(cancelClose);
box.setWindowTitle(tr("Close Qt Creator?"));
box.setText(tr("A project is currently being built."));
box.setInformativeText(tr("Do you want to cancel the build process and close Qt Creator anyway?"));
box.exec();
return (box.clickedButton() == closeAnyway);
}
return true;
return ProjectExplorerPlugin::instance()->coreAboutToClose();
}
}
......
......@@ -34,20 +34,15 @@
namespace ProjectExplorer {
class BuildManager;
namespace Internal {
class CoreListenerCheckingForRunningBuild : public Core::ICoreListener
class CoreListener : public Core::ICoreListener
{
Q_OBJECT
public:
explicit CoreListenerCheckingForRunningBuild(BuildManager *manager);
CoreListener();
bool coreAboutToClose();
private:
BuildManager *m_manager;
};
} // namespace Internal
......
......@@ -47,6 +47,7 @@
#include <texteditor/basetexteditor.h>
#include <projectexplorer/project.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
#include <utils/qtcassert.h>
#include <QtGui/QIcon>
#include <QtGui/QScrollBar>
......@@ -62,13 +63,26 @@
#include <QtGui/QToolButton>
#include <QtGui/QShowEvent>
using namespace ProjectExplorer::Internal;
using namespace ProjectExplorer;
#include <QtCore/QDebug>
static const int MaxBlockCount = 100000;
OutputPane::OutputPane()
: m_mainWidget(new QWidget)
enum { debug = 0 };
namespace ProjectExplorer {
namespace Internal {
OutputPane::RunControlTab::RunControlTab(RunControl *rc, OutputWindow *w) :
runControl(rc), window(w), asyncClosing(false)
{
}
OutputPane::OutputPane() :
m_mainWidget(new QWidget),
m_tabWidget(new QTabWidget),
m_stopAction(new QAction(QIcon(QLatin1String(Constants::ICON_STOP)), tr("Stop"), this)),
m_reRunButton(new QToolButton),
m_stopButton(new QToolButton)
{
m_runIcon.addFile(Constants::ICON_RUN);
m_runIcon.addFile(Constants::ICON_RUN_SMALL);
......@@ -77,7 +91,6 @@ OutputPane::OutputPane()
m_debugIcon.addFile(Constants::ICON_DEBUG_SMALL);
// Rerun
m_reRunButton = new QToolButton;
m_reRunButton->setIcon(m_runIcon);
m_reRunButton->setToolTip(tr("Re-run this run-configuration"));
m_reRunButton->setAutoRaise(true);
......@@ -89,13 +102,11 @@ OutputPane::OutputPane()
Core::ActionManager *am = Core::ICore::instance()->actionManager();
Core::Context globalcontext(Core::Constants::C_GLOBAL);
m_stopAction = new QAction(QIcon(Constants::ICON_STOP), tr("Stop"), this);
m_stopAction->setToolTip(tr("Stop"));
m_stopAction->setEnabled(false);
Core::Command *cmd = am->registerAction(m_stopAction, Constants::STOP, globalcontext);
m_stopButton = new QToolButton;
m_stopButton->setDefaultAction(cmd->action());
m_stopButton->setAutoRaise(true);
......@@ -106,7 +117,6 @@ OutputPane::OutputPane()
QVBoxLayout *layout = new QVBoxLayout;
layout->setMargin(0);
m_tabWidget = new QTabWidget;
m_tabWidget->setDocumentMode(true);
m_tabWidget->setTabsClosable(true);
m_tabWidget->setMovable(true);
......@@ -117,36 +127,69 @@ OutputPane::OutputPane()
m_mainWidget->setLayout(layout);
connect(Core::ICore::instance(), SIGNAL(coreAboutToClose()),
this, SLOT(coreAboutToClose()));
connect(ProjectExplorer::ProjectExplorerPlugin::instance()->session(), SIGNAL(aboutToUnloadSession()),
this, SLOT(aboutToUnloadSession()));
}
void OutputPane::coreAboutToClose()
OutputPane::~OutputPane()
{
while (m_tabWidget->count()) {
RunControl *rc = runControlForTab(0);
if (rc->isRunning())
rc->stop();
closeTab(0);
}
if (debug)
qDebug() << "OutputPane::~OutputPane: Entries left" << m_runControlTabs.size();
foreach(const RunControlTab &rt, m_runControlTabs)
delete rt.runControl;
delete m_mainWidget;
}
void OutputPane::aboutToUnloadSession()
int OutputPane::currentIndex() const
{
int i = 0;
while (i < m_tabWidget->count()) {
bool closed = closeTab(i);
if (!closed) // skip to next one
++i;
}
if (const QWidget *w = m_tabWidget->currentWidget())
return indexOf(w);
return -1;
}
OutputPane::~OutputPane()
RunControl *OutputPane::currentRunControl() const
{
delete m_mainWidget;
const int index = currentIndex();
if (index != -1)
return m_runControlTabs.at(index).runControl;
return 0;
}
int OutputPane::indexOf(const RunControl *rc) const
{
for (int i = m_runControlTabs.size() - 1; i >= 0; i--)
if (m_runControlTabs.at(i).runControl == rc)
return i;
return -1;
}
int OutputPane::indexOf(const QWidget *outputWindow) const
{
for (int i = m_runControlTabs.size() - 1; i >= 0; i--)
if (m_runControlTabs.at(i).window == outputWindow)
return i;
return -1;
}
int OutputPane::tabWidgetIndexOf(int runControlIndex) const
{
if (runControlIndex >= 0 && runControlIndex < m_runControlTabs.size())
return m_tabWidget->indexOf(m_runControlTabs.at(runControlIndex).window);
return -1;
}
bool OutputPane::aboutToClose() const
{
foreach(const RunControlTab &rt, m_runControlTabs)
if (rt.runControl->isRunning() && !rt.runControl->aboutToStop())
return false;
return true;
}
void OutputPane::aboutToUnloadSession()
{
closeTabs(true);
}
QWidget *OutputPane::outputWidget(QWidget *)
......@@ -204,106 +247,136 @@ void OutputPane::createNewOutputWindow(RunControl *rc)
this, SLOT(runControlFinished()));
// First look if we can reuse a tab
bool found = false;
for (int i = 0; i < m_tabWidget->count(); ++i) {
RunControl *old = runControlForTab(i);
if (old->sameRunConfiguration(rc) && !old->isRunning()) {
const int size = m_runControlTabs.size();
for (int i = 0; i < size; i++) {
RunControlTab &tab =m_runControlTabs[i];
if (tab.runControl->sameRunConfiguration(rc) && !tab.runControl->isRunning()) {
// Reuse this tab
delete old;
m_outputWindows.remove(old);
OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(i));
ow->grayOutOldContent();
ow->verticalScrollBar()->setValue(ow->verticalScrollBar()->maximum());
ow->setFormatter(rc->outputFormatter());
m_outputWindows.insert(rc, ow);
found = true;
break;
delete tab.runControl;
tab.runControl = rc;
tab.window->grayOutOldContent();
tab.window->scrollToBottom();
tab.window->setFormatter(rc->outputFormatter());
if (debug)
qDebug() << "OutputPane::createNewOutputWindow: Reusing tab" << i << " for " << rc;
return;
}
}
if (!found) {
OutputWindow *ow = new OutputWindow(m_tabWidget);
ow->setWindowTitle(tr("Application Output Window"));
ow->setWindowIcon(QIcon(QLatin1String(Qt4ProjectManager::Constants::ICON_WINDOW)));
ow->setFormatter(rc->outputFormatter());
Aggregation::Aggregate *agg = new Aggregation::Aggregate;
agg->add(ow);
agg->add(new Find::BaseTextFind(ow));
m_outputWindows.insert(rc, ow);
m_tabWidget->addTab(ow, rc->displayName());
}
// Create new
OutputWindow *ow = new OutputWindow(m_tabWidget);
ow->setWindowTitle(tr("Application Output Window"));
ow->setWindowIcon(QIcon(QLatin1String(Qt4ProjectManager::Constants::ICON_WINDOW)));
ow->setFormatter(rc->outputFormatter());
Aggregation::Aggregate *agg = new Aggregation::Aggregate;
agg->add(ow);
agg->add(new Find::BaseTextFind(ow));
m_runControlTabs.push_back(RunControlTab(rc, ow));
m_tabWidget->addTab(ow, rc->displayName());
if (debug)
qDebug() << "OutputPane::createNewOutputWindow: Adding tab for " << rc;
}
void OutputPane::appendApplicationOutput(RunControl *rc, const QString &out,
bool onStdErr)
{
OutputWindow *ow = m_outputWindows.value(rc);
ow->appendApplicationOutput(out, onStdErr);
const int index = indexOf(rc);
if (index != -1)
m_runControlTabs.at(index).window->appendApplicationOutput(out, onStdErr);
}
void OutputPane::appendApplicationOutputInline(RunControl *rc,
const QString &out,
bool onStdErr)
{
OutputWindow *ow = m_outputWindows.value(rc);
ow->appendApplicationOutputInline(out, onStdErr);
const int index = indexOf(rc);
if (index != -1)
m_runControlTabs.at(index).window->appendApplicationOutputInline(out, onStdErr);
}
void OutputPane::appendMessage(RunControl *rc, const QString &out, bool isError)
{
OutputWindow *ow = m_outputWindows.value(rc);
ow->appendMessage(out, isError);
const int index = indexOf(rc);
if (index != -1)
m_runControlTabs.at(index).window->appendMessage(out, isError);
}
void OutputPane::showTabFor(RunControl *rc)
{
OutputWindow *ow = m_outputWindows.value(rc);
m_tabWidget->setCurrentWidget(ow);
m_tabWidget->setCurrentIndex(tabWidgetIndexOf(indexOf(rc)));
}
void OutputPane::reRunRunControl()
{
int index = m_tabWidget->currentIndex();
RunControl *rc = runControlForTab(index);
OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(index));
if (ProjectExplorerPlugin::instance()->projectExplorerSettings().cleanOldAppOutput)
ow->clear();
else
ow->grayOutOldContent();
ow->verticalScrollBar()->setValue(ow->verticalScrollBar()->maximum());
rc->start();
const int index = currentIndex();