qmlinspectoradapter.cpp 13.3 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

#include "qmlinspectoradapter.h"

hjk's avatar
hjk committed
33
#include "qmlengine.h"
34
#include "qmlinspectoragent.h"
hjk's avatar
hjk committed
35

36 37 38 39
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerstringutils.h>
#include <debugger/debuggerengine.h>
40 41 42

#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/icore.h>
43 44 45
#include <coreplugin/idocument.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/documentmodel.h>
46
#include <qmldebug/declarativeenginedebugclient.h>
47
#include <qmldebug/declarativeenginedebugclientv2.h>
48 49 50 51 52 53
#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
54 55
#include <QFileInfo>

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.
 */
hjk's avatar
hjk committed
64 65 66
QmlInspectorAdapter::QmlInspectorAdapter(QmlEngine *engine, QmlDebugConnection *connection)
    : m_qmlEngine(engine)
    , m_masterEngine(engine)
67 68
    , m_engineClient(0)
    , m_toolsClient(0)
hjk's avatar
hjk committed
69
    , m_agent(new QmlInspectorAgent(engine))
70 71 72 73 74 75 76
    , 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
77
    , m_showAppOnTopAction(action(ShowAppOnTop))
78
    , m_engineClientConnected(false)
79
{
hjk's avatar
hjk committed
80 81 82
    if (!m_masterEngine->isMasterEngine())
        m_masterEngine = m_masterEngine->masterEngine();
    connect(m_masterEngine, &DebuggerEngine::stateChanged,
83 84 85 86 87
            this, &QmlInspectorAdapter::onEngineStateChanged);
    connect(m_agent, &QmlInspectorAgent::objectFetched,
            this, &QmlInspectorAdapter::onObjectFetched);
    connect(m_agent, &QmlInspectorAgent::jumpToObjectDefinition,
            this, &QmlInspectorAdapter::jumpToObjectDefinitionInEditor);
88

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    auto engineClient1 = new DeclarativeEngineDebugClient(connection);
    connect(engineClient1, &BaseEngineDebugClient::newState,
            this, &QmlInspectorAdapter::clientStateChanged);
    connect(engineClient1, &BaseEngineDebugClient::newState,
            this, &QmlInspectorAdapter::engineClientStateChanged);

    auto engineClient2 = new QmlEngineDebugClient(connection);
    connect(engineClient2, &BaseEngineDebugClient::newState,
            this, &QmlInspectorAdapter::clientStateChanged);
    connect(engineClient2, &BaseEngineDebugClient::newState,
            this, &QmlInspectorAdapter::engineClientStateChanged);

    auto engineClient3 = new DeclarativeEngineDebugClientV2(connection);
    connect(engineClient3, &BaseEngineDebugClient::newState,
            this, &QmlInspectorAdapter::clientStateChanged);
    connect(engineClient3, &BaseEngineDebugClient::newState,
            this, &QmlInspectorAdapter::engineClientStateChanged);
106

107 108
    m_engineClients.insert(engineClient1->name(), engineClient1);
    m_engineClients.insert(engineClient2->name(), engineClient2);
109
    m_engineClients.insert(engineClient3->name(), engineClient3);
110

111
    if (engineClient1->state() == QmlDebugClient::Enabled)
112
        setActiveEngineClient(engineClient1);
113
    if (engineClient2->state() == QmlDebugClient::Enabled)
114
        setActiveEngineClient(engineClient2);
115
    if (engineClient3->state() == QmlDebugClient::Enabled)
116
        setActiveEngineClient(engineClient3);
117

118 119 120 121 122
    auto toolsClient1 = new DeclarativeToolsClient(connection);
    connect(toolsClient1, &BaseToolsClient::newState,
            this, &QmlInspectorAdapter::clientStateChanged);
    connect(toolsClient1, &BaseToolsClient::newState,
            this, &QmlInspectorAdapter::toolsClientStateChanged);
123

124
    auto toolsClient2 = new QmlToolsClient(connection);
hjk's avatar
hjk committed
125 126
    connect(toolsClient2, &BaseToolsClient::newState,
            this, &QmlInspectorAdapter::clientStateChanged);
127 128
    connect(toolsClient2, &BaseToolsClient::newState,
            this, &QmlInspectorAdapter::toolsClientStateChanged);
129 130

    // toolbar
131 132
    m_selectAction->setObjectName(QLatin1String("QML Select Action"));
    m_zoomAction->setObjectName(QLatin1String("QML Zoom Action"));
133 134
    m_selectAction->setCheckable(true);
    m_zoomAction->setCheckable(true);
135 136 137 138
    m_showAppOnTopAction->setCheckable(true);
    m_selectAction->setEnabled(false);
    m_zoomAction->setEnabled(false);
    m_showAppOnTopAction->setEnabled(false);
139

140 141 142 143 144 145
    connect(m_selectAction, &QAction::triggered,
            this, &QmlInspectorAdapter::onSelectActionTriggered);
    connect(m_zoomAction, &QAction::triggered,
            this, &QmlInspectorAdapter::onZoomActionTriggered);
    connect(m_showAppOnTopAction, &QAction::triggered,
            this, &QmlInspectorAdapter::onShowAppOnTopChanged);
146 147 148 149 150 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
}

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;
}

177
void QmlInspectorAdapter::clientStateChanged(QmlDebugClient::State state)
178 179 180 181 182
{
    QString serviceName;
    float version = 0;
    if (QmlDebugClient *client = qobject_cast<QmlDebugClient*>(sender())) {
        serviceName = client->name();
183
        version = client->remoteVersion();
184 185
    }

hjk's avatar
hjk committed
186
    m_qmlEngine->logServiceStateChange(serviceName, version, state);
187 188
}

189
void QmlInspectorAdapter::toolsClientStateChanged(QmlDebugClient::State state)
190 191
{
    BaseToolsClient *client = qobject_cast<BaseToolsClient*>(sender());
192
    QTC_ASSERT(client, return);
193
    if (state == QmlDebugClient::Enabled) {
194 195
        m_toolsClient = client;

196 197 198
        connect(client, &BaseToolsClient::currentObjectsChanged,
                this, &QmlInspectorAdapter::selectObjectsFromToolsClient);
        connect(client, &BaseToolsClient::logActivity,
hjk's avatar
hjk committed
199
                m_qmlEngine, &QmlEngine::logServiceActivity);
200
        connect(client, &BaseToolsClient::reloaded, this, &QmlInspectorAdapter::onReloaded);
201 202 203 204

        // 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
205
        Core::ActionManager::registerAction(m_selectAction,
206 207
                                            Core::Id(Constants::QML_SELECTTOOL),
                                            m_inspectorToolsContext);
Eike Ziller's avatar
Eike Ziller committed
208
        Core::ActionManager::registerAction(m_zoomAction, Core::Id(Constants::QML_ZOOMTOOL),
209 210 211 212
                                            m_inspectorToolsContext);
        Core::ActionManager::registerAction(m_showAppOnTopAction,
                                            Core::Id(Constants::QML_SHOW_APP_ON_TOP),
                                            m_inspectorToolsContext);
213

214
        Core::ICore::addAdditionalContext(m_inspectorToolsContext);
215

216
        m_toolsClientConnected = true;
hjk's avatar
hjk committed
217
        onEngineStateChanged(m_masterEngine->state());
218
        if (m_showAppOnTopAction->isChecked())
219 220
            m_toolsClient->showAppOnTop(true);

221
    } else if (m_toolsClientConnected && client == m_toolsClient) {
hjk's avatar
hjk committed
222 223 224 225
        disconnect(client, &BaseToolsClient::currentObjectsChanged,
                   this, &QmlInspectorAdapter::selectObjectsFromToolsClient);
        disconnect(client, &BaseToolsClient::logActivity,
                   m_qmlEngine, &QmlEngine::logServiceActivity);
226

227 228 229 230
        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));
231

232
        Core::ICore::removeAdditionalContext(m_inspectorToolsContext);
233

234
        enableTools(false);
235
        m_toolsClientConnected = false;
236 237 238
        m_selectAction->setCheckable(false);
        m_zoomAction->setCheckable(false);
        m_showAppOnTopAction->setCheckable(false);
239 240 241
    }
}

242
void QmlInspectorAdapter::engineClientStateChanged(QmlDebugClient::State state)
243 244 245
{
    BaseEngineDebugClient *client
            = qobject_cast<BaseEngineDebugClient*>(sender());
246

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

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

261 262
    m_targetToSync = EditorTarget;
    m_debugIdToSelect = debugIds.first();
263
    selectObject(agent()->objectForId(m_debugIdToSelect), EditorTarget);
264 265
}

Kai Koehne's avatar
Kai Koehne committed
266
void QmlInspectorAdapter::onObjectFetched(const ObjectReference &ref)
267 268 269 270 271 272 273 274 275
{
    if (ref.debugId() == m_debugIdToSelect) {
        m_debugIdToSelect = -1;
        selectObject(ref, m_targetToSync);
    }
}

void QmlInspectorAdapter::onSelectActionTriggered(bool checked)
{
276
    QTC_ASSERT(toolsClient(), return);
277 278 279 280 281 282 283 284 285 286 287
    if (checked) {
        toolsClient()->setDesignModeBehavior(true);
        toolsClient()->changeToSelectTool();
        m_zoomAction->setChecked(false);
    } else {
        toolsClient()->setDesignModeBehavior(false);
    }
}

void QmlInspectorAdapter::onZoomActionTriggered(bool checked)
{
288
    QTC_ASSERT(toolsClient(), return);
289 290 291 292 293 294 295 296 297
    if (checked) {
        toolsClient()->setDesignModeBehavior(true);
        toolsClient()->changeToZoomTool();
        m_selectAction->setChecked(false);
    } else {
        toolsClient()->setDesignModeBehavior(false);
    }
}

298
void QmlInspectorAdapter::onShowAppOnTopChanged(bool checked)
299
{
300 301
    QTC_ASSERT(toolsClient(), return);
    toolsClient()->showAppOnTop(checked);
302 303 304 305 306 307 308 309 310
}

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

    m_engineClient = client;
    m_agent->setEngineClient(m_engineClient);
311
    m_engineClientConnected = true;
312 313
}

314
void QmlInspectorAdapter::showConnectionStateMessage(const QString &message)
315
{
hjk's avatar
hjk committed
316
    m_masterEngine->showMessage(_("QML Inspector: ") + message, LogStatus);
317 318
}

319
void QmlInspectorAdapter::jumpToObjectDefinitionInEditor(
Aurindam Jana's avatar
Aurindam Jana committed
320
        const FileReference &objSource, int debugId)
321
{
hjk's avatar
hjk committed
322
    const QString fileName = m_masterEngine->toFileInProject(objSource.url());
323

Eike Ziller's avatar
Eike Ziller committed
324
    Core::EditorManager::openEditorAt(fileName, objSource.lineNumber());
Aurindam Jana's avatar
Aurindam Jana committed
325 326 327 328
    if (debugId != -1 && debugId != m_currentSelectedDebugId) {
        m_currentSelectedDebugId = debugId;
        m_currentSelectedDebugName = agent()->displayName(debugId);
    }
329 330
}

Kai Koehne's avatar
Kai Koehne committed
331
void QmlInspectorAdapter::selectObject(const ObjectReference &obj,
332 333
                                       SelectionTarget target)
{
334
    if (m_toolsClient && target == ToolTarget)
335
        m_toolsClient->setObjectIdList(
Kai Koehne's avatar
Kai Koehne committed
336
                    QList<ObjectReference>() << obj);
337 338

    if (target == EditorTarget)
339
        jumpToObjectDefinitionInEditor(obj.source());
340

341
    agent()->selectObjectInTree(obj.debugId());
342 343
}

344 345 346 347 348 349 350 351 352 353 354 355
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);
}

356 357
void QmlInspectorAdapter::onReloaded()
{
358
    m_agent->reloadEngines();
359 360
}

361 362 363 364 365
void QmlInspectorAdapter::onEngineStateChanged(const DebuggerState state)
{
    enableTools(state == InferiorRunOk);
}

366 367
} // namespace Internal
} // namespace Debugger