qmlprojectruncontrol.cpp 9.37 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
Kai Koehne's avatar
Kai Koehne committed
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
Kai Koehne's avatar
Kai Koehne committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
Kai Koehne's avatar
Kai Koehne committed
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** 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
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
Kai Koehne's avatar
Kai Koehne committed
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
Kai Koehne's avatar
Kai Koehne committed
29
30
31
32
33

#include "qmlprojectruncontrol.h"
#include "qmlprojectrunconfiguration.h"
#include <coreplugin/icore.h>
#include <projectexplorer/projectexplorerconstants.h>
34
#include <projectexplorer/target.h>
Tobias Hunger's avatar
Tobias Hunger committed
35
#include <projectexplorer/kit.h>
36
#include <projectexplorer/kitinformation.h>
37
#include <projectexplorer/project.h>
38
#include <projectexplorer/projectexplorer.h>
Kai Koehne's avatar
Kai Koehne committed
39
#include <utils/qtcassert.h>
40
41
#include <utils/qtcprocess.h>
#include <utils/tcpportsgatherer.h>
Kai Koehne's avatar
Kai Koehne committed
42

Lasse Holmstedt's avatar
Lasse Holmstedt committed
43
44
#include <debugger/debuggerrunner.h>
#include <debugger/debuggerplugin.h>
45
#include <debugger/debuggerconstants.h>
Friedemann Kleint's avatar
Friedemann Kleint committed
46
#include <debugger/debuggerstartparameters.h>
hjk's avatar
hjk committed
47
#include <debugger/debuggerruncontrolfactory.h>
Daniel Teske's avatar
Daniel Teske committed
48
#include <qtsupport/baseqtversion.h>
49
#include <qtsupport/qmlobservertool.h>
50

51
#include <qmlprojectmanager/qmlprojectplugin.h>
52

53
using namespace ProjectExplorer;
Kai Koehne's avatar
Kai Koehne committed
54
55

namespace QmlProjectManager {
56

Kai Koehne's avatar
Kai Koehne committed
57
58
namespace Internal {

59
QmlProjectRunControl::QmlProjectRunControl(QmlProjectRunConfiguration *runConfiguration, RunMode mode)
dt's avatar
dt committed
60
    : RunControl(runConfiguration, mode)
Kai Koehne's avatar
Kai Koehne committed
61
{
62
    m_applicationLauncher.setEnvironment(runConfiguration->environment());
Kai Koehne's avatar
Kai Koehne committed
63
64
    m_applicationLauncher.setWorkingDirectory(runConfiguration->workingDirectory());

65
    if (mode == NormalRunMode)
66
        m_executable = runConfiguration->viewerPath();
67
    else
68
        m_executable = runConfiguration->observerPath();
Kai Koehne's avatar
Kai Koehne committed
69
    m_commandLineArguments = runConfiguration->viewerArguments();
70
    m_mainQmlFile = runConfiguration->mainScript();
Kai Koehne's avatar
Kai Koehne committed
71

con's avatar
con committed
72
    connect(&m_applicationLauncher, SIGNAL(appendMessage(QString,Utils::OutputFormat)),
Robert Loehning's avatar
Robert Loehning committed
73
            this, SLOT(slotAppendMessage(QString,Utils::OutputFormat)));
Kai Koehne's avatar
Kai Koehne committed
74
75
76
77
78
79
    connect(&m_applicationLauncher, SIGNAL(processExited(int)),
            this, SLOT(processExited(int)));
    connect(&m_applicationLauncher, SIGNAL(bringToForegroundRequested(qint64)),
            this, SLOT(slotBringApplicationToForeground(qint64)));
}

80
QmlProjectRunControl::~QmlProjectRunControl()
Kai Koehne's avatar
Kai Koehne committed
81
{
82
    stop();
Kai Koehne's avatar
Kai Koehne committed
83
84
}

85
void QmlProjectRunControl::start()
Kai Koehne's avatar
Kai Koehne committed
86
{
87
    m_applicationLauncher.start(ApplicationLauncher::Gui, m_executable,
Kai Koehne's avatar
Kai Koehne committed
88
                                m_commandLineArguments);
89
    setApplicationProcessHandle(ProcessHandle(m_applicationLauncher.applicationPID()));
Kai Koehne's avatar
Kai Koehne committed
90
    emit started();
dt's avatar
dt committed
91
    QString msg = tr("Starting %1 %2\n")
92
        .arg(QDir::toNativeSeparators(m_executable), m_commandLineArguments);
con's avatar
con committed
93
    appendMessage(msg, Utils::NormalMessageFormat);
Kai Koehne's avatar
Kai Koehne committed
94
95
}

96
RunControl::StopResult QmlProjectRunControl::stop()
Kai Koehne's avatar
Kai Koehne committed
97
98
{
    m_applicationLauncher.stop();
99
    return StoppedSynchronously;
Kai Koehne's avatar
Kai Koehne committed
100
101
}

102
bool QmlProjectRunControl::isRunning() const
Kai Koehne's avatar
Kai Koehne committed
103
104
105
106
{
    return m_applicationLauncher.isRunning();
}

107
QIcon QmlProjectRunControl::icon() const
108
{
109
    return QIcon(QLatin1String(ProjectExplorer::Constants::ICON_RUN_SMALL));
110
111
}

112
void QmlProjectRunControl::slotBringApplicationToForeground(qint64 pid)
Kai Koehne's avatar
Kai Koehne committed
113
114
115
116
{
    bringApplicationToForeground(pid);
}

117
void QmlProjectRunControl::slotAppendMessage(const QString &line, Utils::OutputFormat format)
Kai Koehne's avatar
Kai Koehne committed
118
{
119
    appendMessage(line, format);
Kai Koehne's avatar
Kai Koehne committed
120
121
}

122
void QmlProjectRunControl::processExited(int exitCode)
Kai Koehne's avatar
Kai Koehne committed
123
{
dt's avatar
dt committed
124
    QString msg = tr("%1 exited with code %2\n")
125
        .arg(QDir::toNativeSeparators(m_executable)).arg(exitCode);
con's avatar
con committed
126
    appendMessage(msg, exitCode ? Utils::ErrorMessageFormat : Utils::NormalMessageFormat);
Kai Koehne's avatar
Kai Koehne committed
127
128
129
    emit finished();
}

130
131
132
133
134
QString QmlProjectRunControl::mainQmlFile() const
{
    return m_mainQmlFile;
}

135
QmlProjectRunControlFactory::QmlProjectRunControlFactory(QObject *parent)
Kai Koehne's avatar
Kai Koehne committed
136
137
138
139
    : IRunControlFactory(parent)
{
}

140
QmlProjectRunControlFactory::~QmlProjectRunControlFactory()
Kai Koehne's avatar
Kai Koehne committed
141
142
143
{
}

144
bool QmlProjectRunControlFactory::canRun(RunConfiguration *runConfiguration,
145
                                         RunMode mode) const
Kai Koehne's avatar
Kai Koehne committed
146
{
147
148
    QmlProjectRunConfiguration *config =
        qobject_cast<QmlProjectRunConfiguration*>(runConfiguration);
149
150
    if (!config)
        return false;
151
    if (mode == NormalRunMode)
152
        return !config->viewerPath().isEmpty();
153
    if (mode != DebugRunMode)
154
        return false;
155

156
157
    if (!Debugger::DebuggerPlugin::isActiveDebugLanguage(Debugger::QmlLanguage))
        return false;
Lasse Holmstedt's avatar
Lasse Holmstedt committed
158

159
160
161
162
163
164
165
166
    if (!config->observerPath().isEmpty())
        return true;
    if (!config->qtVersion())
        return false;
    if (!config->qtVersion()->needsQmlDebuggingLibrary())
        return true;
    if (QtSupport::QmlObserverTool::canBuild(config->qtVersion()))
        return true;
Lasse Holmstedt's avatar
Lasse Holmstedt committed
167
    return false;
Kai Koehne's avatar
Kai Koehne committed
168
169
}

170
RunControl *QmlProjectRunControlFactory::create(RunConfiguration *runConfiguration,
171
                                                RunMode mode, QString *errorMessage)
Kai Koehne's avatar
Kai Koehne committed
172
173
{
    QTC_ASSERT(canRun(runConfiguration, mode), return 0);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
174
    QmlProjectRunConfiguration *config = qobject_cast<QmlProjectRunConfiguration *>(runConfiguration);
175
176
177
178
179
180
181
182
183
184
185
186

    QList<ProjectExplorer::RunControl *> runcontrols =
            ProjectExplorer::ProjectExplorerPlugin::instance()->runControls();
    foreach (ProjectExplorer::RunControl *rc, runcontrols) {
        if (QmlProjectRunControl *qrc = qobject_cast<QmlProjectRunControl *>(rc)) {
            if (qrc->mainQmlFile() == config->mainScript())
                // Asking the user defeats the purpose
                // Making it configureable might be worth it
                qrc->stop();
        }
    }

Lasse Holmstedt's avatar
Lasse Holmstedt committed
187
    RunControl *runControl = 0;
188
    if (mode == NormalRunMode)
189
        runControl = new QmlProjectRunControl(config, mode);
190
    else if (mode == DebugRunMode)
191
        runControl = createDebugRunControl(config, errorMessage);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
192
    return runControl;
Kai Koehne's avatar
Kai Koehne committed
193
194
}

195
QString QmlProjectRunControlFactory::displayName() const
Kai Koehne's avatar
Kai Koehne committed
196
197
198
199
{
    return tr("Run");
}

200
RunControl *QmlProjectRunControlFactory::createDebugRunControl(QmlProjectRunConfiguration *runConfig, QString *errorMessage)
Lasse Holmstedt's avatar
Lasse Holmstedt committed
201
202
203
{
    Debugger::DebuggerStartParameters params;
    params.startMode = Debugger::StartInternal;
204
    params.executable = runConfig->observerPath();
205
    params.processArgs = runConfig->viewerArguments();
Lasse Holmstedt's avatar
Lasse Holmstedt committed
206
    params.workingDirectory = runConfig->workingDirectory();
207
    params.environment = runConfig->environment();
Lasse Holmstedt's avatar
Lasse Holmstedt committed
208
    params.displayName = runConfig->displayName();
209
210
    params.projectSourceDirectory = runConfig->target()->project()->projectDirectory();
    params.projectSourceFiles = runConfig->target()->project()->files(Project::ExcludeGeneratedFiles);
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
    if (runConfig->debuggerAspect()->useQmlDebugger()) {
        const ProjectExplorer::IDevice::ConstPtr device =
                DeviceKitInformation::device(runConfig->target()->kit());
        params.qmlServerAddress = QLatin1String("127.0.0.1");
        QTC_ASSERT(device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE, return 0);
        Utils::TcpPortsGatherer portsGatherer;
        portsGatherer.update(QAbstractSocket::UnknownNetworkLayerProtocol);
        Utils::PortList portList = device->freePorts();
        int freePort = portsGatherer.getNextFreePort(&portList);
        if (freePort == -1) {
            if (errorMessage)
                *errorMessage = tr("Not enough free ports for QML debugging. Increase the "
                                   "port range for Desktop device in Device settings.");
            return 0;
        }
        params.qmlServerPort = freePort;
Kai Koehne's avatar
Kai Koehne committed
227
        params.languages |= Debugger::QmlLanguage;
228
229
230
231
232
233
234
235
236
237
238

        // Makes sure that all bindings go through the JavaScript engine, so that
        // breakpoints are actually hit!
        const QString optimizerKey = QLatin1String("QML_DISABLE_OPTIMIZER");
        if (!params.environment.hasKey(optimizerKey))
            params.environment.set(optimizerKey, QLatin1String("1"));

        Utils::QtcProcess::addArg(&params.processArgs,
                                  QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(
                                      params.qmlServerPort));
    }
239
    if (runConfig->debuggerAspect()->useCppDebugger())
Kai Koehne's avatar
Kai Koehne committed
240
241
        params.languages |= Debugger::CppLanguage;

242
    if (params.executable.isEmpty()) {
243
        QmlProjectPlugin::showQmlObserverToolWarning();
244
        errorMessage->clear(); // hack, we already showed a error message
245
246
247
        return 0;
    }

248
    return Debugger::DebuggerPlugin::createDebugger(params, runConfig, errorMessage);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
249
250
}

Kai Koehne's avatar
Kai Koehne committed
251
252
} // namespace Internal
} // namespace QmlProjectManager