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
This commit is contained in:
Friedemann Kleint
2010-08-20 14:19:25 +02:00
parent fa68a545a8
commit 6840c1d198
22 changed files with 376 additions and 256 deletions

View File

@@ -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"

View File

@@ -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();

View File

@@ -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()

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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;
}
int OutputPane::currentIndex() const
{
if (const QWidget *w = m_tabWidget->currentWidget())
return indexOf(w);
return -1;
}
RunControl *OutputPane::currentRunControl() const
{
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()
{
int i = 0;
while (i < m_tabWidget->count()) {
bool closed = closeTab(i);
if (!closed) // skip to next one
++i;
}
}
OutputPane::~OutputPane()
{
delete m_mainWidget;
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();
QTC_ASSERT(index != -1 && !m_runControlTabs.at(index).runControl->isRunning(), return;)
RunControlTab &tab = m_runControlTabs[index];
if (ProjectExplorerPlugin::instance()->projectExplorerSettings().cleanOldAppOutput) {
tab.window->clear();
} else {
tab.window->grayOutOldContent();
}
tab.window->scrollToBottom();
tab.runControl->start();
}
void OutputPane::stopRunControl()
{
RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
rc->stop();
const int index = currentIndex();
QTC_ASSERT(index != -1 && m_runControlTabs.at(index).runControl->isRunning(), return;)
RunControl *rc = m_runControlTabs.at(index).runControl;
if (rc->isRunning() && rc->aboutToStop())
rc->stop();
if (debug)
qDebug() << "OutputPane::stopRunControl " << rc;
}
bool OutputPane::closeTabs(bool prompt)
{
bool allClosed = true;
for (int t = m_tabWidget->count() - 1; t >= 0; t--)
if (!closeTab(t, prompt))
allClosed = false;
if (debug)
qDebug() << "OutputPane::closeTabs() returns " << allClosed;
return allClosed;
}
bool OutputPane::closeTab(int index)
{
OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(index));
RunControl *rc = m_outputWindows.key(ow);
return closeTab(index, true);
}
if (rc->isRunning()) {
QMessageBox messageBox(QMessageBox::Warning,
tr("Unable to close"),
tr("%1 is still running.").arg(rc->displayName()),
QMessageBox::Cancel | QMessageBox::Yes,
ow->window());
messageBox.setInformativeText(tr("Force it to quit?"));
messageBox.setDefaultButton(QMessageBox::Yes);
messageBox.button(QMessageBox::Yes)->setText(tr("Force Quit"));
messageBox.button(QMessageBox::Cancel)->setText(tr("Keep Running"));
bool OutputPane::closeTab(int tabIndex, bool prompt)
{
const int index = indexOf(m_tabWidget->widget(tabIndex));
QTC_ASSERT(index != -1, return true;)
if (messageBox.exec() != QMessageBox::Yes)
RunControlTab &tab = m_runControlTabs[index];
if (debug)
qDebug() << "OutputPane::closeTab tab " << tabIndex << tab.runControl
<< tab.window << tab.asyncClosing;
// Prompt user to stop
if (tab.runControl->isRunning()) {
if (prompt && !tab.runControl->aboutToStop())
return false;
rc->stop();
if (tab.runControl->stop() == RunControl::AsynchronousStop) {
tab.asyncClosing = true;
return false;
}
}
m_tabWidget->removeTab(index);
delete ow;
delete rc;
m_tabWidget->removeTab(tabIndex);
if (tab.asyncClosing) { // We were invoked from its finished() signal.
tab.runControl->deleteLater();
} else {
delete tab.runControl;
}
delete tab.window;
m_runControlTabs.removeAt(index);
return true;
}
@@ -318,7 +391,10 @@ void OutputPane::tabChanged(int i)
m_stopAction->setEnabled(false);
m_reRunButton->setEnabled(false);
} else {
RunControl *rc = runControlForTab(i);
const int index = indexOf(m_tabWidget->widget(i));
QTC_ASSERT(index != -1, return; )
RunControl *rc = m_runControlTabs.at(index).runControl;
m_stopAction->setEnabled(rc->isRunning());
m_reRunButton->setEnabled(!rc->isRunning());
m_reRunButton->setIcon(rc->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
@@ -327,27 +403,47 @@ void OutputPane::tabChanged(int i)
void OutputPane::runControlStarted()
{
RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
if (rc == qobject_cast<RunControl *>(sender())) {
RunControl *current = currentRunControl();
if (current && current == sender()) {
m_reRunButton->setEnabled(false);
m_stopAction->setEnabled(true);
m_reRunButton->setIcon(rc->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
m_reRunButton->setIcon(current->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
}
}
void OutputPane::runControlFinished()
{
RunControl *rc = runControlForTab(m_tabWidget->currentIndex());
if (rc == qobject_cast<RunControl *>(sender())) {
m_reRunButton->setEnabled(rc);
RunControl *senderRunControl = qobject_cast<RunControl *>(sender());
const int senderIndex = indexOf(senderRunControl);
QTC_ASSERT(senderIndex != -1, return; )
// Enable buttons for current
RunControl *current = currentRunControl();
if (debug)
qDebug() << "OutputPane::runControlFinished" << senderRunControl << senderIndex
<< " current " << current << m_runControlTabs.size();
if (current && current == sender()) {
m_reRunButton->setEnabled(true);
m_stopAction->setEnabled(false);
m_reRunButton->setIcon(rc->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
m_reRunButton->setIcon(current->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
}
// Check for asynchronous close. Close the tab.
if (m_runControlTabs.at(senderIndex).asyncClosing)
closeTab(tabWidgetIndexOf(senderIndex), false);
if (!isRunning())
emit allRunControlsFinished();
}
RunControl* OutputPane::runControlForTab(int index) const
bool OutputPane::isRunning() const
{
return m_outputWindows.key(qobject_cast<OutputWindow *>(m_tabWidget->widget(index)));
foreach(const RunControlTab &rt, m_runControlTabs)
if (rt.runControl->isRunning())
return true;
return false;
}
bool OutputPane::canNext()
@@ -441,7 +537,6 @@ void OutputWindow::mousePressEvent(QMouseEvent * e)
QPlainTextEdit::mousePressEvent(e);
}
void OutputWindow::mouseReleaseEvent(QMouseEvent *e)
{
m_mousePressed = false;
@@ -631,3 +726,6 @@ void OutputWindow::enableUndoRedo()
setMaximumBlockCount(0);
setUndoRedoEnabled(true);
}
} // namespace Internal
} // namespace ProjectExplorer

View File

@@ -32,9 +32,8 @@
#include <coreplugin/ioutputpane.h>
#include <QtCore/QHash>
#include <QtGui/QIcon>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QIcon>
QT_BEGIN_NAMESPACE
class QTabWidget;
@@ -59,13 +58,15 @@ namespace Internal {
class OutputWindow;
struct OutputPanePrivate;
class OutputPane : public Core::IOutputPane
{
Q_OBJECT
public:
OutputPane();
~OutputPane();
virtual ~OutputPane();
QWidget *outputWidget(QWidget *);
QList<QWidget*> toolBarWidgets() const;
@@ -85,11 +86,16 @@ public:
void showTabFor(RunControl *rc);
bool aboutToClose() const;
bool closeTabs(bool prompt);
signals:
void allRunControlsFinished();
public slots:
// ApplicationOutputspecifics
void createNewOutputWindow(RunControl *rc);
void projectRemoved();
void coreAboutToClose();
void appendApplicationOutput(ProjectExplorer::RunControl *rc, const QString &out,
bool onStdErr);
@@ -108,11 +114,27 @@ private slots:
void aboutToUnloadSession();
private:
RunControl *runControlForTab(int index) const;
struct RunControlTab {
explicit RunControlTab(RunControl *runControl = 0,
OutputWindow *window = 0);
RunControl* runControl;
OutputWindow *window;
// Is the run control stopping asynchronously, close the tab once it finishes
bool asyncClosing;
};
bool isRunning() const;
bool closeTab(int index, bool prompt);
int indexOf(const RunControl *) const;
int indexOf(const QWidget *outputWindow) const;
int currentIndex() const;
RunControl *currentRunControl() const;
int tabWidgetIndexOf(int runControlIndex) const;
QWidget *m_mainWidget;
QTabWidget *m_tabWidget;
QHash<RunControl *, OutputWindow *> m_outputWindows;
QList<RunControlTab> m_runControlTabs;
QAction *m_stopAction;
QToolButton *m_reRunButton;
QToolButton *m_stopButton;
@@ -148,9 +170,10 @@ public:
QPlainTextEdit::clear();
}
void scrollToBottom();
protected:
bool isScrollbarAtBottom() const;
void scrollToBottom();
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);

View File

@@ -297,7 +297,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
connect(d->m_buildManager, SIGNAL(buildQueueFinished(bool)),
this, SLOT(buildQueueFinished(bool)));
addAutoReleasedObject(new CoreListenerCheckingForRunningBuild(d->m_buildManager));
addAutoReleasedObject(new CoreListener);
d->m_outputPane = new OutputPane;
addAutoReleasedObject(d->m_outputPane);
@@ -956,8 +956,14 @@ ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown()
d->m_proWindow->aboutToShutdown(); // disconnect from session
d->m_session->clear();
d->m_projectsMode = 0;
// d->m_proWindow->saveConfigChanges();
return SynchronousShutdown;
// Attempt to synchronously shutdown all run controls.
// If that fails, fall back to asynchronous shutdown (Debugger run controls
// might shutdown asynchronously).
if (d->m_outputPane->closeTabs(false /* No prompt any more */))
return SynchronousShutdown;
connect(d->m_outputPane, SIGNAL(allRunControlsFinished()),
this, SIGNAL(asynchronousShutdownFinished()));
return AsynchronousShutdown;
}
void ProjectExplorerPlugin::newProject()
@@ -1647,6 +1653,25 @@ bool ProjectExplorerPlugin::hasBuildSettings(Project *pro)
return false;
}
bool ProjectExplorerPlugin::coreAboutToClose()
{
if (d->m_buildManager->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();
if (box.clickedButton() != closeAnyway)
return false;
}
if (!d->m_outputPane->aboutToClose())
return false;
return true;
}
bool ProjectExplorerPlugin::hasDeploySettings(Project *pro)
{
const QList<Project *> & projects = d->m_session->projectOrder(pro);

View File

@@ -110,6 +110,7 @@ public:
// internal public for FlatModel
void renameFile(Node *node, const QString &to);
static QStringList projectFilePatterns();
bool coreAboutToClose();
signals:
void aboutToShowContextMenu(ProjectExplorer::Project *project,

View File

@@ -35,8 +35,13 @@
#include "buildconfiguration.h"
#include <extensionsystem/pluginmanager.h>
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
#include <QtCore/QTimer>
#include <QtGui/QMainWindow>
#include <QtGui/QMessageBox>
#include <QtGui/QAbstractButton>
#ifdef Q_OS_MAC
#include <Carbon/Carbon.h>
@@ -250,7 +255,23 @@ QString RunControl::displayName() const
return m_displayName;
}
bool RunControl::sameRunConfiguration(RunControl *other)
bool RunControl::aboutToStop() const
{
QTC_ASSERT(isRunning(), return true;)
QMessageBox messageBox(QMessageBox::Warning,
tr("Application Still Running"),
tr("%1 is still running.").arg(displayName()),
QMessageBox::Cancel | QMessageBox::Yes,
Core::ICore::instance()->mainWindow());
messageBox.setInformativeText(tr("Force it to quit?"));
messageBox.setDefaultButton(QMessageBox::Yes);
messageBox.button(QMessageBox::Yes)->setText(tr("Force Quit"));
messageBox.button(QMessageBox::Cancel)->setText(tr("Keep Running"));
return messageBox.exec() == QMessageBox::Yes;
}
bool RunControl::sameRunConfiguration(const RunControl *other) const
{
return other->m_runConfiguration.data() == m_runConfiguration.data();
}

View File

@@ -159,14 +159,20 @@ class PROJECTEXPLORER_EXPORT RunControl : public QObject
{
Q_OBJECT
public:
enum StopResult {
StoppedSynchronously, // Stopped.
AsynchronousStop, // Stop sequence has been started
};
explicit RunControl(RunConfiguration *runConfiguration, QString mode);
virtual ~RunControl();
virtual void start() = 0;
virtual void stop() = 0; // Warning: assumed to be synchroneous!
virtual bool aboutToStop() const;
virtual StopResult stop() = 0;
virtual bool isRunning() const = 0;
virtual QString displayName() const;
bool sameRunConfiguration(RunControl *other);
bool sameRunConfiguration(const RunControl *other) const;
OutputFormatter *outputFormatter();
QString runMode() const;

View File

@@ -94,9 +94,10 @@ void QmlRunControl::start()
m_commandLineArguments.join(QLatin1String(" "))), false);
}
void QmlRunControl::stop()
RunControl::StopResult QmlRunControl::stop()
{
m_applicationLauncher.stop();
return StoppedSynchronously;
}
bool QmlRunControl::isRunning() const

View File

@@ -48,7 +48,7 @@ public:
// RunControl
virtual void start();
virtual void stop();
virtual StopResult stop();
virtual bool isRunning() const;
private slots:

View File

@@ -93,9 +93,10 @@ void MaemoRunControl::start()
}
}
void MaemoRunControl::stop()
ProjectExplorer::RunControl::StopResult MaemoRunControl::stop()
{
m_runner->stop();
return StoppedSynchronously;
}
void MaemoRunControl::handleSshError(const QString &error)

