qmlprojectruncontrol.cpp 9.28 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

#include "qmlprojectruncontrol.h"
#include "qmlprojectrunconfiguration.h"
32
#include <debugger/debuggerrunconfigurationaspect.h>
33
34
#include <projectexplorer/environmentaspect.h>
#include <projectexplorer/projectexplorerconstants.h>
35
#include <projectexplorer/target.h>
36
#include <projectexplorer/kitinformation.h>
37
#include <projectexplorer/project.h>
38
#include <projectexplorer/projectexplorer.h>
39
#include <utils/qtcprocess.h>
Kai Koehne's avatar
Kai Koehne committed
40

Lasse Holmstedt's avatar
Lasse Holmstedt committed
41
42
#include <debugger/debuggerrunner.h>
#include <debugger/debuggerplugin.h>
Friedemann Kleint's avatar
Friedemann Kleint committed
43
#include <debugger/debuggerstartparameters.h>
Daniel Teske's avatar
Daniel Teske committed
44
#include <qtsupport/baseqtversion.h>
45
#include <qtsupport/qmlobservertool.h>
46

47
#include <qmlprojectmanager/qmlprojectplugin.h>
48

49
50
#include <QTcpServer>

51
using namespace ProjectExplorer;
Kai Koehne's avatar
Kai Koehne committed
52
53

namespace QmlProjectManager {
54

Kai Koehne's avatar
Kai Koehne committed
55
56
namespace Internal {

57
QmlProjectRunControl::QmlProjectRunControl(QmlProjectRunConfiguration *runConfiguration, RunMode mode)
dt's avatar
dt committed
58
    : RunControl(runConfiguration, mode)
Kai Koehne's avatar
Kai Koehne committed
59
{
60
61
62
    EnvironmentAspect *environment = runConfiguration->extraAspect<EnvironmentAspect>();
    if (environment)
        m_applicationLauncher.setEnvironment(environment->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;
Lasse Holmstedt's avatar
Lasse Holmstedt committed
155

156
157
158
159
160
161
162
163
    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
164
    return false;
Kai Koehne's avatar
Kai Koehne committed
165
166
}

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

    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
184
    RunControl *runControl = 0;
185
    if (mode == NormalRunMode)
186
        runControl = new QmlProjectRunControl(config, mode);
187
    else if (mode == DebugRunMode)
188
        runControl = createDebugRunControl(config, errorMessage);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
189
    return runControl;
Kai Koehne's avatar
Kai Koehne committed
190
191
}

192
RunControl *QmlProjectRunControlFactory::createDebugRunControl(QmlProjectRunConfiguration *runConfig, QString *errorMessage)
Lasse Holmstedt's avatar
Lasse Holmstedt committed
193
194
{
    Debugger::DebuggerStartParameters params;
195
196

    Debugger::DebuggerRunConfigurationAspect *debugger
197
            = runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
198
199
200
    QTC_ASSERT(debugger, return 0);
    EnvironmentAspect *environment = runConfig->extraAspect<EnvironmentAspect>();

Lasse Holmstedt's avatar
Lasse Holmstedt committed
201
    params.startMode = Debugger::StartInternal;
202
    params.executable = runConfig->observerPath();
203
    params.processArgs = runConfig->viewerArguments();
Lasse Holmstedt's avatar
Lasse Holmstedt committed
204
    params.workingDirectory = runConfig->workingDirectory();
205
206
    if (environment)
        params.environment = environment->environment();
Lasse Holmstedt's avatar
Lasse Holmstedt committed
207
    params.displayName = runConfig->displayName();
208
209
    params.projectSourceDirectory = runConfig->target()->project()->projectDirectory();
    params.projectSourceFiles = runConfig->target()->project()->files(Project::ExcludeGeneratedFiles);
210
    if (debugger->useQmlDebugger()) {
211
212
213
        const ProjectExplorer::IDevice::ConstPtr device =
                DeviceKitInformation::device(runConfig->target()->kit());
        QTC_ASSERT(device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE, return 0);
214
        QTcpServer server;
215
216
        const bool canListen = server.listen(QHostAddress::LocalHost)
                || server.listen(QHostAddress::LocalHostIPv6);
217
        if (!canListen) {
218
            if (errorMessage)
219
                *errorMessage = tr("Not enough free ports for QML debugging. ");
220
221
            return 0;
        }
222
        params.qmlServerAddress = server.serverAddress().toString();
223
        params.qmlServerPort = server.serverPort();
Kai Koehne's avatar
Kai Koehne committed
224
        params.languages |= Debugger::QmlLanguage;
225
226
227
228
229
230
231
232
233
234
235

        // 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));
    }
236
    if (debugger->useCppDebugger())
Kai Koehne's avatar
Kai Koehne committed
237
238
        params.languages |= Debugger::CppLanguage;

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

245
    return Debugger::DebuggerPlugin::createDebugger(params, runConfig, errorMessage);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
246
247
}

Kai Koehne's avatar
Kai Koehne committed
248
249
} // namespace Internal
} // namespace QmlProjectManager