diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index d65636d6212efe2c70f3f82378678f2b6eae57b3..a1c88ba96ea8190d00a64a7775e9adadf2c33356 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -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" diff --git a/src/plugins/debugger/debuggerplugin.h b/src/plugins/debugger/debuggerplugin.h index a62e008a2284fddb51ed29356d1136ca318baa66..181617bf3382343b90454f2bbee8a9495f6b5275 100644 --- a/src/plugins/debugger/debuggerplugin.h +++ b/src/plugins/debugger/debuggerplugin.h @@ -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(); diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index 66935a4d12113a699830f43256217607437f2442..7895c28f0c2d0961a24bd5f052081831db82bd2f 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -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() diff --git a/src/plugins/debugger/debuggerrunner.h b/src/plugins/debugger/debuggerrunner.h index 6f983b3bd34296128a56becbb8681ee7f3c8e43b..08f26801769e93ac2d2fff7c1b4fac0ffc81de41 100644 --- a/src/plugins/debugger/debuggerrunner.h +++ b/src/plugins/debugger/debuggerrunner.h @@ -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; diff --git a/src/plugins/projectexplorer/applicationrunconfiguration.cpp b/src/plugins/projectexplorer/applicationrunconfiguration.cpp index 05ae8f87650b3f22bae51023f6d08c32c20c25c8..3467dc61cd95cd12280a02b872736ab092decb93 100644 --- a/src/plugins/projectexplorer/applicationrunconfiguration.cpp +++ b/src/plugins/projectexplorer/applicationrunconfiguration.cpp @@ -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 diff --git a/src/plugins/projectexplorer/applicationrunconfiguration.h b/src/plugins/projectexplorer/applicationrunconfiguration.h index a9c4241a580b22c23edbe72450962a08f9a361ea..2325841e771702fda37a9e59e6aceeb179dfb479 100644 --- a/src/plugins/projectexplorer/applicationrunconfiguration.h +++ b/src/plugins/projectexplorer/applicationrunconfiguration.h @@ -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); diff --git a/src/plugins/projectexplorer/corelistenercheckingforrunningbuild.cpp b/src/plugins/projectexplorer/corelistenercheckingforrunningbuild.cpp index 667614095f0172c60fe5939e50002253afa1de83..9e7de557ba7dc26f9be07f6aa13c4cb77c62efeb 100644 --- a/src/plugins/projectexplorer/corelistenercheckingforrunningbuild.cpp +++ b/src/plugins/projectexplorer/corelistenercheckingforrunningbuild.cpp @@ -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(); } } diff --git a/src/plugins/projectexplorer/corelistenercheckingforrunningbuild.h b/src/plugins/projectexplorer/corelistenercheckingforrunningbuild.h index 011f79adc8677ca63d32cd6c20e5e2e907c2a6de..3e6ac38c8dfea623af2beee053b714305b85319b 100644 --- a/src/plugins/projectexplorer/corelistenercheckingforrunningbuild.h +++ b/src/plugins/projectexplorer/corelistenercheckingforrunningbuild.h @@ -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 diff --git a/src/plugins/projectexplorer/outputwindow.cpp b/src/plugins/projectexplorer/outputwindow.cpp index ad111bfc2a90297dc4b85a37c722cc600a0e5191..4b37ca08e64f0e8ec97622b9461263da8438bf4e 100644 --- a/src/plugins/projectexplorer/outputwindow.cpp +++ b/src/plugins/projectexplorer/outputwindow.cpp @@ -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(); + 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); - - 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")); - - if (messageBox.exec() != QMessageBox::Yes) - return false; + return closeTab(index, true); +} - rc->stop(); +bool OutputPane::closeTab(int tabIndex, bool prompt) +{ + const int index = indexOf(m_tabWidget->widget(tabIndex)); + QTC_ASSERT(index != -1, return true;) + + 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; + 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 diff --git a/src/plugins/projectexplorer/outputwindow.h b/src/plugins/projectexplorer/outputwindow.h index 4cc3eecb031868adbdc8327e963175447b1f07da..ebe0ecd658707bf50b72201af50c4653a6b1d776 100644 --- a/src/plugins/projectexplorer/outputwindow.h +++ b/src/plugins/projectexplorer/outputwindow.h @@ -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); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 6b12b85091e9d40c97dc6464bfa947ed0e5a5f47..d8584451a1caedace1c76e5db730e192d93a1d0a 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -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); diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index 6233616e684ce4228d3c08bf5f9e38912c05d4a1..9ca130fbacc2b05e2a2599ccc7c8f32e2e77ac0f 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -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, diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 7d52e7bdfe197d90f41564238bbf72178ce6773a..16e4e9ed660e9bc676b2491008f58fa0a5b8a0d6 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -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(); } diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index 352d6326d28d8cd297414eff488aaf5c2fbfce61..6dd881a9151142ab70d6ae678c1c2692a0a198a9 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -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; diff --git a/src/plugins/qmlprojectmanager/qmlprojectruncontrol.cpp b/src/plugins/qmlprojectmanager/qmlprojectruncontrol.cpp index 8f480105571ce1d68c7aa3d8311da97bddc58f9b..8d19e78b5b3dd9eec971947344404fed706bef5d 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectruncontrol.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectruncontrol.cpp @@ -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 diff --git a/src/plugins/qmlprojectmanager/qmlprojectruncontrol.h b/src/plugins/qmlprojectmanager/qmlprojectruncontrol.h index 8a1bc940a2e672e61b34e9957b46ad7bb66bab19..cf260c2eca70dbd12049c6be458f779fdb39be5d 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectruncontrol.h +++ b/src/plugins/qmlprojectmanager/qmlprojectruncontrol.h @@ -48,7 +48,7 @@ public: // RunControl virtual void start(); - virtual void stop(); + virtual StopResult stop(); virtual bool isRunning() const; private slots: diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp index 7d8d72b44dff910c8b86f9348c3b931def0bc6cc..270e4cce723d71ea776fc8591d3ca046cb970f9e 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp @@ -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) diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h index 3797703cde70d9dc7ab77a7de51f417d187f7b9f..204fb1e34294173e1af24ca4ed7d08767b40f8e0 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h @@ -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); diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp index 5060d799762ebdc3324856e7698e70a2d7a0e2ee..6368145faf8bce66e49a9fff3613c821de267e07 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp @@ -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 diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h index 49b825455e0c40e64f85090875bc12ce9bb62b20..00dabf5aba45138ff160501e2bbc1dfbfc0ca977 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h @@ -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: diff --git a/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp index 20dc6b8c2c13f8876d1740df2b0747c7cfb26564..c828a7f4f946d42ab394d1995322d30b7d50a9b4 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp @@ -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 diff --git a/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h index 62f0435e5f219161a6af49ab0b0f10e899ad73e0..ccf2a372ee2c8ace8a162545dd1f14a911f17a29 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h @@ -134,7 +134,7 @@ public: explicit S60EmulatorRunControl(S60EmulatorRunConfiguration *runConfiguration, QString mode); ~S60EmulatorRunControl() {} void start(); - void stop(); + virtual StopResult stop(); bool isRunning() const; private slots: