diff --git a/share/qtcreator/qmljsdebugger/include/qdeclarativedesignview.h b/share/qtcreator/qmljsdebugger/include/qdeclarativedesignview.h index 7b8241e242b68ab06935f797ecbba4b3ef539316..543aaada671018956f050a0400f40cbd441d9154 100644 --- a/share/qtcreator/qmljsdebugger/include/qdeclarativedesignview.h +++ b/share/qtcreator/qmljsdebugger/include/qdeclarativedesignview.h @@ -58,6 +58,7 @@ public: QToolBar *toolbar() const; static QString idStringForObject(QObject *obj); QRectF adjustToScreenBoundaries(const QRectF &boundingRectInSceneSpace); + void setDebugMode(bool isDebugMode); public Q_SLOTS: void setDesignModeBehavior(bool value); diff --git a/share/qtcreator/qmljsdebugger/qdeclarativedesignview.cpp b/share/qtcreator/qmljsdebugger/qdeclarativedesignview.cpp index de0d21f86bf1e60ad5ece6b2b298a3c668df102b..704711f9da8eb58df8573442e1407b5f4d8cfec6 100644 --- a/share/qtcreator/qmljsdebugger/qdeclarativedesignview.cpp +++ b/share/qtcreator/qmljsdebugger/qdeclarativedesignview.cpp @@ -37,6 +37,7 @@ #include "boundingrecthighlighter.h" #include "subcomponenteditortool.h" #include "qmltoolbar.h" +#include "jsdebuggeragent.h" #include <QDeclarativeItem> #include <QDeclarativeEngine> @@ -48,6 +49,7 @@ #include <QApplication> #include <QAbstractAnimation> +#include <private/qdeclarativeengine_p.h> #include <private/qabstractanimation_p.h> namespace QmlViewer { @@ -61,6 +63,7 @@ QDeclarativeDesignViewPrivate::QDeclarativeDesignViewPrivate(QDeclarativeDesignV designModeBehavior(false), executionPaused(false), slowdownFactor(1.0f), + jsDebuggerAgent(0), toolbar(0) { sceneChangedTimer.setInterval(SceneChangeUpdateInterval); @@ -116,6 +119,9 @@ QDeclarativeDesignView::QDeclarativeDesignView(QWidget *parent) : data->createToolbar(); data->_q_changeToSingleSelectTool(); + + // always start debug mode - that's what this design view is for. + setDebugMode(true); } QDeclarativeDesignView::~QDeclarativeDesignView() @@ -763,6 +769,12 @@ void QDeclarativeDesignViewPrivate::createToolbar() QObject::connect(q, SIGNAL(marqueeSelectToolActivated()), toolbar, SLOT(activateMarqueeSelectTool())); } +void QDeclarativeDesignView::setDebugMode(bool isDebugMode) +{ + if (isDebugMode && !data->jsDebuggerAgent) + data->jsDebuggerAgent = new JSDebuggerAgent(QDeclarativeEnginePrivate::getScriptEngine(engine())); +} + } //namespace QmlViewer #include <moc_qdeclarativedesignview.cpp> diff --git a/share/qtcreator/qmljsdebugger/qdeclarativedesignview_p.h b/share/qtcreator/qmljsdebugger/qdeclarativedesignview_p.h index 54df7cf36b6c94243a45ba4b3202df11124a3291..d83f46aca9cad4abdd45d362dd28d4edbc385fff 100644 --- a/share/qtcreator/qmljsdebugger/qdeclarativedesignview_p.h +++ b/share/qtcreator/qmljsdebugger/qdeclarativedesignview_p.h @@ -36,6 +36,8 @@ #include "qdeclarativedesignview.h" +QT_FORWARD_DECLARE_CLASS(JSDebuggerAgent) + namespace QmlViewer { class QDeclarativeDesignView; @@ -82,6 +84,8 @@ public: bool executionPaused; qreal slowdownFactor; + JSDebuggerAgent *jsDebuggerAgent; + QmlToolbar *toolbar; QTimer sceneChangedTimer; QSet<QGraphicsObject *> sceneGraphicsObjects; diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index 34d31bfc45da539472e8db939483d9669ea76343..c048bb47c8d7d93dca933ca4fef83c97fd0b428f 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -38,19 +38,19 @@ namespace Constants { // modes and their priorities const char * const MODE_DEBUG = "Debugger.Mode.Debug"; const int P_MODE_DEBUG = 85; -const char * const LANG_CPP = "C++"; + // common actions -const char * const STOP = "Debugger.Interrupt"; +const char * const STOP = "Debugger.Interrupt"; const char * const RESET = "Debugger.Reset"; const char * const STEP = "Debugger.StepLine"; const char * const STEPOUT = "Debugger.StepOut"; const char * const NEXT = "Debugger.NextLine"; const char * const REVERSE = "Debugger.ReverseDirection"; -const char * const M_DEBUG_LANGUAGES = "Debugger.Menu.View.Languages"; -const char * const M_DEBUG_VIEWS = "Debugger.Menu.View.Debug"; +const char * const M_DEBUG_DEBUGGING_LANGUAGES = "Debugger.Menu.View.DebugLanguages"; +const char * const M_DEBUG_VIEWS = "Debugger.Menu.View.Debug"; -const char * const C_DEBUGMODE = "Debugger.DebugMode"; +const char * const C_DEBUGMODE = "Debugger.DebugMode"; const char * const C_CPPDEBUGGER = "Gdb Debugger"; const char * const DEBUGGER_COMMON_SETTINGS_ID = "A.Common"; @@ -62,6 +62,22 @@ const char * const DEBUGGER_SETTINGS_TR_CATEGORY = const char * const DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON = ":/core/images/category_debug.png"; +const int QML_DEFAULT_DEBUG_SERVER_PORT = 3768; +const char * const E_QML_DEBUG_SERVER_PORT = "QML_DEBUG_SERVER_PORT"; + +// dock widget names +const char * const DW_BREAK = "Debugger.Docks.Break"; +const char * const DW_MODULES = "Debugger.Docks.Modules"; +const char * const DW_REGISTER = "Debugger.Docks.Register"; +const char * const DW_OUTPUT = "Debugger.Docks.Output"; +const char * const DW_SNAPSHOTS = "Debugger.Docks.Snapshots"; +const char * const DW_STACK = "Debugger.Docks.Stack"; +const char * const DW_SOURCE_FILES = "Debugger.Docks.SourceFiles"; +const char * const DW_THREADS = "Debugger.Docks.Threads"; +const char * const DW_WATCHERS = "Debugger.Docks.LocalsAndWatchers"; + +const char * const DW_QML_INSPECTOR = "Debugger.Docks.QmlInspector"; + namespace Internal { enum { debug = 0 }; #ifdef Q_OS_MAC @@ -71,6 +87,7 @@ namespace Internal { #endif } // namespace Internal + } // namespace Constants @@ -267,13 +284,23 @@ enum DebuggerEngineType PdbEngineType = 0x08, TcfEngineType = 0x10, QmlEngineType = 0x20, + QmlCppEngineType = 0x40, AllEngineTypes = GdbEngineType | ScriptEngineType | CdbEngineType | PdbEngineType | TcfEngineType | QmlEngineType + | QmlCppEngineType +}; + +enum DebuggerLanguage +{ + Lang_None = 0x0, + Lang_Cpp = 0x1, + Lang_Qml = 0x2 }; +Q_DECLARE_FLAGS(DebuggerLanguages, DebuggerLanguage) } // namespace Debugger diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 1cfd45bf4c7ce893babefbb1c6455af50aaebdbf..6c68b25990e38b49437c10d09781cfbe8c55f539 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -106,12 +106,14 @@ using namespace TextEditor; /////////////////////////////////////////////////////////////////////// DebuggerStartParameters::DebuggerStartParameters() - : attachPID(-1), - useTerminal(false), - breakAtMain(false), - toolChainType(ToolChain::UNKNOWN), - startMode(NoStartMode), - executableUid(0) + : attachPID(-1) + , useTerminal(false) + , breakAtMain(false) + , qmlServerAddress("127.0.0.1") + , qmlServerPort(0) + , toolChainType(ToolChain::UNKNOWN) + , executableUid(0) + , startMode(NoStartMode) {} void DebuggerStartParameters::clear() @@ -233,7 +235,8 @@ public: m_stackHandler(engine), m_threadsHandler(engine), m_watchHandler(engine), - m_disassemblerViewAgent(engine) + m_disassemblerViewAgent(engine), + m_runInWrapperEngine(false) {} ~DebuggerEnginePrivate() {} @@ -312,6 +315,8 @@ public: WatchHandler m_watchHandler; DisassemblerViewAgent m_disassemblerViewAgent; QFutureInterface<void> m_progress; + + bool m_runInWrapperEngine; }; void DebuggerEnginePrivate::breakpointSetRemoveMarginActionTriggered() @@ -1329,7 +1334,11 @@ void DebuggerEngine::notifyEngineShutdownOk() showMessage(_("NOTE: ENGINE SHUTDOWN OK")); QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state()); setState(EngineShutdownOk); - d->queueFinishDebugger(); + if (!d->m_runInWrapperEngine) { + d->queueFinishDebugger(); + } else { + setState(DebuggerFinished); + } } void DebuggerEngine::notifyEngineShutdownFailed() @@ -1337,7 +1346,11 @@ void DebuggerEngine::notifyEngineShutdownFailed() showMessage(_("NOTE: ENGINE SHUTDOWN FAILED")); QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state()); setState(EngineShutdownFailed); - d->queueFinishDebugger(); + if (!d->m_runInWrapperEngine) { + d->queueFinishDebugger(); + } else { + setState(DebuggerFinished); + } } void DebuggerEnginePrivate::doFinishDebugger() @@ -1395,7 +1408,7 @@ void DebuggerEngine::notifyInferiorExited() void DebuggerEngine::setState(DebuggerState state, bool forced) { //qDebug() << "STATUS CHANGE: FROM " << stateName(d->m_state) - // << " TO " << stateName(state); + // << " TO " << stateName(state); DebuggerState oldState = d->m_state; d->m_state = state; @@ -1412,6 +1425,13 @@ void DebuggerEngine::setState(DebuggerState state, bool forced) showMessage(msg, LogDebug); plugin()->updateState(this); + + emit stateChanged(d->m_state); +} + +void DebuggerEngine::setRunInWrapperEngine(bool value) +{ + d->m_runInWrapperEngine = value; } bool DebuggerEngine::debuggerActionsEnabled() const @@ -1528,6 +1548,11 @@ QMessageBox *DebuggerEngine::showMessageBox(int icon, const QString &title, return plugin()->showMessageBox(icon, title, text, buttons); } +DebuggerRunControl *DebuggerEngine::runControl() const +{ + return d->m_runControl; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index a4c0a7c3e5aa5394355cf710e0b40643f19169aa..378905b96fbb0b4f78dd48e24c312400f2d49428 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -79,6 +79,7 @@ public: // for qml debugging QString qmlServerAddress; quint16 qmlServerPort; + DebuggerEngineType cppEngineType; // for cpp+qml debugging // for remote debugging QString remoteChannel; @@ -218,17 +219,17 @@ public: WatchHandler *watchHandler() const; SourceFilesHandler *sourceFilesHandler() const; - QAbstractItemModel *commandModel() const; - QAbstractItemModel *modulesModel() const; - QAbstractItemModel *breakModel() const; - QAbstractItemModel *registerModel() const; - QAbstractItemModel *stackModel() const; - QAbstractItemModel *threadsModel() const; - QAbstractItemModel *localsModel() const; - QAbstractItemModel *watchersModel() const; - QAbstractItemModel *returnModel() const; + virtual QAbstractItemModel *commandModel() const; + virtual QAbstractItemModel *modulesModel() const; + virtual QAbstractItemModel *breakModel() const; + virtual QAbstractItemModel *registerModel() const; + virtual QAbstractItemModel *stackModel() const; + virtual QAbstractItemModel *threadsModel() const; + virtual QAbstractItemModel *localsModel() const; + virtual QAbstractItemModel *watchersModel() const; + virtual QAbstractItemModel *returnModel() const; //QAbstractItemModel *snapshotModel() const; - QAbstractItemModel *sourceFilesModel() const; + virtual QAbstractItemModel *sourceFilesModel() const; void progressPing(); void handleFinished(); @@ -275,6 +276,9 @@ public: void gotoLocation(const StackFrame &frame, bool setMarker); virtual void quitDebugger(); // called by DebuggerRunControl +signals: + void stateChanged(const DebuggerState &state); + protected: // The base notify*() function implementation should be sufficient // in most cases, but engines are free to override them to do some @@ -318,8 +322,11 @@ protected: virtual void shutdownInferior() = 0; virtual void shutdownEngine() = 0; -private: void setState(DebuggerState state, bool forced = false); + void setRunInWrapperEngine(bool value); + +private: + DebuggerRunControl *runControl() const; private: void executeRunToLine(); @@ -327,6 +334,9 @@ private: void executeJumpToLine(); void addToWatchWindow(); + // wrapper engine needs access to state of its subengines + friend class QmlCppEngine; + friend class DebuggerEnginePrivate; DebuggerEnginePrivate *d; }; diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index ba4709813d1c6c4dd7fa286dc74a0e5f795741cf..913e7218bffedbce056262befee021f573b57b91 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -71,9 +71,7 @@ QMenu* DebuggerMainWindow::createPopupMenu() for (int i = 0; i < dockwidgets.size(); ++i) { QDockWidget *dockWidget = dockwidgets.at(i)->m_dockWidget; - if (dockWidget->parentWidget() == this && - dockwidgets.at(i)->m_languageId == m_uiSwitcher->activeLanguageId()) { - + if (dockWidget->parentWidget() == this) { menu->addAction(dockWidget->toggleViewAction()); } } diff --git a/src/plugins/debugger/debuggermainwindow.h b/src/plugins/debugger/debuggermainwindow.h index 536e6082313a2f85dbb1291f665d3110eb536dc6..de70ff01f54a0ea21504a220fa063ed23a3a18fa 100644 --- a/src/plugins/debugger/debuggermainwindow.h +++ b/src/plugins/debugger/debuggermainwindow.h @@ -31,6 +31,7 @@ #define DEBUGGERMAINWINDOW_H #include <utils/fancymainwindow.h> +#include "debuggerconstants.h" QT_FORWARD_DECLARE_CLASS(QMenu); @@ -42,10 +43,9 @@ namespace Internal { class DebugToolWindow { public: - DebugToolWindow() : m_dockWidget(0), m_languageId(-1), m_visible(false) {} + DebugToolWindow() : m_dockWidget(0), m_visible(false) {} QDockWidget *m_dockWidget; - int m_languageId; bool m_visible; }; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 1d381ee8fa3eef4bc40f666419ca773b4eaf7ea7..33fc79bcc895e9356b3e3267f66553e542b81ccf 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -75,6 +75,7 @@ #include <coreplugin/findplaceholder.h> #include <coreplugin/icontext.h> #include <coreplugin/icore.h> +#include <coreplugin/imode.h> #include <coreplugin/icorelistener.h> #include <coreplugin/manhattanstyle.h> #include <coreplugin/messagemanager.h> @@ -791,18 +792,6 @@ static TextEditor::ITextEditor *currentTextEditor() 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"); -} - - /////////////////////////////////////////////////////////////////////// // // DebuggerPluginPrivate @@ -868,7 +857,7 @@ public slots: { if (on) notifyCurrentEngine(RequestReloadRegistersRole); } void onAction(); - void setSimpleDockWidgetArrangement(const QString &activeLanguage); + void setSimpleDockWidgetArrangement(const Debugger::DebuggerLanguages &activeLanguages); void editorOpened(Core::IEditor *editor); void editorAboutToClose(Core::IEditor *editor); @@ -900,7 +889,7 @@ public slots: void exitDebugger(); void enableReverseDebuggingTriggered(const QVariant &value); - void languageChanged(const QString &debuggerLanguage); + void languagesChanged(const Debugger::DebuggerLanguages &languages); void showStatusMessage(const QString &msg, int timeout = -1); DebuggerMainWindow *mainWindow() @@ -915,7 +904,7 @@ public slots: DebuggerRunControl *createDebugger(const DebuggerStartParameters &sp, ProjectExplorer::RunConfiguration *rc = 0); void startDebugger(ProjectExplorer::RunControl *runControl); - void displayDebugger(ProjectExplorer::RunControl *runControl); + void displayDebugger(DebuggerEngine *engine, bool updateEngine = true); void dumpLog(); void cleanupViews(); @@ -1234,36 +1223,40 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *er 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); - + m_uiSwitcher->addLanguage(Lang_Cpp, tr("C++"), cppDebuggercontext); // Dock widgets - m_breakDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_breakWindow); - - m_modulesDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_modulesWindow, + m_breakDock = m_uiSwitcher->createDockWidget(Lang_Cpp, m_breakWindow); + m_breakDock->setObjectName(QString(DW_BREAK)); + m_modulesDock = m_uiSwitcher->createDockWidget(Lang_Cpp, m_modulesWindow, Qt::TopDockWidgetArea, false); + m_modulesDock->setObjectName(QString(DW_MODULES)); connect(m_modulesDock->toggleViewAction(), SIGNAL(toggled(bool)), SLOT(modulesDockToggled(bool)), Qt::QueuedConnection); - m_registerDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_registerWindow, + m_registerDock = m_uiSwitcher->createDockWidget(Lang_Cpp, m_registerWindow, Qt::TopDockWidgetArea, false); + m_registerDock->setObjectName(QString(DW_REGISTER)); connect(m_registerDock->toggleViewAction(), SIGNAL(toggled(bool)), SLOT(registerDockToggled(bool)), Qt::QueuedConnection); - m_outputDock = m_uiSwitcher->createDockWidget(QString(), m_outputWindow, + m_outputDock = m_uiSwitcher->createDockWidget(Lang_None, m_outputWindow, Qt::TopDockWidgetArea, false); + m_outputDock->setObjectName(QString(DW_OUTPUT)); + m_snapshotDock = m_uiSwitcher->createDockWidget(Lang_Cpp, m_snapshotWindow); + m_snapshotDock->setObjectName(QString(DW_SNAPSHOTS)); - m_snapshotDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_snapshotWindow); - - m_stackDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_stackWindow); + m_stackDock = m_uiSwitcher->createDockWidget(Lang_Cpp, m_stackWindow); + m_stackDock->setObjectName(QString(DW_STACK)); - m_sourceFilesDock = m_uiSwitcher->createDockWidget(LANG_CPP, + m_sourceFilesDock = m_uiSwitcher->createDockWidget(Lang_Cpp, m_sourceFilesWindow, Qt::TopDockWidgetArea, false); + m_sourceFilesDock->setObjectName(QString(DW_SOURCE_FILES)); connect(m_sourceFilesDock->toggleViewAction(), SIGNAL(toggled(bool)), SLOT(sourceFilesDockToggled(bool)), Qt::QueuedConnection); - m_threadsDock = m_uiSwitcher->createDockWidget(LANG_CPP, m_threadsWindow); + m_threadsDock = m_uiSwitcher->createDockWidget(Lang_Cpp, m_threadsWindow); + m_threadsDock->setObjectName(QString(DW_THREADS)); QSplitter *localsAndWatchers = new Core::MiniSplitter(Qt::Vertical); localsAndWatchers->setObjectName(QLatin1String("CppDebugLocalsAndWatchers")); @@ -1275,10 +1268,12 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *er localsAndWatchers->setStretchFactor(1, 1); localsAndWatchers->setStretchFactor(2, 1); - m_watchDock = m_uiSwitcher->createDockWidget(LANG_CPP, localsAndWatchers); + m_watchDock = m_uiSwitcher->createDockWidget(Lang_Cpp, localsAndWatchers); + m_watchDock->setObjectName(QString(DW_WATCHERS)); + m_dockWidgets << m_breakDock << m_modulesDock << m_registerDock - << m_outputDock << m_stackDock << m_sourceFilesDock - << m_threadsDock << m_watchDock; + << m_outputDock << m_snapshotDock << m_stackDock + << m_sourceFilesDock << m_threadsDock << m_watchDock; // Do not fail the whole plugin if something goes wrong here. uint cmdLineEnabledEngines = AllEngineTypes; @@ -1369,7 +1364,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *er cmd = am->registerAction(m_detachAction, Constants::DETACH, globalcontext); cmd->setAttribute(Command::CA_Hide); - m_uiSwitcher->addMenuAction(cmd, CC::G_DEFAULT_ONE); + m_uiSwitcher->addMenuAction(cmd, Lang_None, CC::G_DEFAULT_ONE); cmd = am->registerAction(m_actions.stopAction, Constants::STOP, globalcontext); @@ -1377,7 +1372,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *er cmd->setAttribute(Command::CA_UpdateIcon); //cmd->setDefaultKeySequence(QKeySequence(Constants::STOP_KEY)); cmd->setDefaultText(tr("Stop Debugger")); - m_uiSwitcher->addMenuAction(cmd, CC::G_DEFAULT_ONE); + m_uiSwitcher->addMenuAction(cmd, Lang_None, CC::G_DEFAULT_ONE); cmd = am->registerAction(m_actions.interruptAction, PE::DEBUG, m_interruptibleContext); @@ -1391,77 +1386,77 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *er 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); + m_uiSwitcher->addMenuAction(cmd, Lang_None, 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); + m_uiSwitcher->addMenuAction(cmd, 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); + m_uiSwitcher->addMenuAction(cmd, 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); + m_uiSwitcher->addMenuAction(cmd, 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); + m_uiSwitcher->addMenuAction(cmd, 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); + m_uiSwitcher->addMenuAction(cmd, 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); + m_uiSwitcher->addMenuAction(cmd, 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); + m_uiSwitcher->addMenuAction(cmd, 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); + m_uiSwitcher->addMenuAction(cmd, 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); + m_uiSwitcher->addMenuAction(cmd, Lang_Cpp); sep = new QAction(this); sep->setSeparator(true); cmd = am->registerAction(sep, _("Debugger.Sep.Break"), globalcontext); - m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP); + m_uiSwitcher->addMenuAction(cmd, 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); + m_uiSwitcher->addMenuAction(cmd, Lang_Cpp); cmd = am->registerAction(m_actions.frameDownAction, Constants::FRAME_DOWN, cppDebuggercontext); @@ -1472,13 +1467,13 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *er cmd = am->registerAction(theDebuggerAction(OperateByInstruction), Constants::OPERATE_BY_INSTRUCTION, cppDebuggercontext); cmd->setAttribute(Command::CA_Hide); - m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP); + m_uiSwitcher->addMenuAction(cmd, Lang_Cpp); cmd = am->registerAction(m_actions.breakAction, Constants::TOGGLE_BREAK, globalcontext); cmd->setDefaultKeySequence(QKeySequence(Constants::TOGGLE_BREAK_KEY)); - m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP); + m_uiSwitcher->addMenuAction(cmd, Lang_Cpp); connect(m_actions.breakAction, SIGNAL(triggered()), this, SLOT(toggleBreakpoint())); @@ -1487,14 +1482,14 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *er sep = new QAction(this); sep->setSeparator(true); cmd = am->registerAction(sep, _("Debugger.Sep.Watch"), globalcontext); - m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP); + m_uiSwitcher->addMenuAction(cmd, Lang_Cpp); cmd = am->registerAction(m_actions.watchAction1, Constants::ADD_TO_WATCH1, cppeditorcontext); cmd->action()->setEnabled(true); //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+W"))); - m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP); + m_uiSwitcher->addMenuAction(cmd, Lang_Cpp); // Editor context menu @@ -1541,7 +1536,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *er m_locationMark = 0; - //setSimpleDockWidgetArrangement(LANG_CPP); + //setSimpleDockWidgetArrangement(Lang_Cpp); connect(ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*)), this, SLOT(onModeChanged(Core::IMode*))); @@ -1606,16 +1601,16 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, QString *er 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))); + m_uiSwitcher->setToolbar(Lang_Cpp, toolbarContainer); + connect(m_uiSwitcher, SIGNAL(dockResetRequested(Debugger::DebuggerLanguages)), + this, SLOT(setSimpleDockWidgetArrangement(Debugger::DebuggerLanguages))); connect(theDebuggerAction(EnableReverseDebugging), SIGNAL(valueChanged(QVariant)), this, SLOT(enableReverseDebuggingTriggered(QVariant))); // UI Switcher - connect(m_uiSwitcher, SIGNAL(languageChanged(QString)), - this, SLOT(languageChanged(QString))); + connect(m_uiSwitcher, SIGNAL(activeLanguagesChanged(Debugger::DebuggerLanguages)), + this, SLOT(languagesChanged(Debugger::DebuggerLanguages))); setInitialState(); connectEngine(m_sessionEngine, false); @@ -1662,9 +1657,9 @@ void DebuggerPluginPrivate::onAction() notifyCurrentEngine(role); } -void DebuggerPluginPrivate::languageChanged(const QString &language) +void DebuggerPluginPrivate::languagesChanged(const Debugger::DebuggerLanguages &languages) { - const bool debuggerIsCPP = (language == Constants::LANG_CPP); + const bool debuggerIsCPP = (languages & Lang_Cpp); //qDebug() << "DEBUGGER IS CPP: " << debuggerIsCPP; m_startExternalAction->setVisible(debuggerIsCPP); @@ -1970,14 +1965,14 @@ DebuggerPluginPrivate::createDebugger(const DebuggerStartParameters &sp, return m_debuggerRunControlFactory->create(sp, rc); } -void DebuggerPluginPrivate::displayDebugger(ProjectExplorer::RunControl *rc) +void DebuggerPluginPrivate::displayDebugger(DebuggerEngine *engine, bool updateEngine) { - DebuggerRunControl *runControl = qobject_cast<DebuggerRunControl *>(rc); - QTC_ASSERT(runControl, return); + QTC_ASSERT(engine, return); disconnectEngine(); - connectEngine(runControl->engine()); - runControl->engine()->updateAll(); - updateState(runControl->engine()); + connectEngine(engine); + if (updateEngine) + engine->updateAll(); + updateState(engine); } void DebuggerPluginPrivate::startDebugger(ProjectExplorer::RunControl *rc) @@ -2079,48 +2074,58 @@ void DebuggerPluginPrivate::setBusyCursor(bool busy) m_snapshotWindow->setCursor(cursor); } -void DebuggerPluginPrivate::setSimpleDockWidgetArrangement(const QString &activeLanguage) +void DebuggerPluginPrivate::setSimpleDockWidgetArrangement(const Debugger::DebuggerLanguages &activeLanguages) { + Debugger::DebuggerUISwitcher *uiSwitcher = DebuggerUISwitcher::instance(); 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); - } - } + mw->setTrackingEnabled(false); - 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(); - } + QList<QDockWidget *> dockWidgets = mw->dockWidgets(); + foreach (QDockWidget *dockWidget, dockWidgets) { + dockWidget->setFloating(false); + mw->removeDockWidget(dockWidget); + } + + foreach (QDockWidget *dockWidget, dockWidgets) { + if (dockWidget == m_outputDock) { + mw->addDockWidget(Qt::TopDockWidgetArea, dockWidget); + } else { + mw->addDockWidget(Qt::BottomDockWidgetArea, dockWidget); } + dockWidget->hide(); + } - mw->splitDockWidget(mw->toolBarDockWidget(), m_stackDock, Qt::Vertical); - mw->splitDockWidget(m_stackDock, m_watchDock, Qt::Horizontal); - 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); + if ((activeLanguages.testFlag(Lang_Cpp) && !activeLanguages.testFlag(Lang_Qml)) + || activeLanguages == Lang_None + || !uiSwitcher->qmlInspectorWindow()) + { + m_stackDock->show(); + m_breakDock->show(); + m_watchDock->show(); + m_threadsDock->show(); + m_snapshotDock->show(); } else { - //qDebug() << "SETTING SIMPLE QML ARRANGEMENT" << activeLanguage; + m_stackDock->show(); + m_breakDock->show(); + m_watchDock->show(); + m_threadsDock->show(); + m_snapshotDock->show(); + uiSwitcher->qmlInspectorWindow()->show(); } + + mw->splitDockWidget(mw->toolBarDockWidget(), m_stackDock, Qt::Vertical); + mw->splitDockWidget(m_stackDock, m_watchDock, Qt::Horizontal); + 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); + mw->tabifyDockWidget(m_watchDock, m_snapshotDock); + if (uiSwitcher->qmlInspectorWindow()) + mw->tabifyDockWidget(m_watchDock, uiSwitcher->qmlInspectorWindow()); + + mw->setTrackingEnabled(true); } void DebuggerPluginPrivate::setInitialState() @@ -2324,12 +2329,8 @@ void DebuggerPluginPrivate::onModeChanged(IMode *mode) return; EditorManager *editorManager = EditorManager::instance(); - if (editorManager->currentEditor()) { + if (editorManager->currentEditor()) editorManager->currentEditor()->widget()->setFocus(); - - if (isCurrentProjectCppBased()) - m_uiSwitcher->setActiveLanguage(LANG_CPP); - } } void DebuggerPluginPrivate::showSettingsDialog() @@ -2373,7 +2374,8 @@ void DebuggerPluginPrivate::activatePreviousMode() void DebuggerPluginPrivate::activateDebugMode() { - //qDebug() << "ACTIVATING DEBUG MODE"; + // ### FIXME m_capabilities is not updated yet when this method is called + // from startDebugger() const bool canReverse = (m_capabilities & ReverseSteppingCapability) && theDebuggerBoolSetting(EnableReverseDebugging); m_actions.reverseDirectionAction->setChecked(false); @@ -2680,7 +2682,15 @@ void DebuggerPlugin::startDebugger(ProjectExplorer::RunControl *runControl) void DebuggerPlugin::displayDebugger(ProjectExplorer::RunControl *runControl) { - instance()->d->displayDebugger(runControl); + DebuggerRunControl *rc = qobject_cast<DebuggerRunControl *>(runControl); + QTC_ASSERT(rc, return); + instance()->d->displayDebugger(rc->engine()); +} + +// if updateEngine is set, the engine will update its threads/modules and so forth. +void DebuggerPlugin::displayDebugger(DebuggerEngine *engine, bool updateEngine) +{ + instance()->d->displayDebugger(engine, updateEngine); } void DebuggerPlugin::updateState(DebuggerEngine *engine) @@ -2701,7 +2711,7 @@ void DebuggerPlugin::activateDebugMode() void DebuggerPlugin::createNewDock(QWidget *widget) { QDockWidget *dockWidget = - DebuggerUISwitcher::instance()->createDockWidget(LANG_CPP, widget); + DebuggerUISwitcher::instance()->createDockWidget(Lang_Cpp, widget); dockWidget->setWindowTitle(widget->windowTitle()); dockWidget->setObjectName(widget->windowTitle()); dockWidget->setFeatures(QDockWidget::DockWidgetClosable); @@ -2723,6 +2733,11 @@ void DebuggerPlugin::runControlFinished(DebuggerRunControl *runControl) d->disconnectEngine(); } +DebuggerLanguages DebuggerPlugin::activeLanguages() const +{ + return DebuggerUISwitcher::instance()->activeDebugLanguages(); +} + DebuggerEngine *DebuggerPlugin::sessionTemplate() { return d->m_sessionEngine; diff --git a/src/plugins/debugger/debuggerplugin.h b/src/plugins/debugger/debuggerplugin.h index 181617bf3382343b90454f2bbee8a9495f6b5275..b1bbc0e328999ad1b028f724fea4f035f7d7bd4c 100644 --- a/src/plugins/debugger/debuggerplugin.h +++ b/src/plugins/debugger/debuggerplugin.h @@ -31,6 +31,7 @@ #define DEBUGGERPLUGIN_H #include "debugger_global.h" +#include "debuggerconstants.h" #include <extensionsystem/iplugin.h> @@ -73,6 +74,7 @@ public: ProjectExplorer::RunConfiguration *rc = 0); static void startDebugger(ProjectExplorer::RunControl *runControl); static void displayDebugger(ProjectExplorer::RunControl *runControl); + static void displayDebugger(Internal::DebuggerEngine *engine, bool updateEngine = true); QVariant sessionValue(const QString &name); void setSessionValue(const QString &name, const QVariant &value); @@ -110,6 +112,7 @@ private: void createNewDock(QWidget *widget); void runControlStarted(DebuggerRunControl *runControl); void runControlFinished(DebuggerRunControl *runControl); + DebuggerLanguages activeLanguages() const; // This contains per-session data like breakpoints and watched // expression. It serves as a template for new engine instantiations. diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index 7bd3107bfde34f4776d2c9472ba94a10ed92d3f5..5c658d7f1a18e62667bcae89d58861ed5b15432e 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -43,6 +43,7 @@ #include <projectexplorer/debugginghelper.h> #include <projectexplorer/environment.h> #include <projectexplorer/project.h> +#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/target.h> #include <projectexplorer/buildconfiguration.h> @@ -74,6 +75,7 @@ DebuggerEngine *createScriptEngine(const DebuggerStartParameters &); DebuggerEngine *createPdbEngine(const DebuggerStartParameters &); DebuggerEngine *createTcfEngine(const DebuggerStartParameters &); DebuggerEngine *createQmlEngine(const DebuggerStartParameters &); +DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &); bool checkGdbConfiguration(int toolChain, QString *errorMsg, QString *settingsPage); @@ -148,6 +150,17 @@ static DebuggerStartParameters localStartParameters(RunConfiguration *runConfigu sp.useTerminal = rc->runMode() == LocalApplicationRunConfiguration::Console; sp.dumperLibrary = rc->dumperLibrary(); sp.dumperLibraryLocations = rc->dumperLibraryLocations(); + + if (DebuggerRunControl::isQmlProject(runConfiguration)) { + sp.qmlServerAddress = QLatin1String("127.0.0.1"); + sp.qmlServerPort = rc->environment().value("QML_DEBUG_SERVER_PORT").toUInt(); + if (sp.qmlServerPort == 0) + sp.qmlServerPort = Constants::QML_DEFAULT_DEBUG_SERVER_PORT; + + sp.environment << QString(Constants::E_QML_DEBUG_SERVER_PORT) + + QLatin1Char('=') + QString::number(sp.qmlServerPort); + } + // FIXME: If it's not yet build this will be empty and not filled // when rebuild as the runConfiguration is not stored and therefore // cannot be used to retrieve the dumper location. @@ -208,14 +221,15 @@ QWidget *DebuggerRunControlFactory::createConfigurationWidget //////////////////////////////////////////////////////////////////////// DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration, - DebuggerEngineType enabledEngines, const DebuggerStartParameters &sp) : - RunControl(runConfiguration, ProjectExplorer::Constants::DEBUGMODE), - m_engine(0), - m_myRunConfiguration(runConfiguration), - m_running(false), - m_enabledEngines(enabledEngines) + DebuggerEngineType enabledEngines, const DebuggerStartParameters &sp) + : RunControl(runConfiguration, ProjectExplorer::Constants::DEBUGMODE) + , m_myRunConfiguration(runConfiguration) + , m_running(false) + , m_started(false) + { connect(this, SIGNAL(finished()), this, SLOT(handleFinished())); + m_isQmlProject = isQmlProject(runConfiguration); createEngine(sp); } @@ -332,10 +346,13 @@ DebuggerEngineType DebuggerRunControl::engineForMode(DebuggerStartMode startMode #endif } -void DebuggerRunControl::createEngine(const DebuggerStartParameters &sp) +void DebuggerRunControl::createEngine(const DebuggerStartParameters &startParams) { + DebuggerStartParameters sp = startParams; + // Figure out engine according to toolchain, executable, attach or default. DebuggerEngineType engineType = NoEngineType; + DebuggerLanguages activeLangs = DebuggerPlugin::instance()->activeLanguages(); bool isQmlExecutable = sp.executable.endsWith(_("qmlviewer")) || sp.executable.endsWith(_("qmlobserver")); #ifdef Q_OS_MAC isQmlExecutable = sp.executable.endsWith(_("QMLViewer.app")) || sp.executable.endsWith(_("QMLObserver.app")); @@ -361,6 +378,15 @@ void DebuggerRunControl::createEngine(const DebuggerStartParameters &sp) if (!engineType) engineType = engineForMode(sp.startMode); + if (engineType != QmlEngineType && m_isQmlProject && (activeLangs & Lang_Qml)) { + if (activeLangs & Lang_Cpp) { + sp.cppEngineType = engineType; + engineType = QmlCppEngineType; + } else { + engineType = QmlEngineType; + } + } + // qDebug() << "USING ENGINE : " << engineType; switch (engineType) { @@ -382,6 +408,9 @@ void DebuggerRunControl::createEngine(const DebuggerStartParameters &sp) case QmlEngineType: m_engine = createQmlEngine(sp); break; + case QmlCppEngineType: + m_engine = createQmlCppEngine(sp); + break; default: { // Could not find anything suitable. debuggingFinished(); @@ -553,5 +582,45 @@ Internal::DebuggerEngine *DebuggerRunControl::engine() return m_engine; } +bool DebuggerRunControl::isQmlProject(RunConfiguration *config) +{ + if (!config || !config->target() || !config->target()->project()) + return false; + + QStringList projectFiles = config->target()->project()->files(ProjectExplorer::Project::ExcludeGeneratedFiles); + foreach(const QString &filename, projectFiles) { + if (filename.endsWith(".qml")) + return true; + } + + return false; +} + +bool DebuggerRunControl::isCurrentProjectQmlCppBased() +{ + Project *startupProject = ProjectExplorerPlugin::instance()->startupProject(); + if (!startupProject) + return false; + + if (!startupProject->activeTarget()) + return false; + + RunConfiguration *rc = startupProject->activeTarget()->activeRunConfiguration(); + + return isQmlProject(rc); +} + +bool DebuggerRunControl::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"); +} + + } // namespace Debugger diff --git a/src/plugins/debugger/debuggerrunner.h b/src/plugins/debugger/debuggerrunner.h index 12a3d4d362b13ee801ce9d1a61e36019a0c6c41b..0bd841aabdc22992250834b70a034d384492d485 100644 --- a/src/plugins/debugger/debuggerrunner.h +++ b/src/plugins/debugger/debuggerrunner.h @@ -117,6 +117,10 @@ public: QString *settingsCategory = 0, QString *settingsPage = 0); + static bool isQmlProject(RunConfiguration *config); + static bool isCurrentProjectQmlCppBased(); + static bool isCurrentProjectCppBased(); + private slots: void handleFinished(); @@ -130,6 +134,8 @@ private: Internal::DebuggerEngine *m_engine; const QWeakPointer<RunConfiguration> m_myRunConfiguration; bool m_running; + bool m_started; + bool m_isQmlProject; DebuggerEngineType m_enabledEngines; QString m_errorMessage; QString m_settingsIdHint; diff --git a/src/plugins/debugger/debuggeruiswitcher.cpp b/src/plugins/debugger/debuggeruiswitcher.cpp index 3304f97fe7e185f3707c04b1c73b1a0399535a7b..a6f7f7c4a26d32e5af3505b1572e2db743cb3a42 100644 --- a/src/plugins/debugger/debuggeruiswitcher.cpp +++ b/src/plugins/debugger/debuggeruiswitcher.cpp @@ -31,6 +31,7 @@ #include "debuggermainwindow.h" #include "debuggeractions.h" #include "debuggerconstants.h" +#include "debuggerrunner.h" #include "savedaction.h" #include <utils/savedaction.h> @@ -52,13 +53,18 @@ #include <coreplugin/rightpane.h> #include <projectexplorer/projectexplorerconstants.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/session.h> +#include <projectexplorer/project.h> +#include <projectexplorer/target.h> +#include <projectexplorer/runconfiguration.h> #include <QtGui/QActionGroup> #include <QtGui/QStackedWidget> #include <QtGui/QVBoxLayout> #include <QtGui/QMenu> #include <QtGui/QDockWidget> - +#include <QtGui/QResizeEvent> #include <QtCore/QDebug> #include <QtCore/QList> #include <QtCore/QMap> @@ -68,8 +74,25 @@ namespace Debugger { using namespace Debugger::Internal; + + +DockWidgetEventFilter::DockWidgetEventFilter(QObject *parent) + : QObject(parent) +{ + +} + +bool DockWidgetEventFilter::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::Resize || event->type() == QEvent::ZOrderChange) { + emit widgetResized(); + } + + return QObject::eventFilter(obj, event); +} + // first: language id, second: menu item -typedef QPair<int, QAction *> ViewsMenuItems; +typedef QPair<DebuggerLanguage, QAction *> ViewsMenuItems; struct DebuggerUISwitcherPrivate { @@ -78,38 +101,63 @@ struct DebuggerUISwitcherPrivate QList<ViewsMenuItems> m_viewsMenuItems; QList<Internal::DebugToolWindow *> m_dockWidgets; - QMap<QString, QWidget *> m_toolBars; - QStringList m_languages; + QHash<QString, QVariant> m_dockWidgetActiveStateCpp; + QHash<QString, QVariant> m_dockWidgetActiveStateQmlCpp; + Internal::DockWidgetEventFilter *m_resizeEventFilter; + + QMap<DebuggerLanguage, QWidget *> m_toolBars; + + DebuggerLanguages m_supportedLanguages; + int m_languageCount; QStackedWidget *m_toolbarStack; Internal::DebuggerMainWindow *m_mainWindow; - QHash<int, Core::Context> m_contextsForLanguage; + QHash<DebuggerLanguage, Core::Context> m_contextsForLanguage; QActionGroup *m_languageActionGroup; - - int m_activeLanguage; - bool m_isActiveMode; + bool m_inDebugMode; bool m_changingUI; - Core::ActionContainer *m_languageMenu; + Core::ActionContainer *m_debuggerLanguageMenu; + DebuggerLanguages m_previousDebugLanguages; + DebuggerLanguages m_activeDebugLanguages; + QAction *m_activateCppAction; + QAction *m_activateQmlAction; + bool m_qmlEnabled; + Core::ActionContainer *m_viewsMenu; Core::ActionContainer *m_debugMenu; - QMultiHash<int, Core::Command *> m_menuCommands; + QMultiHash<DebuggerLanguage, Core::Command *> m_menuCommands; + + QWeakPointer<ProjectExplorer::Project> m_previousProject; + QWeakPointer<ProjectExplorer::Target> m_previousTarget; + + bool m_initialized; static DebuggerUISwitcher *m_instance; }; -DebuggerUISwitcherPrivate::DebuggerUISwitcherPrivate(DebuggerUISwitcher *q) : - m_toolbarStack(new QStackedWidget), - m_languageActionGroup(new QActionGroup(q)), - m_activeLanguage(-1), - m_isActiveMode(false), - m_changingUI(false), - m_viewsMenu(0), - m_debugMenu(0) +DebuggerUISwitcherPrivate::DebuggerUISwitcherPrivate(DebuggerUISwitcher *q) + : m_resizeEventFilter(new Internal::DockWidgetEventFilter(q)) + , m_supportedLanguages(Lang_None) + , m_languageCount(0) + , m_toolbarStack(new QStackedWidget) + , m_languageActionGroup(new QActionGroup(q)) + , m_inDebugMode(false) + , m_changingUI(false) + , m_debuggerLanguageMenu(0) + , m_previousDebugLanguages(Lang_None) + , m_activeDebugLanguages(Lang_None) + , m_activateCppAction(0) + , m_activateQmlAction(0) + , m_qmlEnabled(false) + , m_viewsMenu(0) + , m_debugMenu(0) + , m_initialized(false) { + m_languageActionGroup->setExclusive(false); } DebuggerUISwitcher *DebuggerUISwitcherPrivate::m_instance = 0; @@ -122,16 +170,19 @@ DebuggerUISwitcher::DebuggerUISwitcher(Core::BaseMode *mode, QObject* parent) : Core::ICore *core = Core::ICore::instance(); Core::ActionManager *am = core->actionManager(); + ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance(); + connect(pe->session(), SIGNAL(startupProjectChanged(ProjectExplorer::Project*)), + SLOT(updateUiForProject(ProjectExplorer::Project*))); connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*)), SLOT(modeChanged(Core::IMode*))); + connect(d->m_resizeEventFilter, SIGNAL(widgetResized()), SLOT(updateDockWidgetSettings())); d->m_debugMenu = am->actionContainer(ProjectExplorer::Constants::M_DEBUG); d->m_viewsMenu = am->actionContainer(QLatin1String(Core::Constants::M_WINDOW_VIEWS)); QTC_ASSERT(d->m_viewsMenu, return) - d->m_languageMenu = am->createMenu(Debugger::Constants::M_DEBUG_LANGUAGES); - d->m_languageActionGroup->setExclusive(true); + d->m_debuggerLanguageMenu = am->createMenu(Debugger::Constants::M_DEBUG_DEBUGGING_LANGUAGES); DebuggerUISwitcherPrivate::m_instance = this; } @@ -144,63 +195,135 @@ DebuggerUISwitcher::~DebuggerUISwitcher() delete d; } -QStringList DebuggerUISwitcher::supportedLanguages() const +void DebuggerUISwitcher::updateUiOnFileListChange() { - return d->m_languages; + if (d->m_previousProject) { + updateUiForTarget(d->m_previousProject.data()->activeTarget()); + } } -void DebuggerUISwitcher::addMenuAction(Core::Command *command, const QString &langName, - const QString &group) +void DebuggerUISwitcher::updateUiForProject(ProjectExplorer::Project *project) { - d->m_debugMenu->addAction(command, group); - d->m_menuCommands.insert(d->m_languages.indexOf(langName), command); + if (project) { + if (d->m_previousProject) { + disconnect(d->m_previousProject.data(), SIGNAL(activeTargetChanged(ProjectExplorer::Target*)), + this, SLOT(updateUiForTarget(ProjectExplorer::Target*))); + } + d->m_previousProject = project; + connect(project, SIGNAL(fileListChanged()), SLOT(updateUiOnFileListChange())); + connect(project, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)), + this, SLOT(updateUiForTarget(ProjectExplorer::Target*))); + updateUiForTarget(project->activeTarget()); + } } -void DebuggerUISwitcher::setActiveLanguage(const QString &langName) +void DebuggerUISwitcher::updateUiForTarget(ProjectExplorer::Target *target) { - //qDebug() << "SET ACTIVE LANGUAGE: " << langName - // << theDebuggerAction(SwitchLanguageAutomatically)->isChecked() - // << d->m_languages; - if (theDebuggerAction(SwitchLanguageAutomatically)->isChecked() - && d->m_languages.contains(langName)) - { - changeDebuggerUI(langName); + if (target) { + if (d->m_previousTarget) { + disconnect(target, SIGNAL(activeRunConfigurationChanged(ProjectExplorer::RunConfiguration*)), + this, SLOT(updateUiForRunConfiguration(ProjectExplorer::RunConfiguration*))); + } + d->m_previousTarget = target; + connect(target, SIGNAL(activeRunConfigurationChanged(ProjectExplorer::RunConfiguration*)), + this, SLOT(updateUiForRunConfiguration(ProjectExplorer::RunConfiguration*))); + updateUiForRunConfiguration(target->activeRunConfiguration()); } } -int DebuggerUISwitcher::activeLanguageId() const +// updates default debug language settings per run config. +void DebuggerUISwitcher::updateUiForRunConfiguration(ProjectExplorer::RunConfiguration *rc) { - return d->m_activeLanguage; + if (rc) { + d->m_languageActionGroup->setDisabled(false); + if (DebuggerRunControl::isQmlProject(rc) && d->m_qmlEnabled) { + d->m_activateCppAction->setChecked(true); + d->m_activateQmlAction->setChecked(true); + } else { + if (d->m_activateQmlAction) { + d->m_activateQmlAction->setChecked(false); + } + } + } else { + if (d->m_activateCppAction) + d->m_activateCppAction->setChecked(true); + if (d->m_activateQmlAction) + d->m_activateQmlAction->setChecked(false); + d->m_languageActionGroup->setDisabled(true); + } + + updateActiveLanguages(); +} + +void DebuggerUISwitcher::updateActiveLanguages() +{ + d->m_activeDebugLanguages = Lang_None; + + if (d->m_activateCppAction->isChecked()) + d->m_activeDebugLanguages = Lang_Cpp; + + if (d->m_qmlEnabled && d->m_activateQmlAction->isChecked()) + d->m_activeDebugLanguages = d->m_activeDebugLanguages | Lang_Qml; + + if (d->m_activeDebugLanguages == Lang_None) { + d->m_activateCppAction->setChecked(true); + d->m_activeDebugLanguages = Lang_Cpp; + } + + emit activeLanguagesChanged(d->m_activeDebugLanguages); + + updateUi(); +} + +DebuggerLanguages DebuggerUISwitcher::supportedLanguages() const +{ + return d->m_supportedLanguages; +} + +void DebuggerUISwitcher::addMenuAction(Core::Command *command, const DebuggerLanguage &language, + const QString &group) +{ + d->m_debugMenu->addAction(command, group); + d->m_menuCommands.insert(language, command); +} + +DebuggerLanguages DebuggerUISwitcher::activeDebugLanguages() const +{ + return d->m_activeDebugLanguages; } void DebuggerUISwitcher::modeChanged(Core::IMode *mode) { - d->m_isActiveMode = (mode->id() == Debugger::Constants::MODE_DEBUG); - d->m_mainWindow->setDockActionsVisible(d->m_isActiveMode); + d->m_inDebugMode = (mode->id() == Constants::MODE_DEBUG); + d->m_mainWindow->setDockActionsVisible(d->m_inDebugMode); hideInactiveWidgets(); + + if (mode->id() != Constants::MODE_DEBUG) + return; + + Core::EditorManager *editorManager = Core::EditorManager::instance(); + if (editorManager->currentEditor()) { + DebuggerLanguages activeLangs; + if (DebuggerRunControl::isCurrentProjectCppBased()) + activeLangs |= Lang_Cpp; + + if (DebuggerRunControl::isCurrentProjectQmlCppBased()) + activeLangs |= Lang_Qml; + + d->m_activateCppAction->setChecked(activeLangs & Lang_Cpp); + d->m_activateQmlAction->setChecked(activeLangs & Lang_Qml); + updateActiveLanguages(); + } } void DebuggerUISwitcher::hideInactiveWidgets() { - // Hide/Show dock widgets manually in case they are floating. - if (!d->m_isActiveMode) { + // Hide dock widgets manually in case they are floating. + if (!d->m_inDebugMode) { // hide all the debugger windows if mode is different foreach(Internal::DebugToolWindow *window, d->m_dockWidgets) { - if (window->m_languageId == d->m_activeLanguage && - window->m_dockWidget->isVisible()) - { + if (window->m_dockWidget->isFloating()) window->m_dockWidget->hide(); - } - } - } else { - // bring them back - foreach(Internal::DebugToolWindow *window, d->m_dockWidgets) { - if (window->m_languageId == d->m_activeLanguage && - window->m_visible && - !window->m_dockWidget->isVisible()) - { - window->m_dockWidget->show(); - } } } } @@ -211,9 +334,8 @@ void DebuggerUISwitcher::createViewsMenuItems() Core::ActionManager *am = core->actionManager(); Core::Context globalcontext(Core::Constants::C_GLOBAL); - QMenu *mLang = d->m_languageMenu->menu(); - mLang->setTitle(tr("&Languages")); - d->m_debugMenu->addMenu(d->m_languageMenu, Core::Constants::G_DEFAULT_THREE); + d->m_debugMenu->addMenu(d->m_debuggerLanguageMenu, Core::Constants::G_DEFAULT_THREE); + d->m_debuggerLanguageMenu->menu()->setTitle(tr("&Debug Languages")); // Add menu items Core::Command *cmd = am->registerAction(d->m_mainWindow->menuSeparator1(), @@ -235,93 +357,110 @@ DebuggerUISwitcher *DebuggerUISwitcher::instance() return DebuggerUISwitcherPrivate::m_instance; } -void DebuggerUISwitcher::addLanguage(const QString &langName, const Core::Context &context) +void DebuggerUISwitcher::addLanguage(const DebuggerLanguage &languageId, + const QString &languageName, const Core::Context &context) { - //qDebug() << "ADD UI LANGUAGE: " << langName; - d->m_toolBars.insert(langName, 0); - d->m_contextsForLanguage.insert(d->m_languages.count(), context); - d->m_languages.append(langName); + bool activate = (d->m_supportedLanguages == Lang_None); + d->m_supportedLanguages = d->m_supportedLanguages | languageId; + d->m_languageCount++; - Core::ActionManager *am = Core::ICore::instance()->actionManager(); - QAction *langChange = new QAction(langName, this); - langChange->setCheckable(true); - langChange->setChecked(false); - - d->m_languageActionGroup->addAction(langChange); + d->m_toolBars.insert(languageId, 0); + d->m_contextsForLanguage.insert(languageId, context); + Core::ActionManager *am = Core::ICore::instance()->actionManager(); - QString prefix = tr("Alt+L"); - connect(langChange, SIGNAL(triggered()), SLOT(langChangeTriggered())); - Core::Command *cmd = am->registerAction(langChange, - "Debugger.Language." + langName, + QAction *debuggableLang = new QAction(languageName, this); + debuggableLang->setCheckable(true); + debuggableLang->setText(languageName); + d->m_languageActionGroup->addAction(debuggableLang); + Core::Command *activeDebugLanguageCmd = am->registerAction(debuggableLang, + "Debugger.DebugLanguage." + languageName, Core::Context(Core::Constants::C_GLOBAL)); - cmd->setDefaultKeySequence(QKeySequence( - QString("%1,%2").arg(prefix).arg(d->m_languages.count()))); + d->m_debuggerLanguageMenu->addAction(activeDebugLanguageCmd); + + QString shortcutPrefix = tr("Alt+L"); + QString shortcutIndex = QString::number(d->m_languageCount); + activeDebugLanguageCmd->setDefaultKeySequence(QKeySequence( + QString("%1,%2").arg(shortcutPrefix).arg(shortcutIndex))); + + if (languageId == Lang_Qml) { + d->m_qmlEnabled = true; + d->m_activateQmlAction = debuggableLang; + } else if (!d->m_activateCppAction) { + d->m_activateCppAction = debuggableLang; + } + connect(debuggableLang, SIGNAL(triggered()), SLOT(updateActiveLanguages())); - d->m_languageMenu->addAction(cmd); -} + updateUiForRunConfiguration(0); -void DebuggerUISwitcher::langChangeTriggered() -{ - QObject *sdr = sender(); - QAction *act = qobject_cast<QAction*>(sdr); - changeDebuggerUI(act->text()); + if (activate) + updateUi(); } -void DebuggerUISwitcher::changeDebuggerUI(const QString &langName) +void DebuggerUISwitcher::updateUi() { - //qDebug() << "CHANGE DEBUGGER UI: " << langName << d->m_changingUI; - if (d->m_changingUI) + if (d->m_changingUI || !d->m_initialized || !d->m_inDebugMode) return; + d->m_changingUI = true; - int langId = d->m_languages.indexOf(langName); - if (langId != d->m_activeLanguage) { - d->m_languageActionGroup->actions()[langId]->setChecked(true); - if ((d->m_toolBars.value(langName))) - d->m_toolbarStack->setCurrentWidget(d->m_toolBars.value(langName)); - - foreach (DebugToolWindow *window, d->m_dockWidgets) { - //qDebug() << " WINDOW " << window->m_dockWidget->objectName() - // << window->m_visible; - - if (window->m_languageId != langId) { - // visibleTo must be used because during init, debugger is - // not visible, although visibility is explicitly set through - // both default layout and QSettings. - window->m_visible = window->m_dockWidget->isVisibleTo(d->m_mainWindow); - window->m_dockWidget->hide(); - } else { - if (window->m_visible) { - window->m_dockWidget->show(); - } - } - } + if (isQmlActive()) { + activateQmlCppLayout(); + } else { + activateCppLayout(); + } - foreach (ViewsMenuItems menuitem, d->m_viewsMenuItems) { - bool enable = menuitem.first == langId || menuitem.first == -1; - menuitem.second->setEnabled(enable); - } + d->m_previousDebugLanguages = d->m_activeDebugLanguages; - d->m_languageMenu->menu()->setTitle(tr("Language") + " (" + langName + ")"); + d->m_changingUI = false; +} - Core::ICore *core = Core::ICore::instance(); - const Core::Context &oldContexts = d->m_contextsForLanguage.value(d->m_activeLanguage); - const Core::Context &newContexts = d->m_contextsForLanguage.value(langId); - core->updateAdditionalContexts(oldContexts, newContexts); +void DebuggerUISwitcher::activateQmlCppLayout() +{ + Core::ICore *core = Core::ICore::instance(); + Core::Context qmlCppContext = d->m_contextsForLanguage.value(Lang_Qml); + qmlCppContext.add(d->m_contextsForLanguage.value(Lang_Cpp)); + + // always use cpp toolbar + d->m_toolbarStack->setCurrentWidget(d->m_toolBars.value(Lang_Cpp)); + + if (d->m_previousDebugLanguages & Lang_Qml) { + d->m_dockWidgetActiveStateQmlCpp = d->m_mainWindow->saveSettings(); + core->updateAdditionalContexts(qmlCppContext, Core::Context()); + } else if (d->m_previousDebugLanguages & Lang_Cpp) { + d->m_dockWidgetActiveStateCpp = d->m_mainWindow->saveSettings(); + core->updateAdditionalContexts(d->m_contextsForLanguage.value(Lang_Cpp), Core::Context()); + } - d->m_activeLanguage = langId; + d->m_mainWindow->restoreSettings(d->m_dockWidgetActiveStateQmlCpp); + core->updateAdditionalContexts(Core::Context(), qmlCppContext); +} - emit languageChanged(langName); +void DebuggerUISwitcher::activateCppLayout() +{ + Core::ICore *core = Core::ICore::instance(); + Core::Context qmlCppContext = d->m_contextsForLanguage.value(Lang_Qml); + qmlCppContext.add(d->m_contextsForLanguage.value(Lang_Cpp)); + d->m_toolbarStack->setCurrentWidget(d->m_toolBars.value(Lang_Cpp)); + + if (d->m_previousDebugLanguages & Lang_Qml) { + d->m_dockWidgetActiveStateQmlCpp = d->m_mainWindow->saveSettings(); + core->updateAdditionalContexts(qmlCppContext, Core::Context()); + } else if (d->m_previousDebugLanguages & Lang_Cpp) { + d->m_dockWidgetActiveStateCpp = d->m_mainWindow->saveSettings(); + core->updateAdditionalContexts(d->m_contextsForLanguage.value(Lang_Cpp), Core::Context()); } - d->m_changingUI = false; + d->m_mainWindow->restoreSettings(d->m_dockWidgetActiveStateCpp); + + const Core::Context &cppContext = d->m_contextsForLanguage.value(Lang_Cpp); + core->updateAdditionalContexts(Core::Context(), cppContext); } -void DebuggerUISwitcher::setToolbar(const QString &langName, QWidget *widget) +void DebuggerUISwitcher::setToolbar(const DebuggerLanguage &language, QWidget *widget) { - Q_ASSERT(d->m_toolBars.contains(langName)); - d->m_toolBars[langName] = widget; + Q_ASSERT(d->m_toolBars.contains(language)); + d->m_toolBars[language] = widget; d->m_toolbarStack->addWidget(widget); } @@ -337,6 +476,7 @@ QWidget *DebuggerUISwitcher::createMainWindow(Core::BaseMode *mode) d->m_mainWindow->setDockNestingEnabled(true); connect(d->m_mainWindow, SIGNAL(resetLayout()), this, SLOT(resetDebuggerLayout())); + connect(d->m_mainWindow->toggleLockedAction(), SIGNAL(triggered()), SLOT(updateDockWidgetSettings())); QBoxLayout *editorHolderLayout = new QVBoxLayout; editorHolderLayout->setMargin(0); @@ -385,11 +525,54 @@ QWidget *DebuggerUISwitcher::createMainWindow(Core::BaseMode *mode) return d->m_mainWindow; } +QDockWidget *DebuggerUISwitcher::breakWindow() const +{ + return dockWidget(Constants::DW_BREAK); +} + +QDockWidget *DebuggerUISwitcher::stackWindow() const +{ + return dockWidget(Constants::DW_STACK); +} + +QDockWidget *DebuggerUISwitcher::watchWindow() const +{ + return dockWidget(Constants::DW_WATCHERS); +} + +QDockWidget *DebuggerUISwitcher::outputWindow() const +{ + return dockWidget(Constants::DW_OUTPUT); +} + +QDockWidget *DebuggerUISwitcher::snapshotsWindow() const +{ + return dockWidget(Constants::DW_SNAPSHOTS); +} + +QDockWidget *DebuggerUISwitcher::threadsWindow() const +{ + return dockWidget(Constants::DW_THREADS); +} + +QDockWidget *DebuggerUISwitcher::qmlInspectorWindow() const +{ + return dockWidget(Constants::DW_QML_INSPECTOR); +} + +QDockWidget *DebuggerUISwitcher::dockWidget(const QString &objectName) const +{ + foreach(const Debugger::Internal::DebugToolWindow *toolWindow, d->m_dockWidgets) { + if (toolWindow->m_dockWidget->objectName() == objectName) + return toolWindow->m_dockWidget; + } + return 0; +} /*! Keep track of dock widgets so they can be shown/hidden for different languages */ -QDockWidget *DebuggerUISwitcher::createDockWidget(const QString &langName, +QDockWidget *DebuggerUISwitcher::createDockWidget(const DebuggerLanguage &language, QWidget *widget, Qt::DockWidgetArea area, bool visibleByDefault) { //qDebug() << "CREATE DOCK" << widget->objectName() << langName @@ -397,25 +580,31 @@ QDockWidget *DebuggerUISwitcher::createDockWidget(const QString &langName, QDockWidget *dockWidget = d->m_mainWindow->addDockForWidget(widget); d->m_mainWindow->addDockWidget(area, dockWidget); DebugToolWindow *window = new DebugToolWindow; - window->m_languageId = d->m_languages.indexOf(langName); window->m_dockWidget = dockWidget; window->m_visible = visibleByDefault; d->m_dockWidgets.append(window); - if (d->m_languages.indexOf(langName) != d->m_activeLanguage) + if (!(d->m_activeDebugLanguages & language)) { dockWidget->hide(); + } Core::Context globalContext(Core::Constants::C_GLOBAL); Core::ActionManager *am = Core::ICore::instance()->actionManager(); - QAction *action = dockWidget->toggleViewAction(); - Core::Command *cmd = am->registerAction(action, + QAction *toggleViewAction = dockWidget->toggleViewAction(); + Core::Command *cmd = am->registerAction(toggleViewAction, "Debugger." + dockWidget->objectName(), globalContext); cmd->setAttribute(Core::Command::CA_Hide); d->m_viewsMenu->addAction(cmd); - d->m_viewsMenuItems.append(qMakePair(d->m_languages.indexOf(langName), action)); + d->m_viewsMenuItems.append(qMakePair(language, toggleViewAction)); + + dockWidget->installEventFilter(d->m_resizeEventFilter); + + connect(dockWidget->toggleViewAction(), SIGNAL(triggered(bool)), SLOT(updateDockWidgetSettings())); + connect(dockWidget, SIGNAL(topLevelChanged(bool)), SLOT(updateDockWidgetSettings())); + connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), SLOT(updateDockWidgetSettings())); return dockWidget; } @@ -446,58 +635,93 @@ void DebuggerUISwitcher::aboutToShutdown() void DebuggerUISwitcher::writeSettings() const { - QSettings *s = Core::ICore::instance()->settings(); - s->beginGroup(QLatin1String("DebugMode")); - - foreach(Internal::DebugToolWindow *toolWindow, d->m_dockWidgets) { - bool visible = toolWindow->m_visible; - if (toolWindow->m_languageId == d->m_activeLanguage) { - visible = toolWindow->m_dockWidget->isVisibleTo(d->m_mainWindow); + QSettings *settings = Core::ICore::instance()->settings(); + { + settings->beginGroup(QLatin1String("DebugMode.CppMode")); + QHashIterator<QString, QVariant> it(d->m_dockWidgetActiveStateCpp); + while (it.hasNext()) { + it.next(); + settings->setValue(it.key(), it.value()); } - toolWindow->m_dockWidget->setMinimumSize(1, 1); - toolWindow->m_dockWidget->setVisible(visible); + settings->endGroup(); + } + { + settings->beginGroup(QLatin1String("DebugMode.CppQmlMode")); + QHashIterator<QString, QVariant> it(d->m_dockWidgetActiveStateQmlCpp); + while (it.hasNext()) { + it.next(); + settings->setValue(it.key(), it.value()); + } + settings->endGroup(); } - - d->m_mainWindow->saveSettings(s); - s->endGroup(); } void DebuggerUISwitcher::readSettings() { - //qDebug() << "\n SWITCHER READ SETTINGS \n"; - QSettings *s = Core::ICore::instance()->settings(); - s->beginGroup(QLatin1String("DebugMode")); - d->m_mainWindow->restoreSettings(s); - s->endGroup(); -/* - foreach(Internal::DebugToolWindow *toolWindow, d->m_dockWidgets) { - toolWindow->m_visible = toolWindow->m_dockWidget->isVisibleTo(d->m_mainWindow); + QSettings *settings = Core::ICore::instance()->settings(); + d->m_dockWidgetActiveStateCpp.clear(); + d->m_dockWidgetActiveStateQmlCpp.clear(); + + settings->beginGroup(QLatin1String("DebugMode.CppMode")); + foreach (const QString &key, settings->childKeys()) { + d->m_dockWidgetActiveStateCpp.insert(key, settings->value(key)); } -*/ + settings->endGroup(); + + settings->beginGroup(QLatin1String("DebugMode.CppQmlMode")); + foreach (const QString &key, settings->childKeys()) { + d->m_dockWidgetActiveStateQmlCpp.insert(key, settings->value(key)); + } + settings->endGroup(); } void DebuggerUISwitcher::initialize() { createViewsMenuItems(); - //qDebug() << "UI SWITCHER INITIALIZE"; - emit dockArranged(QString()); + emit dockResetRequested(Lang_None); readSettings(); - const QString &activeLang = (d->m_activeLanguage != -1 - ? d->m_languages.at(d->m_activeLanguage) - : d->m_languages.first()); - d->m_activeLanguage = -1; // enforce refresh - changeDebuggerUI(activeLang); + updateUi(); hideInactiveWidgets(); d->m_mainWindow->setDockActionsVisible(false); + d->m_initialized = true; } void DebuggerUISwitcher::resetDebuggerLayout() { - //qDebug() << "RESET DEBUGGER LAYOUT" << d->m_languages.at(d->m_activeLanguage); - emit dockArranged(d->m_languages.at(d->m_activeLanguage)); + emit dockResetRequested(d->m_activeDebugLanguages); + + if (isQmlActive()) { + d->m_dockWidgetActiveStateQmlCpp = d->m_mainWindow->saveSettings(); + } else { + d->m_dockWidgetActiveStateCpp = d->m_mainWindow->saveSettings(); + } + + updateActiveLanguages(); +} + +void DebuggerUISwitcher::updateDockWidgetSettings() +{ + if (!d->m_inDebugMode || d->m_changingUI) + return; + + if (isQmlActive()) { + d->m_dockWidgetActiveStateQmlCpp = d->m_mainWindow->saveSettings(); + } else { + d->m_dockWidgetActiveStateCpp = d->m_mainWindow->saveSettings(); + } +} + +bool DebuggerUISwitcher::isQmlCppActive() const +{ + return (d->m_activeDebugLanguages & Lang_Cpp) && (d->m_activeDebugLanguages & Lang_Qml); +} + +bool DebuggerUISwitcher::isQmlActive() const +{ + return (d->m_activeDebugLanguages & Lang_Qml); } QList<Internal::DebugToolWindow* > DebuggerUISwitcher::i_mw_debugToolWindows() const diff --git a/src/plugins/debugger/debuggeruiswitcher.h b/src/plugins/debugger/debuggeruiswitcher.h index f7fcb2bd82ab8b3fd423b3dc743b43d3b1efab7a..f4fca6b49971fafa55eea9d9e7cf7783210be2f6 100644 --- a/src/plugins/debugger/debuggeruiswitcher.h +++ b/src/plugins/debugger/debuggeruiswitcher.h @@ -31,11 +31,13 @@ #define DEBUGGERUISWITCHER_H #include "debugger_global.h" +#include "debuggerconstants.h" #include <QtCore/QObject> #include <QtCore/QMultiHash> -QT_FORWARD_DECLARE_CLASS(QDockWidget); +QT_FORWARD_DECLARE_CLASS(QEvent) +QT_FORWARD_DECLARE_CLASS(QDockWidget) namespace Core { class ActionContainer; @@ -50,6 +52,11 @@ class FancyMainWindow; class SavedAction; } +namespace ProjectExplorer { + class Project; + class Target; + class RunConfiguration; +} namespace Debugger { struct DebuggerUISwitcherPrivate; @@ -69,62 +76,105 @@ public: static DebuggerUISwitcher *instance(); // debuggable languages are registered with this function. - void addLanguage(const QString &langName, const Core::Context &context); + void addLanguage(const DebuggerLanguage &language, const QString &languageName, + const Core::Context &context); // debugger toolbars are registered with this function - void setToolbar(const QString &langName, QWidget *widget); + void setToolbar(const DebuggerLanguage &language, QWidget *widget); // menu actions are registered with this function - void addMenuAction(Core::Command *command, const QString &langName, + void addMenuAction(Core::Command *command, const DebuggerLanguage &language, const QString &group = QString()); - QStringList supportedLanguages() const; + // all supported languagess + DebuggerLanguages supportedLanguages() const; - // Changes the active language UI to the one specified by langName. - // Does nothing if automatic switching is toggled off from settings. - void setActiveLanguage(const QString &langName); - int activeLanguageId() const; + // active languages to be debugged. + DebuggerLanguages activeDebugLanguages() const; // called when all dependent plugins have loaded void initialize(); void aboutToShutdown(); + // most common debugger windows + QDockWidget *breakWindow() const; + QDockWidget *stackWindow() const; + QDockWidget *watchWindow() const; + QDockWidget *snapshotsWindow() const; + QDockWidget *threadsWindow() const; + QDockWidget *outputWindow() const; + QDockWidget *qmlInspectorWindow() const; + + QDockWidget *dockWidget(const QString &objectName) const; + // dockwidgets are registered to the main window - QDockWidget *createDockWidget(const QString &langName, QWidget *widget, + QDockWidget *createDockWidget(const DebuggerLanguage &language, QWidget *widget, Qt::DockWidgetArea area = Qt::TopDockWidgetArea, bool visibleByDefault = true); Utils::FancyMainWindow *mainWindow() const; signals: - void languageChanged(const QString &langName); - // emit when dock needs to be reset - void dockArranged(const QString &activeLanguage); + // emit when user changes active languages from the menu. + // Both UI and debugger startup are affected. + void activeLanguagesChanged(Debugger::DebuggerLanguages activeLanguages); + + void dockResetRequested(const Debugger::DebuggerLanguages &activeLanguages); private slots: void modeChanged(Core::IMode *mode); - void changeDebuggerUI(const QString &langName); + void updateUi(); void resetDebuggerLayout(); - void langChangeTriggered(); + + void updateUiForProject(ProjectExplorer::Project *project); + void updateUiForTarget(ProjectExplorer::Target *target); + void updateUiForRunConfiguration(ProjectExplorer::RunConfiguration *rc); + void updateUiOnFileListChange(); + + void updateActiveLanguages(); + void updateDockWidgetSettings(); + + void onModeChanged(Core::IMode *mode); private: // Used by MainWindow friend class Internal::DebuggerMainWindow; QList<Internal::DebugToolWindow *> i_mw_debugToolWindows() const; + void activateQmlCppLayout(); + void activateCppLayout(); + void hideInactiveWidgets(); void createViewsMenuItems(); void readSettings(); void writeSettings() const; + bool isQmlCppActive() const; + bool isQmlActive() const; QWidget *createContents(Core::BaseMode *mode); QWidget *createMainWindow(Core::BaseMode *mode); DebuggerUISwitcherPrivate *d; - Utils::SavedAction *m_changeLanguageAction; }; +namespace Internal { +class DockWidgetEventFilter : public QObject +{ + Q_OBJECT + +public: + DockWidgetEventFilter(QObject *parent = 0); + +signals: + void widgetResized(); + +protected: + bool eventFilter(QObject *obj, QEvent *event); +}; + +} // namespace Internal + } // namespace Debugger #endif // DEBUGGERUISWITCHER_H diff --git a/src/plugins/debugger/qml/qml.pri b/src/plugins/debugger/qml/qml.pri index 2bc5e8ebd4ae0aee537972196ed333d96675595d..622215080d30d822275c81c9a1c36081872dab3a 100644 --- a/src/plugins/debugger/qml/qml.pri +++ b/src/plugins/debugger/qml/qml.pri @@ -4,9 +4,10 @@ HEADERS += \ $$PWD/qmlengine.h \ $$PWD/qmladapter.h \ $$PWD/qmldebuggerclient.h \ - $$PWD/qmljsprivateapi.h - + $$PWD/qmljsprivateapi.h \ + $$PWD/qmlcppengine.h SOURCES += \ $$PWD/qmlengine.cpp \ $$PWD/qmladapter.cpp \ - $$PWD/qmldebuggerclient.cpp + $$PWD/qmldebuggerclient.cpp \ + $$PWD/qmlcppengine.cpp diff --git a/src/plugins/debugger/qml/qmladapter.cpp b/src/plugins/debugger/qml/qmladapter.cpp index 2e77cfad262fde7e28c86906d60c4efabb2a31ea..a322b807f093828099e1d4e20e10ff93cba3eb30 100644 --- a/src/plugins/debugger/qml/qmladapter.cpp +++ b/src/plugins/debugger/qml/qmladapter.cpp @@ -56,9 +56,26 @@ QmlAdapter::QmlAdapter(DebuggerEngine *engine, QObject *parent) void QmlAdapter::beginConnection() { + m_connectionAttempts = 0; m_connectionTimer->start(); } +void QmlAdapter::pauseConnection() +{ + m_connectionTimer->stop(); +} + +void QmlAdapter::closeConnection() +{ + if (m_connectionTimer->isActive()) { + m_connectionTimer->stop(); + } else { + if (m_conn) { + m_conn->disconnectFromHost(); + } + } +} + void QmlAdapter::pollInferior() { ++m_connectionAttempts; diff --git a/src/plugins/debugger/qml/qmladapter.h b/src/plugins/debugger/qml/qmladapter.h index 1def1ade698e5111dc113bc0a99f0d95e6b7d8dd..0bed65885386ed329e4eedb88a55e0c4094fb93c 100644 --- a/src/plugins/debugger/qml/qmladapter.h +++ b/src/plugins/debugger/qml/qmladapter.h @@ -49,6 +49,8 @@ class DEBUGGER_EXPORT QmlAdapter : public QObject public: explicit QmlAdapter(DebuggerEngine *engine, QObject *parent = 0); void beginConnection(); + void pauseConnection(); + void closeConnection(); bool isConnected() const; bool isUnconnected() const; diff --git a/src/plugins/debugger/qml/qmlcppengine.cpp b/src/plugins/debugger/qml/qmlcppengine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0cd8931349e783dc0627e77e5f587878b1cfca0b --- /dev/null +++ b/src/plugins/debugger/qml/qmlcppengine.cpp @@ -0,0 +1,649 @@ +#include "qmlcppengine.h" +#include "qmlengine.h" +#include "debuggeruiswitcher.h" +#include "debuggerplugin.h" + +#include <qmljseditor/qmljseditorconstants.h> +#include <coreplugin/editormanager/editormanager.h> +#include <coreplugin/editormanager/ieditor.h> + + +namespace Debugger { +namespace Internal { + +const int ConnectionWaitTimeMs = 5000; + +DebuggerEngine *createCdbEngine(const DebuggerStartParameters &); +DebuggerEngine *createGdbEngine(const DebuggerStartParameters &); +DebuggerEngine *createQmlEngine(const DebuggerStartParameters &); + +DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &sp) +{ + return new QmlCppEngine(sp); +} + +QmlCppEngine::QmlCppEngine(const DebuggerStartParameters &sp) + : DebuggerEngine(sp) + , m_shutdownOk(true) + , m_shutdownDeferred(false) + , m_shutdownDone(false) + , m_isInitialStartup(true) +{ + m_qmlEngine = qobject_cast<QmlEngine*>(createQmlEngine(sp)); + m_qmlEngine->setAttachToRunningExternalApp(true); + + if (startParameters().cppEngineType == GdbEngineType) { + m_cppEngine = createGdbEngine(sp); + } else { + m_cppEngine = createCdbEngine(sp); + } + + m_cppEngine->setRunInWrapperEngine(true); + m_qmlEngine->setRunInWrapperEngine(true); + + m_activeEngine = m_cppEngine; + connect(m_cppEngine, SIGNAL(stateChanged(DebuggerState)), SLOT(masterEngineStateChanged(DebuggerState))); + connect(m_qmlEngine, SIGNAL(stateChanged(DebuggerState)), SLOT(slaveEngineStateChanged(DebuggerState))); + + Core::EditorManager *em = Core::EditorManager::instance(); + connect(em, SIGNAL(currentEditorChanged(Core::IEditor*)), SLOT(editorChanged(Core::IEditor*))); +} + +QmlCppEngine::~QmlCppEngine() +{ + delete m_qmlEngine; + delete m_cppEngine; + m_qmlEngine = 0; + m_cppEngine = 0; +} + +void QmlCppEngine::editorChanged(Core::IEditor *editor) +{ + // change the engine based on editor, but only if we're not currently in stopped state. + if (state() != InferiorRunOk || !editor) + return; + + if (editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) { + setActiveEngine(Lang_Qml); + } else { + setActiveEngine(Lang_Cpp); + } +} + +void QmlCppEngine::setActiveEngine(DebuggerLanguage language) +{ + DebuggerEngine *previousEngine = m_activeEngine; + bool updateEngine = false; + QString engineName; + + if (language == Lang_Cpp) { + engineName = QLatin1String("C++"); + m_activeEngine = m_cppEngine; + // don't update cpp engine - at least gdb will stop temporarily, + // which is not nice when you're just switching files. + } else if (language == Lang_Qml) { + engineName = QLatin1String("QML"); + m_activeEngine = m_qmlEngine; + updateEngine = true; + } + if (previousEngine != m_activeEngine) { + showStatusMessage(tr("%1 debugger activated").arg(engineName)); + plugin()->displayDebugger(m_activeEngine, updateEngine); + } +} + +void QmlCppEngine::setToolTipExpression(const QPoint & mousePos, + TextEditor::ITextEditor *editor, int cursorPos) +{ + m_activeEngine->setToolTipExpression(mousePos, editor, cursorPos); +} + +void QmlCppEngine::updateWatchData(const WatchData &data) +{ + m_activeEngine->updateWatchData(data); +} + +void QmlCppEngine::watchPoint(const QPoint &point) +{ + m_cppEngine->watchPoint(point); +} + +void QmlCppEngine::fetchMemory(MemoryViewAgent *mva, QObject *obj, + quint64 addr, quint64 length) +{ + m_cppEngine->fetchMemory(mva, obj, addr, length); +} + +void QmlCppEngine::fetchDisassembler(DisassemblerViewAgent *dva) +{ + m_cppEngine->fetchDisassembler(dva); +} + +void QmlCppEngine::activateFrame(int index) +{ + m_cppEngine->activateFrame(index); +} + +void QmlCppEngine::reloadModules() +{ + m_cppEngine->reloadModules(); +} + +void QmlCppEngine::examineModules() +{ + m_cppEngine->examineModules(); +} + +void QmlCppEngine::loadSymbols(const QString &moduleName) +{ + m_cppEngine->loadSymbols(moduleName); +} + +void QmlCppEngine::loadAllSymbols() +{ + m_cppEngine->loadAllSymbols(); +} + +void QmlCppEngine::requestModuleSymbols(const QString &moduleName) +{ + m_cppEngine->requestModuleSymbols(moduleName); +} + +void QmlCppEngine::reloadRegisters() +{ + m_cppEngine->reloadRegisters(); +} + +void QmlCppEngine::reloadSourceFiles() +{ + m_cppEngine->reloadSourceFiles(); +} + +void QmlCppEngine::reloadFullStack() +{ + m_cppEngine->reloadFullStack(); +} + +void QmlCppEngine::setRegisterValue(int regnr, const QString &value) +{ + m_cppEngine->setRegisterValue(regnr, value); +} + +unsigned QmlCppEngine::debuggerCapabilities() const +{ + // ### this could also be an OR of both engines' capabilities + return m_cppEngine->debuggerCapabilities(); +} + +bool QmlCppEngine::isSynchroneous() const +{ + return m_activeEngine->isSynchroneous(); +} + +QString QmlCppEngine::qtNamespace() const +{ + return m_cppEngine->qtNamespace(); +} + +void QmlCppEngine::createSnapshot() +{ + m_cppEngine->createSnapshot(); +} + +void QmlCppEngine::updateAll() +{ + m_activeEngine->updateAll(); +} + +void QmlCppEngine::attemptBreakpointSynchronization() +{ + m_cppEngine->attemptBreakpointSynchronization(); + static_cast<DebuggerEngine*>(m_qmlEngine)->attemptBreakpointSynchronization(); +} + +void QmlCppEngine::selectThread(int index) +{ + m_cppEngine->selectThread(index); +} + +void QmlCppEngine::assignValueInDebugger(const QString &expr, const QString &value) +{ + m_activeEngine->assignValueInDebugger(expr, value); +} + +QAbstractItemModel *QmlCppEngine::commandModel() const +{ + return m_activeEngine->commandModel(); +} + +QAbstractItemModel *QmlCppEngine::modulesModel() const +{ + return m_cppEngine->modulesModel(); +} + +QAbstractItemModel *QmlCppEngine::breakModel() const +{ + return m_activeEngine->breakModel(); +} + +QAbstractItemModel *QmlCppEngine::registerModel() const +{ + return m_cppEngine->registerModel(); +} + +QAbstractItemModel *QmlCppEngine::stackModel() const +{ + return m_activeEngine->stackModel(); +} + +QAbstractItemModel *QmlCppEngine::threadsModel() const +{ + return m_cppEngine->threadsModel(); +} + +QAbstractItemModel *QmlCppEngine::localsModel() const +{ + return m_activeEngine->localsModel(); +} + +QAbstractItemModel *QmlCppEngine::watchersModel() const +{ + return m_activeEngine->watchersModel(); +} + +QAbstractItemModel *QmlCppEngine::returnModel() const +{ + return m_cppEngine->returnModel(); +} + +QAbstractItemModel *QmlCppEngine::sourceFilesModel() const +{ + return m_cppEngine->sourceFilesModel(); +} + +void QmlCppEngine::detachDebugger() +{ + m_qmlEngine->detachDebugger(); + m_cppEngine->detachDebugger(); +} + +void QmlCppEngine::executeStep() +{ + m_activeEngine->executeStep(); +} + +void QmlCppEngine::executeStepOut() +{ + m_activeEngine->executeStepOut(); +} + +void QmlCppEngine::executeNext() +{ + m_activeEngine->executeNext(); +} + +void QmlCppEngine::executeStepI() +{ + m_activeEngine->executeStepI(); +} + +void QmlCppEngine::executeNextI() +{ + m_activeEngine->executeNextI(); +} + +void QmlCppEngine::executeReturn() +{ + m_activeEngine->executeReturn(); +} + +void QmlCppEngine::continueInferior() +{ + m_activeEngine->continueInferior(); +} + +void QmlCppEngine::interruptInferior() +{ + m_activeEngine->interruptInferior(); +} + +void QmlCppEngine::requestInterruptInferior() +{ + m_activeEngine->requestInterruptInferior(); +} + +void QmlCppEngine::executeRunToLine(const QString &fileName, int lineNumber) +{ + m_activeEngine->executeRunToLine(fileName, lineNumber); +} + +void QmlCppEngine::executeRunToFunction(const QString &functionName) +{ + m_activeEngine->executeRunToFunction(functionName); +} + +void QmlCppEngine::executeJumpToLine(const QString &fileName, int lineNumber) +{ + m_activeEngine->executeJumpToLine(fileName, lineNumber); +} + +void QmlCppEngine::executeDebuggerCommand(const QString &command) +{ + m_activeEngine->executeDebuggerCommand(command); +} + +void QmlCppEngine::frameUp() +{ + m_activeEngine->frameUp(); +} + +void QmlCppEngine::frameDown() +{ + m_activeEngine->frameDown(); +} + +void QmlCppEngine::notifyInferiorRunOk() +{ + DebuggerEngine::notifyInferiorRunOk(); + + Core::EditorManager *em = Core::EditorManager::instance(); + editorChanged(em->currentEditor()); +} + +void QmlCppEngine::setupEngine() +{ + m_cppEngine->startDebugger(runControl()); +} + +void QmlCppEngine::setupInferior() +{ + // called through notifyEngineSetupOk +} + +void QmlCppEngine::runEngine() +{ + // should never happen + showMessage(QString(Q_FUNC_INFO), LogError); +} + +void QmlCppEngine::shutdownInferior() +{ + // user wants to stop inferior: always use cpp engine for this. + if (m_activeEngine == m_qmlEngine) { + m_activeEngine = m_cppEngine; + + // we end up in this state after trying to shut down while debugging qml. + // b/c qml does not shutdown by itself, restore previous state and continue. + if (m_qmlEngine->state() == InferiorShutdownRequested) { + m_qmlEngine->setState(InferiorStopOk, true); + } + + if (m_qmlEngine->state() == InferiorStopOk) { + m_qmlEngine->continueInferior(); + } + } + if (m_cppEngine->state() == InferiorRunOk) { + // first interrupt c++ engine; when done, we can shutdown. + m_shutdownDeferred = true; + m_cppEngine->requestInterruptInferior(); + } + if (!m_shutdownDeferred) + m_cppEngine->shutdownInferior(); +} + +void QmlCppEngine::shutdownEngine() +{ + m_cppEngine->shutdownEngine(); + m_qmlEngine->shutdownEngineAsSlave(); + notifyEngineShutdownOk(); +} + +void QmlCppEngine::finishDebugger() +{ + if (!m_shutdownDone) { + m_shutdownDone = true; + if (m_shutdownOk) { + notifyEngineShutdownOk(); + } else { + notifyEngineShutdownFailed(); + } + } +} + +void QmlCppEngine::setupSlaveEngineOnTimer() +{ + QTimer::singleShot(ConnectionWaitTimeMs, this, SLOT(setupSlaveEngine())); +} + +void QmlCppEngine::setupSlaveEngine() +{ + if (state() == InferiorRunRequested) + m_qmlEngine->startDebugger(runControl()); +} + +void QmlCppEngine::masterEngineStateChanged(const DebuggerState &newState) +{ + //qDebug() << "gdb state set to" << newState; + + switch(newState) { + case EngineSetupRequested: + // go through this state + break; + + case EngineSetupFailed: + notifyEngineSetupFailed(); + break; + + case EngineSetupOk: + notifyEngineSetupOk(); + break; + + case InferiorSetupRequested: + // go through this state + break; + + case InferiorSetupFailed: + notifyInferiorSetupFailed(); + break; + + case EngineRunRequested: + setState(newState); + break; + + case EngineRunFailed: + notifyEngineRunFailed(); + break; + + case InferiorUnrunnable: + setState(newState); + break; + + case InferiorRunRequested: + setState(newState); + break; + + case InferiorRunOk: + if (m_qmlEngine->state() == DebuggerNotReady) { + if (m_isInitialStartup) { + m_isInitialStartup = false; + setupSlaveEngineOnTimer(); + } else { + setupSlaveEngine(); + } + } else { + notifyInferiorRunOk(); + } + break; + + case InferiorRunFailed: + notifyInferiorRunFailed(); + break; + + case InferiorStopRequested: + if (state() == InferiorRunRequested) { + // if stopping on startup, move on to normal state + // and go forward. Also, stop connection and continue later if needed. + m_qmlEngine->pauseConnection(); + setState(EngineRunRequested, true); + notifyEngineRunAndInferiorRunOk(); + setState(newState); + } else { + setState(newState); + } + break; + + case InferiorStopOk: + // debugger can stop while qml connection is not made yet, so we can + // end up in an illegal state transition here. + if (state() == InferiorStopRequested + || state() == InferiorRunFailed) + { + setState(newState); + } else if (state() == InferiorRunOk) { + // if we break on CPP side while running & engine is QML, switch. + if (m_activeEngine == m_qmlEngine) { + setActiveEngine(Lang_Cpp); + } + setState(newState); + } else if (state() == InferiorRunRequested) { + setState(newState, true); + } + if (m_shutdownDeferred) { + m_activeEngine = m_cppEngine; + m_shutdownDeferred = false; + shutdownInferior(); + } + break; + + case InferiorStopFailed: + setState(newState); + if (m_shutdownDeferred) { + m_activeEngine = m_cppEngine; + m_shutdownDeferred = false; + shutdownInferior(); + } + break; + + // here, we shut down the qml engine first. + // but due to everything being asyncronous, we cannot guarantee + // that it is shut down completely before gdb engine is shut down. + case InferiorShutdownRequested: + if (m_activeEngine == m_qmlEngine) { + m_activeEngine = m_cppEngine; + } + + m_qmlEngine->shutdownInferiorAsSlave(); + setState(newState); + break; + + case InferiorShutdownOk: + setState(newState); + m_qmlEngine->shutdownEngineAsSlave(); + break; + + case InferiorShutdownFailed: + setState(newState); + m_qmlEngine->shutdownEngineAsSlave(); + break; + + case EngineShutdownRequested: + setState(newState); + break; + + case EngineShutdownOk: + finishDebugger(); + break; + + case EngineShutdownFailed: + m_shutdownOk = false; + finishDebugger(); + break; + + default: + break; + } +} + +void QmlCppEngine::slaveEngineStateChanged(const DebuggerState &newState) +{ + //qDebug() << " qml engine changed to" << newState; + + if (m_activeEngine == m_qmlEngine) { + handleSlaveEngineStateChangeAsActive(newState); + } else { + handleSlaveEngineStateChange(newState); + } +} + +void QmlCppEngine::handleSlaveEngineStateChange(const DebuggerState &newState) +{ + switch(newState) { + case InferiorRunOk: + if (state() == InferiorRunRequested) { + // force state back so that the notification will succeed on init + setState(EngineRunRequested, true); + notifyEngineRunAndInferiorRunOk(); + } else { + // we have to manually override state with current one, because + // otherwise we'll have debugger controls in inconsistent state. + setState(state(), true); + } + + break; + + case InferiorStopOk: + if (state() == InferiorRunOk) { + // breakpoint was hit while running the app; change the active engine. + setActiveEngine(Lang_Qml); + setState(InferiorStopOk); + } + break; + + case InferiorRunFailed: + notifyInferiorRunFailed(); + break; + + case EngineShutdownFailed: + m_shutdownOk = false; + break; + + default: + // reset wrapper engine state to current state. + setState(state(), true); + break; + } +} + +void QmlCppEngine::handleSlaveEngineStateChangeAsActive(const DebuggerState &newState) +{ + switch(newState) { + case InferiorRunRequested: + setState(newState); + break; + + case InferiorRunOk: + setState(newState); + break; + + case InferiorStopOk: + setState(newState); + break; + + case InferiorRunFailed: + notifyInferiorRunFailed(); + break; + + case InferiorShutdownRequested: + if (m_cppEngine->state() == InferiorRunOk) { + // occurs when user presses stop button from debugger UI. + shutdownInferior(); + } + break; + + default: + break; + } +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/qml/qmlcppengine.h b/src/plugins/debugger/qml/qmlcppengine.h new file mode 100644 index 0000000000000000000000000000000000000000..1c1a8d0b383fe5421a17f01ddf5904552616e113 --- /dev/null +++ b/src/plugins/debugger/qml/qmlcppengine.h @@ -0,0 +1,124 @@ +#ifndef QMLGDBENGINE_H +#define QMLGDBENGINE_H + +#include "debuggerengine.h" + +namespace Core { +class IEditor; +} + +namespace Debugger { +namespace Internal { + +class GdbEngine; +class QmlEngine; + +class QmlCppEngine : public DebuggerEngine +{ + Q_OBJECT +public: + QmlCppEngine(const DebuggerStartParameters &sp); + virtual ~QmlCppEngine(); + + void setActiveEngine(DebuggerLanguage language); + + virtual void setToolTipExpression(const QPoint & /* mousePos */, + TextEditor::ITextEditor * /* editor */, int /* cursorPos */); + virtual void updateWatchData(const WatchData & /* data */); + + virtual void watchPoint(const QPoint &); + virtual void fetchMemory(MemoryViewAgent *, QObject *, + quint64 addr, quint64 length); + virtual void fetchDisassembler(DisassemblerViewAgent *); + virtual void activateFrame(int index); + + virtual void reloadModules(); + virtual void examineModules(); + virtual void loadSymbols(const QString &moduleName); + virtual void loadAllSymbols(); + virtual void requestModuleSymbols(const QString &moduleName); + + virtual void reloadRegisters(); + virtual void reloadSourceFiles(); + virtual void reloadFullStack(); + + virtual void setRegisterValue(int regnr, const QString &value); + virtual unsigned debuggerCapabilities() const; + + virtual bool isSynchroneous() const; + virtual QString qtNamespace() const; + + virtual void createSnapshot(); + virtual void updateAll(); + + virtual void attemptBreakpointSynchronization(); + virtual void selectThread(int index); + + virtual void assignValueInDebugger(const QString &expr, const QString &value); + + QAbstractItemModel *commandModel() const; + QAbstractItemModel *modulesModel() const; + QAbstractItemModel *breakModel() const; + QAbstractItemModel *registerModel() const; + QAbstractItemModel *stackModel() const; + QAbstractItemModel *threadsModel() const; + QAbstractItemModel *localsModel() const; + QAbstractItemModel *watchersModel() const; + QAbstractItemModel *returnModel() const; + QAbstractItemModel *sourceFilesModel() const; + +protected: + virtual void detachDebugger(); + virtual void executeStep(); + virtual void executeStepOut(); + virtual void executeNext(); + virtual void executeStepI(); + virtual void executeNextI(); + virtual void executeReturn(); + virtual void continueInferior(); + virtual void interruptInferior(); + virtual void requestInterruptInferior(); + + virtual void executeRunToLine(const QString &fileName, int lineNumber); + virtual void executeRunToFunction(const QString &functionName); + virtual void executeJumpToLine(const QString &fileName, int lineNumber); + virtual void executeDebuggerCommand(const QString &command); + + virtual void frameUp(); + virtual void frameDown(); + + virtual void notifyInferiorRunOk(); + +protected: + virtual void setupEngine(); + virtual void setupInferior(); + virtual void runEngine(); + virtual void shutdownInferior(); + virtual void shutdownEngine(); + +private slots: + void masterEngineStateChanged(const DebuggerState &state); + void slaveEngineStateChanged(const DebuggerState &state); + void setupSlaveEngine(); + void editorChanged(Core::IEditor *editor); + +private: + void setupSlaveEngineOnTimer(); + void finishDebugger(); + void handleSlaveEngineStateChange(const DebuggerState &newState); + void handleSlaveEngineStateChangeAsActive(const DebuggerState &newState); + +private: + QmlEngine *m_qmlEngine; + DebuggerEngine *m_cppEngine; + DebuggerEngine *m_activeEngine; + bool m_shutdownOk; + bool m_shutdownDeferred; + bool m_shutdownDone; + bool m_isInitialStartup; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // QMLGDBENGINE_H diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 7d4177b132c19f6b7670fd44dc8b9c6101f8001a..f0b3577213b4cecd931f030c4fbeee70bdd9a405 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -105,6 +105,8 @@ QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters) , m_ping(0) , m_adapter(new QmlAdapter(this)) , m_addedAdapterToObjectPool(false) + , m_attachToRunningExternalApp(false) + , m_hasShutdown(false) { setObjectName(QLatin1String("QmlEngine")); } @@ -113,6 +115,16 @@ QmlEngine::~QmlEngine() { } +void QmlEngine::setAttachToRunningExternalApp(bool value) +{ + m_attachToRunningExternalApp = value; +} + +void QmlEngine::pauseConnection() +{ + m_adapter->pauseConnection(); +} + void QmlEngine::setupInferior() { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); @@ -154,26 +166,71 @@ void QmlEngine::runEngine() { QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); - // ### TODO for non-qmlproject apps, start in a different way - m_applicationLauncher.start(ProjectExplorer::ApplicationLauncher::Gui, - startParameters().executable, - startParameters().processArgs); + if (!m_attachToRunningExternalApp) { + m_applicationLauncher.start(ProjectExplorer::ApplicationLauncher::Gui, + startParameters().executable, + startParameters().processArgs); + } m_adapter->beginConnection(); plugin()->showMessage(tr("QML Debugger connecting..."), StatusBar); +} + +void QmlEngine::shutdownInferiorAsSlave() +{ + resetLocation(); - // FIXME: refactor the UI - Debugger::DebuggerUISwitcher::instance()->setActiveLanguage("QML"); + // This can be issued in almost any state. We assume, though, + // that at this point of time the inferior is not running anymore, + // even if stop notification were not issued or got lost. + if (state() == InferiorRunOk) { + setState(InferiorStopRequested); + setState(InferiorStopOk); + } + setState(InferiorShutdownRequested); + setState(InferiorShutdownOk); +} + +void QmlEngine::shutdownEngineAsSlave() +{ + if (m_hasShutdown) + return; + + disconnect(m_adapter, SIGNAL(connectionStartupFailed()), this, SLOT(connectionStartupFailed())); + m_adapter->closeConnection(); + + if (m_addedAdapterToObjectPool) { + ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance(); + pluginManager->removeObject(m_adapter); + } + + if (m_attachToRunningExternalApp) { + setState(EngineShutdownRequested, true); + setState(EngineShutdownOk, true); + setState(DebuggerFinished, true); + } else { + if (m_applicationLauncher.isRunning()) { + // should only happen if engine is ill + disconnect(&m_applicationLauncher, SIGNAL(processExited(int)), this, SLOT(disconnected())); + m_applicationLauncher.stop(); + } + } + m_hasShutdown = true; } void QmlEngine::shutdownInferior() { + // don't do normal shutdown if running as slave engine + if (m_attachToRunningExternalApp) + return; + QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state()); if (!m_applicationLauncher.isRunning()) { showMessage(tr("Trying to stop while process is no longer running."), LogError); } else { disconnect(&m_applicationLauncher, SIGNAL(processExited(int)), this, SLOT(disconnected())); - m_applicationLauncher.stop(); + if (!m_attachToRunningExternalApp) + m_applicationLauncher.stop(); } notifyInferiorShutdownOk(); } @@ -182,16 +239,7 @@ void QmlEngine::shutdownEngine() { QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state()); - if (m_addedAdapterToObjectPool) { - ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance(); - pluginManager->removeObject(m_adapter); - } - - if (m_applicationLauncher.isRunning()) { - // should only happen if engine is ill - disconnect(&m_applicationLauncher, SIGNAL(processExited(int)), this, SLOT(disconnected())); - m_applicationLauncher.stop(); - } + shutdownEngineAsSlave(); notifyEngineShutdownOk(); } @@ -468,7 +516,9 @@ void QmlEngine::messageReceived(const QByteArray &message) showMessage(_("RECEIVED RESPONSE: ") + quoteUnprintableLatin1(message)); if (command == "STOPPED") { - notifyInferiorSpontaneousStop(); + if (state() == InferiorRunOk) { + notifyInferiorSpontaneousStop(); + } QList<QPair<QString, QPair<QString, qint32> > > backtrace; QList<WatchData> watches; @@ -516,14 +566,9 @@ void QmlEngine::messageReceived(const QByteArray &message) else watchHandler()->endCycle(); - // Ensure we got the right ui right now. - Debugger::DebuggerUISwitcher *uiSwitcher - = Debugger::DebuggerUISwitcher::instance(); - uiSwitcher->setActiveLanguage("C++"); - - bool becauseOfexception; - stream >> becauseOfexception; - if (becauseOfexception) { + bool becauseOfException; + stream >> becauseOfException; + if (becauseOfException) { QString error; stream >> error; diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index 9c77d2e4dff185633efeb9d62343d5ceafdac683..2a25a0e6ce9683cdb7443b281f8c72768ecac10b 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -63,6 +63,11 @@ public: explicit QmlEngine(const DebuggerStartParameters &startParameters); ~QmlEngine(); + void setAttachToRunningExternalApp(bool value); + void shutdownInferiorAsSlave(); + void shutdownEngineAsSlave(); + void pauseConnection(); + public slots: void messageReceived(const QByteArray &message); void disconnected(); @@ -119,15 +124,18 @@ private slots: void connectionError(); private: - void expandObject(const QByteArray &iname, quint64 objectId); void sendPing(); private: + friend class QmlCppEngine; + int m_ping; QmlAdapter *m_adapter; ProjectExplorer::ApplicationLauncher m_applicationLauncher; bool m_addedAdapterToObjectPool; + bool m_attachToRunningExternalApp; + bool m_hasShutdown; }; } // namespace Internal diff --git a/src/plugins/qmljsinspector/qmlinspectortoolbar.cpp b/src/plugins/qmljsinspector/qmlinspectortoolbar.cpp index f7e5ffb6dbb90957fe388b99ec4794af1f82e026..55a0908b6638d761edb01978a41806703dde83e5 100644 --- a/src/plugins/qmljsinspector/qmlinspectortoolbar.cpp +++ b/src/plugins/qmljsinspector/qmlinspectortoolbar.cpp @@ -33,11 +33,13 @@ #include <extensionsystem/pluginmanager.h> #include <coreplugin/icore.h> -#include <debugger/debuggeruiswitcher.h> #include <projectexplorer/projectexplorerconstants.h> #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/command.h> +#include <utils/styledbar.h> +#include <utils/filterlineedit.h> + #include <QHBoxLayout> #include <QAction> #include <QToolButton> @@ -77,7 +79,8 @@ QmlInspectorToolbar::QmlInspectorToolbar(QObject *parent) : m_isRunning(false), m_animationSpeed(1.0f), m_previousAnimationSpeed(0.0f), - m_activeTool(NoTool) + m_activeTool(NoTool), + m_barWidget(0) { } @@ -182,8 +185,6 @@ void QmlInspectorToolbar::createActions(const Core::Context &context) { Core::ICore *core = Core::ICore::instance(); Core::ActionManager *am = core->actionManager(); - ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance(); - Debugger::DebuggerUISwitcher *uiSwitcher = pluginManager->getObject<Debugger::DebuggerUISwitcher>(); m_fromQmlAction = new QAction(QIcon(QLatin1String(":/qml/images/from-qml-small.png")), tr("Apply Changes to Document"), this); m_designmodeAction = new QAction(QIcon(QLatin1String(":/qml/images/designmode.png")), tr("Design Mode"), this); @@ -221,14 +222,15 @@ void QmlInspectorToolbar::createActions(const Core::Context &context) am->registerAction(m_toQmlAction, QmlJSInspector::Constants::TO_QML_ACTION, context); am->registerAction(m_fromQmlAction, QmlJSInspector::Constants::FROM_QML_ACTION, context); - QWidget *configBar = new QWidget; - configBar->setProperty("topBorder", true); + m_barWidget = new Utils::StyledBar; + m_barWidget->setSingleRow(true); + m_barWidget->setProperty("topBorder", true); - QHBoxLayout *configBarLayout = new QHBoxLayout(configBar); + QHBoxLayout *configBarLayout = new QHBoxLayout(m_barWidget); configBarLayout->setMargin(0); configBarLayout->setSpacing(5); - QMenu *playSpeedMenu = new QMenu(configBar); + QMenu *playSpeedMenu = new QMenu(m_barWidget); QActionGroup *playSpeedMenuActions = new QActionGroup(this); playSpeedMenuActions->setExclusive(true); playSpeedMenu->addAction(tr("Animation Speed")); @@ -258,8 +260,8 @@ void QmlInspectorToolbar::createActions(const Core::Context &context) m_menuPauseAction->setCheckable(true); playSpeedMenuActions->addAction(m_menuPauseAction); - configBarLayout->addWidget(createToolButton(am->command(ProjectExplorer::Constants::DEBUG)->action())); - configBarLayout->addWidget(createToolButton(am->command(ProjectExplorer::Constants::STOP)->action())); +// configBarLayout->addWidget(createToolButton(am->command(ProjectExplorer::Constants::DEBUG)->action())); +// configBarLayout->addWidget(createToolButton(am->command(ProjectExplorer::Constants::STOP)->action())); configBarLayout->addWidget(createToolButton(am->command(QmlJSInspector::Constants::FROM_QML_ACTION)->action())); configBarLayout->addWidget(createToolButton(am->command(QmlJSInspector::Constants::DESIGNMODE_ACTION)->action())); configBarLayout->addWidget(createToolButton(am->command(QmlJSInspector::Constants::RELOAD_ACTION)->action())); @@ -275,7 +277,7 @@ void QmlInspectorToolbar::createActions(const Core::Context &context) configBarLayout->addWidget(createToolButton(am->command(QmlJSInspector::Constants::ZOOM_ACTION)->action())); configBarLayout->addWidget(createToolButton(am->command(QmlJSInspector::Constants::COLOR_PICKER_ACTION)->action())); - m_colorBox = new ToolBarColorBox(configBar); + m_colorBox = new ToolBarColorBox(m_barWidget); m_colorBox->setMinimumSize(20, 20); m_colorBox->setMaximumSize(20, 20); m_colorBox->setInnerBorderColor(QColor(192,192,192)); @@ -283,9 +285,11 @@ void QmlInspectorToolbar::createActions(const Core::Context &context) configBarLayout->addWidget(m_colorBox); //configBarLayout->addWidget(createToolButton(am->command(QmlJSInspector::Constants::TO_QML_ACTION)->action())); + m_filterLineEdit = new Utils::FilterLineEdit(m_barWidget); + configBarLayout->addStretch(); + configBarLayout->addWidget(m_filterLineEdit); - uiSwitcher->setToolbar(QmlJSInspector::Constants::LANG_QML, configBar); setEnabled(false); connect(m_designmodeAction, SIGNAL(triggered()), SLOT(activateDesignModeOnClick())); @@ -305,6 +309,11 @@ void QmlInspectorToolbar::createActions(const Core::Context &context) connect(m_fromQmlAction, SIGNAL(triggered()), SLOT(activateFromQml())); } +QWidget *QmlInspectorToolbar::widget() const +{ + return m_barWidget; +} + void QmlInspectorToolbar::changeToDefaultAnimSpeed() { m_animationSpeed = 1.0f; diff --git a/src/plugins/qmljsinspector/qmlinspectortoolbar.h b/src/plugins/qmljsinspector/qmlinspectortoolbar.h index 957044ed645ca6a479861baaffd5695bfd8127c4..8b9309a05124d3087f9d15ef58b09b8630e40e56 100644 --- a/src/plugins/qmljsinspector/qmlinspectortoolbar.h +++ b/src/plugins/qmljsinspector/qmlinspectortoolbar.h @@ -39,6 +39,11 @@ namespace Core { class Context; } +namespace Utils { + class StyledBar; + class FilterLineEdit; +} + namespace QmlJSInspector { class ToolBarColorBox; @@ -61,6 +66,7 @@ public: explicit QmlInspectorToolbar(QObject *parent = 0); void createActions(const Core::Context &context); + QWidget *widget() const; public slots: void setEnabled(bool value); @@ -136,6 +142,9 @@ private: DesignTool m_activeTool; + Utils::StyledBar *m_barWidget; + Utils::FilterLineEdit *m_filterLineEdit; + }; } // namespace Internal diff --git a/src/plugins/qmljsinspector/qmljsinspector.cpp b/src/plugins/qmljsinspector/qmljsinspector.cpp index eedbd5ec32bbc4f4cc66325fee0b352f7db8128c..315126abeabba76fbb08845a9a1872afb6e3ce4e 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.cpp +++ b/src/plugins/qmljsinspector/qmljsinspector.cpp @@ -34,6 +34,7 @@ #include "qmljsprivateapi.h" #include "qmljscontextcrumblepath.h" #include "qmljsinspectorsettings.h" +#include "qmljsobjecttree.h" #include <qmljseditor/qmljseditorconstants.h> @@ -73,6 +74,7 @@ #include <texteditor/basetexteditor.h> #include <projectexplorer/runconfiguration.h> +#include <projectexplorer/buildconfiguration.h> #include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/project.h> @@ -91,6 +93,7 @@ #include <QtGui/QLabel> #include <QtGui/QDockWidget> +#include <QtGui/QVBoxLayout> #include <QtGui/QAction> #include <QtGui/QLineEdit> #include <QtGui/QLabel> @@ -123,6 +126,10 @@ QmlJS::ModelManagerInterface *modelManager() InspectorUi::InspectorUi(QObject *parent) : QObject(parent) , m_listeningToEditorManager(false) + , m_toolbar(0) + , m_crumblePath(0) + , m_objectTreeWidget(0) + , m_inspectorDockWidget(0) , m_settings(new InspectorSettings(this)) , m_clientProxy(0) , m_debugProject(0) @@ -138,7 +145,6 @@ InspectorUi::~InspectorUi() void InspectorUi::setupUi() { setupDockWidgets(); - m_toolbar->createActions(Core::Context(Constants::C_INSPECTOR)); restoreSettings(); } @@ -165,6 +171,13 @@ void InspectorUi::connected(ClientProxy *clientProxy) m_crumblePath, SLOT(updateContextPath(QStringList))); m_debugProject = ProjectExplorer::ProjectExplorerPlugin::instance()->startupProject(); + if (m_debugProject->activeTarget() + && m_debugProject->activeTarget()->activeBuildConfiguration()) + { + ProjectExplorer::BuildConfiguration *bc = m_debugProject->activeTarget()->activeBuildConfiguration(); + m_debugProjectBuildDir = bc->buildDirectory(); + } + connect(m_debugProject, SIGNAL(destroyed()), SLOT(currentDebugProjectRemoved())); setupToolbar(true); @@ -176,6 +189,7 @@ void InspectorUi::connected(ClientProxy *clientProxy) while(iter.hasNext()) { iter.next(); iter.value()->setClientProxy(m_clientProxy); + iter.value()->updateDebugIds(); } } @@ -200,8 +214,9 @@ void InspectorUi::disconnected() iter.next(); iter.value()->setClientProxy(0); } - m_clientProxy = 0; + m_objectTreeWidget->clear(); + m_pendingPreviewDocumentNames.clear(); } void InspectorUi::updateEngineList() @@ -235,6 +250,9 @@ void InspectorUi::initializeDocuments() m_listeningToEditorManager = true; connect(em, SIGNAL(editorAboutToClose(Core::IEditor*)), SLOT(removePreviewForEditor(Core::IEditor*))); connect(em, SIGNAL(editorOpened(Core::IEditor*)), SLOT(createPreviewForEditor(Core::IEditor*))); + connect(modelManager(), + SIGNAL(documentChangedOnDisk(QmlJS::Document::Ptr)), + SLOT(updatePendingPreviewDocuments(QmlJS::Document::Ptr))); } // initial update @@ -265,8 +283,10 @@ void InspectorUi::removePreviewForEditor(Core::IEditor *oldEditor) } } -void InspectorUi::createPreviewForEditor(Core::IEditor *newEditor) +QmlJSLiveTextPreview *InspectorUi::createPreviewForEditor(Core::IEditor *newEditor) { + QmlJSLiveTextPreview *preview = 0; + if (m_clientProxy && m_clientProxy->isConnected() && newEditor @@ -275,16 +295,26 @@ void InspectorUi::createPreviewForEditor(Core::IEditor *newEditor) { QString filename = newEditor->file()->fileName(); QmlJS::Document::Ptr doc = modelManager()->snapshot().document(filename); - if (!doc || !doc->qmlProgram()) - return; + if (!doc) { + if (filename.endsWith(".qml")) { + // add to list of docs that we have to update when + // snapshot figures out that there's a new document + m_pendingPreviewDocumentNames.append(filename); + } + return 0; + } + if (!doc->qmlProgram()) + return 0; + QmlJS::Document::Ptr initdoc = m_loadedSnapshot.document(filename); if (!initdoc) initdoc = doc; if (m_textPreviews.contains(filename)) { - m_textPreviews.value(filename)->associateEditor(newEditor); + preview = m_textPreviews.value(filename); + preview->associateEditor(newEditor); } else { - QmlJSLiveTextPreview *preview = new QmlJSLiveTextPreview(doc, initdoc, m_clientProxy, this); + preview = new QmlJSLiveTextPreview(doc, initdoc, m_clientProxy, this); connect(preview, SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)), SLOT(changeSelectedItems(QList<QDeclarativeDebugObjectReference>))); @@ -296,6 +326,8 @@ void InspectorUi::createPreviewForEditor(Core::IEditor *newEditor) preview->updateDebugIds(); } } + + return preview; } void InspectorUi::currentDebugProjectRemoved() @@ -314,16 +346,49 @@ void InspectorUi::reloadQmlViewer() m_clientProxy->reloadQmlViewer(); } -void InspectorUi::setSimpleDockWidgetArrangement() +void InspectorUi::setSimpleDockWidgetArrangement(const Debugger::DebuggerLanguages &activeLanguages) { - Utils::FancyMainWindow *mainWindow = Debugger::DebuggerUISwitcher::instance()->mainWindow(); + Debugger::DebuggerUISwitcher *uiSwitcher = Debugger::DebuggerUISwitcher::instance(); + Utils::FancyMainWindow *mw = uiSwitcher->mainWindow(); + + mw->setTrackingEnabled(false); + + if (activeLanguages.testFlag(Debugger::Lang_Cpp) && activeLanguages.testFlag(Debugger::Lang_Qml)) { + // cpp + qml + QList<QDockWidget *> dockWidgets = mw->dockWidgets(); + foreach (QDockWidget *dockWidget, dockWidgets) { + dockWidget->setFloating(false); + mw->removeDockWidget(dockWidget); + } + foreach (QDockWidget *dockWidget, dockWidgets) { + if (dockWidget == uiSwitcher->outputWindow()) { + mw->addDockWidget(Qt::TopDockWidgetArea, dockWidget); + } else { + mw->addDockWidget(Qt::BottomDockWidgetArea, dockWidget); + } + + if (dockWidget == m_inspectorDockWidget) { + dockWidget->show(); + } else { + dockWidget->hide(); + } + } - mainWindow->setTrackingEnabled(false); - mainWindow->removeDockWidget(m_crumblePathDock); - mainWindow->addDockWidget(Qt::BottomDockWidgetArea, m_crumblePathDock); - mainWindow->splitDockWidget(mainWindow->toolBarDockWidget(), m_crumblePathDock, Qt::Vertical); - m_crumblePathDock->setVisible(true); - mainWindow->setTrackingEnabled(true); + uiSwitcher->stackWindow()->show(); + uiSwitcher->watchWindow()->show(); + uiSwitcher->breakWindow()->show(); + uiSwitcher->threadsWindow()->show(); + uiSwitcher->snapshotsWindow()->show(); + m_inspectorDockWidget->show(); + + mw->splitDockWidget(mw->toolBarDockWidget(), uiSwitcher->stackWindow(), Qt::Vertical); + mw->splitDockWidget(uiSwitcher->stackWindow(), uiSwitcher->watchWindow(), Qt::Horizontal); + mw->tabifyDockWidget(uiSwitcher->watchWindow(), uiSwitcher->breakWindow()); + mw->tabifyDockWidget(uiSwitcher->watchWindow(), m_inspectorDockWidget); + + } + + mw->setTrackingEnabled(true); } void InspectorUi::setSelectedItemsByObjectReference(QList<QDeclarativeDebugObjectReference> objectReferences) @@ -337,11 +402,18 @@ void InspectorUi::gotoObjectReferenceDefinition(const QDeclarativeDebugObjectRef Q_UNUSED(obj); QDeclarativeDebugFileReference source = obj.source(); - const QString fileName = source.url().toLocalFile(); + QString fileName = source.url().toLocalFile(); if (source.lineNumber() < 0 || !QFile::exists(fileName)) return; + + // do some extra checking for filenames with shadow builds - we don't want to + // open the shadow build file, but the real one by default. + if (isShadowBuildProject()) { + fileName = filenameForShadowBuildFile(fileName); + } + Core::EditorManager *editorManager = Core::EditorManager::instance(); Core::IEditor *editor = editorManager->openEditor(fileName, QString(), Core::EditorManager::NoModeSwitch); TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor); @@ -353,6 +425,28 @@ void InspectorUi::gotoObjectReferenceDefinition(const QDeclarativeDebugObjectRef } } +QString InspectorUi::filenameForShadowBuildFile(const QString &filename) const +{ + if (!debugProject() || !isShadowBuildProject()) + return filename; + + QDir projectDir(debugProject()->projectDirectory()); + QDir buildDir(debugProjectBuildDirectory()); + QFileInfo fileInfo(filename); + + if (projectDir.exists() && buildDir.exists() && fileInfo.exists()) { + if (fileInfo.absoluteFilePath().startsWith(buildDir.canonicalPath())) { + QString fileRelativePath = fileInfo.canonicalFilePath().mid(debugProjectBuildDirectory().length()); + QFileInfo projectFile(projectDir.canonicalPath() + QLatin1Char('/') + fileRelativePath); + + if (projectFile.exists()) + return projectFile.canonicalFilePath(); + } + + } + return filename; +} + bool InspectorUi::addQuotesForData(const QVariant &value) const { switch (value.type()) { @@ -369,15 +463,35 @@ bool InspectorUi::addQuotesForData(const QVariant &value) const void InspectorUi::setupDockWidgets() { + Debugger::DebuggerUISwitcher *uiSwitcher = Debugger::DebuggerUISwitcher::instance(); + + m_toolbar->createActions(Core::Context(Constants::C_INSPECTOR)); + m_toolbar->setObjectName("QmlInspectorToolbar"); + m_crumblePath = new ContextCrumblePath; m_crumblePath->setObjectName("QmlContextPath"); - m_crumblePath->setWindowTitle("Context Path"); + m_crumblePath->setWindowTitle(tr("Context Path")); connect(m_crumblePath, SIGNAL(elementClicked(int)), SLOT(crumblePathElementClicked(int))); - Debugger::DebuggerUISwitcher *uiSwitcher = Debugger::DebuggerUISwitcher::instance(); - m_crumblePathDock = uiSwitcher->createDockWidget(QmlJSInspector::Constants::LANG_QML, - m_crumblePath, Qt::BottomDockWidgetArea); - m_crumblePathDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); - m_crumblePathDock->setTitleBarWidget(new QWidget(m_crumblePathDock)); + + m_objectTreeWidget = new QmlJSObjectTree; + + QWidget *inspectorWidget = new QWidget; + inspectorWidget->setWindowTitle(tr("Inspector")); + + QVBoxLayout *wlay = new QVBoxLayout(inspectorWidget); + wlay->setMargin(0); + wlay->setSpacing(0); + inspectorWidget->setLayout(wlay); + wlay->addWidget(m_toolbar->widget()); + wlay->addWidget(m_objectTreeWidget); + wlay->addWidget(m_crumblePath); + + + m_inspectorDockWidget = uiSwitcher->createDockWidget(Debugger::Lang_Qml, + inspectorWidget, Qt::BottomDockWidgetArea); + m_inspectorDockWidget->setObjectName(Debugger::Constants::DW_QML_INSPECTOR); + m_inspectorDockWidget->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); + m_inspectorDockWidget->setTitleBarWidget(new QWidget(m_inspectorDockWidget)); } void InspectorUi::crumblePathElementClicked(int pathIndex) @@ -407,6 +521,19 @@ ProjectExplorer::Project *InspectorUi::debugProject() const return m_debugProject; } +bool InspectorUi::isShadowBuildProject() const +{ + if (!debugProject()) + return false; + + return (debugProject()->projectDirectory() != debugProjectBuildDirectory()); +} + +QString InspectorUi::debugProjectBuildDirectory() const +{ + return m_debugProjectBuildDir; +} + void InspectorUi::setApplyChangesToQmlObserver(bool applyChanges) { emit livePreviewActivated(applyChanges); @@ -422,6 +549,29 @@ void InspectorUi::applyChangesToQmlObserverHelper(bool applyChanges) } } +void InspectorUi::updatePendingPreviewDocuments(QmlJS::Document::Ptr doc) +{ + int idx = -1; + idx = m_pendingPreviewDocumentNames.indexOf(doc->fileName()); + + if (idx == -1) + return; + + QList<Core::IEditor *> editors = Core::EditorManager::instance()->editorsForFileName(doc->fileName()); + + if (editors.isEmpty()) + return; + + m_pendingPreviewDocumentNames.removeAt(idx); + + QmlJSLiveTextPreview *preview = createPreviewForEditor(editors.first()); + editors.removeFirst(); + + foreach(Core::IEditor *editor, editors) { + preview->associateEditor(editor); + } +} + void InspectorUi::disableLivePreview() { setApplyChangesToQmlObserver(false); diff --git a/src/plugins/qmljsinspector/qmljsinspector.h b/src/plugins/qmljsinspector/qmljsinspector.h index b7b5020a2a48f58078cc296e2c89eeca90851954..3c53ce2daad362002420f1289da5b3a9dec8387f 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.h +++ b/src/plugins/qmljsinspector/qmljsinspector.h @@ -33,6 +33,7 @@ #include "qmljsprivateapi.h" #include <coreplugin/basemode.h> +#include <debugger/debuggerconstants.h> #include <qmlprojectmanager/qmlprojectrunconfiguration.h> #include <qmljs/qmljsdocument.h> @@ -60,6 +61,7 @@ namespace QmlJSInspector { namespace Internal { class QmlInspectorToolbar; +class QmlJSObjectTree; class ClientProxy; class InspectorSettings; class ContextCrumblePath; @@ -89,6 +91,8 @@ public: // returns the project being currently debugged, or 0 if not debugging anything ProjectExplorer::Project *debugProject() const; + QString debugProjectBuildDirectory() const; + bool isShadowBuildProject() const; void setupUi(); void connected(ClientProxy *clientProxy); @@ -99,7 +103,7 @@ signals: void livePreviewActivated(bool isActivated); public slots: - void setSimpleDockWidgetArrangement(); + void setSimpleDockWidgetArrangement(const Debugger::DebuggerLanguages &activeLanguages); void reloadQmlViewer(); void serverReloaded(); void setApplyChangesToQmlObserver(bool applyChanges); @@ -114,12 +118,13 @@ private slots: void removePreviewForEditor(Core::IEditor *newEditor); - void createPreviewForEditor(Core::IEditor *newEditor); + QmlJSLiveTextPreview *createPreviewForEditor(Core::IEditor *newEditor); void disableLivePreview(); void crumblePathElementClicked(int); void currentDebugProjectRemoved(); + void updatePendingPreviewDocuments(QmlJS::Document::Ptr doc); private: bool addQuotesForData(const QVariant &value) const; @@ -129,15 +134,15 @@ private: void applyChangesToQmlObserverHelper(bool applyChanges); void setupToolbar(bool doConnect); void setupDockWidgets(); + QString filenameForShadowBuildFile(const QString &filename) const; private: - QWeakPointer<QDeclarativeEngineDebug> m_client; - bool m_listeningToEditorManager; QmlInspectorToolbar *m_toolbar; ContextCrumblePath *m_crumblePath; - QDockWidget *m_crumblePathDock; + QmlJSObjectTree *m_objectTreeWidget; + QDockWidget *m_inspectorDockWidget; InspectorSettings *m_settings; ClientProxy *m_clientProxy; @@ -145,7 +150,12 @@ private: // Qml/JS integration QHash<QString, QmlJSLiveTextPreview *> m_textPreviews; QmlJS::Snapshot m_loadedSnapshot; //the snapshot loaded by the viewer + + // project is needed for matching filenames, esp. with shadow builds. ProjectExplorer::Project *m_debugProject; + QString m_debugProjectBuildDir; + + QStringList m_pendingPreviewDocumentNames; static InspectorUi *m_instance; }; diff --git a/src/plugins/qmljsinspector/qmljsinspector.pro b/src/plugins/qmljsinspector/qmljsinspector.pro index 31b405eb7c3cdefb80feaf698cad590d685d7a36..27eaeaf3b29928dd62b0d89b75afc5e70ca1c493 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.pro +++ b/src/plugins/qmljsinspector/qmljsinspector.pro @@ -18,7 +18,8 @@ qmljslivetextpreview.h \ qmljstoolbarcolorbox.h \ qmljsdesigndebugclient.h \ qmljscontextcrumblepath.h \ -qmljsinspectorsettings.h +qmljsinspectorsettings.h \ +qmljsobjecttree.h SOURCES += \ qmljsinspectorplugin.cpp \ @@ -29,7 +30,8 @@ qmljslivetextpreview.cpp \ qmljstoolbarcolorbox.cpp \ qmljsdesigndebugclient.cpp \ qmljscontextcrumblepath.cpp \ -qmljsinspectorsettings.cpp +qmljsinspectorsettings.cpp \ +qmljsobjecttree.cpp include(../../libs/qmljsdebugclient/qmljsdebugclient-lib.pri) diff --git a/src/plugins/qmljsinspector/qmljsinspectorconstants.h b/src/plugins/qmljsinspector/qmljsinspectorconstants.h index 1f9b5313b72fe90256d59428557e6dbe8ce9e9f4..d9f08fbd7c267f225ed738181dc2eb3d425a6fd0 100644 --- a/src/plugins/qmljsinspector/qmljsinspectorconstants.h +++ b/src/plugins/qmljsinspector/qmljsinspectorconstants.h @@ -43,8 +43,6 @@ const char * const M_DEBUG_SIMULTANEOUSLY = "QmlInspector.Menu.SimultaneousDebug const char * const INFO_EXPERIMENTAL = "QmlInspector.Experimental"; const char * const INFO_OUT_OF_SYNC = "QmlInspector.OutOfSyncWarning"; -const char * const LANG_QML = "QML"; - const char * const DESIGNMODE_ACTION = "QmlInspector.DesignMode"; const char * const RELOAD_ACTION = "QmlInspector.Reload"; const char * const PLAY_ACTION = "QmlInspector.Play"; diff --git a/src/plugins/qmljsinspector/qmljsinspectorplugin.cpp b/src/plugins/qmljsinspector/qmljsinspectorplugin.cpp index 211a55f325de669a3a528fb6fe4ca17aff864a8a..a344b8d2facb0e44202ee11271e846544f296f0d 100644 --- a/src/plugins/qmljsinspector/qmljsinspectorplugin.cpp +++ b/src/plugins/qmljsinspector/qmljsinspectorplugin.cpp @@ -107,7 +107,7 @@ bool InspectorPlugin::initialize(const QStringList &arguments, QString *errorStr ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance(); Debugger::DebuggerUISwitcher *uiSwitcher = pluginManager->getObject<Debugger::DebuggerUISwitcher>(); - uiSwitcher->addLanguage(LANG_QML, Core::Context(C_INSPECTOR)); + uiSwitcher->addLanguage(Debugger::Lang_Qml, tr("QML"), Core::Context(C_INSPECTOR)); return true; } @@ -116,21 +116,12 @@ void InspectorPlugin::extensionsInitialized() { ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance(); - Debugger::DebuggerUISwitcher *uiSwitcher = pluginManager->getObject<Debugger::DebuggerUISwitcher>(); - connect(uiSwitcher, SIGNAL(dockArranged(QString)), SLOT(setDockWidgetArrangement(QString))); - connect(pluginManager, SIGNAL(objectAdded(QObject*)), SLOT(objectAdded(QObject*))); connect(pluginManager, SIGNAL(aboutToRemoveObject(QObject*)), SLOT(aboutToRemoveObject(QObject*))); m_inspectorUi->setupUi(); } -void InspectorPlugin::setDockWidgetArrangement(const QString &activeLanguage) -{ - if (activeLanguage == QmlJSInspector::Constants::LANG_QML || activeLanguage.isEmpty()) - m_inspectorUi->setSimpleDockWidgetArrangement(); -} - // The adapter object is only added to the pool with a succesful connection, // so we can immediately init our stuff. void InspectorPlugin::objectAdded(QObject *object) diff --git a/src/plugins/qmljsinspector/qmljsinspectorplugin.h b/src/plugins/qmljsinspector/qmljsinspectorplugin.h index 7634643041b4d216e6cce4409e9e3bebcd3d05da..ea4a378c74e701231e940e64b4b3dcd6799a1e36 100644 --- a/src/plugins/qmljsinspector/qmljsinspectorplugin.h +++ b/src/plugins/qmljsinspector/qmljsinspectorplugin.h @@ -31,6 +31,7 @@ #include <extensionsystem/iplugin.h> #include <qmljs/qmljsmodelmanagerinterface.h> +#include <debugger/debuggerconstants.h> #include <QtCore/QObject> #include <QtCore/QPointer> @@ -70,9 +71,6 @@ public: virtual void extensionsInitialized(); virtual ExtensionSystem::IPlugin::ShutdownFlag aboutToShutdown(); -public slots: - void setDockWidgetArrangement(const QString &activeLanguage); - private slots: void objectAdded(QObject *object); void aboutToRemoveObject(QObject *obj); diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp index 3a731d65166fe9fc558a542cec98a015c97bf078..4d88481645e03f76593b1580891bce1748f9e983 100644 --- a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp +++ b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp @@ -76,6 +76,8 @@ class MapObjectWithDebugReference : public Visitor QHash<UiObjectMember *, DebugIdList> result; QSet<QmlJS::AST::UiObjectMember *> lookupObjects; Document::Ptr doc; + private: + bool filenamesMatch(const QString &objectFileName, const QString &buildFilename) const; private: int activated; void processRecursive(const QDeclarativeDebugObjectReference &object, UiObjectMember *ast); @@ -117,6 +119,26 @@ void MapObjectWithDebugReference::endVisit(UiObjectBinding* ast) activated--; } +bool MapObjectWithDebugReference::filenamesMatch(const QString &objectFileName, const QString &buildFilename) const +{ + bool isShadowBuild = InspectorUi::instance()->isShadowBuildProject(); + ProjectExplorer::Project *debugProject = InspectorUi::instance()->debugProject(); + + if (!isShadowBuild) { + return (objectFileName == buildFilename); + } else { + QString projectDir = debugProject->projectDirectory(); + QString shadowBuildDir = InspectorUi::instance()->debugProjectBuildDirectory(); + + QFileInfo objectFileInfo(objectFileName); + QFileInfo buildFileInfo(buildFilename); + QString objectRelativePath = objectFileInfo.absoluteFilePath().mid(shadowBuildDir.length()); + QString buildRelativePath = buildFileInfo.absoluteFilePath().mid(projectDir.length()); + + return (objectRelativePath == buildRelativePath); + } +} + void MapObjectWithDebugReference::processRecursive(const QDeclarativeDebugObjectReference& object, UiObjectMember* ast) { // If this is too slow, it can be speed up by indexing @@ -125,7 +147,7 @@ void MapObjectWithDebugReference::processRecursive(const QDeclarativeDebugObject SourceLocation loc = ast->firstSourceLocation(); if (object.source().columnNumber() == int(loc.startColumn)) { QString objectFileName = object.source().url().toLocalFile(); - if (!doc && object.source().lineNumber() == int(loc.startLine) && objectFileName == filename) { + if (!doc && object.source().lineNumber() == int(loc.startLine) && filenamesMatch(objectFileName, filename)) { result[ast] += object.debugId(); } else if (doc && objectFileName.startsWith(filename + QLatin1Char('_') + QString::number(doc->editorRevision()) + QLatin1Char(':'))) { bool ok; @@ -548,7 +570,7 @@ public: void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) { - if (doc->fileName() != m_previousDoc->fileName() || !m_clientProxy) + if (doc->fileName() != m_previousDoc->fileName() || m_clientProxy.isNull()) return; Core::ICore *core = Core::ICore::instance(); diff --git a/src/plugins/qmljsinspector/qmljsobjecttree.cpp b/src/plugins/qmljsinspector/qmljsobjecttree.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d6befb1e21255fcd9d39b1331b54a9aa76d96cc --- /dev/null +++ b/src/plugins/qmljsinspector/qmljsobjecttree.cpp @@ -0,0 +1,238 @@ +/************************************************************************** +** +** 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 "qmljsobjecttree.h" + +#include <QContextMenuEvent> +#include <QEvent> +#include <QtGui/QMenu> +#include <QtGui/QAction> +#include <QApplication> +#include <QInputDialog> + +#include <QDebug> + +namespace QmlJSInspector { +namespace Internal { + +// ************************************************************************* +// ObjectTreeItem +// ************************************************************************* + +class ObjectTreeItem : public QTreeWidgetItem +{ +public: + explicit ObjectTreeItem(QTreeWidget *widget, int type = 0); + ObjectTreeItem(QTreeWidgetItem *parentItem, int type = 0); + QVariant data (int column, int role) const; + void setData (int column, int role, const QVariant & value); + + void setHasValidDebugId(bool value); + + +private: + bool m_hasValidDebugId; +}; + +ObjectTreeItem::ObjectTreeItem(QTreeWidget *widget, int type) : + QTreeWidgetItem(widget, type), m_hasValidDebugId(true) +{ + +} + +ObjectTreeItem::ObjectTreeItem(QTreeWidgetItem *parentItem, int type) : + QTreeWidgetItem(parentItem, type), m_hasValidDebugId(true) +{ + +} + +QVariant ObjectTreeItem::data (int column, int role) const +{ + if (role == Qt::ForegroundRole) + return m_hasValidDebugId ? qApp->palette().color(QPalette::Foreground) : qApp->palette().color(QPalette::Disabled, QPalette::Foreground); + + return QTreeWidgetItem::data(column, role); +} + +void ObjectTreeItem::setData (int column, int role, const QVariant & value) +{ + QTreeWidgetItem::setData(column, role, value); +} + +void ObjectTreeItem::setHasValidDebugId(bool value) +{ + m_hasValidDebugId = value; +} + +// ************************************************************************* +// QmlJSObjectTree +// ************************************************************************* + +QmlJSObjectTree::QmlJSObjectTree(QWidget *parent) + : QTreeWidget(parent) + , m_clickedItem(0) + , m_currentObjectDebugId(0) +{ + setAttribute(Qt::WA_MacShowFocusRect, false); + setFrameStyle(QFrame::NoFrame); + setHeaderHidden(true); + setExpandsOnDoubleClick(false); + + m_goToFileAction = new QAction(tr("Go to file"), this); + connect(m_goToFileAction, SIGNAL(triggered()), SLOT(goToFile())); + + connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), + SLOT(currentItemChanged(QTreeWidgetItem *))); + connect(this, SIGNAL(itemActivated(QTreeWidgetItem *, int)), + SLOT(activated(QTreeWidgetItem *))); + connect(this, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged())); +} + +void QmlJSObjectTree::selectionChanged() +{ + if (selectedItems().isEmpty()) + return; + + // TODO +} + +void QmlJSObjectTree::setCurrentObject(int debugId) +{ + QTreeWidgetItem *item = findItemByObjectId(debugId); + if (item) { + setCurrentItem(item); + scrollToItem(item); + item->setExpanded(true); + } +} + +void QmlJSObjectTree::currentItemChanged(QTreeWidgetItem *item) +{ + if (!item) + return; + + QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>(); + if (obj.debugId() >= 0) + emit currentObjectChanged(obj); +} + +void QmlJSObjectTree::activated(QTreeWidgetItem *item) +{ + if (!item) + return; + + QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>(); + if (obj.debugId() >= 0) + emit activated(obj); +} + +void QmlJSObjectTree::buildTree(const QDeclarativeDebugObjectReference &obj, QTreeWidgetItem *parent) +{ + if (!parent) + clear(); + + if (obj.contextDebugId() < 0) + return; + + ObjectTreeItem *item = parent ? new ObjectTreeItem(parent) : new ObjectTreeItem(this); + if (obj.idString().isEmpty()) + item->setText(0, QString("<%1>").arg(obj.className())); + else + item->setText(0, obj.idString()); + item->setData(0, Qt::UserRole, qVariantFromValue(obj)); + + if (parent && obj.contextDebugId() >= 0 + && obj.contextDebugId() != parent->data(0, Qt::UserRole + ).value<QDeclarativeDebugObjectReference>().contextDebugId()) + { + + QDeclarativeDebugFileReference source = obj.source(); + if (!source.url().isEmpty()) { + QString toolTipString = tr("Url: ") + source.url().toString(); + item->setToolTip(0, toolTipString); + } + } else { + item->setExpanded(true); + } + + if (obj.contextDebugId() < 0) + item->setHasValidDebugId(false); + + for (int ii = 0; ii < obj.children().count(); ++ii) + buildTree(obj.children().at(ii), item); +} + +QTreeWidgetItem *QmlJSObjectTree::findItemByObjectId(int debugId) const +{ + for (int i=0; i<topLevelItemCount(); ++i) { + QTreeWidgetItem *item = findItem(topLevelItem(i), debugId); + if (item) + return item; + } + + return 0; +} + +QTreeWidgetItem *QmlJSObjectTree::findItem(QTreeWidgetItem *item, int debugId) const +{ + if (item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>().debugId() == debugId) + return item; + + QTreeWidgetItem *child; + for (int i=0; i<item->childCount(); ++i) { + child = findItem(item->child(i), debugId); + if (child) + return child; + } + + return 0; +} + +void QmlJSObjectTree::goToFile() +{ + QDeclarativeDebugObjectReference obj = + currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>(); + + if (obj.debugId() >= 0) + emit activated(obj); +} + +void QmlJSObjectTree::contextMenuEvent(QContextMenuEvent *event) +{ + m_clickedItem = itemAt(QPoint(event->pos().x(), + event->pos().y() )); + if (!m_clickedItem) + return; + + QMenu menu; + menu.addAction(m_goToFileAction); + menu.exec(event->globalPos()); +} + +} // Internal +} // QmlJSInspector diff --git a/src/plugins/qmljsinspector/qmljsobjecttree.h b/src/plugins/qmljsinspector/qmljsobjecttree.h new file mode 100644 index 0000000000000000000000000000000000000000..4f56e0393d7bf452e7fe76730326af2a51702098 --- /dev/null +++ b/src/plugins/qmljsinspector/qmljsobjecttree.h @@ -0,0 +1,84 @@ +/************************************************************************** +** +** 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. +** +**************************************************************************/ +#ifndef OBJECTTREE_H +#define OBJECTTREE_H + +#include <qmljsprivateapi.h> +#include <QtGui/QTreeWidget> + +QT_BEGIN_NAMESPACE + +class QTreeWidgetItem; + +QT_END_NAMESPACE + +namespace QmlJSInspector { +namespace Internal { + +class QmlJSObjectTree : public QTreeWidget +{ + Q_OBJECT +public: + QmlJSObjectTree(QWidget *parent = 0); + +signals: + void currentObjectChanged(const QDeclarativeDebugObjectReference &); + void activated(const QDeclarativeDebugObjectReference &); + void expressionWatchRequested(const QDeclarativeDebugObjectReference &, const QString &); + void contextHelpIdChanged(const QString &contextHelpId); + +public slots: + void reload(int objectDebugId); // set the root object + void setCurrentObject(int debugId); // select an object in the tree + +protected: + virtual void contextMenuEvent(QContextMenuEvent *); + +private slots: + void addWatch(); + void currentItemChanged(QTreeWidgetItem *); + void activated(QTreeWidgetItem *); + void selectionChanged(); + void goToFile(); + +private: + QTreeWidgetItem *findItemByObjectId(int debugId) const; + QTreeWidgetItem *findItem(QTreeWidgetItem *item, int debugId) const; + void buildTree(const QDeclarativeDebugObjectReference &, QTreeWidgetItem *parent); + + QTreeWidgetItem *m_clickedItem; + QAction *m_addWatchAction; + QAction *m_goToFileAction; + int m_currentObjectDebugId; +}; + +} // Internal +} // QmlJSInspector + +#endif diff --git a/src/plugins/qmlprojectmanager/qmlprojectruncontrol.cpp b/src/plugins/qmlprojectmanager/qmlprojectruncontrol.cpp index 8d19e78b5b3dd9eec971947344404fed706bef5d..d1a607d25d0bf54818576c5caebfbf49abaafc98 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectruncontrol.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectruncontrol.cpp @@ -85,10 +85,6 @@ void QmlRunControl::start() m_applicationLauncher.start(ProjectExplorer::ApplicationLauncher::Gui, m_executable, m_commandLineArguments); - // FIXME this line should be refactored out in order to remove the dependency between - // debugger and qmlprojectmanager, because debugger also relies on cpptools. - Debugger::DebuggerUISwitcher::instance()->setActiveLanguage(QmlJSInspector::Constants::LANG_QML); - emit started(); emit appendMessage(this, tr("Starting %1 %2").arg(QDir::toNativeSeparators(m_executable), m_commandLineArguments.join(QLatin1String(" "))), false); @@ -148,7 +144,8 @@ bool QmlRunControlFactory::canRun(RunConfiguration *runConfiguration, if (mode == ProjectExplorer::Constants::RUNMODE) { return config != 0; } else if (mode == ProjectExplorer::Constants::DEBUGMODE) { - bool qmlDebugSupportInstalled = Debugger::DebuggerUISwitcher::instance()->supportedLanguages().contains(QmlProjectManager::Constants::LANG_QML); + bool qmlDebugSupportInstalled = Debugger::DebuggerUISwitcher::instance()->supportedLanguages() + & Debugger::Lang_Qml; return (config != 0) && qmlDebugSupportInstalled; } diff --git a/src/tools/qml/qmlobserver/main.cpp b/src/tools/qml/qmlobserver/main.cpp index b57e6093f7d60dbe06501ace804c6772d3996ef7..786c494d5c928903e0ec9238a23ca55f15ea5846 100644 --- a/src/tools/qml/qmlobserver/main.cpp +++ b/src/tools/qml/qmlobserver/main.cpp @@ -409,6 +409,9 @@ int main(int argc, char ** argv) viewer->enableExperimentalGestures(); viewer->setDesignModeBehavior(designModeBehavior); + + // FIXME debug mode is always on for qml observer + debuggerModeBehavior = true; viewer->setDebugMode(debuggerModeBehavior); foreach (QString lib, imports) diff --git a/src/tools/qml/qmlobserver/qmlruntime.cpp b/src/tools/qml/qmlobserver/qmlruntime.cpp index 6fef7bfd8014b96937a4f1594157237fac2cbc5b..6e53705f9d415a30a5f2015b39357652337eaa4e 100644 --- a/src/tools/qml/qmlobserver/qmlruntime.cpp +++ b/src/tools/qml/qmlobserver/qmlruntime.cpp @@ -64,7 +64,6 @@ #include "qdeclarative.h" #include <QAbstractAnimation> #include <private/qabstractanimation_p.h> -#include <private/qdeclarativeengine_p.h> #include <QSettings> #include <QXmlStreamReader> @@ -672,14 +671,9 @@ void QDeclarativeViewer::setDesignModeBehavior(bool value) void QDeclarativeViewer::setDebugMode(bool on) { - Q_UNUSED(on); - //if (on) - { - new JSDebuggerAgent(QDeclarativeEnginePrivate::getScriptEngine(canvas->engine())); - } + canvas->setDebugMode(on); } - void QDeclarativeViewer::enableExperimentalGestures() { canvas->viewport()->grabGesture(Qt::TapGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent);