qmlprojectrunconfiguration.cpp 13.5 KB
Newer Older
Kai Koehne's avatar
Kai Koehne committed
1 2 3 4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
Kai Koehne's avatar
Kai Koehne committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

dt's avatar
dt committed
30
#include "qmlprojectrunconfiguration.h"
Kai Koehne's avatar
Kai Koehne committed
31 32 33
#include "qmlproject.h"
#include "qmlprojectmanagerconstants.h"
#include "qmlprojecttarget.h"
34
#include "projectexplorer/projectexplorer.h"
35 36
#include <coreplugin/mimedatabase.h>
#include <projectexplorer/buildconfiguration.h>
Kai Koehne's avatar
Kai Koehne committed
37 38 39 40 41 42
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/icore.h>
#include <coreplugin/ifile.h>
#include <utils/synchronousprocess.h>
#include <utils/pathchooser.h>
43
#include <utils/debuggerlanguagechooser.h>
44
#include <utils/detailswidget.h>
45 46
#include <qt4projectmanager/qtversionmanager.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
47
#include <qt4projectmanager/qmlobservertool.h>
Kai Koehne's avatar
Kai Koehne committed
48 49 50 51 52 53

#include <QFormLayout>
#include <QComboBox>
#include <QCoreApplication>
#include <QLineEdit>
#include <QSpinBox>
54
#include <QStringListModel>
55
#include <QDebug>
Kai Koehne's avatar
Kai Koehne committed
56 57 58 59 60

namespace QmlProjectManager {

QmlProjectRunConfiguration::QmlProjectRunConfiguration(Internal::QmlProjectTarget *parent) :
    ProjectExplorer::RunConfiguration(parent, QLatin1String(Constants::QML_RC_ID)),
61
    m_fileListModel(new QStringListModel(this)),
62
    m_projectTarget(parent),
63
    m_usingCurrentFile(true),
64
    m_isEnabled(false)
Kai Koehne's avatar
Kai Koehne committed
65 66 67 68 69 70 71
{
    ctor();
}

QmlProjectRunConfiguration::QmlProjectRunConfiguration(Internal::QmlProjectTarget *parent, QmlProjectRunConfiguration *source) :
    ProjectExplorer::RunConfiguration(parent, source),
    m_qmlViewerCustomPath(source->m_qmlViewerCustomPath),
72
    m_qmlViewerArgs(source->m_qmlViewerArgs),
73
    m_fileListModel(new QStringListModel(this)),
74
    m_projectTarget(parent)
Kai Koehne's avatar
Kai Koehne committed
75
{
76 77
    ctor();
    setMainScript(source->m_scriptFile);
Kai Koehne's avatar
Kai Koehne committed
78 79
}

80 81 82 83
bool QmlProjectRunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *bc) const
{
    Q_UNUSED(bc);

84
    return m_isEnabled;
85 86
}

Kai Koehne's avatar
Kai Koehne committed
87 88
void QmlProjectRunConfiguration::ctor()
{
89 90 91 92
    // reset default settings in constructor
    setUseCppDebugger(false);
    setUseQmlDebugger(true);

93 94 95 96
    Core::EditorManager *em = Core::EditorManager::instance();
    connect(em, SIGNAL(currentEditorChanged(Core::IEditor*)),
            this, SLOT(changeCurrentFile(Core::IEditor*)));

97 98
    Qt4ProjectManager::QtVersionManager *qtVersions = Qt4ProjectManager::QtVersionManager::instance();
    connect(qtVersions, SIGNAL(qtVersionsChanged(QList<int>)), this, SLOT(updateEnabled()));
99
    connect(qtVersions, SIGNAL(qtVersionsChanged(QList<int>)), this, SLOT(onViewerChanged()));
100

101
    setDisplayName(tr("QML Viewer", "QMLRunConfiguration display name."));
Kai Koehne's avatar
Kai Koehne committed
102 103 104 105 106 107 108 109 110 111 112
}

QmlProjectRunConfiguration::~QmlProjectRunConfiguration()
{
}

Internal::QmlProjectTarget *QmlProjectRunConfiguration::qmlTarget() const
{
    return static_cast<Internal::QmlProjectTarget *>(target());
}

113 114 115 116 117
bool QmlProjectRunConfiguration::qmlObserverAvailable() const
{
    return m_qmlObserverAvailable;
}

Kai Koehne's avatar
Kai Koehne committed
118 119 120 121
QString QmlProjectRunConfiguration::viewerPath() const
{
    if (!m_qmlViewerCustomPath.isEmpty())
        return m_qmlViewerCustomPath;
122 123

    return viewerDefaultPath();
Kai Koehne's avatar
Kai Koehne committed
124 125 126 127 128 129 130 131
}

QStringList QmlProjectRunConfiguration::viewerArguments() const
{
    QStringList args;

    // arguments in .user file
    if (!m_qmlViewerArgs.isEmpty())
132
        args.append(m_qmlViewerArgs.split(QLatin1Char(' ')));
Kai Koehne's avatar
Kai Koehne committed
133 134

    // arguments from .qmlproject file
135
    foreach (const QString &importPath, qmlTarget()->qmlProject()->importPaths()) {
136
        args.append(QLatin1String("-I"));
137
        args.append(importPath);
Kai Koehne's avatar
Kai Koehne committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151
    }

    const QString s = mainScript();
    if (! s.isEmpty())
        args.append(s);
    return args;
}

QString QmlProjectRunConfiguration::workingDirectory() const
{
    QFileInfo projectFile(qmlTarget()->qmlProject()->file()->fileName());
    return projectFile.absolutePath();
}

152 153 154 155 156
static bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
{
    return s1.toLower() < s2.toLower();
}

157
QWidget *QmlProjectRunConfiguration::createConfigurationWidget()
Kai Koehne's avatar
Kai Koehne committed
158
{
159 160 161 162 163 164 165
    Utils::DetailsWidget *detailsWidget = new Utils::DetailsWidget();
    detailsWidget->setState(Utils::DetailsWidget::NoSummary);

    QWidget *formWidget = new QWidget(detailsWidget);
    detailsWidget->setWidget(formWidget);
    QFormLayout *form = new QFormLayout(formWidget);
    form->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
Kai Koehne's avatar
Kai Koehne committed
166

167 168 169
    m_fileListCombo = new QComboBox;
    m_fileListCombo.data()->setModel(m_fileListModel);
    updateFileComboBox();
Kai Koehne's avatar
Kai Koehne committed
170

171 172
    connect(m_fileListCombo.data(), SIGNAL(activated(QString)), this, SLOT(setMainScript(QString)));
    connect(ProjectExplorer::ProjectExplorerPlugin::instance(), SIGNAL(fileListChanged()), SLOT(updateFileComboBox()));
Kai Koehne's avatar
Kai Koehne committed
173 174

    Utils::PathChooser *qmlViewer = new Utils::PathChooser;
175
    qmlViewer->setExpectedKind(Utils::PathChooser::ExistingCommand);
176
    qmlViewer->setPath(m_qmlViewerCustomPath);
177

178
    connect(qmlViewer, SIGNAL(changed(QString)), this, SLOT(onViewerChanged()));
Kai Koehne's avatar
Kai Koehne committed
179

180 181 182
    m_qmlViewerExecutable = new QLabel;
    m_qmlViewerExecutable.data()->setText(viewerPath() + " " + m_qmlViewerArgs);

Kai Koehne's avatar
Kai Koehne committed
183 184
    QLineEdit *qmlViewerArgs = new QLineEdit;
    qmlViewerArgs->setText(m_qmlViewerArgs);
185
    connect(qmlViewerArgs, SIGNAL(textChanged(QString)), this, SLOT(onViewerArgsChanged()));
Kai Koehne's avatar
Kai Koehne committed
186

187
    form->addRow(tr("Custom QML Viewer:"), qmlViewer);
188
    form->addRow(tr("Arguments:"), qmlViewerArgs);
189
    form->addRow(QString(), m_qmlViewerExecutable.data());
Kai Koehne's avatar
Kai Koehne committed
190

191 192 193 194 195 196 197 198 199
    QWidget *debuggerLabelWidget = new QWidget;
    QVBoxLayout *debuggerLabelLayout = new QVBoxLayout(debuggerLabelWidget);
    debuggerLabelLayout->setMargin(0);
    debuggerLabelLayout->setSpacing(0);
    debuggerLabelWidget->setLayout(debuggerLabelLayout);
    QLabel *debuggerLabel = new QLabel(tr("Debugger:"));
    debuggerLabelLayout->addWidget(debuggerLabel);
    debuggerLabelLayout->addStretch(10);

200
    Utils::DebuggerLanguageChooser *debuggerLanguageChooser = new Utils::DebuggerLanguageChooser(formWidget);
201

Leena Miettinen's avatar
Leena Miettinen committed
202
    form->addRow(tr("Main QML file:"), m_fileListCombo.data());
203
    form->addRow(debuggerLabelWidget, debuggerLanguageChooser);
204 205 206

    debuggerLanguageChooser->setCppChecked(useCppDebugger());
    debuggerLanguageChooser->setQmlChecked(useQmlDebugger());
207
    debuggerLanguageChooser->setQmlDebugServerPort(qmlDebugServerPort());
208 209 210 211 212

    connect(debuggerLanguageChooser, SIGNAL(cppLanguageToggled(bool)),
            this, SLOT(useCppDebuggerToggled(bool)));
    connect(debuggerLanguageChooser, SIGNAL(qmlLanguageToggled(bool)),
            this, SLOT(useQmlDebuggerToggled(bool)));
213 214
    connect(debuggerLanguageChooser, SIGNAL(qmlDebugServerPortChanged(uint)),
            this, SLOT(qmlDebugServerPortChanged(uint)));
Kai Koehne's avatar
Kai Koehne committed
215

216
    return detailsWidget;
Kai Koehne's avatar
Kai Koehne committed
217 218
}

219

Kai Koehne's avatar
Kai Koehne committed
220 221
QString QmlProjectRunConfiguration::mainScript() const
{
222 223
    if (m_usingCurrentFile)
        return m_currentFileFilename;
Kai Koehne's avatar
Kai Koehne committed
224

225
    return m_mainScriptFilename;
Kai Koehne's avatar
Kai Koehne committed
226 227
}

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
void QmlProjectRunConfiguration::updateFileComboBox()
{
    if (m_fileListCombo.isNull())
        return;

    QDir projectDir = qmlTarget()->qmlProject()->projectDir();
    QStringList files;

    files.append(CURRENT_FILE);
    int currentIndex = -1;
    QStringList sortedFiles = qmlTarget()->qmlProject()->files();
    qStableSort(sortedFiles.begin(), sortedFiles.end(), caseInsensitiveLessThan);

    foreach (const QString &fn, sortedFiles) {
        QFileInfo fileInfo(fn);
        if (fileInfo.suffix() != QLatin1String("qml"))
            continue;

        QString fileName = projectDir.relativeFilePath(fn);
        if (fileName == m_scriptFile)
            currentIndex = files.size();

        files.append(fileName);
    }
    m_fileListModel->setStringList(files);

    if (currentIndex != -1)
        m_fileListCombo.data()->setCurrentIndex(currentIndex);
    else
        m_fileListCombo.data()->setCurrentIndex(0);
}

Kai Koehne's avatar
Kai Koehne committed
260 261 262
void QmlProjectRunConfiguration::setMainScript(const QString &scriptFile)
{
    m_scriptFile = scriptFile;
263 264 265
    // replace with locale-agnostic string
    if (m_scriptFile == CURRENT_FILE)
        m_scriptFile = M_CURRENT_FILE;
266

267
    if (m_scriptFile.isEmpty() || m_scriptFile == M_CURRENT_FILE) {
268 269 270 271 272
        m_usingCurrentFile = true;
        changeCurrentFile(Core::EditorManager::instance()->currentEditor());
    } else {
        m_usingCurrentFile = false;
        m_mainScriptFilename = qmlTarget()->qmlProject()->projectDir().absoluteFilePath(scriptFile);
273
        updateEnabled();
274
    }
Kai Koehne's avatar
Kai Koehne committed
275 276
}

277
void QmlProjectRunConfiguration::onViewerChanged()
Kai Koehne's avatar
Kai Koehne committed
278 279 280 281
{
    if (Utils::PathChooser *chooser = qobject_cast<Utils::PathChooser *>(sender())) {
        m_qmlViewerCustomPath = chooser->path();
    }
282 283 284
    if (!m_qmlViewerExecutable.isNull()) {
        m_qmlViewerExecutable.data()->setText(viewerPath() + " " + m_qmlViewerArgs);
    }
Kai Koehne's avatar
Kai Koehne committed
285 286
}

287
void QmlProjectRunConfiguration::onViewerArgsChanged()
Kai Koehne's avatar
Kai Koehne committed
288 289 290
{
    if (QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender()))
        m_qmlViewerArgs = lineEdit->text();
291 292 293 294

    if (!m_qmlViewerExecutable.isNull()) {
        m_qmlViewerExecutable.data()->setText(viewerPath() + " " + m_qmlViewerArgs);
    }
Kai Koehne's avatar
Kai Koehne committed
295 296
}

297 298 299 300 301 302 303 304 305 306
void QmlProjectRunConfiguration::useCppDebuggerToggled(bool toggled)
{
    setUseCppDebugger(toggled);
}

void QmlProjectRunConfiguration::useQmlDebuggerToggled(bool toggled)
{
    setUseQmlDebugger(toggled);
}

307 308 309 310
void QmlProjectRunConfiguration::qmlDebugServerPortChanged(uint port)
{
    setQmlDebugServerPort(port);
}
311

Kai Koehne's avatar
Kai Koehne committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325
QVariantMap QmlProjectRunConfiguration::toMap() const
{
    QVariantMap map(ProjectExplorer::RunConfiguration::toMap());

    map.insert(QLatin1String(Constants::QML_VIEWER_KEY), m_qmlViewerCustomPath);
    map.insert(QLatin1String(Constants::QML_VIEWER_ARGUMENTS_KEY), m_qmlViewerArgs);
    map.insert(QLatin1String(Constants::QML_MAINSCRIPT_KEY),  m_scriptFile);
    return map;
}

bool QmlProjectRunConfiguration::fromMap(const QVariantMap &map)
{
    m_qmlViewerCustomPath = map.value(QLatin1String(Constants::QML_VIEWER_KEY)).toString();
    m_qmlViewerArgs = map.value(QLatin1String(Constants::QML_VIEWER_ARGUMENTS_KEY)).toString();
326
    m_scriptFile = map.value(QLatin1String(Constants::QML_MAINSCRIPT_KEY), M_CURRENT_FILE).toString();
327
    setMainScript(m_scriptFile);
Kai Koehne's avatar
Kai Koehne committed
328 329 330 331

    return RunConfiguration::fromMap(map);
}

332 333 334 335 336 337
void QmlProjectRunConfiguration::changeCurrentFile(Core::IEditor * /*editor*/)
{
    updateEnabled();
}

void QmlProjectRunConfiguration::updateEnabled()
338
{
339
    bool qmlFileFound = false;
340
    if (m_usingCurrentFile) {
341
        Core::IEditor *editor = Core::EditorManager::instance()->currentEditor();
342 343
        if (editor) {
            m_currentFileFilename = editor->file()->fileName();
344
            if (Core::ICore::instance()->mimeDatabase()->findByFile(mainScript()).type() == QLatin1String("application/x-qml"))
345
                qmlFileFound = true;
346 347 348
        }
        if (!editor
            || Core::ICore::instance()->mimeDatabase()->findByFile(mainScript()).type() == QLatin1String("application/x-qmlproject")) {
349
            // find a qml file with lowercase filename. This is slow but only done in initialization/other border cases.
350
            foreach(const QString &filename, m_projectTarget->qmlProject()->files()) {
351 352 353
                const QFileInfo fi(filename);

                if (!filename.isEmpty() && fi.baseName()[0].isLower()
354
                    && Core::ICore::instance()->mimeDatabase()->findByFile(fi).type() == QLatin1String("application/x-qml"))
355 356
                {
                    m_currentFileFilename = filename;
357
                    qmlFileFound = true;
358 359 360 361
                    break;
                }

            }
362
        }
363 364 365 366 367
    } else { // use default one
        qmlFileFound = !m_mainScriptFilename.isEmpty();
    }

    bool newValue = QFileInfo(viewerPath()).exists() && qmlFileFound;
368

369 370 371
    if (m_isEnabled != newValue) {
        m_isEnabled = newValue;
        emit isEnabledChanged(m_isEnabled);
372 373 374
    }
}

375
QString QmlProjectRunConfiguration::viewerDefaultPath() const
376
{
377 378 379 380 381
    QString path;

    // Try to locate default path in Qt Versions
    Qt4ProjectManager::QtVersionManager *qtVersions = Qt4ProjectManager::QtVersionManager::instance();
    foreach (Qt4ProjectManager::QtVersion *version, qtVersions->validVersions()) {
382 383 384 385
        if (version->supportsTargetId(Qt4ProjectManager::Constants::DESKTOP_TARGET_ID)) {
            // Search for QmlObserver
            const QString qtInstallData = version->versionInfo().value("QT_INSTALL_DATA");
            path = Qt4ProjectManager::QmlObserverTool::toolByInstallData(qtInstallData);
386
            m_qmlObserverAvailable = !path.isEmpty();
387 388 389 390 391

            if (path.isEmpty() && !version->qmlviewerCommand().isEmpty()) {
                path = version->qmlviewerCommand();
                break;
            }
392 393 394 395
        }
    }

    return path;
396 397
}

Kai Koehne's avatar
Kai Koehne committed
398
} // namespace QmlProjectManager