Skip to content
Snippets Groups Projects
debuggerplugin.cpp 90.13 KiB
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "debuggerplugin.h"

#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerconstants.h"
#include "debuggerdialogs.h"
#include "debuggerengine.h"
#include "debuggermainwindow.h"
#include "debuggeroutputwindow.h"
#include "debuggerplugin.h"
#include "debuggerrunner.h"
#include "debuggerstringutils.h"
#include "debuggertooltip.h"
#include "debuggeruiswitcher.h"

#include "breakwindow.h"
#include "moduleswindow.h"
#include "registerwindow.h"
#include "snapshotwindow.h"
#include "stackwindow.h"
#include "sourcefileswindow.h"
#include "threadswindow.h"
#include "watchwindow.h"

#include "watchutils.h"
#include "breakhandler.h"
#include "stackhandler.h"
#include "watchhandler.h"

#ifdef Q_OS_WIN
#  include "shared/peutils.h"
#endif


#include "ui_commonoptionspage.h"
#include "ui_dumperoptionpage.h"

#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/basemode.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/dialogs/ioptionspage.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/findplaceholder.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/icorelistener.h>
#include <coreplugin/manhattanstyle.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/minisplitter.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/navigationwidget.h>
#include <coreplugin/outputpane.h>
#include <coreplugin/rightpane.h>

#include <cplusplus/ExpressionUnderCursor.h>
#include <cplusplus/CppDocument.h>

#include <cppeditor/cppeditorconstants.h>
#include <cpptools/cppmodelmanagerinterface.h>

#include <extensionsystem/pluginmanager.h>

#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
#include <projectexplorer/toolchain.h>

#include <texteditor/basetexteditor.h>
#include <texteditor/basetextmark.h>
#include <texteditor/fontsettings.h>
#include <texteditor/itexteditor.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/texteditorsettings.h>

//#include <qt4projectmanager/qt4projectmanagerconstants.h>

#include <utils/qtcassert.h>
#include <utils/savedaction.h>
#include <utils/styledbar.h>

#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QObject>
#include <QtCore/QPoint>
#include <QtCore/QSettings>
#include <QtCore/QTextStream>
#include <QtCore/QTime>
#include <QtCore/QTimer>
#include <QtCore/QVariant>
#include <QtCore/QtPlugin>

#include <QtGui/QAbstractItemView>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QComboBox>
#include <QtGui/QDockWidget>
#include <QtGui/QErrorMessage>
#include <QtGui/QFileDialog>
#include <QtGui/QHeaderView>
#include <QtGui/QLabel>
#include <QtGui/QLineEdit>
#include <QtGui/QMenu>
#include <QtGui/QMessageBox>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QPushButton>
#include <QtGui/QStatusBar>
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
#include <QtGui/QToolButton>
#include <QtGui/QToolTip>
#include <QtGui/QTreeWidget>

#include <climits>

#define DEBUG_STATE 1
#ifdef DEBUG_STATE
//#   define STATE_DEBUG(s)
//    do { QString msg; QTextStream ts(&msg); ts << s;
//      showMessage(msg, LogDebug); } while (0)
#   define STATE_DEBUG(s) do { qDebug() << s; } while(0)
#else
#   define STATE_DEBUG(s)
#endif

// Note: the Debugger process itself and any helper processes like
// gdbserver, the trk client etc are referred to as 'Adapter',
// whereas the debugged process is referred to as 'Inferior'.
//
//              0 == DebuggerNotReady
//                          |
//                    EngineStarting
//                          |
//                    AdapterStarting --> AdapterStartFailed --> 0
//                          |
//                    AdapterStarted ------------------------------------.
//                          |                                            v
//                   InferiorStarting ----> InferiorStartFailed -------->|
//                          |                                            |
//         (core)           |     (attach) (term) (remote)               |
//      .-----------------<-|->------------------.                       |
//      |                   v                    |                       |
//  InferiorUnrunnable      | (plain)            |                       |
//      |                   | (trk)              |                       |
//      |                   |                    |                       |
//      |    .--> InferiorRunningRequested       |                       |
//      |    |              |                    |                       |
//      |    |       InferiorRunning             |                       |
//      |    |              |                    |                       |
//      |    |       InferiorStopping            |                       |
//      |    |              |                    |                       |
//      |    '------ InferiorStopped <-----------'                       |
//      |                   |                                            v
//      |          InferiorShuttingDown  ->  InferiorShutdownFailed ---->|
//      |                   |                                            |
//      |            InferiorShutDown                                    |
//      |                   |                                            |
//      '-------->  EngineShuttingDown  <--------------------------------'
//                          |
//                          0
//
// Allowed actions:
//    [R] :  Run
//    [C] :  Continue
//    [N] :  Step, Next

using namespace Core;
using namespace Debugger;
using namespace Debugger::Constants;
using namespace Debugger::Internal;
using namespace ProjectExplorer;
using namespace TextEditor;

namespace CC = Core::Constants;
namespace PE = ProjectExplorer::Constants;

namespace Debugger {
namespace Constants {

const char * const M_DEBUG_START_DEBUGGING = "QtCreator.Menu.Debug.StartDebugging";

const char * const STARTEXTERNAL        = "Debugger.StartExternal";
const char * const ATTACHEXTERNAL       = "Debugger.AttachExternal";
const char * const ATTACHCORE           = "Debugger.AttachCore";
const char * const ATTACHTCF            = "Debugger.AttachTcf";
const char * const ATTACHREMOTE         = "Debugger.AttachRemote";
const char * const DETACH               = "Debugger.Detach";

const char * const RUN_TO_LINE1         = "Debugger.RunToLine1";
const char * const RUN_TO_LINE2         = "Debugger.RunToLine2";
const char * const RUN_TO_FUNCTION      = "Debugger.RunToFunction";
const char * const JUMP_TO_LINE1        = "Debugger.JumpToLine1";
const char * const JUMP_TO_LINE2        = "Debugger.JumpToLine2";
const char * const RETURN_FROM_FUNCTION = "Debugger.ReturnFromFunction";
const char * const SNAPSHOT             = "Debugger.Snapshot";
const char * const TOGGLE_BREAK         = "Debugger.ToggleBreak";
const char * const BREAK_BY_FUNCTION    = "Debugger.BreakByFunction";
const char * const BREAK_AT_MAIN        = "Debugger.BreakAtMain";
const char * const ADD_TO_WATCH1        = "Debugger.AddToWatch1";
const char * const ADD_TO_WATCH2        = "Debugger.AddToWatch2";
const char * const OPERATE_BY_INSTRUCTION  = "Debugger.OperateByInstruction";
const char * const FRAME_UP             = "Debugger.FrameUp";
const char * const FRAME_DOWN           = "Debugger.FrameDown";

#ifdef Q_WS_MAC
const char * const INTERRUPT_KEY            = "Shift+F5";
const char * const RESET_KEY                = "Ctrl+Shift+F5";
const char * const STEP_KEY                 = "F7";
const char * const STEPOUT_KEY              = "Shift+F7";
const char * const NEXT_KEY                 = "F6";
const char * const REVERSE_KEY              = "";
const char * const RUN_TO_LINE_KEY          = "Shift+F8";
const char * const RUN_TO_FUNCTION_KEY      = "Ctrl+F6";
const char * const JUMP_TO_LINE_KEY         = "Alt+D,Alt+L";
const char * const TOGGLE_BREAK_KEY         = "F8";
const char * const BREAK_BY_FUNCTION_KEY    = "Alt+D,Alt+F";
const char * const BREAK_AT_MAIN_KEY        = "Alt+D,Alt+M";
const char * const ADD_TO_WATCH_KEY         = "Alt+D,Alt+W";
const char * const SNAPSHOT_KEY             = "Alt+D,Alt+S";
#else
const char * const INTERRUPT_KEY            = "Shift+F5";
const char * const RESET_KEY                = "Ctrl+Shift+F5";
const char * const STEP_KEY                 = "F11";
const char * const STEPOUT_KEY              = "Shift+F11";
const char * const NEXT_KEY                 = "F10";
const char * const REVERSE_KEY              = "F12";
const char * const RUN_TO_LINE_KEY          = "";
const char * const RUN_TO_FUNCTION_KEY      = "";
const char * const JUMP_TO_LINE_KEY         = "";
const char * const TOGGLE_BREAK_KEY         = "F9";
const char * const BREAK_BY_FUNCTION_KEY    = "";
const char * const BREAK_AT_MAIN_KEY        = "";
const char * const ADD_TO_WATCH_KEY         = "Ctrl+Alt+Q";
const char * const SNAPSHOT_KEY             = "Alt+D,Alt+S";
#endif

} // namespace Constants
} // namespace Debugger



static ProjectExplorer::SessionManager *sessionManager()
{
    return ProjectExplorer::ProjectExplorerPlugin::instance()->session();
}
static QSettings *settings()
{
    return ICore::instance()->settings();
}

static QToolButton *toolButton(QAction *action)
{
    QToolButton *button = new QToolButton;
    button->setDefaultAction(action);
    return button;
}

namespace Debugger {
namespace Internal {

static const char *Role = "ROLE";

// FIXME: Outdated?
// The createCdbEngine function takes a list of options pages it can add to.
// This allows for having a "enabled" toggle on the page independently
// of the engine. That's good for not enabling the related ActiveX control
// unnecessarily.

void addGdbOptionPages(QList<Core::IOptionsPage*> *opts);
void addScriptOptionPages(QList<Core::IOptionsPage*> *opts);
void addTcfOptionPages(QList<Core::IOptionsPage*> *opts);
#ifdef CDB_ENABLED
void addCdbOptionPages(QList<Core::IOptionsPage*> *opts);
#endif


struct AttachRemoteParameters
{
    AttachRemoteParameters() : attachPid(0), winCrashEvent(0) {}

    quint64 attachPid;
    QString attachCore;
    // Event handle for attaching to crashed Windows processes.
    quint64 winCrashEvent;
};


///////////////////////////////////////////////////////////////////////
//
// DebugMode
//
///////////////////////////////////////////////////////////////////////

class DebugMode : public Core::BaseMode
{
public:
    DebugMode(QObject *parent = 0) : BaseMode(parent)
    {
        setDisplayName(tr("Debug"));
        setId(MODE_DEBUG);
        setIcon(QIcon(":/fancyactionbar/images/mode_Debug.png"));
        setPriority(P_MODE_DEBUG);
    }

    ~DebugMode()
    {
        // Make sure the editor manager does not get deleted.
        EditorManager::instance()->setParent(0);
    }
};


///////////////////////////////////////////////////////////////////////
//
// DebuggerListener: Close the debugging session if running.
//
///////////////////////////////////////////////////////////////////////

class DebuggerListener : public Core::ICoreListener
{
public:
    DebuggerListener() {}
    virtual bool coreAboutToClose();
};


///////////////////////////////////////////////////////////////////////
//
// LocationMark
//
///////////////////////////////////////////////////////////////////////

// Used in "real" editors
class LocationMark : public TextEditor::BaseTextMark
{
public:
    LocationMark(const QString &fileName, int linenumber)
        : BaseTextMark(fileName, linenumber)
    {}

    QIcon icon() const { return DebuggerPlugin::instance()->locationMarkIcon(); }
    void updateLineNumber(int /*lineNumber*/) {}
    void updateBlock(const QTextBlock & /*block*/) {}
    void removedFromEditor() {}
};


///////////////////////////////////////////////////////////////////////
//
// CommonOptionsPage
//
///////////////////////////////////////////////////////////////////////

class CommonOptionsPage : public Core::IOptionsPage
{
public:
    CommonOptionsPage() {}

    // IOptionsPage
    QString id() const
        { return _(DEBUGGER_COMMON_SETTINGS_ID); }
    QString displayName() const
        { return QCoreApplication::translate("Debugger", DEBUGGER_COMMON_SETTINGS_NAME); }
    QString category() const
        { return _(DEBUGGER_SETTINGS_CATEGORY);  }
    QString displayCategory() const
        { return QCoreApplication::translate("Debugger", DEBUGGER_SETTINGS_TR_CATEGORY); }
    QIcon categoryIcon() const
        { return QIcon(QLatin1String(DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON)); }

    QWidget *createPage(QWidget *parent);
    void apply() { m_group.apply(settings()); }
    void finish() { m_group.finish(); }
    virtual bool matches(const QString &s) const;

private:
    Ui::CommonOptionsPage m_ui;
    Utils::SavedActionSet m_group;
    QString m_searchKeywords;
};

QWidget *CommonOptionsPage::createPage(QWidget *parent)
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);
    m_group.clear();

    m_group.insert(theDebuggerAction(SwitchLanguageAutomatically),
        m_ui.checkBoxChangeLanguageAutomatically);

    m_group.insert(theDebuggerAction(ListSourceFiles),
        m_ui.checkBoxListSourceFiles);
    m_group.insert(theDebuggerAction(UseAlternatingRowColors),
        m_ui.checkBoxUseAlternatingRowColors);
    m_group.insert(theDebuggerAction(UseToolTipsInMainEditor),
        m_ui.checkBoxUseToolTipsInMainEditor);
    m_group.insert(theDebuggerAction(AutoDerefPointers), 0);
    m_group.insert(theDebuggerAction(UseToolTipsInLocalsView), 0);
    m_group.insert(theDebuggerAction(UseToolTipsInBreakpointsView), 0);
    m_group.insert(theDebuggerAction(UseAddressInBreakpointsView), 0);
    m_group.insert(theDebuggerAction(UseAddressInStackView), 0);
    m_group.insert(theDebuggerAction(MaximalStackDepth),
        m_ui.spinBoxMaximalStackDepth);
    m_group.insert(theDebuggerAction(ShowStdNamespace), 0);
    m_group.insert(theDebuggerAction(ShowQtNamespace), 0);
    m_group.insert(theDebuggerAction(LogTimeStamps), 0);
    m_group.insert(theDebuggerAction(VerboseLog), 0);
    m_group.insert(theDebuggerAction(UsePreciseBreakpoints), 0);
    m_group.insert(theDebuggerAction(BreakOnThrow), 0);
    m_group.insert(theDebuggerAction(BreakOnCatch), 0);
#ifdef Q_OS_WIN
    Utils::SavedAction *registerAction = theDebuggerAction(RegisterForPostMortem);
    m_group.insert(registerAction,
        m_ui.checkBoxRegisterForPostMortem);
    connect(registerAction, SIGNAL(toggled(bool)),
            m_ui.checkBoxRegisterForPostMortem, SLOT(setChecked(bool)));
#endif

    if (m_searchKeywords.isEmpty()) {
        QTextStream(&m_searchKeywords) << ' '
                << m_ui.checkBoxChangeLanguageAutomatically->text()
                << m_ui.checkBoxListSourceFiles->text()
                << ' ' << m_ui.checkBoxUseAlternatingRowColors->text()
                << ' ' << m_ui.checkBoxUseToolTipsInMainEditor->text()
#ifdef Q_OS_WIN
                << ' ' << m_ui.checkBoxRegisterForPostMortem->text()
#endif
                << ' ' << m_ui.labelMaximalStackDepth->text();
        m_searchKeywords.remove(QLatin1Char('&'));
    }
#ifndef Q_OS_WIN
    m_ui.checkBoxRegisterForPostMortem->setVisible(false);
#endif
    return w;
}

bool CommonOptionsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

///////////////////////////////////////////////////////////////////////
//
// DebuggingHelperOptionPage
//
///////////////////////////////////////////////////////////////////////

static inline bool oxygenStyle()
{
    if (const ManhattanStyle *ms = qobject_cast<const ManhattanStyle *>(qApp->style()))
        return !qstrcmp("OxygenStyle", ms->baseStyle()->metaObject()->className());
    return false;
}

class DebuggingHelperOptionPage : public Core::IOptionsPage
{
public:
    DebuggingHelperOptionPage() {}

    // IOptionsPage
    QString id() const { return _("Z.DebuggingHelper"); }
    QString displayName() const { return tr("Debugging Helper"); }
    QString category() const { return _(DEBUGGER_SETTINGS_CATEGORY); }
    QString displayCategory() const { return QCoreApplication::translate("Debugger", DEBUGGER_SETTINGS_TR_CATEGORY); }
    QIcon categoryIcon() const { return QIcon(QLatin1String(DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON)); }

    QWidget *createPage(QWidget *parent);
    void apply() { m_group.apply(settings()); }
    void finish() { m_group.finish(); }
    virtual bool matches(const QString &s) const;

private:
    Ui::DebuggingHelperOptionPage m_ui;
    Utils::SavedActionSet m_group;
    QString m_searchKeywords;
};

QWidget *DebuggingHelperOptionPage::createPage(QWidget *parent)
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);

    m_ui.dumperLocationChooser->setExpectedKind(Utils::PathChooser::Command);
    m_ui.dumperLocationChooser->setPromptDialogTitle(tr("Choose DebuggingHelper Location"));
    m_ui.dumperLocationChooser->setInitialBrowsePathBackup(
        Core::ICore::instance()->resourcePath() + "../../lib");

    m_group.clear();
    m_group.insert(theDebuggerAction(UseDebuggingHelpers),
        m_ui.debuggingHelperGroupBox);
    m_group.insert(theDebuggerAction(UseCustomDebuggingHelperLocation),
        m_ui.customLocationGroupBox);
    // Suppress Oxygen style's giving flat group boxes bold titles.
    if (oxygenStyle())
        m_ui.customLocationGroupBox->setStyleSheet(_("QGroupBox::title { font: ; }"));

    m_group.insert(theDebuggerAction(CustomDebuggingHelperLocation),
        m_ui.dumperLocationChooser);

    m_group.insert(theDebuggerAction(UseCodeModel),
        m_ui.checkBoxUseCodeModel);

#ifdef QT_DEBUG
    m_group.insert(theDebuggerAction(DebugDebuggingHelpers),
        m_ui.checkBoxDebugDebuggingHelpers);
#else
    m_ui.checkBoxDebugDebuggingHelpers->hide();
#endif

#ifndef QT_DEBUG
#if 0
    cmd = am->registerAction(m_manager->m_dumpLogAction,
        DUMP_LOG, globalcontext);
    //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+L")));
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F11")));
    mdebug->addAction(cmd);
#endif
#endif

    if (m_searchKeywords.isEmpty()) {
        QTextStream(&m_searchKeywords)
                << ' ' << m_ui.debuggingHelperGroupBox->title()
                << ' ' << m_ui.customLocationGroupBox->title()
                << ' ' << m_ui.dumperLocationLabel->text()
                << ' ' << m_ui.checkBoxUseCodeModel->text()
                << ' ' << m_ui.checkBoxDebugDebuggingHelpers->text();
        m_searchKeywords.remove(QLatin1Char('&'));
    }
    return w;
}

bool DebuggingHelperOptionPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}


///////////////////////////////////////////////////////////////////////
//
// Argument parsing
//
///////////////////////////////////////////////////////////////////////

static QString msgParameterMissing(const QString &a)
{
    return DebuggerPlugin::tr("Option '%1' is missing the parameter.").arg(a);
}

static QString msgInvalidNumericParameter(const QString &a, const QString &number)
{
    return DebuggerPlugin::tr("The parameter '%1' of option '%2' is not a number.").arg(number, a);
}

static bool parseArgument(QStringList::const_iterator &it,
    const QStringList::const_iterator &cend,
    AttachRemoteParameters *attachRemoteParameters,
    unsigned *enabledEngines, QString *errorMessage)
{
    const QString &option = *it;
    // '-debug <pid>'
    if (*it == _("-debug")) {
        ++it;
        if (it == cend) {
            *errorMessage = msgParameterMissing(*it);
            return false;
        }
        bool ok;
        attachRemoteParameters->attachPid = it->toULongLong(&ok);
        if (!ok) {
            attachRemoteParameters->attachPid = 0;
            attachRemoteParameters->attachCore = *it;
        }
        return true;
    }
    // -wincrashevent <event-handle>. A handle used for
    // a handshake when attaching to a crashed Windows process.
    if (*it == _("-wincrashevent")) {
        ++it;
        if (it == cend) {
            *errorMessage = msgParameterMissing(*it);
            return false;
        }
        bool ok;
        attachRemoteParameters->winCrashEvent = it->toULongLong(&ok);
        if (!ok) {
            *errorMessage = msgInvalidNumericParameter(option, *it);
            return false;
        }
        return true;
    }
    // Engine disabling.
    if (option == _("-disable-cdb")) {
        *enabledEngines &= ~Debugger::CdbEngineType;
        return true;
    }
    if (option == _("-disable-gdb")) {
        *enabledEngines &= ~Debugger::GdbEngineType;
        return true;
    }
    if (option == _("-disable-qmldb")) {
        *enabledEngines &= ~Debugger::QmlEngineType;
        return true;
    }
    if (option == _("-disable-sdb")) {
        *enabledEngines &= ~Debugger::ScriptEngineType;
        return true;
    }
    if (option == _("-disable-tcf")) {
        *enabledEngines &= ~TcfEngineType;
        return true;
    }

    *errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option);
    return false;
}

static bool parseArguments(const QStringList &args,
   AttachRemoteParameters *attachRemoteParameters,
   unsigned *enabledEngines, QString *errorMessage)
{
    const QStringList::const_iterator cend = args.constEnd();
    for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it)
        if (!parseArgument(it, cend, attachRemoteParameters, enabledEngines, errorMessage))
            return false;
    if (Debugger::Constants::Internal::debug)
        qDebug().nospace() << args << "engines=0x"
            << QString::number(*enabledEngines, 16)
            << " pid" << attachRemoteParameters->attachPid
            << " core" << attachRemoteParameters->attachCore << '\n';
    return true;
}


///////////////////////////////////////////////////////////////////////
//
// Misc
//
///////////////////////////////////////////////////////////////////////

static bool isDebuggable(Core::IEditor *editor)
{
    // Only blacklist Qml. Whitelisting would fail on C++ code in files
    // with strange names, more harm would be done this way.
    //Core::IFile *file = editor->file();
    //return !(file && file->mimeType() == "application/x-qml");

    // Nowadays, even Qml is debuggable.
    Q_UNUSED(editor);
    return true;
}

static TextEditor::ITextEditor *currentTextEditor()
{
    EditorManager *editorManager = EditorManager::instance();
    if (!editorManager)
        return 0;
    Core::IEditor *editor = editorManager->currentEditor();
    return qobject_cast<ITextEditor*>(editor);
}

static bool isCurrentProjectCppBased()
{
    Project *startupProject = ProjectExplorerPlugin::instance()->startupProject();
    if (!startupProject)
        return false;
    const QString id = startupProject->id();
    return id == _("GenericProjectManager.GenericProject")
        || id == _("CMakeProjectManager.CMakeProject")
        || id == _("Qt4ProjectManager.Qt4Project");
}


///////////////////////////////////////////////////////////////////////
//
// SessionEngine
//
///////////////////////////////////////////////////////////////////////

// This class contains data serving as a template for debugger engines
// started during a session.

class SessionEngine : public DebuggerEngine
{
public:
    SessionEngine() : DebuggerEngine(DebuggerStartParameters()) {}

    bool isSessionEngine() const { return true; }

    void loadSessionData()
    {
        breakHandler()->loadSessionData();
        watchHandler()->loadSessionData();
    }

    void saveSessionData()
    {
        watchHandler()->saveSessionData();
        breakHandler()->saveSessionData();
    }

};


///////////////////////////////////////////////////////////////////////
//
// DebuggerPluginPrivate
//
///////////////////////////////////////////////////////////////////////

struct DebuggerActions
{
    QAction *continueAction;
    QAction *stopAction;
    QAction *resetAction; // FIXME: Should not be needed in a stable release
    QAction *stepAction;
    QAction *stepOutAction;
    QAction *runToLineAction1; // in the Debug menu
    QAction *runToLineAction2; // in the text editor context menu
    QAction *runToFunctionAction;
    QAction *jumpToLineAction1; // in the Debug menu
    QAction *jumpToLineAction2; // in the text editor context menu
    QAction *returnFromFunctionAction;
    QAction *nextAction;
    QAction *snapshotAction;
    QAction *watchAction1; // in the Debug menu
    QAction *watchAction2; // in the text editor context menu
    QAction *breakAction;
    QAction *sepAction;
    QAction *reverseDirectionAction;
    QAction *frameUpAction;
    QAction *frameDownAction;
};

} // namespace Internal
using namespace Debugger::Internal;

///////////////////////////////////////////////////////////////////////
//
// DebuggerPluginPrivate
//
///////////////////////////////////////////////////////////////////////

class DebuggerPluginPrivate : public QObject
{
    Q_OBJECT

public:
    explicit DebuggerPluginPrivate(DebuggerPlugin *plugin);

    bool initialize(const QStringList &arguments, QString *errorMessage);
    void notifyCurrentEngine(int role, const QVariant &value = QVariant());
    void connectEngine(DebuggerEngine *engine);
    void disconnectEngine() { connectEngine(m_sessionEngine); }

public slots:
    void updateWatchersHeader(int section, int, int newSize)
        { m_watchersWindow->header()->resizeSection(section, newSize); }

    void sourceFilesDockToggled(bool on)
        { if (on) notifyCurrentEngine(RequestReloadSourceFilesRole); }
    void modulesDockToggled(bool on)
        { if (on) notifyCurrentEngine(RequestReloadModulesRole); }
    void registerDockToggled(bool on)
        { if (on) notifyCurrentEngine(RequestReloadRegistersRole); }

    void onAction();
    void setSimpleDockWidgetArrangement(const QString &activeLanguage);

    void editorOpened(Core::IEditor *editor);
    void editorAboutToClose(Core::IEditor *editor);
    void setBusyCursor(bool busy);
    void requestMark(TextEditor::ITextEditor *editor, int lineNumber);
    void showToolTip(TextEditor::ITextEditor *editor, const QPoint &pnt, int pos);
    void requestContextMenu(TextEditor::ITextEditor *editor,
        int lineNumber, QMenu *menu);

    void activatePreviousMode();
    void activateDebugMode();
    void toggleBreakpoint();
    void toggleBreakpoint(const QString &fileName, int lineNumber);
    void onModeChanged(Core::IMode *mode);
    void showSettingsDialog();

    void startExternalApplication();
    void startRemoteApplication();
    void attachExternalApplication();
    void attachExternalApplication
        (qint64 pid, const QString &binary, const QString &crashParameter);
    void attachCore();
    void attachCore(const QString &core, const QString &exeFileName);
    void attachCmdLine();
    void attachRemoteTcf();

    void interruptDebuggingRequest();
    void exitDebugger();

    void enableReverseDebuggingTriggered(const QVariant &value);
    void languageChanged(const QString &debuggerLanguage);
    void showStatusMessage(const QString &msg, int timeout = -1);

    DebuggerMainWindow *mainWindow()
        { return qobject_cast<DebuggerMainWindow*>
            (DebuggerUISwitcher::instance()->mainWindow()); }
    void setConfigValue(const QString &name, const QVariant &value)
        { settings()->setValue(name, value); }
    QVariant configValue(const QString &name) const
        { return settings()->value(name); }

    DebuggerRunControl *createDebugger(const DebuggerStartParameters &sp);
    void startDebugger(ProjectExplorer::RunControl *runControl);

    void dumpLog();
    void cleanupViews();

    void fontSettingsChanged(const TextEditor::FontSettings &settings);
    DebuggerState state() const { return m_state; }

    void updateState(DebuggerEngine *engine);

    void resetLocation();
    void gotoLocation(const QString &file, int line, bool setMarker);

    void clearStatusMessage();

    void sessionLoaded();
    void aboutToUnloadSession();
    void aboutToSaveSession();

    void executeDebuggerCommand();

public:
    DebuggerState m_state;
    uint m_capabilities;
    DebuggerUISwitcher *m_uiSwitcher;
    DebuggerPlugin *m_manager;
    DebugMode *m_debugMode;
    DebuggerRunControlFactory *m_debuggerRunControlFactory;

    QString m_previousMode;
    TextEditor::BaseTextMark *m_locationMark;
    Core::Context m_gdbRunningContext;
    AttachRemoteParameters m_attachRemoteParameters;

    QAction *m_startExternalAction;
    QAction *m_startRemoteAction;
    QAction *m_attachExternalAction;
    QAction *m_attachCoreAction;
    QAction *m_attachTcfAction;
    QAction *m_detachAction;
    QComboBox *m_langBox;
    QToolButton *m_reverseToolButton;

    QIcon m_stopIcon;
    QIcon m_interruptIcon;
    QIcon m_locationMarkIcon;

    QLabel *m_statusLabel;
    QComboBox *m_threadBox;

    QDockWidget *m_breakDock;
    QDockWidget *m_modulesDock;
    QDockWidget *m_outputDock;
    QDockWidget *m_registerDock;
    QDockWidget *m_snapshotDock;
    QDockWidget *m_sourceFilesDock;
    QDockWidget *m_stackDock;
    QDockWidget *m_threadsDock;
    QDockWidget *m_watchDock;
    QList<QDockWidget *> m_dockWidgets;

    DebuggerActions m_actions;

    BreakWindow *m_breakWindow;
    QTreeView *m_returnWindow;
    QTreeView *m_localsWindow;
    QTreeView *m_watchersWindow;
    QTreeView *m_commandWindow;
    QAbstractItemView *m_registerWindow;
    QAbstractItemView *m_modulesWindow;
    QAbstractItemView *m_snapshotWindow;
    SourceFilesWindow *m_sourceFilesWindow;
    QAbstractItemView *m_stackWindow;
    QAbstractItemView *m_threadsWindow;
    DebuggerOutputWindow *m_outputWindow;

    SessionEngine *m_sessionEngine;

    bool m_busy;
    QTimer m_statusTimer;
    QString m_lastPermanentStatusMessage;

    //SessionData m_sessionData;

    CPlusPlus::Snapshot m_codeModelSnapshot;
    DebuggerPlugin *m_plugin;

    QList<QPointer<DebuggerRunControl> > m_allRunControls;
};

DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin)
{
    m_plugin = plugin;

    m_statusLabel = 0;
    m_threadBox = 0;

    m_breakDock = 0;
    m_modulesDock = 0;
    m_outputDock = 0;
    m_registerDock = 0;
    m_snapshotDock = 0;
    m_sourceFilesDock = 0;
    m_stackDock = 0;
    m_threadsDock = 0;
    m_watchDock = 0;

    m_breakWindow = 0;
    m_returnWindow = 0;
    m_localsWindow = 0;
    m_watchersWindow = 0;
    m_registerWindow = 0;
    m_modulesWindow = 0;
    m_snapshotWindow = 0;
    m_sourceFilesWindow = 0;
    m_stackWindow = 0;
    m_threadsWindow = 0;
    m_outputWindow = 0;

    m_sessionEngine = 0;
    m_debugMode = 0;
    m_locationMark = 0;
    m_gdbRunningContext = Core::Context(0);

    m_debugMode = 0;
    m_uiSwitcher = 0;
    m_state = DebuggerNotReady;
}

bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *errorMessage)
{
    // FIXME: Move part of this to extensionsInitialized()?
    ICore *core = ICore::instance();
    QTC_ASSERT(core, return false);

    Core::ActionManager *am = core->actionManager();
    QTC_ASSERT(am, return false);

    const Core::Context globalcontext(CC::C_GLOBAL_ID);
    const Core::Context cppDebuggercontext(C_CPPDEBUGGER);
    const Core::Context cppeditorcontext(CppEditor::Constants::C_CPPEDITOR);

    m_stopIcon = QIcon(_(":/debugger/images/debugger_stop_small.png"));
    m_stopIcon.addFile(":/debugger/images/debugger_stop.png");
    m_interruptIcon = QIcon(_(":/debugger/images/debugger_interrupt_small.png"));
    m_interruptIcon.addFile(":/debugger/images/debugger_interrupt.png");
    m_locationMarkIcon = QIcon(_(":/debugger/images/location_16.png"));

    m_busy = false;

    m_statusLabel = new QLabel;
    m_statusLabel->setMinimumSize(QSize(30, 10));

    m_breakWindow = new BreakWindow;
    m_breakWindow->setObjectName(QLatin1String("CppDebugBreakpoints"));
    m_modulesWindow = new ModulesWindow;
    m_modulesWindow->setObjectName(QLatin1String("CppDebugModules"));
    m_outputWindow = new DebuggerOutputWindow;
    m_outputWindow->setObjectName(QLatin1String("CppDebugOutput"));

    m_registerWindow = new RegisterWindow;
    m_registerWindow->setObjectName(QLatin1String("CppDebugRegisters"));
    m_snapshotWindow = new SnapshotWindow;
    m_snapshotWindow->setObjectName(QLatin1String("CppDebugSnapshots"));
    m_stackWindow = new StackWindow;
    m_stackWindow->setObjectName(QLatin1String("CppDebugStack"));
    m_sourceFilesWindow = new SourceFilesWindow;
    m_sourceFilesWindow->setObjectName(QLatin1String("CppDebugSources"));
    m_threadsWindow = new ThreadsWindow;
    m_threadsWindow->setObjectName(QLatin1String("CppDebugThreads"));
    m_returnWindow = new WatchWindow(WatchWindow::ReturnType);
    m_returnWindow->setObjectName(QLatin1String("CppDebugReturn"));
    m_localsWindow = new WatchWindow(WatchWindow::LocalsType);
    m_localsWindow->setObjectName(QLatin1String("CppDebugLocals"));
    m_watchersWindow = new WatchWindow(WatchWindow::WatchersType);
    m_watchersWindow->setObjectName(QLatin1String("CppDebugWatchers"));
    m_commandWindow = new QTreeView;

    // Session related data
    m_sessionEngine = new SessionEngine;

    // Debug mode setup
    m_debugMode = new DebugMode(this);

    // Watchers
    connect(m_localsWindow->header(), SIGNAL(sectionResized(int,int,int)),
        this, SLOT(updateWatchersHeader(int,int,int)), Qt::QueuedConnection);

    // Tooltip
    qRegisterMetaType<WatchData>("WatchData");
    qRegisterMetaType<StackCookie>("StackCookie");

    m_actions.continueAction = new QAction(tr("Continue"), this);
    QIcon continueIcon = QIcon(":/debugger/images/debugger_continue_small.png");
    continueIcon.addFile(":/debugger/images/debugger_continue.png");
    m_actions.continueAction->setIcon(continueIcon);
    m_actions.continueAction->setProperty(Role, RequestExecContinueRole);

    m_actions.stopAction = new QAction(tr("Interrupt"), this);
    m_actions.stopAction->setIcon(m_interruptIcon);
    m_actions.stopAction->setProperty(Role, RequestExecInterruptRole);

    m_actions.resetAction = new QAction(tr("Abort Debugging"), this);
    m_actions.resetAction->setProperty(Role, RequestExecResetRole);
    m_actions.resetAction->setToolTip(tr("Aborts debugging and "
        "resets the debugger to the initial state."));

    m_actions.nextAction = new QAction(tr("Step Over"), this);
    m_actions.nextAction->setProperty(Role, RequestExecNextRole);
    m_actions.nextAction->setIcon(
        QIcon(":/debugger/images/debugger_stepover_small.png"));

    m_actions.stepAction = new QAction(tr("Step Into"), this);
    m_actions.stepAction->setProperty(Role, RequestExecStepRole);
    m_actions.stepAction->setIcon(
        QIcon(":/debugger/images/debugger_stepinto_small.png"));

    m_actions.stepOutAction = new QAction(tr("Step Out"), this);
    m_actions.stepOutAction->setProperty(Role, RequestExecStepOutRole);
    m_actions.stepOutAction->setIcon(
        QIcon(":/debugger/images/debugger_stepout_small.png"));

    m_actions.runToLineAction1 = new QAction(tr("Run to Line"), this);
    m_actions.runToLineAction1->setProperty(Role, RequestExecRunToLineRole);
    m_actions.runToLineAction2 = new QAction(tr("Run to Line"), this);
    m_actions.runToLineAction2->setProperty(Role, RequestExecRunToLineRole);

    m_actions.runToFunctionAction =
        new QAction(tr("Run to Outermost Function"), this);
    m_actions.runToFunctionAction->setProperty(Role, RequestExecRunToFunctionRole);

    m_actions.returnFromFunctionAction =
        new QAction(tr("Immediately Return From Inner Function"), this);
    m_actions.returnFromFunctionAction->setProperty(Role, RequestExecReturnFromFunctionRole);

    m_actions.jumpToLineAction1 = new QAction(tr("Jump to Line"), this);
    m_actions.jumpToLineAction1->setProperty(Role, RequestExecJumpToLineRole);
    m_actions.jumpToLineAction2 = new QAction(tr("Jump to Line"), this);
    m_actions.jumpToLineAction1->setProperty(Role, RequestExecJumpToLineRole);

    m_actions.breakAction = new QAction(tr("Toggle Breakpoint"), this);

    m_actions.watchAction1 = new QAction(tr("Add to Watch Window"), this);
    m_actions.watchAction1->setProperty(Role, RequestExecWatchRole);
    m_actions.watchAction2 = new QAction(tr("Add to Watch Window"), this);
    m_actions.watchAction2->setProperty(Role, RequestExecWatchRole);

    m_actions.snapshotAction = new QAction(tr("Snapshot"), this);
    m_actions.snapshotAction->setProperty(Role, RequestExecSnapshotRole);
    m_actions.snapshotAction->setIcon(
        QIcon(":/debugger/images/debugger_snapshot_small.png"));

    m_actions.reverseDirectionAction =
        new QAction(tr("Reverse Direction"), this);
    m_actions.reverseDirectionAction->setCheckable(true);
    m_actions.reverseDirectionAction->setChecked(false);
    m_actions.reverseDirectionAction->setIcon(
        QIcon(":/debugger/images/debugger_reversemode_16.png"));
    m_actions.reverseDirectionAction->setIconVisibleInMenu(false);

    m_actions.frameDownAction =
        new QAction(tr("Move to Called Frame"), this);
    m_actions.frameDownAction->setProperty(Role, RequestExecFrameDownRole);
    m_actions.frameUpAction =
        new QAction(tr("Move to Calling Frame"), this);
    m_actions.frameUpAction->setProperty(Role, RequestExecFrameUpRole);

    m_actions.reverseDirectionAction->setCheckable(false);
    theDebuggerAction(OperateByInstruction)->
        setProperty(Role, RequestOperatedByInstructionTriggeredRole);

    connect(m_actions.continueAction, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.nextAction, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.stepAction, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.stepOutAction, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.runToLineAction1, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.runToLineAction2, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.runToFunctionAction, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.jumpToLineAction1, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.jumpToLineAction2, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.returnFromFunctionAction, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.watchAction1, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.watchAction2, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.snapshotAction, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.frameDownAction, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.frameUpAction, SIGNAL(triggered()), SLOT(onAction()));
    connect(m_actions.stopAction, SIGNAL(triggered()), SLOT(interruptDebuggingRequest()));
    connect(m_actions.resetAction, SIGNAL(triggered()), SLOT(onAction()));
    connect(&m_statusTimer, SIGNAL(timeout()), SLOT(clearStatusMessage()));

    connect(theDebuggerAction(ExecuteCommand), SIGNAL(triggered()),
        SLOT(executeDebuggerCommand()));

    connect(theDebuggerAction(OperateByInstruction), SIGNAL(triggered()),
        SLOT(onAction()));

    m_plugin->readSettings();

    // Cpp/Qml ui setup
    m_uiSwitcher = new DebuggerUISwitcher(m_debugMode, this);
    ExtensionSystem::PluginManager::instance()->addObject(m_uiSwitcher);
    theDebuggerAction(SwitchLanguageAutomatically)->setChecked(true);
    m_uiSwitcher->addLanguage(LANG_CPP, cppDebuggercontext);
    m_uiSwitcher->setActiveLanguage(LANG_CPP);


    // Dock widgets
    m_breakDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_breakWindow);

    m_modulesDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_modulesWindow,
                                                    Qt::TopDockWidgetArea, false);
    connect(m_modulesDock->toggleViewAction(), SIGNAL(toggled(bool)),
        SLOT(modulesDockToggled(bool)), Qt::QueuedConnection);

    m_registerDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_registerWindow,
        Qt::TopDockWidgetArea, false);
    connect(m_registerDock->toggleViewAction(), SIGNAL(toggled(bool)),
        SLOT(registerDockToggled(bool)), Qt::QueuedConnection);

    m_outputDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_outputWindow,
        Qt::TopDockWidgetArea, false);

    m_snapshotDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_snapshotWindow);

    m_stackDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_stackWindow);

    m_sourceFilesDock = m_uiSwitcher->createDockWidget(LANG_CPP,
        m_sourceFilesWindow, Qt::TopDockWidgetArea, false);
    connect(m_sourceFilesDock->toggleViewAction(), SIGNAL(toggled(bool)),
        SLOT(sourceFilesDockToggled(bool)), Qt::QueuedConnection);

    m_threadsDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_threadsWindow);

    QSplitter *localsAndWatchers = new Core::MiniSplitter(Qt::Vertical);
    localsAndWatchers->setObjectName(QLatin1String("CppDebugLocalsAndWatchers"));
    localsAndWatchers->setWindowTitle(m_localsWindow->windowTitle());
    localsAndWatchers->addWidget(m_localsWindow);
    localsAndWatchers->addWidget(m_returnWindow);
    localsAndWatchers->addWidget(m_watchersWindow);
    //localsAndWatchers->addWidget(m_tooltipWindow);
    localsAndWatchers->setStretchFactor(0, 3);
    localsAndWatchers->setStretchFactor(1, 1);
    localsAndWatchers->setStretchFactor(2, 1);
    m_watchDock = m_uiSwitcher->createDockWidget(LANG_CPP, localsAndWatchers);
    m_dockWidgets << m_breakDock << m_modulesDock << m_registerDock
                  << m_outputDock << m_stackDock << m_sourceFilesDock
                  << m_threadsDock << m_watchDock;

    // Do not fail the whole plugin if something goes wrong here.
    uint cmdLineEnabledEngines = AllEngineTypes;
    if (!parseArguments(arguments, &m_attachRemoteParameters, &cmdLineEnabledEngines, errorMessage)) {
        *errorMessage = tr("Error evaluating command line arguments: %1")
            .arg(*errorMessage);
        qWarning("%s\n", qPrintable(*errorMessage));
        errorMessage->clear();
    }

    m_gdbRunningContext = Core::Context(Constants::GDBRUNNING);

    // Register factory of DebuggerRunControl.
    m_debuggerRunControlFactory = new DebuggerRunControlFactory
        (m_plugin, DebuggerEngineType(cmdLineEnabledEngines));
    m_plugin->addAutoReleasedObject(m_debuggerRunControlFactory);

    m_debugMode->setContext(
        Core::Context(CC::C_EDITORMANAGER, C_DEBUGMODE, CC::C_NAVIGATION_PANE));

    m_reverseToolButton = 0;

    // Handling of external applications.
    m_startExternalAction = new QAction(this);
    m_startExternalAction->setText(tr("Start and Debug External Application..."));
    connect(m_startExternalAction, SIGNAL(triggered()),
        this, SLOT(startExternalApplication()));

    m_attachExternalAction = new QAction(this);
    m_attachExternalAction->setText(tr("Attach to Running External Application..."));
    connect(m_attachExternalAction, SIGNAL(triggered()),
        this, SLOT(attachExternalApplication()));

    m_attachCoreAction = new QAction(this);
    m_attachCoreAction->setText(tr("Attach to Core..."));
    connect(m_attachCoreAction, SIGNAL(triggered()), this, SLOT(attachCore()));

    m_attachTcfAction = new QAction(this);
    m_attachTcfAction->setText(tr("Attach to Running Tcf Agent..."));
    m_attachTcfAction->setToolTip(tr("This attaches to a running "
        "'Target Communication Framework' agent."));
    connect(m_attachTcfAction, SIGNAL(triggered()),
        this, SLOT(attachRemoteTcf()));

    m_startRemoteAction = new QAction(this);
    m_startRemoteAction->setText(tr("Start and Attach to Remote Application..."));
    connect(m_startRemoteAction, SIGNAL(triggered()),
        this, SLOT(startRemoteApplication()));

    m_detachAction = new QAction(this);
    m_detachAction->setText(tr("Detach Debugger"));
    m_detachAction->setProperty(Role, RequestExecDetachRole);
    connect(m_detachAction, SIGNAL(triggered()), SLOT(onAction()));

    Core::Command *cmd = 0;

    Core::ActionContainer *mstart =
        am->actionContainer(PE::M_DEBUG_STARTDEBUGGING);

    cmd = am->registerAction(m_actions.continueAction,
        PE::DEBUG, m_gdbRunningContext);
    mstart->addAction(cmd, CC::G_DEFAULT_ONE);

    cmd = am->registerAction(m_startExternalAction,
        Constants::STARTEXTERNAL, globalcontext);
    cmd->setAttribute(Command::CA_Hide);
    mstart->addAction(cmd, CC::G_DEFAULT_ONE);

    cmd = am->registerAction(m_attachExternalAction,
        Constants::ATTACHEXTERNAL, globalcontext);
    cmd->setAttribute(Command::CA_Hide);
    mstart->addAction(cmd, CC::G_DEFAULT_ONE);

    cmd = am->registerAction(m_attachCoreAction,
        Constants::ATTACHCORE, globalcontext);

    cmd->setAttribute(Command::CA_Hide);
    mstart->addAction(cmd, CC::G_DEFAULT_ONE);

    cmd = am->registerAction(m_attachTcfAction,
        Constants::ATTACHTCF, globalcontext);
    mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE);

    cmd = am->registerAction(m_startRemoteAction,
        Constants::ATTACHREMOTE, globalcontext);
    cmd->setAttribute(Command::CA_Hide);
    mstart->addAction(cmd, CC::G_DEFAULT_ONE);

    cmd = am->registerAction(m_detachAction,
        Constants::DETACH, globalcontext);
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, CC::G_DEFAULT_ONE);

    cmd = am->registerAction(m_actions.stopAction,
        Constants::INTERRUPT, globalcontext);
    cmd->setAttribute(Command::CA_UpdateText);
    cmd->setAttribute(Command::CA_UpdateIcon);
    cmd->setDefaultKeySequence(QKeySequence(Constants::INTERRUPT_KEY));
    cmd->setDefaultText(tr("Stop Debugger/Interrupt Debugger"));
    m_uiSwitcher->addMenuAction(cmd, CC::G_DEFAULT_ONE);

    cmd = am->registerAction(m_actions.resetAction,
        Constants::RESET, globalcontext);
    cmd->setAttribute(Core::Command::CA_UpdateText);
    //cmd->setDefaultKeySequence(QKeySequence(Constants::RESET_KEY));
    cmd->setDefaultText(tr("Reset Debugger"));
    m_uiSwitcher->addMenuAction(cmd, CC::G_DEFAULT_ONE);

    QAction *sep = new QAction(this);
    sep->setSeparator(true);
    cmd = am->registerAction(sep, _("Debugger.Sep.Step"), globalcontext);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);

    cmd = am->registerAction(m_actions.nextAction,
        Constants::NEXT, cppDebuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::NEXT_KEY));
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);

    cmd = am->registerAction(m_actions.stepAction,
        Constants::STEP, cppDebuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::STEP_KEY));
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    cmd = am->registerAction(m_actions.stepOutAction,
        Constants::STEPOUT, cppDebuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::STEPOUT_KEY));
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    cmd = am->registerAction(m_actions.runToLineAction1,
        Constants::RUN_TO_LINE1, cppDebuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::RUN_TO_LINE_KEY));
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    cmd = am->registerAction(m_actions.runToFunctionAction,
        Constants::RUN_TO_FUNCTION, cppDebuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::RUN_TO_FUNCTION_KEY));
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    cmd = am->registerAction(m_actions.jumpToLineAction1,
        Constants::JUMP_TO_LINE1, cppDebuggercontext);
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    cmd = am->registerAction(m_actions.returnFromFunctionAction,
        Constants::RETURN_FROM_FUNCTION, cppDebuggercontext);
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    cmd = am->registerAction(m_actions.reverseDirectionAction,
        Constants::REVERSE, cppDebuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::REVERSE_KEY));
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    sep = new QAction(this);
    sep->setSeparator(true);
    cmd = am->registerAction(sep, _("Debugger.Sep.Break"), globalcontext);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    cmd = am->registerAction(m_actions.snapshotAction,
        Constants::SNAPSHOT, cppDebuggercontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::SNAPSHOT_KEY));
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);

    cmd = am->registerAction(m_actions.frameDownAction,
        Constants::FRAME_DOWN, cppDebuggercontext);
    cmd = am->registerAction(m_actions.frameUpAction,
        Constants::FRAME_UP, cppDebuggercontext);


    cmd = am->registerAction(theDebuggerAction(OperateByInstruction),
        Constants::OPERATE_BY_INSTRUCTION, cppDebuggercontext);
    cmd->setAttribute(Command::CA_Hide);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    cmd = am->registerAction(m_actions.breakAction,
        Constants::TOGGLE_BREAK, cppeditorcontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::TOGGLE_BREAK_KEY));
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);
    connect(m_actions.breakAction, SIGNAL(triggered()),
        this, SLOT(toggleBreakpoint()));

    //mcppcontext->addAction(cmd);

    sep = new QAction(this);
    sep->setSeparator(true);
    cmd = am->registerAction(sep, _("Debugger.Sep.Watch"), globalcontext);
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    cmd = am->registerAction(m_actions.watchAction1,
        Constants::ADD_TO_WATCH1, cppeditorcontext);
    cmd->action()->setEnabled(true);
    //cmd->setDefaultKeySequence(QKeySequence(tr("ALT+D,ALT+W")));
    m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);


    // Editor context menu
    ActionContainer *editorContextMenu =
        am->actionContainer(CppEditor::Constants::M_CONTEXT);
    cmd = am->registerAction(sep, _("Debugger.Sep.Views"),
        cppDebuggercontext);
    editorContextMenu->addAction(cmd);
    cmd->setAttribute(Command::CA_Hide);

    cmd = am->registerAction(m_actions.watchAction2,
        Constants::ADD_TO_WATCH2, cppDebuggercontext);
    cmd->action()->setEnabled(true);
    editorContextMenu->addAction(cmd);
    cmd->setAttribute(Command::CA_Hide);

    cmd = am->registerAction(m_actions.runToLineAction2,
        Constants::RUN_TO_LINE2, cppDebuggercontext);
    cmd->action()->setEnabled(true);
    editorContextMenu->addAction(cmd);
    cmd->setAttribute(Command::CA_Hide);

    cmd = am->registerAction(m_actions.jumpToLineAction2,
        Constants::JUMP_TO_LINE2, cppDebuggercontext);
    cmd->action()->setEnabled(true);
    editorContextMenu->addAction(cmd);
    cmd->setAttribute(Command::CA_Hide);

    m_plugin->addAutoReleasedObject(new CommonOptionsPage);
    QList<Core::IOptionsPage *> engineOptionPages;
    if (cmdLineEnabledEngines & GdbEngineType)
        addGdbOptionPages(&engineOptionPages);
