qmlinspectoradapter.cpp 13.9 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
Eike Ziller's avatar
Eike Ziller committed
3 4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12 13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25 26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
27 28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
30 31 32 33 34

#include "qmlinspectoradapter.h"

#include "qmladapter.h"
#include "qmlinspectoragent.h"
35 36 37 38
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerstringutils.h>
#include <debugger/debuggerengine.h>
39 40 41

#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/icore.h>
42 43 44
#include <coreplugin/idocument.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/documentmodel.h>
45
#include <qmldebug/declarativeenginedebugclient.h>
46
#include <qmldebug/declarativeenginedebugclientv2.h>
47 48 49 50 51 52
#include <qmldebug/declarativetoolsclient.h>
#include <qmldebug/qmlenginedebugclient.h>
#include <qmldebug/qmltoolsclient.h>
#include <utils/qtcassert.h>
#include <utils/savedaction.h>

Friedemann Kleint's avatar
Friedemann Kleint committed
53 54
#include <QFileInfo>

55 56 57 58 59 60 61 62 63
using namespace QmlDebug;

namespace Debugger {
namespace Internal {
/*!
 * QmlInspectorAdapter manages the clients for the inspector, and the
 * integration with the text editor.
 */
QmlInspectorAdapter::QmlInspectorAdapter(QmlAdapter *debugAdapter,
64
                                         DebuggerEngine *engine,
65 66 67 68 69 70 71 72 73 74 75 76 77 78
                                         QObject *parent)
    : QObject(parent)
    , m_debugAdapter(debugAdapter)
    , m_engine(engine)
    , m_engineClient(0)
    , m_toolsClient(0)
    , m_agent(new QmlInspectorAgent(engine, this))
    , m_targetToSync(NoTarget)
    , m_debugIdToSelect(-1)
    , m_currentSelectedDebugId(-1)
    , m_toolsClientConnected(false)
    , m_inspectorToolsContext("Debugger.QmlInspector")
    , m_selectAction(new QAction(this))
    , m_zoomAction(new QAction(this))
hjk's avatar
hjk committed
79
    , m_showAppOnTopAction(action(ShowAppOnTop))
80
    , m_engineClientConnected(false)
81
{
82 83 84 85
    if (!m_engine->isMasterEngine())
        m_engine = m_engine->masterEngine();
    connect(m_engine, SIGNAL(stateChanged(Debugger::DebuggerState)),
            SLOT(onEngineStateChanged(Debugger::DebuggerState)));
Kai Koehne's avatar
Kai Koehne committed
86 87
    connect(m_agent, SIGNAL(objectFetched(QmlDebug::ObjectReference)),
            SLOT(onObjectFetched(QmlDebug::ObjectReference)));
Aurindam Jana's avatar
Aurindam Jana committed
88 89
    connect(m_agent, SIGNAL(jumpToObjectDefinition(QmlDebug::FileReference,int)),
            SLOT(jumpToObjectDefinitionInEditor(QmlDebug::FileReference,int)));
90 91 92 93

    QmlDebugConnection *connection = m_debugAdapter->connection();
    DeclarativeEngineDebugClient *engineClient1
            = new DeclarativeEngineDebugClient(connection);
94 95 96 97
    connect(engineClient1, SIGNAL(newState(QmlDebug::QmlDebugClient::State)),
            this, SLOT(clientStateChanged(QmlDebug::QmlDebugClient::State)));
    connect(engineClient1, SIGNAL(newState(QmlDebug::QmlDebugClient::State)),
            this, SLOT(engineClientStateChanged(QmlDebug::QmlDebugClient::State)));
98 99

    QmlEngineDebugClient *engineClient2 = new QmlEngineDebugClient(connection);
100 101 102 103
    connect(engineClient2, SIGNAL(newState(QmlDebug::QmlDebugClient::State)),
            this, SLOT(clientStateChanged(QmlDebug::QmlDebugClient::State)));
    connect(engineClient2, SIGNAL(newState(QmlDebug::QmlDebugClient::State)),
            this, SLOT(engineClientStateChanged(QmlDebug::QmlDebugClient::State)));
104

105 106
    DeclarativeEngineDebugClientV2 *engineClient3
            = new DeclarativeEngineDebugClientV2(connection);
107 108 109 110
    connect(engineClient3, SIGNAL(newState(QmlDebug::QmlDebugClient::State)),
            this, SLOT(clientStateChanged(QmlDebug::QmlDebugClient::State)));
    connect(engineClient3, SIGNAL(newState(QmlDebug::QmlDebugClient::State)),
            this, SLOT(engineClientStateChanged(QmlDebug::QmlDebugClient::State)));
111

112 113
    m_engineClients.insert(engineClient1->name(), engineClient1);
    m_engineClients.insert(engineClient2->name(), engineClient2);
114
    m_engineClients.insert(engineClient3->name(), engineClient3);
115

116
    if (engineClient1->state() == QmlDebugClient::Enabled)
117
        setActiveEngineClient(engineClient1);
118
    if (engineClient2->state() == QmlDebugClient::Enabled)
119
        setActiveEngineClient(engineClient2);
120
    if (engineClient3->state() == QmlDebugClient::Enabled)
121
        setActiveEngineClient(engineClient3);
122 123

    DeclarativeToolsClient *toolsClient1 = new DeclarativeToolsClient(connection);
124 125 126 127
    connect(toolsClient1, SIGNAL(newState(QmlDebug::QmlDebugClient::State)),
            this, SLOT(clientStateChanged(QmlDebug::QmlDebugClient::State)));
    connect(toolsClient1, SIGNAL(newState(QmlDebug::QmlDebugClient::State)),
            this, SLOT(toolsClientStateChanged(QmlDebug::QmlDebugClient::State)));
128 129

    QmlToolsClient *toolsClient2 = new QmlToolsClient(connection);
130 131 132 133
    connect(toolsClient2, SIGNAL(newState(QmlDebug::QmlDebugClient::State)),
            this, SLOT(clientStateChanged(QmlDebug::QmlDebugClient::State)));
    connect(toolsClient2, SIGNAL(newState(QmlDebug::QmlDebugClient::State)),
            this, SLOT(toolsClientStateChanged(QmlDebug::QmlDebugClient::State)));
134 135

    // toolbar
136 137
    m_selectAction->setObjectName(QLatin1String("QML Select Action"));
    m_zoomAction->setObjectName(QLatin1String("QML Zoom Action"));
138 139
    m_selectAction->setCheckable(true);
    m_zoomAction->setCheckable(true);
140 141 142 143
    m_showAppOnTopAction->setCheckable(true);
    m_selectAction->setEnabled(false);
    m_zoomAction->setEnabled(false);
    m_showAppOnTopAction->setEnabled(false);
144 145 146 147 148

    connect(m_selectAction, SIGNAL(triggered(bool)),
            SLOT(onSelectActionTriggered(bool)));
    connect(m_zoomAction, SIGNAL(triggered(bool)),
            SLOT(onZoomActionTriggered(bool)));
149 150
    connect(m_showAppOnTopAction, SIGNAL(triggered(bool)),
            SLOT(onShowAppOnTopChanged(bool)));
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
}

QmlInspectorAdapter::~QmlInspectorAdapter()
{
}

BaseEngineDebugClient *QmlInspectorAdapter::engineClient() const
{
    return m_engineClient;
}

BaseToolsClient *QmlInspectorAdapter::toolsClient() const
{
    return m_toolsClient;
}

QmlInspectorAgent *QmlInspectorAdapter::agent() const
{
    return m_agent;
}

int QmlInspectorAdapter::currentSelectedDebugId() const
{
    return m_currentSelectedDebugId;
}

QString QmlInspectorAdapter::currentSelectedDisplayName() const
{
    return m_currentSelectedDebugName;
}

182
void QmlInspectorAdapter::clientStateChanged(QmlDebugClient::State state)
183 184 185 186 187
{
    QString serviceName;
    float version = 0;
    if (QmlDebugClient *client = qobject_cast<QmlDebugClient*>(sender())) {
        serviceName = client->name();
188
        version = client->remoteVersion();
189 190
    }

191
    m_debugAdapter->logServiceStateChange(serviceName, version, state);
192 193
}

194
void QmlInspectorAdapter::toolsClientStateChanged(QmlDebugClient::State state)
195 196
{
    BaseToolsClient *client = qobject_cast<BaseToolsClient*>(sender());
197
    QTC_ASSERT(client, return);
198
    if (state == QmlDebugClient::Enabled) {
199 200 201 202 203 204
        m_toolsClient = client;

        connect(client, SIGNAL(currentObjectsChanged(QList<int>)),
                SLOT(selectObjectsFromToolsClient(QList<int>)));
        connect(client, SIGNAL(logActivity(QString,QString)),
                m_debugAdapter, SLOT(logServiceActivity(QString,QString)));
205
        connect(client, SIGNAL(reloaded()), SLOT(onReloaded()));
206 207 208 209

        // register actions here
        // because there can be multiple QmlEngines
        // at the same time (but hopefully one one is connected)
Eike Ziller's avatar
Eike Ziller committed
210
        Core::ActionManager::registerAction(m_selectAction,
211 212
                                            Core::Id(Constants::QML_SELECTTOOL),
                                            m_inspectorToolsContext);
Eike Ziller's avatar
Eike Ziller committed
213
        Core::ActionManager::registerAction(m_zoomAction, Core::Id(Constants::QML_ZOOMTOOL),
214 215 216 217
                                            m_inspectorToolsContext);
        Core::ActionManager::registerAction(m_showAppOnTopAction,
                                            Core::Id(Constants::QML_SHOW_APP_ON_TOP),
                                            m_inspectorToolsContext);
218

219
        Core::ICore::addAdditionalContext(m_inspectorToolsContext);
220

221 222 223
        m_toolsClientConnected = true;
        onEngineStateChanged(m_engine->state());
        if (m_showAppOnTopAction->isChecked())
224 225
            m_toolsClient->showAppOnTop(true);

226
    } else if (m_toolsClientConnected && client == m_toolsClient) {
227 228 229 230 231
        disconnect(client, SIGNAL(currentObjectsChanged(QList<int>)),
                   this, SLOT(selectObjectsFromToolsClient(QList<int>)));
        disconnect(client, SIGNAL(logActivity(QString,QString)),
                   m_debugAdapter, SLOT(logServiceActivity(QString,QString)));

232 233 234 235
        Core::ActionManager::unregisterAction(m_selectAction, Core::Id(Constants::QML_SELECTTOOL));
        Core::ActionManager::unregisterAction(m_zoomAction, Core::Id(Constants::QML_ZOOMTOOL));
        Core::ActionManager::unregisterAction(m_showAppOnTopAction,
                                              Core::Id(Constants::QML_SHOW_APP_ON_TOP));
236

237
        Core::ICore::removeAdditionalContext(m_inspectorToolsContext);
238

239
        enableTools(false);
240
        m_toolsClientConnected = false;
241 242 243
        m_selectAction->setCheckable(false);
        m_zoomAction->setCheckable(false);
        m_showAppOnTopAction->setCheckable(false);
244 245 246
    }
}

247
void QmlInspectorAdapter::engineClientStateChanged(QmlDebugClient::State state)
248 249 250
{
    BaseEngineDebugClient *client
            = qobject_cast<BaseEngineDebugClient*>(sender());
251

252
    if (state == QmlDebugClient::Enabled && !m_engineClientConnected) {
253
        // We accept the first client that is enabled and reject the others.
254 255
        QTC_ASSERT(client, return);
        setActiveEngineClient(client);
256
    } else if (m_engineClientConnected && client == m_engineClient) {
257 258
        m_engineClientConnected = false;
    }
259 260 261 262 263 264 265
}

void QmlInspectorAdapter::selectObjectsFromToolsClient(const QList<int> &debugIds)
{
    if (debugIds.isEmpty())
        return;

266 267
    m_targetToSync = EditorTarget;
    m_debugIdToSelect = debugIds.first();
268
    selectObject(agent()->objectForId(m_debugIdToSelect), EditorTarget);
269 270
}

Kai Koehne's avatar
Kai Koehne committed
271
void QmlInspectorAdapter::onObjectFetched(const ObjectReference &ref)
272 273 274 275 276 277 278 279 280
{
    if (ref.debugId() == m_debugIdToSelect) {
        m_debugIdToSelect = -1;
        selectObject(ref, m_targetToSync);
    }
}

void QmlInspectorAdapter::onSelectActionTriggered(bool checked)
{
281
    QTC_ASSERT(toolsClient(), return);
282 283 284 285 286 287 288 289 290 291 292
    if (checked) {
        toolsClient()->setDesignModeBehavior(true);
        toolsClient()->changeToSelectTool();
        m_zoomAction->setChecked(false);
    } else {
        toolsClient()->setDesignModeBehavior(false);
    }
}

void QmlInspectorAdapter::onZoomActionTriggered(bool checked)
{
293
    QTC_ASSERT(toolsClient(), return);
294 295 296 297 298 299 300 301 302
    if (checked) {
        toolsClient()->setDesignModeBehavior(true);
        toolsClient()->changeToZoomTool();
        m_selectAction->setChecked(false);
    } else {
        toolsClient()->setDesignModeBehavior(false);
    }
}

303
void QmlInspectorAdapter::onShowAppOnTopChanged(bool checked)
304
{
305 306
    QTC_ASSERT(toolsClient(), return);
    toolsClient()->showAppOnTop(checked);
307 308 309 310 311 312 313 314 315
}

void QmlInspectorAdapter::setActiveEngineClient(BaseEngineDebugClient *client)
{
    if (m_engineClient == client)
        return;

    m_engineClient = client;
    m_agent->setEngineClient(m_engineClient);
316
    m_engineClientConnected = true;
317 318
}

319
void QmlInspectorAdapter::showConnectionStateMessage(const QString &message)
320 321 322 323
{
    m_engine->showMessage(_("QML Inspector: ") + message, LogStatus);
}

324
void QmlInspectorAdapter::jumpToObjectDefinitionInEditor(
Aurindam Jana's avatar
Aurindam Jana committed
325
        const FileReference &objSource, int debugId)
326
{
327
    const QString fileName = m_engine->toFileInProject(objSource.url());
328

Eike Ziller's avatar
Eike Ziller committed
329
    Core::EditorManager::openEditorAt(fileName, objSource.lineNumber());
Aurindam Jana's avatar
Aurindam Jana committed
330 331 332 333
    if (debugId != -1 && debugId != m_currentSelectedDebugId) {
        m_currentSelectedDebugId = debugId;
        m_currentSelectedDebugName = agent()->displayName(debugId);
    }
334 335
}

Kai Koehne's avatar
Kai Koehne committed
336
void QmlInspectorAdapter::selectObject(const ObjectReference &obj,
337 338
                                       SelectionTarget target)
{
339
    if (m_toolsClient && target == ToolTarget)
340
        m_toolsClient->setObjectIdList(
Kai Koehne's avatar
Kai Koehne committed
341
                    QList<ObjectReference>() << obj);
342 343

    if (target == EditorTarget)
344
        jumpToObjectDefinitionInEditor(obj.source());
345

346
    agent()->selectObjectInTree(obj.debugId());
347 348
}

349 350 351 352 353 354 355 356 357 358 359 360
void QmlInspectorAdapter::enableTools(const bool enable)
{
    if (!m_toolsClientConnected)
        return;
    m_selectAction->setEnabled(enable);
    m_showAppOnTopAction->setEnabled(enable);
    // only enable zoom action for Qt 4.x/old client
    // (zooming is integrated into selection tool in Qt 5).
    if (!qobject_cast<QmlToolsClient*>(m_toolsClient))
        m_zoomAction->setEnabled(enable);
}

361 362
void QmlInspectorAdapter::onReloaded()
{
363
    m_agent->reloadEngines();
364 365
}

366 367 368 369 370
void QmlInspectorAdapter::onEngineStateChanged(const DebuggerState state)
{
    enableTools(state == InferiorRunOk);
}

371 372
} // namespace Internal
} // namespace Debugger