View File

@@ -53,6 +53,10 @@ public:
explicit MaemoRunControl(ProjectExplorer::RunConfiguration *runConfig);
virtual ~MaemoRunControl();
virtual void start();
virtual StopResult stop();
virtual bool isRunning() const;
private slots:
void startExecution();
void handleSshError(const QString &error);
@@ -63,10 +67,6 @@ private slots:
void handleProgressReport(const QString &progressString);
private:
virtual void start();
virtual void stop();
virtual bool isRunning() const;
void setFinished();
void handleError(const QString &errString);

View File

@@ -392,10 +392,11 @@ void S60DeviceRunControl::start()
startLaunching();
}
void S60DeviceRunControl::stop()
RunControl::StopResult S60DeviceRunControl::stop()
{
if (m_launcher)
m_launcher->terminate();
return AsynchronousStop;
}
bool S60DeviceRunControl::isRunning() const
@@ -660,15 +661,20 @@ S60DeviceDebugRunControl::~S60DeviceDebugRunControl()
// FIXME: Needed? m_debuggerRunControl->deleteLater();
}
void S60DeviceDebugRunControl::stop()
bool S60DeviceDebugRunControl::aboutToStop() const
{
QTC_ASSERT(m_debuggerRunControl, return)
if (m_debuggerRunControl->state() == Debugger::DebuggerNotReady)
m_debuggerRunControl->stop();
return m_debuggerRunControl ? m_debuggerRunControl->aboutToStop() : true;
}
RunControl::StopResult S60DeviceDebugRunControl::stop()
{
QTC_ASSERT(m_debuggerRunControl, return StoppedSynchronously)
if (m_debugProgress)
m_debugProgress->reportCanceled();
delete m_debugProgress;
m_debugProgress = 0;
return m_debuggerRunControl->stop();
}
bool S60DeviceDebugRunControl::isRunning() const

View File

@@ -131,7 +131,7 @@ public:
explicit S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration, QString mode);
~S60DeviceRunControl();
virtual void start();
virtual void stop();
virtual StopResult stop();
virtual bool isRunning() const;
static QMessageBox *createTrkWaitingMessageBox(const QString &port, QWidget *parent = 0);
@@ -189,7 +189,8 @@ public:
explicit S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration, QString mode);
virtual ~S60DeviceDebugRunControl();
virtual void start();
virtual void stop();
virtual bool aboutToStop() const;
virtual StopResult stop();
virtual bool isRunning() const;
protected:

View File

@@ -326,9 +326,10 @@ void S60EmulatorRunControl::start()
emit appendMessage(this, tr("Starting %1...").arg(QDir::toNativeSeparators(m_executable)), false);
}
void S60EmulatorRunControl::stop()
RunControl::StopResult S60EmulatorRunControl::stop()
{
m_applicationLauncher.stop();
return StoppedSynchronously;
}
bool S60EmulatorRunControl::isRunning() const

View File

@@ -134,7 +134,7 @@ public:
explicit S60EmulatorRunControl(S60EmulatorRunConfiguration *runConfiguration, QString mode);
~S60EmulatorRunControl() {}
void start();
void stop();
virtual StopResult stop();
bool isRunning() const;
private slots: