Skip to content
Snippets Groups Projects
Commit de59fe3f authored by hjk's avatar hjk
Browse files

debugger: work on the qmlengine

parent d0c2e11a
No related branches found
No related tags found
No related merge requests found
......@@ -161,10 +161,27 @@ QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters)
{
m_conn = 0;
m_client = 0;
m_engineQuery = 0;
m_contextQuery = 0;
m_engineDebugInterface = 0;
m_frameRate = 0;
/*
m_watchTableModel = new Internal::WatchTableModel(0, this);
m_objectTreeWidget = new Internal::ObjectTree;
m_propertiesWidget = new Internal::ObjectPropertiesView(m_watchTableModel);
m_watchTableView = new Internal::WatchTableView(m_watchTableModel);
m_expressionWidget = new Internal::ExpressionQueryWidget(Internal::ExpressionQueryWidget::SeparateEntryMode);
// m_frameRateWidget = new Internal::CanvasFrameRate;
// m_frameRateWidget->setObjectName(QLatin1String("QmlDebugFrameRate"));
connect(Debugger::DebuggerPlugin::instance(),
SIGNAL(stateChanged(int)), this, SLOT(debuggerStateChanged(int)));
m_editablePropertyTypes = QStringList() << "qreal" << "bool" << "QString"
<< "int" << "QVariant" << "QUrl" << "QColor";
connect(m_connectionTimer, SIGNAL(timeout()), SLOT(pollInspector()));
*/
}
QmlEngine::~QmlEngine()
......@@ -189,6 +206,10 @@ void QmlEngine::executeDebuggerCommand(const QString &command)
void QmlEngine::shutdown()
{
exitDebugger();
//m_objectTreeWidget->saveSettings(m_settings);
//m_propertiesWidget->saveSettings(m_settings);
//m_settings.saveSettings(Core::ICore::instance()->settings());
}
void QmlEngine::exitDebugger()
......@@ -254,14 +275,16 @@ void QmlEngine::setupConnection()
m_client = new QmlDebuggerClient(m_conn, this);
(void) new QmlFrameRateClient(m_conn, this);
//m_objectTreeWidget->setEngineDebug(m_client);
//m_propertiesWidget->setEngineDebug(m_client);
//m_watchTableModel->setEngineDebug(m_client);
//m_expressionWidget->setEngineDebug(m_client);
// resetViews();
// m_frameRateWidget->reset(m_conn);
// reloadEngines();
QTC_ASSERT(m_engineDebugInterface == 0, /**/);
m_engineDebugInterface = new QDeclarativeEngineDebug(m_conn, this);
//m_objectTreeWidget->setEngineDebug(m_engineDebugInterface);
//m_propertiesWidget->setEngineDebug(m_engineDebugInterface);
//m_watchTableModel->setEngineDebug(m_engineDebugInterface);
//m_expressionWidget->setEngineDebug(m_engineDebugInterface);
//resetViews();
//m_frameRateWidget->reset(m_conn);
QHostAddress ha(QHostAddress::LocalHost);
......@@ -278,6 +301,8 @@ void QmlEngine::setupConnection()
qDebug() << "CONNECTION SUCCESSFUL";
setState(InferiorRunning);
startSuccessful();
reloadEngines();
}
void QmlEngine::continueInferior()
......@@ -462,10 +487,12 @@ void QmlEngine::assignValueInDebugger(const QString &expression,
void QmlEngine::updateLocals()
{
qDebug() << "UPDATE LOCALS";
}
void QmlEngine::updateWatchData(const WatchData &data)
{
qDebug() << "UPDATE WATCH DATA" << data.toString();
//watchHandler()->rebuildModel();
showStatusMessage(tr("Stopped."), 5000);
......@@ -624,6 +651,14 @@ void QmlEngine::messageReceived(const QByteArray &message)
watchHandler()->endCycle();
foreach (QDeclarativeDebugWatch *watch, m_watches) {
qDebug() << "WATCH"
<< watch->objectName()
<< watch->queryId()
<< watch->state()
<< watch->objectDebugId();
}
} else if (command == "RESULT") {
WatchData data;
QVariant variant;
......@@ -710,12 +745,6 @@ void QmlEngine::connectionStateChanged()
case QAbstractSocket::UnconnectedState:
{
showStatusMessage(tr("[QmlEngine] disconnected.\n\n"));
delete m_engineQuery;
m_engineQuery = 0;
delete m_contextQuery;
m_contextQuery = 0;
// resetViews();
// updateMenuActions();
......@@ -762,6 +791,950 @@ void QmlEngine::connectionConnected()
}
#if 0
class EngineComboBox : public QComboBox
{
Q_OBJECT
public:
struct EngineInfo
{
QString name;
int id;
};
EngineComboBox(QWidget *parent = 0);
void addEngine(int engine, const QString &name);
void clearEngines();
protected:
private:
QList<EngineInfo> m_engines;
};
EngineComboBox::EngineComboBox(QWidget *parent)
: QComboBox(parent)
{
setEnabled(false);
setEditable(false);
}
void EngineComboBox::addEngine(int engine, const QString &name)
{
EngineInfo info;
info.id = engine;
if (name.isEmpty())
info.name = tr("Engine %1", "engine number").arg(engine);
else
info.name = name;
m_engines << info;
addItem(info.name);
}
void EngineComboBox::clearEngines()
{
m_engines.clear();
clear();
}
} // Internal
bool QmlEngine::setDebugConfigurationDataFromProject(ProjectExplorer::Project *projectToDebug)
{
if (!projectToDebug) {
emit statusMessage(tr("Invalid project, debugging canceled."));
return false;
}
QmlProjectManager::QmlProjectRunConfiguration* config =
qobject_cast<QmlProjectManager::QmlProjectRunConfiguration*>(projectToDebug->activeTarget()->activeRunConfiguration());
if (!config) {
emit statusMessage(tr("Cannot find project run configuration, debugging canceled."));
return false;
}
m_runConfigurationDebugData.serverAddress = config->debugServerAddress();
m_runConfigurationDebugData.serverPort = config->debugServerPort();
m_connectionTimer->setInterval(ConnectionAttemptDefaultInterval);
return true;
}
void QmlEngine::startQmlProjectDebugger()
{
m_simultaneousCppAndQmlDebugMode = false;
m_connectionTimer->start();
}
bool QmlEngine::connectToViewer()
{
if (m_conn && m_conn->state() != QAbstractSocket::UnconnectedState)
return false;
delete m_engineDebugInterface; m_engineDebugInterface = 0;
if (m_conn) {
m_conn->disconnectFromHost();
delete m_conn;
m_conn = 0;
}
QString host = m_runConfigurationDebugData.serverAddress;
quint16 port = quint16(m_runConfigurationDebugData.serverPort);
m_conn = new QDeclarativeDebugConnection(this);
connect(m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
SLOT(connectionStateChanged()));
connect(m_conn, SIGNAL(error(QAbstractSocket::SocketError)),
SLOT(connectionError()));
emit statusMessage(tr("[Inspector] set to connect to debug server %1:%2").arg(host).arg(port));
m_conn->connectToHost(host, port);
// blocks until connected; if no connection is available, will fail immediately
if (!m_conn->waitForConnected())
return false;
QTC_ASSERT(m_debuggerRunControl, return false);
QmlEngine *engine = qobject_cast<QmlEngine *>(m_debuggerRunControl->engine());
QTC_ASSERT(engine, return false);
(void) new DebuggerClient(m_conn, engine);
return true;
}
void QmlEngine::disconnectFromViewer()
{
m_conn->disconnectFromHost();
updateMenuActions();
}
void QmlEngine::connectionStateChanged()
{
switch (m_conn->state()) {
case QAbstractSocket::UnconnectedState:
{
emit statusMessage(tr("[Inspector] disconnected.\n\n"));
resetViews();
updateMenuActions();
break;
}
case QAbstractSocket::HostLookupState:
emit statusMessage(tr("[Inspector] resolving host..."));
break;
case QAbstractSocket::ConnectingState:
emit statusMessage(tr("[Inspector] connecting to debug server..."));
break;
case QAbstractSocket::ConnectedState:
{
emit statusMessage(tr("[Inspector] connected.\n"));
resetViews();
// m_frameRateWidget->reset(m_conn);
break;
}
case QAbstractSocket::ClosingState:
emit statusMessage(tr("[Inspector] closing..."));
break;
case QAbstractSocket::BoundState:
case QAbstractSocket::ListeningState:
break;
}
}
void QmlEngine::resetViews()
{
m_objectTreeWidget->cleanup();
m_propertiesWidget->clear();
m_expressionWidget->clear();
m_watchTableModel->removeAllWatches();
}
void QmlEngine::createDockWidgets()
{
m_engineComboBox = new Internal::EngineComboBox;
m_engineComboBox->setEnabled(false);
connect(m_engineComboBox, SIGNAL(currentIndexChanged(int)),
SLOT(queryEngineContext(int)));
// FancyMainWindow uses widgets' window titles for tab labels
// m_frameRateWidget->setWindowTitle(tr("Frame rate"));
Utils::StyledBar *treeOptionBar = new Utils::StyledBar;
QHBoxLayout *treeOptionBarLayout = new QHBoxLayout(treeOptionBar);
treeOptionBarLayout->setContentsMargins(5, 0, 5, 0);
treeOptionBarLayout->setSpacing(5);
treeOptionBarLayout->addWidget(new QLabel(tr("QML engine:")));
treeOptionBarLayout->addWidget(m_engineComboBox);
QWidget *treeWindow = new QWidget;
treeWindow->setObjectName(QLatin1String("QmlDebugTree"));
treeWindow->setWindowTitle(tr("Object Tree"));
QVBoxLayout *treeWindowLayout = new QVBoxLayout(treeWindow);
treeWindowLayout->setMargin(0);
treeWindowLayout->setSpacing(0);
treeWindowLayout->setContentsMargins(0,0,0,0);
treeWindowLayout->addWidget(treeOptionBar);
treeWindowLayout->addWidget(m_objectTreeWidget);
m_watchTableView->setModel(m_watchTableModel);
Internal::WatchTableHeaderView *header = new Internal::WatchTableHeaderView(m_watchTableModel);
m_watchTableView->setHorizontalHeader(header);
connect(m_objectTreeWidget, SIGNAL(activated(QDeclarativeDebugObjectReference)),
this, SLOT(treeObjectActivated(QDeclarativeDebugObjectReference)));
connect(m_objectTreeWidget, SIGNAL(currentObjectChanged(QDeclarativeDebugObjectReference)),
m_propertiesWidget, SLOT(reload(QDeclarativeDebugObjectReference)));
connect(m_objectTreeWidget, SIGNAL(expressionWatchRequested(QDeclarativeDebugObjectReference,QString)),
m_watchTableModel, SLOT(expressionWatchRequested(QDeclarativeDebugObjectReference,QString)));
connect(m_propertiesWidget, SIGNAL(watchToggleRequested(QDeclarativeDebugObjectReference,QDeclarativeDebugPropertyReference)),
m_watchTableModel, SLOT(togglePropertyWatch(QDeclarativeDebugObjectReference,QDeclarativeDebugPropertyReference)));
connect(m_watchTableModel, SIGNAL(watchCreated(QDeclarativeDebugWatch*)),
m_propertiesWidget, SLOT(watchCreated(QDeclarativeDebugWatch*)));
connect(m_watchTableModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
m_watchTableView, SLOT(scrollToBottom()));
connect(m_watchTableView, SIGNAL(objectActivated(int)),
m_objectTreeWidget, SLOT(setCurrentObject(int)));
connect(m_objectTreeWidget, SIGNAL(currentObjectChanged(QDeclarativeDebugObjectReference)),
m_expressionWidget, SLOT(setCurrentObject(QDeclarativeDebugObjectReference)));
Core::MiniSplitter *propSplitter = new Core::MiniSplitter(Qt::Horizontal);
Core::MiniSplitter *propWatcherSplitter = new Core::MiniSplitter(Qt::Vertical);
propWatcherSplitter->addWidget(m_propertiesWidget);
propWatcherSplitter->addWidget(m_watchTableView);
propWatcherSplitter->setStretchFactor(0, 2);
propWatcherSplitter->setStretchFactor(1, 1);
propWatcherSplitter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
propSplitter->setWindowTitle(tr("Properties and Watchers"));
propSplitter->setObjectName(QLatin1String("QmlDebugProperties"));
propSplitter->addWidget(m_objectTreeWidget);
propSplitter->addWidget(propWatcherSplitter);
propSplitter->setStretchFactor(0, 1);
propSplitter->setStretchFactor(1, 3);
InspectorOutputWidget *inspectorOutput = new InspectorOutputWidget();
inspectorOutput->setObjectName(QLatin1String("QmlDebugInspectorOutput"));
connect(this, SIGNAL(statusMessage(QString)),
inspectorOutput, SLOT(addInspectorStatus(QString)));
Debugger::DebuggerUISwitcher *uiSwitcher = Debugger::DebuggerUISwitcher::instance();
m_watchTableView->hide();
// m_objectTreeDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML,
// treeWindow, Qt::BottomDockWidgetArea);
// m_frameRateDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML,
// m_frameRateWidget, Qt::BottomDockWidgetArea);
m_propertyWatcherDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML,
propSplitter, Qt::BottomDockWidgetArea);
m_inspectorOutputDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML,
inspectorOutput, Qt::BottomDockWidgetArea);
m_expressionWidget->setWindowTitle(tr("Script Console"));
m_expressionQueryDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML,
m_expressionWidget, Qt::BottomDockWidgetArea);
m_inspectorOutputDock->setToolTip(tr("Output of the QML inspector, such as information on connecting to the server."));
m_dockWidgets << /*m_objectTreeDock << *//*m_frameRateDock << */ m_propertyWatcherDock
<< m_inspectorOutputDock << m_expressionQueryDock;
m_context = new Internal::InspectorContext(m_objectTreeWidget);
m_propWatcherContext = new Internal::InspectorContext(m_propertyWatcherDock);
Core::ICore *core = Core::ICore::instance();
core->addContextObject(m_propWatcherContext);
core->addContextObject(m_context);
m_simultaneousDebugAction = new QAction(this);
m_simultaneousDebugAction->setText(tr("Start Debugging C++ and QML Simultaneously..."));
connect(m_simultaneousDebugAction, SIGNAL(triggered()),
this, SLOT(simultaneouslyDebugQmlCppApplication()));
Core::ActionManager *am = core->actionManager();
Core::ActionContainer *mstart = am->actionContainer(ProjectExplorer::Constants::M_DEBUG_STARTDEBUGGING);
Core::Command *cmd = am->registerAction(m_simultaneousDebugAction, Constants::M_DEBUG_SIMULTANEOUSLY,
m_context->context());
cmd->setAttribute(Core::Command::CA_Hide);
mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
m_settings.readSettings(core->settings());
m_objectTreeWidget->readSettings(m_settings);
m_propertiesWidget->readSettings(m_settings);
connect(m_objectTreeWidget, SIGNAL(contextHelpIdChanged(QString)), m_context,
SLOT(setContextHelpId(QString)));
connect(m_watchTableView, SIGNAL(contextHelpIdChanged(QString)), m_propWatcherContext,
SLOT(setContextHelpId(QString)));
connect(m_propertiesWidget, SIGNAL(contextHelpIdChanged(QString)), m_propWatcherContext,
SLOT(setContextHelpId(QString)));
connect(m_expressionWidget, SIGNAL(contextHelpIdChanged(QString)), m_propWatcherContext,
SLOT(setContextHelpId(QString)));
}
void QmlEngine::simultaneouslyDebugQmlCppApplication()
{
QString errorMessage;
ProjectExplorer::ProjectExplorerPlugin *pex = ProjectExplorer::ProjectExplorerPlugin::instance();
ProjectExplorer::Project *project = pex->startupProject();
if (!project)
errorMessage = QString(tr("No project was found."));
else {
if (project->id() == "QmlProjectManager.QmlProject")
errorMessage = attachToQmlViewerAsExternalApp(project);
else {
errorMessage = attachToExternalCppAppWithQml(project);
}
}
if (!errorMessage.isEmpty())
QMessageBox::warning(Core::ICore::instance()->mainWindow(), "Failed to debug C++ and QML", errorMessage);
}
QString QmlEngine::attachToQmlViewerAsExternalApp(ProjectExplorer::Project *project)
{
m_debugMode = QmlProjectWithCppPlugins;
QmlProjectManager::QmlProjectRunConfiguration* runConfig =
qobject_cast<QmlProjectManager::QmlProjectRunConfiguration*>(project->activeTarget()->activeRunConfiguration());
if (!runConfig)
return QString(tr("No run configurations were found for the project '%1'.").arg(project->displayName()));
Internal::StartExternalQmlDialog dlg(Debugger::DebuggerUISwitcher::instance()->mainWindow());
QString importPathArgument = "-I";
QString execArgs;
if (runConfig->viewerArguments().contains(importPathArgument))
execArgs = runConfig->viewerArguments().join(" ");
else {
QFileInfo qmlFileInfo(runConfig->viewerArguments().last());
importPathArgument.append(" " + qmlFileInfo.absolutePath() + " ");
execArgs = importPathArgument + runConfig->viewerArguments().join(" ");
}
dlg.setPort(runConfig->debugServerPort());
dlg.setDebuggerUrl(runConfig->debugServerAddress());
dlg.setProjectDisplayName(project->displayName());
dlg.setDebugMode(Internal::StartExternalQmlDialog::QmlProjectWithCppPlugins);
dlg.setQmlViewerArguments(execArgs);
dlg.setQmlViewerPath(runConfig->viewerPath());
if (dlg.exec() != QDialog::Accepted)
return QString();
m_runConfigurationDebugData.serverAddress = dlg.debuggerUrl();
m_runConfigurationDebugData.serverPort = dlg.port();
m_settings.setExternalPort(dlg.port());
m_settings.setExternalUrl(dlg.debuggerUrl());
ProjectExplorer::Environment customEnv = ProjectExplorer::Environment::systemEnvironment(); // empty env by default
customEnv.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(m_settings.externalPort()));
Debugger::DebuggerRunControl *debuggableRunControl =
createDebuggerRunControl(runConfig, dlg.qmlViewerPath(), dlg.qmlViewerArguments());
return executeDebuggerRunControl(debuggableRunControl, &customEnv);
}
QString QmlEngine::attachToExternalCppAppWithQml(ProjectExplorer::Project *project)
{
m_debugMode = CppProjectWithQmlEngines;
ProjectExplorer::LocalApplicationRunConfiguration* runConfig =
qobject_cast<ProjectExplorer::LocalApplicationRunConfiguration*>(project->activeTarget()->activeRunConfiguration());
if (!project->activeTarget() || !project->activeTarget()->activeRunConfiguration())
return QString(tr("No run configurations were found for the project '%1'.").arg(project->displayName()));
else if (!runConfig)
return QString(tr("No valid run configuration was found for the project %1. "
"Only locally runnable configurations are supported.\n"
"Please check your project settings.").arg(project->displayName()));
Internal::StartExternalQmlDialog dlg(Debugger::DebuggerUISwitcher::instance()->mainWindow());
dlg.setPort(m_settings.externalPort());
dlg.setDebuggerUrl(m_settings.externalUrl());
dlg.setProjectDisplayName(project->displayName());
dlg.setDebugMode(Internal::StartExternalQmlDialog::CppProjectWithQmlEngine);
if (dlg.exec() != QDialog::Accepted)
return QString();
m_runConfigurationDebugData.serverAddress = dlg.debuggerUrl();
m_runConfigurationDebugData.serverPort = dlg.port();
m_settings.setExternalPort(dlg.port());
m_settings.setExternalUrl(dlg.debuggerUrl());
ProjectExplorer::Environment customEnv = runConfig->environment();
customEnv.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(m_settings.externalPort()));
Debugger::DebuggerRunControl *debuggableRunControl = createDebuggerRunControl(runConfig);
return executeDebuggerRunControl(debuggableRunControl, &customEnv);
}
QString QmlEngine::executeDebuggerRunControl(Debugger::DebuggerRunControl *debuggableRunControl, ProjectExplorer::Environment *environment)
{
ProjectExplorer::ProjectExplorerPlugin *pex = ProjectExplorer::ProjectExplorerPlugin::instance();
// to make sure we have a valid, debuggable run control, find the correct factory for it
if (debuggableRunControl) {
// modify the env
debuggableRunControl->setCustomEnvironment(*environment);
pex->startRunControl(debuggableRunControl, ProjectExplorer::Constants::DEBUGMODE);
m_simultaneousCppAndQmlDebugMode = true;
return QString();
}
return QString(tr("A valid run control was not registered in Qt Creator for this project run configuration."));;
}
Debugger::DebuggerRunControl *QmlEngine::createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig,
const QString &executableFile, const QString &executableArguments)
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
const QList<Debugger::DebuggerRunControlFactory *> factories = pm->getObjects<Debugger::DebuggerRunControlFactory>();
ProjectExplorer::RunControl *runControl = 0;
if (m_debugMode == QmlProjectWithCppPlugins) {
Debugger::DebuggerStartParameters sp;
sp.startMode = Debugger::StartExternal;
sp.executable = executableFile;
sp.processArgs = executableArguments.split(QLatin1Char(' '));
runControl = factories.first()->create(sp);
return qobject_cast<Debugger::DebuggerRunControl *>(runControl);
}
if (m_debugMode == CppProjectWithQmlEngines) {
if (factories.length() && factories.first()->canRun(runConfig, ProjectExplorer::Constants::DEBUGMODE)) {
runControl = factories.first()->create(runConfig, ProjectExplorer::Constants::DEBUGMODE);
return qobject_cast<Debugger::DebuggerRunControl *>(runControl);
}
}
return 0;
}
void QmlEngine::updateMenuActions()
{
bool enabled = true;
if (m_simultaneousCppAndQmlDebugMode)
enabled = (m_cppDebuggerState == Debugger::DebuggerNotReady && (!m_conn || m_conn->state() == QAbstractSocket::UnconnectedState));
else
enabled = (!m_conn || m_conn->state() == QAbstractSocket::UnconnectedState);
m_simultaneousDebugAction->setEnabled(enabled);
}
void QmlEngine::debuggerStateChanged(int newState)
{
if (m_simultaneousCppAndQmlDebugMode) {
switch(newState) {
case Debugger::EngineStarting:
{
m_connectionInitialized = false;
break;
}
case Debugger::AdapterStartFailed:
case Debugger::InferiorStartFailed:
emit statusMessage(QString(tr("Debugging failed: could not start C++ debugger.")));
break;
case Debugger::InferiorRunningRequested:
{
if (m_cppDebuggerState == Debugger::InferiorStopped) {
// re-enable UI again
m_objectTreeWidget->setEnabled(true);
m_propertiesWidget->setEnabled(true);
m_expressionWidget->setEnabled(true);
}
break;
}
case Debugger::InferiorRunning:
{
if (!m_connectionInitialized) {
m_connectionInitialized = true;
m_connectionTimer->setInterval(ConnectionAttemptSimultaneousInterval);
m_connectionTimer->start();
}
break;
}
case Debugger::InferiorStopped:
{
m_objectTreeWidget->setEnabled(false);
m_propertiesWidget->setEnabled(false);
m_expressionWidget->setEnabled(false);
break;
}
case Debugger::EngineShuttingDown:
{
m_connectionInitialized = false;
// here it's safe to enable the debugger windows again -
// disabled ones look ugly.
m_objectTreeWidget->setEnabled(true);
m_propertiesWidget->setEnabled(true);
m_expressionWidget->setEnabled(true);
m_simultaneousCppAndQmlDebugMode = false;
break;
}
default:
break;
}
}
m_cppDebuggerState = newState;
updateMenuActions();
}
void QmlEngine::setSimpleDockWidgetArrangement()
{
Utils::FancyMainWindow *mainWindow = Debugger::DebuggerUISwitcher::instance()->mainWindow();
mainWindow->setTrackingEnabled(false);
QList<QDockWidget *> dockWidgets = mainWindow->dockWidgets();
foreach (QDockWidget *dockWidget, dockWidgets) {
if (m_dockWidgets.contains(dockWidget)) {
dockWidget->setFloating(false);
mainWindow->removeDockWidget(dockWidget);
}
}
foreach (QDockWidget *dockWidget, dockWidgets) {
if (m_dockWidgets.contains(dockWidget)) {
mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
dockWidget->show();
}
}
mainWindow->splitDockWidget(mainWindow->toolBarDockWidget(), m_propertyWatcherDock, Qt::Vertical);
//mainWindow->tabifyDockWidget(m_frameRateDock, m_propertyWatcherDock);
mainWindow->tabifyDockWidget(m_propertyWatcherDock, m_expressionQueryDock);
mainWindow->tabifyDockWidget(m_propertyWatcherDock, m_inspectorOutputDock);
m_propertyWatcherDock->raise();
m_inspectorOutputDock->setVisible(false);
mainWindow->setTrackingEnabled(true);
}
#endif
void QmlEngine::reloadEngines()
{
//m_engineComboBox->setEnabled(false);
QDeclarativeDebugEnginesQuery *query =
m_engineDebugInterface->queryAvailableEngines(this);
if (!query->isWaiting())
enginesChanged(query);
else
QObject::connect(query, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
this, SLOT(enginesChanged()));
}
void QmlEngine::enginesChanged()
{
enginesChanged(qobject_cast<QDeclarativeDebugEnginesQuery *>(sender()));
}
void QmlEngine::enginesChanged(QDeclarativeDebugEnginesQuery *query)
{
//m_engineComboBox->clearEngines();
QList<QDeclarativeDebugEngineReference> engines = query->engines();
if (engines.isEmpty())
qWarning("qmldebugger: no engines found!");
//m_engineComboBox->setEnabled(true);
for (int i = 0; i < engines.count(); ++i)
qDebug() << "ENGINE: " << engines.at(i).debugId() << engines.at(i).name();
// m_engineComboBox->addEngine(engines.at(i).debugId(), engines.at(i).name());
if (engines.count() > 0) {
// m_engineComboBox->setCurrentIndex(engines.at(0).debugId());
queryEngineContext(engines.at(0));
}
}
void QmlEngine::queryEngineContext(const QDeclarativeDebugEngineReference &engine)
{
QDeclarativeDebugRootContextQuery *query =
m_engineDebugInterface->queryRootContexts(engine, this);
if (!query->isWaiting())
contextChanged();
else
QObject::connect(query, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
this, SLOT(contextChanged()));
}
void QmlEngine::contextChanged()
{
contextChanged(qobject_cast<QDeclarativeDebugRootContextQuery *>(sender()));
}
void QmlEngine::contextChanged(QDeclarativeDebugRootContextQuery *query)
{
QTC_ASSERT(query, return);
//dump(query->rootContext(), 0);
foreach (const QDeclarativeDebugObjectReference &object, query->rootContext().objects())
reloadObject(object);
}
void QmlEngine::reloadObject(const QDeclarativeDebugObjectReference &object)
{
qDebug() << "RELOAD OBJECT: " << object.debugId() << object.idString()
<< object.className();
QDeclarativeDebugObjectQuery *query =
m_engineDebugInterface->queryObjectRecursive(object, this);
if (!query->isWaiting())
objectFetched(query, QDeclarativeDebugQuery::Completed);
else
QObject::connect(query, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
this, SLOT(objectFetched(QDeclarativeDebugQuery::State)));
}
void QmlEngine::objectFetched(QDeclarativeDebugQuery::State state)
{
objectFetched(qobject_cast<QDeclarativeDebugObjectQuery *>(sender()), state);
}
void QmlEngine::objectFetched(QDeclarativeDebugObjectQuery *query,
QDeclarativeDebugQuery::State state)
{
QTC_ASSERT(query, return);
QTC_ASSERT(state == QDeclarativeDebugQuery::Completed, return);
//dump(m_query->object(), 0);
m_watches.clear();
buildTree(query->object(), "local");
qDebug() << "WATCHES CREATED: " << m_watches.size();
//watchHandler()->beginCycle();
//watchHandler()->insertBulkData(list);
//watchHandler()->endCycle();
//setCurrentItem(topLevelItem(0));
// this ugly hack is needed if user wants to see internal structs
// on startup - debugger does not load them until towards the end,
// so essentially loading twice gives us the full list as everything
// is already loaded.
//if (m_showUninspectableItems && !m_showUninspectableOnInitDone) {
// m_showUninspectableOnInitDone = true;
// reloadObject(m_currentObjectDebugId);
//}
}
void QmlEngine::buildTree(const QDeclarativeDebugObjectReference &obj,
const QByteArray &iname)
{
//QTC_ASSERT(obj.contextDebugId() >= 0, return);
WatchData data;
data.iname = iname;
if (obj.idString().isEmpty())
data.name = QString("<%1>").arg(obj.className());
else
data.name = obj.idString();
data.value = "?";
data.type = "?";
data.setHasChildren(!obj.children().isEmpty());
data.setAllUnneeded();
qDebug() << "CREATED ITEM " << data.iname << data.name;
m_watches.append(m_engineDebugInterface->addWatch(obj, data.name, 0));
//QDeclarativeDebugPropertyWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugPropertyReference &property, QObject *parent)
//data.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 = QLatin1String("URL: ") + source.url().toString();
item->setToolTip(0, toolTipString);
}
} else {
item->setExpanded(true);
}
if (obj.contextDebugId() < 0)
item->setHasValidDebugId(false);
*/
for (int i = 0; i < obj.children().size(); ++i)
buildTree(obj.children().at(i), iname + '.' + QByteArray::number(i));
}
#if 0
void QmlEngine::treeObjectActivated(const QDeclarativeDebugObjectReference &obj)
{
QDeclarativeDebugFileReference source = obj.source();
QString fileName = source.url().toLocalFile();
if (source.lineNumber() < 0 || !QFile::exists(fileName))
return;
Core::EditorManager *editorManager = Core::EditorManager::instance();
Core::IEditor *editor = editorManager->openEditor(fileName, QString(), Core::EditorManager::NoModeSwitch);
TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor);
if (textEditor) {
editorManager->addCurrentPositionToNavigationHistory();
textEditor->gotoLine(source.lineNumber());
textEditor->widget()->setFocus();
}
}
bool QmlEngine::canEditProperty(const QString &propertyType)
{
return m_editablePropertyTypes.contains(propertyType);
}
QDeclarativeDebugExpressionQuery *QmlEngine::executeExpression(int objectDebugId, const QString &objectId,
const QString &propertyName, const QVariant &value)
{
//qDebug() << entity.property << entity.title << entity.objectId;
if (objectId.length()) {
QString quoteWrappedValue = value.toString();
if (addQuotesForData(value))
quoteWrappedValue = QString("'%1'").arg(quoteWrappedValue);
QString constructedExpression = objectId + "." + propertyName + "=" + quoteWrappedValue;
//qDebug() << "EXPRESSION:" << constructedExpression;
return m_client->queryExpressionResult(objectDebugId, constructedExpression, this);
}
return 0;
}
bool QmlEngine::addQuotesForData(const QVariant &value) const
{
switch (value.type()) {
case QVariant::String:
case QVariant::Color:
case QVariant::Date:
return true;
default:
break;
}
return false;
}
ObjectTree::ObjectTree(QDeclarativeEngineDebug *client, QWidget *parent)
: QTreeWidget(parent),
m_client(client),
m_query(0), m_clickedItem(0), m_showUninspectableItems(false),
m_currentObjectDebugId(0), m_showUninspectableOnInitDone(false)
{
setAttribute(Qt::WA_MacShowFocusRect, false);
setFrameStyle(QFrame::NoFrame);
setHeaderHidden(true);
setExpandsOnDoubleClick(false);
m_addWatchAction = new QAction(tr("Add watch expression..."), this);
m_toggleUninspectableItemsAction = new QAction(tr("Show uninspectable items"), this);
m_toggleUninspectableItemsAction->setCheckable(true);
m_goToFileAction = new QAction(tr("Go to file"), this);
connect(m_toggleUninspectableItemsAction, SIGNAL(triggered()), SLOT(toggleUninspectableItems()));
connect(m_addWatchAction, SIGNAL(triggered()), SLOT(addWatch()));
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 ObjectTree::readSettings(const InspectorSettings &settings)
{
if (settings.showUninspectableItems() != m_showUninspectableItems)
toggleUninspectableItems();
}
void ObjectTree::saveSettings(InspectorSettings &settings)
{
settings.setShowUninspectableItems(m_showUninspectableItems);
}
void ObjectTree::setEngineDebug(QDeclarativeEngineDebug *client)
{
m_client = client;
}
void ObjectTree::toggleUninspectableItems()
{
m_showUninspectableItems = !m_showUninspectableItems;
m_toggleUninspectableItemsAction->setChecked(m_showUninspectableItems);
reload(m_currentObjectDebugId);
}
void ObjectTree::selectionChanged()
{
if (selectedItems().isEmpty())
return;
QTreeWidgetItem *item = selectedItems().first();
if (item)
emit contextHelpIdChanged(InspectorContext::contextHelpIdForItem(item->text(0)));
}
void ObjectTree::setCurrentObject(int debugId)
{
QTreeWidgetItem *item = findItemByObjectId(debugId);
if (item) {
setCurrentItem(item);
scrollToItem(item);
item->setExpanded(true);
}
}
{
if (!item)
return;
QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
if (obj.debugId() >= 0)
emit currentObjectChanged(obj);
}
void ObjectTree::activated(QTreeWidgetItem *item)
{
if (!item)
return;
QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
if (obj.debugId() >= 0)
emit activated(obj);
}
void ObjectTree::cleanup()
{
m_showUninspectableOnInitDone = false;
clear();
}
void ObjectTree::dump(const QDeclarativeDebugContextReference &ctxt, int ind)
{
QByteArray indent(ind * 4, ' ');
qWarning().nospace() << indent.constData() << ctxt.debugId() << " "
<< qPrintable(ctxt.name());
for (int ii = 0; ii < ctxt.contexts().count(); ++ii)
dump(ctxt.contexts().at(ii), ind + 1);
for (int ii = 0; ii < ctxt.objects().count(); ++ii)
dump(ctxt.objects().at(ii), ind);
}
void ObjectTree::dump(const QDeclarativeDebugObjectReference &obj, int ind)
{
QByteArray indent(ind * 4, ' ');
qWarning().nospace() << indent.constData() << qPrintable(obj.className())
<< " " << qPrintable(obj.idString()) << " "
<< obj.debugId();
for (int ii = 0; ii < obj.children().count(); ++ii)
dump(obj.children().at(ii), ind + 1);
}
QTreeWidgetItem *ObjectTree::findItemByObjectId(int debugId) const
{
for (int i=0; i<topLevelItemCount(); ++i) {
QTreeWidgetItem *item = findItem(topLevelItem(i), debugId);
if (item)
return item;
}
return 0;
}
QTreeWidgetItem *ObjectTree::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 ObjectTree::addWatch()
{
QDeclarativeDebugObjectReference obj =
currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
bool ok = false;
QString watch = QInputDialog::getText(this, tr("Watch expression"),
tr("Expression:"), QLineEdit::Normal, QString(), &ok);
if (ok && !watch.isEmpty())
emit expressionWatchRequested(obj, watch);
}
void ObjectTree::goToFile()
{
QDeclarativeDebugObjectReference obj =
currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
if (obj.debugId() >= 0)
emit activated(obj);
}
void ObjectTree::contextMenuEvent(QContextMenuEvent *event)
{
m_clickedItem = itemAt(QPoint(event->pos().x(),
event->pos().y() ));
if (!m_clickedItem)
return;
QMenu menu;
menu.addAction(m_addWatchAction);
menu.addAction(m_goToFileAction);
if (m_currentObjectDebugId) {
menu.addSeparator();
menu.addAction(m_toggleUninspectableItemsAction);
}
menu.exec(event->globalPos());
}
} // Internal
} // Qml
#endif
} // namespace Internal
} // namespace Debugger
......
......@@ -32,6 +32,10 @@
#include "debuggerengine.h"
#include "private/qdeclarativedebug_p.h"
#include "private/qdeclarativedebugclient_p.h"
#include "private/qdeclarativeenginedebug_p.h"
#include <QtCore/QByteArray>
#include <QtCore/QHash>
#include <QtCore/QObject>
......@@ -44,6 +48,7 @@
#include <QtNetwork/QAbstractSocket>
#include <QtNetwork/QTcpSocket>
QT_BEGIN_NAMESPACE
class QTcpSocket;
class QDeclarativeDebugConnection;
......@@ -74,6 +79,7 @@ public:
private:
// DebuggerEngine implementation
bool isSynchroneous() const { return true; }
void executeStep();
void executeStepOut();
void executeNext();
......@@ -130,15 +136,93 @@ private slots:
void connectionConnected();
void connectionStateChanged();
void reloadEngines();
void enginesChanged();
void queryEngineContext(const QDeclarativeDebugEngineReference& engine);
void contextChanged();
void reloadObject(const QDeclarativeDebugObjectReference &object);
void objectFetched(QDeclarativeDebugQuery::State state);
private:
void objectFetched(QDeclarativeDebugObjectQuery *query, QDeclarativeDebugQuery::State state);
void contextChanged(QDeclarativeDebugRootContextQuery *query);
void enginesChanged(QDeclarativeDebugEnginesQuery *query);
void buildTree(const QDeclarativeDebugObjectReference &obj, const QByteArray &iname);
QString errorMessage(QProcess::ProcessError error);
QProcess m_proc;
QDeclarativeDebugConnection *m_conn;
QDeclarativeEngineDebug *m_engineDebugInterface;
QmlDebuggerClient *m_client;
CanvasFrameRate *m_frameRate;
enum DebugMode {
StandaloneMode,
CppProjectWithQmlEngines,
QmlProjectWithCppPlugins
};
QList<QDeclarativeDebugWatch *> m_watches;
#if 0
void createDockWidgets();
bool connectToViewer(); // using host, port from widgets
// returns false if project is not debuggable.
bool setDebugConfigurationDataFromProject(ProjectExplorer::Project *projectToDebug);
void startQmlProjectDebugger();
bool canEditProperty(const QString &propertyType);
QDeclarativeDebugExpressionQuery *executeExpression(int objectDebugId,
const QString &objectId, const QString &propertyName, const QVariant &value);
public slots:
void disconnectFromViewer();
void setSimpleDockWidgetArrangement();
private slots:
void treeObjectActivated(const QDeclarativeDebugObjectReference &obj);
void simultaneouslyDebugQmlCppApplication();
private:
void updateMenuActions();
QString attachToQmlViewerAsExternalApp(ProjectExplorer::Project *project);
QString attachToExternalCppAppWithQml(ProjectExplorer::Project *project);
bool addQuotesForData(const QVariant &value) const;
void resetViews();
QDeclarativeDebugEnginesQuery *m_engineQuery;
QDeclarativeDebugRootContextQuery *m_contextQuery;
CanvasFrameRate *m_frameRate;
Internal::ObjectTree *m_objectTreeWidget;
Internal::ObjectPropertiesView *m_propertiesWidget;
Internal::WatchTableModel *m_watchTableModel;
Internal::WatchTableView *m_watchTableView;
Internal::CanvasFrameRate *m_frameRateWidget;
Internal::ExpressionQueryWidget *m_expressionWidget;
Internal::EngineComboBox *m_engineComboBox;
QDockWidget *m_objectTreeDock;
QDockWidget *m_frameRateDock;
QDockWidget *m_expressionQueryDock;
QDockWidget *m_propertyWatcherDock;
QDockWidget *m_inspectorOutputDock;
Internal::InspectorSettings m_settings;
QmlProjectManager::QmlProjectRunConfigurationDebugData m_runConfigurationDebugData;
QStringList m_editablePropertyTypes;
// simultaneous debug mode stuff
int m_cppDebuggerState;
bool m_connectionInitialized;
bool m_simultaneousCppAndQmlDebugMode;
#endif
};
} // namespace Internal
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment