qmlprojectrunconfiguration.cpp 13.8 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"
Kai Koehne's avatar
Kai Koehne committed
35

36 37
#include <coreplugin/mimedatabase.h>
#include <projectexplorer/buildconfiguration.h>
Kai Koehne's avatar
Kai Koehne committed
38 39 40 41 42 43
#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>
44
#include <utils/debuggerlanguagechooser.h>
45 46
#include <qt4projectmanager/qtversionmanager.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
Kai Koehne's avatar
Kai Koehne committed
47 48 49 50 51 52

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

namespace QmlProjectManager {

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

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

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

83
    return m_isEnabled;
84 85
}

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

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

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

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

QmlProjectRunConfiguration::~QmlProjectRunConfiguration()
{
}

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

QString QmlProjectRunConfiguration::viewerPath() const
{
    if (!m_qmlViewerCustomPath.isEmpty())
        return m_qmlViewerCustomPath;
116 117

    return viewerDefaultPath();
Kai Koehne's avatar
Kai Koehne committed
118 119 120 121 122 123 124 125
}

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

    // arguments in .user file
    if (!m_qmlViewerArgs.isEmpty())
126
        args.append(m_qmlViewerArgs.split(QLatin1Char(' ')));
Kai Koehne's avatar
Kai Koehne committed
127 128

    // arguments from .qmlproject file
129
    foreach (const QString &importPath, qmlTarget()->qmlProject()->importPaths()) {
130
        args.append(QLatin1String("-I"));
131
        args.append(importPath);
Kai Koehne's avatar
Kai Koehne committed
132 133 134 135 136 137 138 139 140 141 142 143 144 145
    }

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

146 147 148 149 150
static bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
{
    return s1.toLower() < s2.toLower();
}

151
QWidget *QmlProjectRunConfiguration::createConfigurationWidget()
Kai Koehne's avatar
Kai Koehne committed
152 153 154 155
{
    QWidget *config = new QWidget;
    QFormLayout *form = new QFormLayout(config);

156 157 158
    m_fileListCombo = new QComboBox;
    m_fileListCombo.data()->setModel(m_fileListModel);
    updateFileComboBox();
Kai Koehne's avatar
Kai Koehne committed
159

160 161
    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
162 163

    Utils::PathChooser *qmlViewer = new Utils::PathChooser;
164
    qmlViewer->setExpectedKind(Utils::PathChooser::ExistingCommand);
165
    qmlViewer->setPath(m_qmlViewerCustomPath);
166

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

169 170 171
    m_qmlViewerExecutable = new QLabel;
    m_qmlViewerExecutable.data()->setText(viewerPath() + " " + m_qmlViewerArgs);

Kai Koehne's avatar
Kai Koehne committed
172 173
    QLineEdit *qmlViewerArgs = new QLineEdit;
    qmlViewerArgs->setText(m_qmlViewerArgs);
174
    connect(qmlViewerArgs, SIGNAL(textChanged(QString)), this, SLOT(onViewerArgsChanged()));
Kai Koehne's avatar
Kai Koehne committed
175

176
    form->addRow(tr("Custom QML Viewer:"), qmlViewer);
177
    form->addRow(tr("QML Viewer arguments:"), qmlViewerArgs);
178
    form->addRow(QString(), m_qmlViewerExecutable.data());
Kai Koehne's avatar
Kai Koehne committed
179

180 181 182 183 184 185 186 187 188
    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);

189 190
    Utils::DebuggerLanguageChooser *debuggerLanguageChooser = new Utils::DebuggerLanguageChooser(config);

Leena Miettinen's avatar
Leena Miettinen committed
191
    form->addRow(tr("Main QML file:"), m_fileListCombo.data());
192
    form->addRow(debuggerLabelWidget, debuggerLanguageChooser);
193 194 195

    debuggerLanguageChooser->setCppChecked(useCppDebugger());
    debuggerLanguageChooser->setQmlChecked(useQmlDebugger());
196
    debuggerLanguageChooser->setQmlDebugServerPort(qmlDebugServerPort());
197 198 199 200 201

    connect(debuggerLanguageChooser, SIGNAL(cppLanguageToggled(bool)),
            this, SLOT(useCppDebuggerToggled(bool)));
    connect(debuggerLanguageChooser, SIGNAL(qmlLanguageToggled(bool)),
            this, SLOT(useQmlDebuggerToggled(bool)));
202 203
    connect(debuggerLanguageChooser, SIGNAL(qmlDebugServerPortChanged(uint)),
            this, SLOT(qmlDebugServerPortChanged(uint)));
Kai Koehne's avatar
Kai Koehne committed
204 205 206 207

    return config;
}

208

Kai Koehne's avatar
Kai Koehne committed
209 210
QString QmlProjectRunConfiguration::mainScript() const
{
211 212
    if (m_usingCurrentFile)
        return m_currentFileFilename;
Kai Koehne's avatar
Kai Koehne committed
213

214
    return m_mainScriptFilename;
Kai Koehne's avatar
Kai Koehne committed
215 216
}

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
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
249 250 251
void QmlProjectRunConfiguration::setMainScript(const QString &scriptFile)
{
    m_scriptFile = scriptFile;
252 253 254
    // replace with locale-agnostic string
    if (m_scriptFile == CURRENT_FILE)
        m_scriptFile = M_CURRENT_FILE;
255

256
    if (m_scriptFile.isEmpty() || m_scriptFile == M_CURRENT_FILE) {
257 258 259 260 261
        m_usingCurrentFile = true;
        changeCurrentFile(Core::EditorManager::instance()->currentEditor());
    } else {
        m_usingCurrentFile = false;
        m_mainScriptFilename = qmlTarget()->qmlProject()->projectDir().absoluteFilePath(scriptFile);
262
        updateEnabled();
263
    }
Kai Koehne's avatar
Kai Koehne committed
264 265
}

266
void QmlProjectRunConfiguration::onViewerChanged()
Kai Koehne's avatar
Kai Koehne committed
267 268 269 270
{
    if (Utils::PathChooser *chooser = qobject_cast<Utils::PathChooser *>(sender())) {
        m_qmlViewerCustomPath = chooser->path();
    }
271 272 273
    if (!m_qmlViewerExecutable.isNull()) {
        m_qmlViewerExecutable.data()->setText(viewerPath() + " " + m_qmlViewerArgs);
    }
Kai Koehne's avatar
Kai Koehne committed
274 275
}

276
void QmlProjectRunConfiguration::onViewerArgsChanged()
Kai Koehne's avatar
Kai Koehne committed
277 278 279
{
    if (QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender()))
        m_qmlViewerArgs = lineEdit->text();
280 281 282 283

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

286 287 288 289 290 291 292 293 294 295
void QmlProjectRunConfiguration::useCppDebuggerToggled(bool toggled)
{
    setUseCppDebugger(toggled);
}

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

296 297 298 299
void QmlProjectRunConfiguration::qmlDebugServerPortChanged(uint port)
{
    setQmlDebugServerPort(port);
}
300

Kai Koehne's avatar
Kai Koehne committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314
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();
315
    m_scriptFile = map.value(QLatin1String(Constants::QML_MAINSCRIPT_KEY), M_CURRENT_FILE).toString();
316
    setMainScript(m_scriptFile);
Kai Koehne's avatar
Kai Koehne committed
317 318 319 320

    return RunConfiguration::fromMap(map);
}

321 322 323 324 325 326
void QmlProjectRunConfiguration::changeCurrentFile(Core::IEditor * /*editor*/)
{
    updateEnabled();
}

void QmlProjectRunConfiguration::updateEnabled()
327
{
328
    bool qmlFileFound = false;
329
    if (m_usingCurrentFile) {
330
        Core::IEditor *editor = Core::EditorManager::instance()->currentEditor();
331 332
        if (editor) {
            m_currentFileFilename = editor->file()->fileName();
333
            if (Core::ICore::instance()->mimeDatabase()->findByFile(mainScript()).type() == QLatin1String("application/x-qml"))
334
                qmlFileFound = true;
335 336 337
        }
        if (!editor
            || Core::ICore::instance()->mimeDatabase()->findByFile(mainScript()).type() == QLatin1String("application/x-qmlproject")) {
338
            // find a qml file with lowercase filename. This is slow but only done in initialization/other border cases.
339
            foreach(const QString &filename, m_projectTarget->qmlProject()->files()) {
340 341 342
                const QFileInfo fi(filename);

                if (!filename.isEmpty() && fi.baseName()[0].isLower()
343
                    && Core::ICore::instance()->mimeDatabase()->findByFile(fi).type() == QLatin1String("application/x-qml"))
344 345
                {
                    m_currentFileFilename = filename;
346
                    qmlFileFound = true;
347 348 349 350
                    break;
                }

            }
351
        }
352 353 354 355 356
    } else { // use default one
        qmlFileFound = !m_mainScriptFilename.isEmpty();
    }

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

358 359 360
    if (m_isEnabled != newValue) {
        m_isEnabled = newValue;
        emit isEnabledChanged(m_isEnabled);
361 362 363
    }
}

364
QString QmlProjectRunConfiguration::viewerDefaultPath() const
365
{
366 367
    QString path;

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
    // Search for QmlObserver
#ifdef Q_OS_MAC
    const QString qmlObserverName = QLatin1String("QMLObserver.app");
#else
    const QString qmlObserverName = QLatin1String("qmlobserver");
#endif

    QDir appDir(QCoreApplication::applicationDirPath());
    QString qmlObserverPath;
#ifdef Q_OS_WIN
    qmlObserverPath = appDir.absoluteFilePath(qmlObserverName + QLatin1String(".exe"));
#else
    qmlObserverPath = appDir.absoluteFilePath(qmlObserverName);
#endif
    if (QFileInfo(qmlObserverPath).exists()) {
        return qmlObserverPath;
    }

    // Search for QmlViewer

388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
    // prepend creator/bin dir to search path (only useful for special creator-qml package)
    const QString searchPath = QCoreApplication::applicationDirPath()
            + Utils::SynchronousProcess::pathSeparator()
            + QString::fromLocal8Bit(qgetenv("PATH"));

#ifdef Q_OS_MAC
    const QString qmlViewerName = QLatin1String("QMLViewer");
#else
    const QString qmlViewerName = QLatin1String("qmlviewer");
#endif

    path = Utils::SynchronousProcess::locateBinary(searchPath, qmlViewerName);
    if (!path.isEmpty())
        return path;

    // Try to locate default path in Qt Versions
    Qt4ProjectManager::QtVersionManager *qtVersions = Qt4ProjectManager::QtVersionManager::instance();
    foreach (Qt4ProjectManager::QtVersion *version, qtVersions->validVersions()) {
        if (!version->qmlviewerCommand().isEmpty()
                && version->supportsTargetId(Qt4ProjectManager::Constants::DESKTOP_TARGET_ID)) {
            return version->qmlviewerCommand();
        }
    }

    return path;
413 414
}

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