#ifdef CDB_ENABLED
    if (cmdLineEnabledEngines & CdbEngineType)
        addCdbOptionPages(&engineOptionPages);
#endif
    //if (cmdLineEnabledEngines & ScriptEngineType)
    //    addScriptOptionPages(&engineOptionPages);
    //if (cmdLineEnabledEngines & TcfEngineType)
    //    addTcfOptionPages(&engineOptionPages);
    foreach (Core::IOptionsPage *op, engineOptionPages)
        m_plugin->addAutoReleasedObject(op);
    m_plugin->addAutoReleasedObject(new DebuggingHelperOptionPage);

    m_plugin->addAutoReleasedObject(new DebuggerListener);
    m_locationMark = 0;

    //setSimpleDockWidgetArrangement(LANG_CPP);

    connect(ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*)),
            this, SLOT(onModeChanged(Core::IMode*)));
    m_debugMode->widget()->setFocusProxy(EditorManager::instance());
    m_plugin->addObject(m_debugMode);


    //
    //  Connections
    //

    // TextEditor
    connect(TextEditorSettings::instance(),
        SIGNAL(fontSettingsChanged(TextEditor::FontSettings)),
        this, SLOT(fontSettingsChanged(TextEditor::FontSettings)));

    // ProjectExplorer
    connect(sessionManager(), SIGNAL(sessionLoaded()),
       this, SLOT(sessionLoaded()));
    connect(sessionManager(), SIGNAL(aboutToSaveSession()),
       this, SLOT(aboutToSaveSession()));
    connect(sessionManager(), SIGNAL(aboutToUnloadSession()),
       this, SLOT(aboutToUnloadSession()));

    // EditorManager
    QObject *editorManager = core->editorManager();
    connect(editorManager, SIGNAL(editorAboutToClose(Core::IEditor*)),
        this, SLOT(editorAboutToClose(Core::IEditor*)));
    connect(editorManager, SIGNAL(editorOpened(Core::IEditor*)),
        this, SLOT(editorOpened(Core::IEditor*)));

    // Application interaction
    connect(theDebuggerAction(SettingsDialog), SIGNAL(triggered()),
        this, SLOT(showSettingsDialog()));

    // Toolbar
    QWidget *toolbarContainer = new QWidget;

    QHBoxLayout *hbox = new QHBoxLayout(toolbarContainer);
    hbox->setMargin(0);
    hbox->setSpacing(0);
    hbox->addWidget(toolButton(am->command(PE::DEBUG)->action()));
    hbox->addWidget(toolButton(am->command(INTERRUPT)->action()));
    hbox->addWidget(toolButton(am->command(NEXT)->action()));
    hbox->addWidget(toolButton(am->command(STEP)->action()));
    hbox->addWidget(toolButton(am->command(STEPOUT)->action()));
    hbox->addWidget(toolButton(am->command(OPERATE_BY_INSTRUCTION)->action()));

    //hbox->addWidget(new Utils::StyledSeparator);
    m_reverseToolButton = toolButton(am->command(REVERSE)->action());
    hbox->addWidget(m_reverseToolButton);
    //m_reverseToolButton->hide();

    hbox->addWidget(new Utils::StyledSeparator);
    hbox->addWidget(new QLabel(tr("Threads:")));

    m_threadBox = new QComboBox;
    connect(m_threadBox, SIGNAL(activated(int)),
        m_threadsWindow, SLOT(selectThread(int)));

    hbox->addWidget(m_threadBox);
    hbox->addSpacerItem(new QSpacerItem(4, 0));
    hbox->addWidget(m_statusLabel, 10);

    m_uiSwitcher->setToolbar(LANG_CPP, toolbarContainer);
    connect(m_uiSwitcher, SIGNAL(dockArranged(QString)),
        this, SLOT(setSimpleDockWidgetArrangement(QString)));

    connect(theDebuggerAction(EnableReverseDebugging), SIGNAL(valueChanged(QVariant)),
        this, SLOT(enableReverseDebuggingTriggered(QVariant)));

    // UI Switcher
    connect(m_uiSwitcher, SIGNAL(languageChanged(QString)),
        this, SLOT(languageChanged(QString)));
    m_uiSwitcher->initialize();
    m_watchersWindow->setVisible(false);
    m_returnWindow->setVisible(false);

    disconnectEngine();
    return true;
}

void DebuggerPluginPrivate::onAction()
{
    QAction *act = qobject_cast<QAction *>(sender());
    QTC_ASSERT(act, return);
    const int role = act->property(Role).toInt();
    notifyCurrentEngine(role);
}

void DebuggerPluginPrivate::languageChanged(const QString &language)
{
    const bool debuggerIsCPP = (language == Constants::LANG_CPP);
    //qDebug() << "DEBUGGER IS CPP: " << debuggerIsCPP;

    m_startExternalAction->setVisible(debuggerIsCPP);
    m_attachExternalAction->setVisible(debuggerIsCPP);
    m_attachCoreAction->setVisible(debuggerIsCPP);
    m_startRemoteAction->setVisible(debuggerIsCPP);
    m_detachAction->setVisible(debuggerIsCPP);
}

void DebuggerPluginPrivate::startExternalApplication()
{
    DebuggerStartParameters sp;
    StartExternalDialog dlg(mainWindow());
    dlg.setExecutableFile(
            configValue(_("LastExternalExecutableFile")).toString());
    dlg.setExecutableArguments(
            configValue(_("LastExternalExecutableArguments")).toString());
    dlg.setWorkingDirectory(
            configValue(_("LastExternalWorkingDirectory")).toString());
    if (dlg.exec() != QDialog::Accepted)
        return;

    setConfigValue(_("LastExternalExecutableFile"),
                   dlg.executableFile());
    setConfigValue(_("LastExternalExecutableArguments"),
                   dlg.executableArguments());
    setConfigValue(_("LastExternalWorkingDirectory"),
                   dlg.workingDirectory());
    sp.executable = dlg.executableFile();
    sp.startMode = StartExternal;
    sp.workingDirectory = dlg.workingDirectory();
    sp.breakAtMain = dlg.breakAtMain();
    if (!dlg.executableArguments().isEmpty())
        sp.processArgs = dlg.executableArguments().split(QLatin1Char(' '));
    // Fixme: 1 of 3 testing hacks.
    if (!sp.processArgs.isEmpty()
        && (sp.processArgs.front() == _("@tcf@") || sp.processArgs.front() == _("@sym@")))
        sp.toolChainType = ProjectExplorer::ToolChain::RVCT_ARMV5;

    startDebugger(m_debuggerRunControlFactory->create(sp));
}

void DebuggerPluginPrivate::notifyCurrentEngine(int role, const QVariant &value)
{
    QTC_ASSERT(m_commandWindow && m_commandWindow->model(), return);
    m_commandWindow->model()->setData(QModelIndex(), value, role);
}

void DebuggerPluginPrivate::attachExternalApplication()
{
    AttachExternalDialog dlg(mainWindow());
    if (dlg.exec() == QDialog::Accepted)
        attachExternalApplication(dlg.attachPID(), dlg.executable(), QString());
}

void DebuggerPluginPrivate::attachExternalApplication
    (qint64 pid, const QString &binary, const QString &crashParameter)
{
    if (pid == 0) {
        QMessageBox::warning(mainWindow(), tr("Warning"),
            tr("Cannot attach to PID 0"));
        return;
    }
    DebuggerStartParameters sp;
    sp.attachPID = pid;
    sp.executable = binary;
    sp.crashParameter = crashParameter;
    sp.startMode = crashParameter.isEmpty() ? AttachExternal:AttachCrashedExternal;
    startDebugger(m_debuggerRunControlFactory->create(sp));
}

void DebuggerPluginPrivate::attachCore()
{
    AttachCoreDialog dlg(mainWindow());
    dlg.setExecutableFile(
            configValue(_("LastExternalExecutableFile")).toString());
    dlg.setCoreFile(
            configValue(_("LastExternalCoreFile")).toString());
    if (dlg.exec() != QDialog::Accepted)
        return;
    setConfigValue(_("LastExternalExecutableFile"),
                   dlg.executableFile());
    setConfigValue(_("LastExternalCoreFile"),
                   dlg.coreFile());
    attachCore(dlg.coreFile(), dlg.executableFile());
}

void DebuggerPluginPrivate::attachCore(const QString &core, const QString &exe)
{
    DebuggerStartParameters sp;
    sp.executable = exe;
    sp.coreFile = core;
    sp.displayName = tr("Core file: \"%1\"").arg(core);
    sp.startMode = AttachCore;
    startDebugger(createDebugger(sp));
}

void DebuggerPluginPrivate::startRemoteApplication()
{
    DebuggerStartParameters sp;
    StartRemoteDialog dlg(mainWindow());
    QStringList arches;
    arches.append(_("i386:x86-64:intel"));
    arches.append(_("i386"));
    QString lastUsed = configValue(_("LastRemoteArchitecture")).toString();
    if (!arches.contains(lastUsed))
        arches.prepend(lastUsed);
    dlg.setRemoteArchitectures(arches);
    dlg.setRemoteChannel(
            configValue(_("LastRemoteChannel")).toString());
    dlg.setLocalExecutable(
            configValue(_("LastLocalExecutable")).toString());
    dlg.setDebugger(configValue(_("LastDebugger")).toString());
    dlg.setRemoteArchitecture(lastUsed);
    dlg.setServerStartScript(
            configValue(_("LastServerStartScript")).toString());
    dlg.setUseServerStartScript(
            configValue(_("LastUseServerStartScript")).toBool());
    dlg.setSysRoot(configValue(_("LastSysroot")).toString());
    if (dlg.exec() != QDialog::Accepted)
        return;
    setConfigValue(_("LastRemoteChannel"), dlg.remoteChannel());
    setConfigValue(_("LastLocalExecutable"), dlg.localExecutable());
    setConfigValue(_("LastDebugger"), dlg.debugger());
    setConfigValue(_("LastRemoteArchitecture"), dlg.remoteArchitecture());
    setConfigValue(_("LastServerStartScript"), dlg.serverStartScript());
    setConfigValue(_("LastUseServerStartScript"), dlg.useServerStartScript());
    setConfigValue(_("LastSysroot"), dlg.sysRoot());
    sp.remoteChannel = dlg.remoteChannel();
    sp.remoteArchitecture = dlg.remoteArchitecture();
    sp.executable = dlg.localExecutable();
    sp.displayName = dlg.localExecutable();
    sp.debuggerCommand = dlg.debugger(); // Override toolchain-detection.
    if (!sp.debuggerCommand.isEmpty())
        sp.toolChainType = ProjectExplorer::ToolChain::INVALID;
    sp.startMode = AttachToRemote;
    if (dlg.useServerStartScript())
        sp.serverStartScript = dlg.serverStartScript();
    sp.sysRoot = dlg.sysRoot();
    startDebugger(createDebugger(sp));
}

void DebuggerPluginPrivate::enableReverseDebuggingTriggered(const QVariant &value)
{
    QTC_ASSERT(m_reverseToolButton, return);
    m_reverseToolButton->setVisible(value.toBool());
    m_actions.reverseDirectionAction->setChecked(false);
    m_actions.reverseDirectionAction->setEnabled(value.toBool());
}

void DebuggerPluginPrivate::attachRemoteTcf()
{
    DebuggerStartParameters sp;
    AttachTcfDialog dlg(mainWindow());
    QStringList arches;
    arches.append(_("i386:x86-64:intel"));
    dlg.setRemoteArchitectures(arches);
    dlg.setRemoteChannel(
            configValue(_("LastTcfRemoteChannel")).toString());
    dlg.setRemoteArchitecture(
            configValue(_("LastTcfRemoteArchitecture")).toString());
    dlg.setServerStartScript(
            configValue(_("LastTcfServerStartScript")).toString());
    dlg.setUseServerStartScript(
            configValue(_("LastTcfUseServerStartScript")).toBool());
    if (dlg.exec() != QDialog::Accepted)
        return;
    setConfigValue(_("LastTcfRemoteChannel"), dlg.remoteChannel());
    setConfigValue(_("LastTcfRemoteArchitecture"), dlg.remoteArchitecture());
    setConfigValue(_("LastTcfServerStartScript"), dlg.serverStartScript());
    setConfigValue(_("LastTcfUseServerStartScript"), dlg.useServerStartScript());
    sp.remoteChannel = dlg.remoteChannel();
    sp.remoteArchitecture = dlg.remoteArchitecture();
    sp.serverStartScript = dlg.serverStartScript();
    sp.startMode = AttachTcf;
    if (dlg.useServerStartScript())
        sp.serverStartScript = dlg.serverStartScript();
    startDebugger(createDebugger(sp));
}

void DebuggerPluginPrivate::attachCmdLine()
{
    if (m_attachRemoteParameters.attachPid) {
        showStatusMessage(tr("Attaching to PID %1.")
            .arg(m_attachRemoteParameters.attachPid));
        const QString crashParameter = m_attachRemoteParameters.winCrashEvent
            ? QString::number(m_attachRemoteParameters.winCrashEvent) : QString();
        attachExternalApplication(m_attachRemoteParameters.attachPid,
            QString(), crashParameter);
        return;
    }
    if (!m_attachRemoteParameters.attachCore.isEmpty()) {
        showStatusMessage(tr("Attaching to core %1.")
            .arg(m_attachRemoteParameters.attachCore));
        attachCore(m_attachRemoteParameters.attachCore, QString());
    }
}

void DebuggerPluginPrivate::editorOpened(Core::IEditor *editor)
{
    if (!isDebuggable(editor))
        return;
    ITextEditor *textEditor = qobject_cast<ITextEditor *>(editor);
    if (!textEditor)
        return;
    connect(textEditor, SIGNAL(markRequested(TextEditor::ITextEditor*,int)),
        this, SLOT(requestMark(TextEditor::ITextEditor*,int)));
    connect(editor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*,QPoint,int)),
        this, SLOT(showToolTip(TextEditor::ITextEditor*,QPoint,int)));
    connect(textEditor, SIGNAL(markContextMenuRequested(TextEditor::ITextEditor*,int,QMenu*)),
        this, SLOT(requestContextMenu(TextEditor::ITextEditor*,int,QMenu*)));
}

void DebuggerPluginPrivate::editorAboutToClose(Core::IEditor *editor)
{
    if (!isDebuggable(editor))
        return;
    ITextEditor *textEditor = qobject_cast<ITextEditor *>(editor);
    if (!textEditor)
        return;
    disconnect(textEditor, SIGNAL(markRequested(TextEditor::ITextEditor*,int)),
        this, SLOT(requestMark(TextEditor::ITextEditor*,int)));
    disconnect(editor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*,QPoint,int)),
        this, SLOT(showToolTip(TextEditor::ITextEditor*,QPoint,int)));
    disconnect(textEditor, SIGNAL(markContextMenuRequested(TextEditor::ITextEditor*,int,QMenu*)),
        this, SLOT(requestContextMenu(TextEditor::ITextEditor*,int,QMenu*)));
}

void DebuggerPluginPrivate::requestContextMenu(TextEditor::ITextEditor *editor,
    int lineNumber, QMenu *menu)
{
    if (!isDebuggable(editor))
        return;

    QList<QVariant> list;
    list.append(quint64(editor));
    list.append(lineNumber);
    list.append(quint64(menu));
    notifyCurrentEngine(RequestContextMenuRole, list);
}

void DebuggerPluginPrivate::toggleBreakpoint()
{
    ITextEditor *textEditor = currentTextEditor();
    QTC_ASSERT(textEditor, return);
    int lineNumber = textEditor->currentLine();
    if (lineNumber >= 0)
        toggleBreakpoint(textEditor->file()->fileName(), lineNumber);
}

void DebuggerPluginPrivate::toggleBreakpoint(const QString &fileName, int lineNumber)
{
    QList<QVariant> list;
    list.append(fileName);
    list.append(lineNumber);
    notifyCurrentEngine(RequestToggleBreakpointRole, list);
}

void DebuggerPluginPrivate::requestMark(ITextEditor *editor, int lineNumber)
{
    if (isDebuggable(editor))
        toggleBreakpoint(editor->file()->fileName(), lineNumber);
}

void DebuggerPluginPrivate::showToolTip(ITextEditor *editor, const QPoint &point, int pos)
{
    if (!isDebuggable(editor))
        return;
    if (!theDebuggerBoolSetting(UseToolTipsInMainEditor))
        return;
    if (state() == DebuggerNotReady)
        return;

    QList<QVariant> list;
    list.append(point);
    list.append(quint64(editor));
    list.append(pos);
    notifyCurrentEngine(RequestToolTipByExpressionRole, list);
}

DebuggerRunControl *
DebuggerPluginPrivate::createDebugger(const DebuggerStartParameters &sp)
{
    return m_debuggerRunControlFactory->create(sp);
}

void DebuggerPluginPrivate::startDebugger(ProjectExplorer::RunControl *rc)
{
    QTC_ASSERT(rc, return);
    DebuggerRunControl *runControl = qobject_cast<DebuggerRunControl *>(rc);
    QTC_ASSERT(runControl, return);
    activateDebugMode();
    connectEngine(runControl->engine());
    ProjectExplorerPlugin::instance()->startRunControl(runControl, PE::DEBUGMODE);
}

void DebuggerPluginPrivate::connectEngine(DebuggerEngine *engine)
{
    //if (engine == m_sessionEngine)
    //    qDebug() << "CONNECTING DUMMY ENGINE" << engine;
    //else
    //    qDebug() << "CONNECTING ENGINE " << engine;
    m_breakWindow->setModel(engine->breakModel());
    m_commandWindow->setModel(engine->commandModel());
    m_localsWindow->setModel(engine->localsModel());
    m_modulesWindow->setModel(engine->modulesModel());
    m_registerWindow->setModel(engine->registerModel());
    m_returnWindow->setModel(engine->returnModel());
    m_snapshotWindow->setModel(engine->snapshotModel());
    m_sourceFilesWindow->setModel(engine->sourceFilesModel());
    m_stackWindow->setModel(engine->stackModel());
    m_threadsWindow->setModel(engine->threadsModel());
    m_threadBox->setModel(engine->threadsModel());
    m_watchersWindow->setModel(engine->watchersModel());
    m_capabilities = engine->debuggerCapabilities();
}

static void changeFontSize(QWidget *widget, int size)
{
    QFont font = widget->font();
    font.setPointSize(size);
    widget->setFont(font);
}

void DebuggerPluginPrivate::fontSettingsChanged
    (const TextEditor::FontSettings &settings)
{
    int size = settings.fontZoom() * settings.fontSize() / 100;
    changeFontSize(m_breakWindow, size);
    changeFontSize(m_localsWindow, size);
    changeFontSize(m_modulesWindow, size);
    changeFontSize(m_outputWindow, size);
    changeFontSize(m_registerWindow, size);
    changeFontSize(m_returnWindow, size);
    changeFontSize(m_sourceFilesWindow, size);
    changeFontSize(m_stackWindow, size);
    changeFontSize(m_threadsWindow, size);
    changeFontSize(m_watchersWindow, size);
}

void DebuggerPluginPrivate::cleanupViews()
{
    resetLocation();
    m_actions.reverseDirectionAction->setChecked(false);
    m_actions.reverseDirectionAction->setEnabled(false);
    hideDebuggerToolTip();

    // FIXME ABC: Delete run control / engine?
    //if (d->m_engine)
    //    d->m_engine->cleanup();

    if (EditorManager *editorManager = EditorManager::instance()) {
        QList<IEditor *> toClose;
        foreach (IEditor *editor, editorManager->openedEditors())
            if (editor->property("OpenedByDebugger").toBool())
                toClose.append(editor);
        editorManager->closeEditors(toClose);
    }
}

void DebuggerPluginPrivate::setBusyCursor(bool busy)
{
    //STATE_DEBUG("BUSY FROM: " << m_busy << " TO: " << busy);
    if (busy == m_busy)
        return;

    m_busy = busy;

    QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
    m_breakWindow->setCursor(cursor);
    m_returnWindow->setCursor(cursor);
    m_localsWindow->setCursor(cursor);
    m_modulesWindow->setCursor(cursor);
    m_outputWindow->setCursor(cursor);
    m_registerWindow->setCursor(cursor);
    m_stackWindow->setCursor(cursor);
    m_sourceFilesWindow->setCursor(cursor);
    m_threadsWindow->setCursor(cursor);
    //m_tooltipWindow->setCursor(cursor);
    m_watchersWindow->setCursor(cursor);

    m_breakWindow->setCursor(cursor);
    m_returnWindow->setCursor(cursor);
    m_localsWindow->setCursor(cursor);
    m_modulesWindow->setCursor(cursor);
    m_outputWindow->setCursor(cursor);
    m_registerWindow->setCursor(cursor);
    m_stackWindow->setCursor(cursor);
    m_sourceFilesWindow->setCursor(cursor);
    m_threadsWindow->setCursor(cursor);
    //m_tooltipWindow->setCursor(cursor);
    m_watchersWindow->setCursor(cursor);
}

void DebuggerPluginPrivate::setSimpleDockWidgetArrangement(const QString &activeLanguage)
{
    DebuggerMainWindow *mw = mainWindow();
    if (activeLanguage == LANG_CPP || activeLanguage.isEmpty()) {
        //qDebug() << "SETTING SIMPLE CPP ARRANGEMENT" << activeLanguage;
        mw->setTrackingEnabled(false);
        QList<QDockWidget *> dockWidgets = mw->dockWidgets();
        foreach (QDockWidget *dockWidget, dockWidgets) {
            if (m_dockWidgets.contains(dockWidget)) {
                dockWidget->setFloating(false);
                mw->removeDockWidget(dockWidget);
            }
        }

        foreach (QDockWidget *dockWidget, dockWidgets) {
            if (m_dockWidgets.contains(dockWidget)) {
                if (dockWidget == m_outputDock)
                    mw->addDockWidget(Qt::TopDockWidgetArea, dockWidget);
                else
                    mw->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
                dockWidget->show();
            }
        }

        mw->tabifyDockWidget(m_watchDock, m_breakDock);
        mw->tabifyDockWidget(m_watchDock, m_modulesDock);
        mw->tabifyDockWidget(m_watchDock, m_registerDock);
        mw->tabifyDockWidget(m_watchDock, m_threadsDock);
        mw->tabifyDockWidget(m_watchDock, m_sourceFilesDock);
        mw->tabifyDockWidget(m_watchDock, m_snapshotDock);
        // They following views are rarely used in ordinary debugging. Hiding them
        // saves cycles since the corresponding information won't be retrieved.
        m_sourceFilesDock->hide();
        m_registerDock->hide();
        m_modulesDock->hide();
        m_outputDock->hide();
        mw->setTrackingEnabled(true);
    } else {
        //qDebug() << "SETTING SIMPLE QML ARRANGEMENT" << activeLanguage;
    }
}

void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
{
    m_watchersWindow->setVisible(
        m_watchersWindow->model()->rowCount(QModelIndex()) > 0);
    m_returnWindow->setVisible(
        m_returnWindow->model()->rowCount(QModelIndex()) > 0);

    QTC_ASSERT(engine, return);
    if (m_state == engine->state())
        return;

    m_state = engine->state();
    bool actionsEnabled = DebuggerEngine::debuggerActionsEnabled(m_state);

    //if (m_state == InferiorStopped)
    //    resetLocation();
    //qDebug() << "PLUGIN SET STATE: " << m_state;

    if (m_state == DebuggerNotReady) {
        setBusyCursor(false);
        cleanupViews();
    }

    const bool startIsContinue = (m_state == InferiorStopped);
    ICore *core = ICore::instance();
    if (startIsContinue)
        core->updateAdditionalContexts(Core::Context(), m_gdbRunningContext);
    else
        core->updateAdditionalContexts(m_gdbRunningContext, Core::Context());

    const bool started = m_state == InferiorRunning
        || m_state == InferiorRunningRequested
        || m_state == InferiorStopping
        || m_state == InferiorStopped;

    const bool starting = m_state == EngineStarting;
    //const bool running = m_state == InferiorRunning;

    m_startExternalAction->setEnabled(!started && !starting);
    m_attachExternalAction->setEnabled(!started && !starting);
#ifdef Q_OS_WIN
    m_attachCoreAction->setEnabled(false);
#else
    m_attachCoreAction->setEnabled(!started && !starting);
#endif
    m_startRemoteAction->setEnabled(!started && !starting);

    const bool detachable = m_state == InferiorStopped
        && engine->startParameters().startMode != AttachCore;
    m_detachAction->setEnabled(detachable);

    const bool stoppable = m_state == InferiorRunning
        || m_state == InferiorRunningRequested
        || m_state == InferiorStopping
        || m_state == InferiorStopped
        || m_state == InferiorUnrunnable;

    const bool running = m_state == InferiorRunning;
// FIXME ABC
//    if (running)
//        threadsHandler()->notifyRunning();
    const bool stopped = m_state == InferiorStopped;

    if (stopped)
        QApplication::alert(mainWindow(), 3000);

    //qDebug() << "FLAGS: " << stoppable << running << stopped;

    m_actions.watchAction1->setEnabled(true);
    m_actions.watchAction2->setEnabled(true);
    m_actions.breakAction->setEnabled(true);
    m_actions.snapshotAction->
        setEnabled(stopped && (m_capabilities & SnapshotCapability));

    theDebuggerAction(OperateByInstruction)->setEnabled(!running);

    const bool interruptIsExit = !running;
    if (interruptIsExit) {
        m_actions.stopAction->setIcon(m_stopIcon);
        m_actions.stopAction->setText(tr("Stop Debugger"));
    } else {
        m_actions.stopAction->setIcon(m_interruptIcon);
        m_actions.stopAction->setText(tr("Interrupt"));
    }

    m_actions.stopAction->setEnabled(stoppable);
    m_actions.resetAction->setEnabled(m_state != DebuggerNotReady);

    m_actions.stepAction->setEnabled(stopped);
    m_actions.stepOutAction->setEnabled(stopped);
    m_actions.runToLineAction1->setEnabled(stopped);
    m_actions.runToLineAction2->setEnabled(stopped);
    m_actions.runToFunctionAction->setEnabled(stopped);
    m_actions.returnFromFunctionAction->
        setEnabled(stopped && (m_capabilities & ReturnFromFunctionCapability));

    const bool canJump = stopped && (m_capabilities & JumpToLineCapability);
    m_actions.jumpToLineAction1->setEnabled(canJump);
    m_actions.jumpToLineAction2->setEnabled(canJump);

    m_actions.nextAction->setEnabled(stopped);

    theDebuggerAction(RecheckDebuggingHelpers)->setEnabled(actionsEnabled);
    const bool canDeref = actionsEnabled
        && (m_capabilities & AutoDerefPointersCapability);
    theDebuggerAction(AutoDerefPointers)->setEnabled(canDeref);
    theDebuggerAction(ExpandStack)->setEnabled(actionsEnabled);
    theDebuggerAction(ExecuteCommand)->setEnabled(m_state == InferiorStopped);

    const bool notbusy = m_state == InferiorStopped
        || m_state == DebuggerNotReady
        || m_state == InferiorUnrunnable;
    setBusyCursor(!notbusy);

    // FIXME: for QML only?
    emit m_plugin->stateChanged(m_state);
}

void DebuggerPluginPrivate::resetLocation()
{
    delete m_locationMark;
    m_locationMark = 0;
}

void DebuggerPluginPrivate::gotoLocation(const QString &file, int line, bool setMarker)
{
    bool newEditor = false;
    ITextEditor *editor =
        BaseTextEditor::openEditorAt(file, line, 0, QString(), &newEditor);
    if (!editor)
        return;
    if (newEditor)
        editor->setProperty("OpenedByDebugger", true);
    if (setMarker) {
        resetLocation();
        m_locationMark = new LocationMark(file, line);
    }
}

void DebuggerPluginPrivate::onModeChanged(IMode *mode)
{
     // FIXME: This one gets always called, even if switching between modes
     //        different then the debugger mode. E.g. Welcome and Help mode and
     //        also on shutdown.

    if (mode != m_debugMode)
        return;

    EditorManager *editorManager = EditorManager::instance();
    if (editorManager->currentEditor()) {
        editorManager->currentEditor()->widget()->setFocus();

        if (isCurrentProjectCppBased())
            m_uiSwitcher->setActiveLanguage(LANG_CPP);
    }
}

void DebuggerPluginPrivate::showSettingsDialog()
{
    Core::ICore::instance()->showOptionsDialog(
        _(DEBUGGER_SETTINGS_CATEGORY),
        _(DEBUGGER_COMMON_SETTINGS_ID));
}

void DebuggerPluginPrivate::dumpLog()
{
    QString fileName = QFileDialog::getSaveFileName(mainWindow(),
        tr("Save Debugger Log"), QDir::tempPath());
    if (fileName.isEmpty())
        return;
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly))
        return;
    QTextStream ts(&file);
    ts << m_outputWindow->inputContents();
    ts << "\n\n=======================================\n\n";
    ts << m_outputWindow->combinedContents();
}

void DebuggerPluginPrivate::clearStatusMessage()
{
    m_statusLabel->setText(m_lastPermanentStatusMessage);
}

/*! Activates the previous mode when the current mode is the debug mode. */
void DebuggerPluginPrivate::activatePreviousMode()
{
    Core::ModeManager *modeManager = ICore::instance()->modeManager();
    if (modeManager->currentMode() == modeManager->mode(MODE_DEBUG)
            && !m_previousMode.isEmpty()) {
        modeManager->activateMode(m_previousMode);
        m_previousMode.clear();
    }
}

void DebuggerPluginPrivate::activateDebugMode()
{
    //qDebug() << "ACTIVATING DEBUG MODE";
    const bool canReverse = (m_capabilities & ReverseSteppingCapability)
                && theDebuggerBoolSetting(EnableReverseDebugging);
    m_actions.reverseDirectionAction->setChecked(false);
    m_actions.reverseDirectionAction->setEnabled(canReverse);
    m_actions.reverseDirectionAction->setEnabled(false);
    ModeManager *modeManager = ModeManager::instance();
    m_previousMode = modeManager->currentMode()->id();
    modeManager->activateMode(_(MODE_DEBUG));
}

void DebuggerPluginPrivate::sessionLoaded()
{
    m_sessionEngine->loadSessionData();
}

void DebuggerPluginPrivate::aboutToUnloadSession()
{
    // Stop debugging the active project when switching sessions.
    // Note that at startup, session switches may occur, which interfer
    // with command-line debugging startup.
    // FIXME ABC: Still wanted? Iterate?
    //if (d->m_engine && state() != DebuggerNotReady
    //    && runControl()->sp().startMode == StartInternal)
    //        d->m_engine->shutdown();
}

void DebuggerPluginPrivate::aboutToSaveSession()
{
    m_sessionEngine->saveSessionData();
}

void DebuggerPluginPrivate::interruptDebuggingRequest()
{
    if (state() == InferiorRunning)
        notifyCurrentEngine(RequestExecInterruptRole);
    else
        exitDebugger();
}

void DebuggerPluginPrivate::exitDebugger()
{
    // The engine will finally call setState(DebuggerNotReady) which
    // in turn will handle the cleanup.
    notifyCurrentEngine(RequestExecExitRole);
    m_codeModelSnapshot = CPlusPlus::Snapshot();
}

void DebuggerPluginPrivate::executeDebuggerCommand()
{
    if (QAction *action = qobject_cast<QAction *>(sender()))
        notifyCurrentEngine(RequestExecuteCommandRole, action->data().toString());
}

void DebuggerPluginPrivate::showStatusMessage(const QString &msg0, int timeout)
{
    m_plugin->showMessage(msg0, LogStatus);
    QString msg = msg0;
    msg.replace(QLatin1Char('\n'), QString());
    m_statusLabel->setText(msg);
    if (timeout > 0) {
        m_statusTimer.setSingleShot(true);
        m_statusTimer.start(timeout);
    } else {
        m_lastPermanentStatusMessage = msg;
        m_statusTimer.stop();
    }
}


///////////////////////////////////////////////////////////////////////
//
// DebuggerPlugin
//
///////////////////////////////////////////////////////////////////////

DebuggerPlugin *theInstance = 0;

DebuggerPlugin *DebuggerPlugin::instance()
{
    return theInstance;
}

DebuggerPlugin::DebuggerPlugin()
{
    d = new DebuggerPluginPrivate(this);
    theInstance = this;
}

DebuggerPlugin::~DebuggerPlugin()
{
    delete d->m_sessionEngine;
    d->m_sessionEngine = 0;

    theInstance = 0;
    delete DebuggerSettings::instance();

    removeObject(d->m_debugMode);

    delete d->m_debugMode;
    d->m_debugMode = 0;

    delete d->m_locationMark;
    d->m_locationMark = 0;

    removeObject(d->m_uiSwitcher);
    delete d->m_uiSwitcher;
    d->m_uiSwitcher = 0;

    delete d;
}

bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMessage)
{
    return d->initialize(arguments, errorMessage);
}

void DebuggerPlugin::setSessionValue(const QString &name, const QVariant &value)
{
    QTC_ASSERT(sessionManager(), return);
    sessionManager()->setValue(name, value);
    //qDebug() << "SET SESSION VALUE: " << name;
}

QVariant DebuggerPlugin::sessionValue(const QString &name)
{
    QTC_ASSERT(sessionManager(), return QVariant());
    //qDebug() << "GET SESSION VALUE: " << name;
    return sessionManager()->value(name);
}
void DebuggerPlugin::setConfigValue(const QString &name, const QVariant &value)
{
    QTC_ASSERT(d->m_debugMode, return);
    settings()->setValue(name, value);
}

QVariant DebuggerPlugin::configValue(const QString &name) const
{
    QTC_ASSERT(d->m_debugMode, return QVariant());
    return settings()->value(name);
}

void DebuggerPlugin::resetLocation()
{
    d->resetLocation();
    //qDebug() << "RESET_LOCATION: current:"  << currentTextEditor();
    //qDebug() << "RESET_LOCATION: locations:"  << m_locationMark;
    //qDebug() << "RESET_LOCATION: stored:"  << m_locationMark->editor();
    delete d->m_locationMark;
    d->m_locationMark = 0;
}

void DebuggerPlugin::gotoLocation(const QString &file, int line, bool setMarker)
{
    bool newEditor = false;
    ITextEditor *editor =
        BaseTextEditor::openEditorAt(file, line, 0, QString(), &newEditor);
    if (!editor)
        return;
    if (newEditor)
        editor->setProperty("OpenedByDebugger", true);
    if (setMarker) {
        resetLocation();
        d->m_locationMark = new LocationMark(file, line);
    }
}

void DebuggerPlugin::openTextEditor(const QString &titlePattern0,
    const QString &contents)
{
    QString titlePattern = titlePattern0;
    EditorManager *editorManager = EditorManager::instance();
    QTC_ASSERT(editorManager, return);
    Core::IEditor *editor = editorManager->openEditorWithContents(
        Core::Constants::K_DEFAULT_TEXT_EDITOR_ID, &titlePattern, contents);
    QTC_ASSERT(editor, return);
    editorManager->activateEditor(editor);
}

void DebuggerPlugin::writeSettings() const
{
    QSettings *s = settings();
    DebuggerSettings::instance()->writeSettings(s);
}

void DebuggerPlugin::readSettings()
{
    //qDebug() << "PLUGIN READ SETTINGS";
    QSettings *s = settings();
    DebuggerSettings::instance()->readSettings(s);
}

const CPlusPlus::Snapshot &DebuggerPlugin::cppCodeModelSnapshot() const
{
    if (d->m_codeModelSnapshot.isEmpty() && theDebuggerAction(UseCodeModel)->isChecked())
        d->m_codeModelSnapshot = CppTools::CppModelManagerInterface::instance()->snapshot();
    return d->m_codeModelSnapshot;
}

void DebuggerPlugin::clearCppCodeModelSnapshot()
{
    d->m_codeModelSnapshot = CPlusPlus::Snapshot();
}

void DebuggerPlugin::aboutToShutdown()
{
    writeSettings();
    if (d->m_uiSwitcher)
        d->m_uiSwitcher->aboutToShutdown();
    //if (d->m_engine)
    //    d->m_engine->shutdown();
}

void DebuggerPlugin::showMessage(const QString &msg, int channel, int timeout)
{
    //qDebug() << "PLUGIN OUTPUT: " << channel << msg;
    DebuggerOutputWindow *ow = d->m_outputWindow;
    QTC_ASSERT(ow, return);
    switch (channel) {
        case StatusBar:
            d->showStatusMessage(msg, timeout);
            ow->showOutput(LogStatus, msg);
            break;
        case LogMiscInput:
            ow->showInput(LogMisc, msg);
            ow->showOutput(LogMisc, msg);
            break;
        case LogInput:
            ow->showInput(channel, msg);
            ow->showOutput(channel, msg);
            break;
        default:
            ow->showOutput(channel, msg);
            break;
    }
}


//////////////////////////////////////////////////////////////////////
//
// Register specific stuff
//
//////////////////////////////////////////////////////////////////////

bool DebuggerPlugin::isReverseDebugging() const
{
    return d->m_actions.reverseDirectionAction->isChecked();
}

QMessageBox *DebuggerPlugin::showMessageBox(int icon, const QString &title,
    const QString &text, int buttons)
{
    QMessageBox *mb = new QMessageBox(QMessageBox::Icon(icon),
        title, text, QMessageBox::StandardButtons(buttons), mainWindow());
    mb->setAttribute(Qt::WA_DeleteOnClose);
    mb->show();
    return mb;
}

void DebuggerPlugin::ensureLogVisible()
{
    QAction *action = d->m_outputDock->toggleViewAction();
    if (!action->isChecked())
        action->trigger();
}

QIcon DebuggerPlugin::locationMarkIcon() const
{
    return d->m_locationMarkIcon;
}

void DebuggerPlugin::remoteCommand(const QStringList &options, const QStringList &)
{
    QString errorMessage;
    AttachRemoteParameters parameters;
    unsigned dummy = 0;
    // Did we receive a request for debugging (unless it is ourselves)?
    if (parseArguments(options, &parameters, &dummy, &errorMessage)
        && parameters.attachPid != quint64(QCoreApplication::applicationPid())) {
        d->m_attachRemoteParameters = parameters;
        d->attachCmdLine();
    }
}

void DebuggerPlugin::extensionsInitialized()
{
    // time gdb -i mi -ex 'debuggerplugin.cpp:800' -ex r -ex q bin/qtcreator.bin
    const QByteArray env = qgetenv("QTC_DEBUGGER_TEST");
    //qDebug() << "EXTENSIONS INITIALIZED:" << env;
    // if (!env.isEmpty())
    //    m_plugin->runTest(QString::fromLocal8Bit(env));
    if (d->m_attachRemoteParameters.attachPid
            || !d->m_attachRemoteParameters.attachCore.isEmpty())
        QTimer::singleShot(0, d, SLOT(attachCmdLine()));

    //qDebug() << "EXTENSIONS INITIALIZED";
    // Already done in initialize(). FIXME: Move stuff to here?
    //readSettings();
    //d->m_uiSwitcher->initialize();
}

QWidget *DebuggerPlugin::mainWindow() const
{
    return d->m_uiSwitcher->mainWindow();
}

DebuggerRunControl *
DebuggerPlugin::createDebugger(const DebuggerStartParameters &sp)
{
    return instance()->d->createDebugger(sp);
}

void DebuggerPlugin::startDebugger(ProjectExplorer::RunControl *runControl)
{
    instance()->d->startDebugger(runControl);
}

void DebuggerPlugin::updateState(DebuggerEngine *engine)
{
    d->updateState(engine);
}

void DebuggerPlugin::activatePreviousMode()
{
    d->activatePreviousMode();
}

void DebuggerPlugin::activateDebugMode()
{
    d->activateDebugMode();
}

void DebuggerPlugin::exitDebugger()
{
    d->exitDebugger();
}

int DebuggerPlugin::state() const
{
    return d->state();
}

void DebuggerPlugin::createNewDock(QWidget *widget)
{
    QDockWidget *dockWidget =
        DebuggerUISwitcher::instance()->createDockWidget(LANG_CPP, widget);
    dockWidget->setWindowTitle(widget->windowTitle());
    dockWidget->setObjectName(widget->windowTitle());
    dockWidget->setFeatures(QDockWidget::DockWidgetClosable);
    //dockWidget->setWidget(widget);
    //mainWindow()->addDockWidget(Qt::TopDockWidgetArea, dockWidget);
    dockWidget->show();
}

void DebuggerPlugin::runControlStarted(DebuggerRunControl *runControl)
{
    d->connectEngine(runControl->engine());
}

void DebuggerPlugin::runControlFinished(DebuggerRunControl *runControl)
{
    Q_UNUSED(runControl);
    d->disconnectEngine();
}

DebuggerEngine *DebuggerPlugin::sessionTemplate()
{
    return d->m_sessionEngine;
}

bool DebuggerPlugin::isRegisterViewVisible() const
{
    return d->m_registerDock->toggleViewAction()->isChecked();
}

//////////////////////////////////////////////////////////////////////
//
// Testing
//
//////////////////////////////////////////////////////////////////////

/*
void DebuggerPlugin::runTest(const QString &fileName)
{
    DebuggerStartParameters sp;
    sp.executable = fileName;
    sp.processArgs = QStringList() << "--run-debuggee";
    sp.workingDirectory.clear();
    startDebugger(m_debuggerRunControlFactory->create(sp));
}
*/

bool DebuggerListener::coreAboutToClose()
{
    DebuggerPlugin *plugin = DebuggerPlugin::instance();
    if (!plugin)
        return true;
    // Ask to terminate the session.
    bool cleanTermination = false;
    switch (plugin->state()) {
    case DebuggerNotReady:
        return true;
    case AdapterStarted:     // Most importantly, terminating a running
    case AdapterStartFailed: // debuggee can cause problems.
    case InferiorUnrunnable:
    case InferiorStartFailed:
    case InferiorStopped:
    case InferiorShutDown:
        cleanTermination = true;
        break;
    default:
        break;
    }

    const QString question = cleanTermination ?
        tr("A debugging session is still in progress.\n"
           "Would you like to terminate it?") :
        tr("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(plugin->state())));

    QMessageBox::StandardButton answer =
        QMessageBox::question(DebuggerUISwitcher::instance()->mainWindow(),
            tr("Close Debugging Session"), question,
            QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);

    if (answer != QMessageBox::Yes)
        return false;

    plugin->d->exitDebugger();
    QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
    return true;
}

} // namespace Debugger

#include "debuggerplugin.moc"

Q_EXPORT_PLUGIN(DebuggerPlugin)