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"
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 164

    Utils::PathChooser *qmlViewer = new Utils::PathChooser;
    qmlViewer->setExpectedKind(Utils::PathChooser::Command);
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
    QLabel *debuggerLabel = new QLabel(tr("Debugger:"), config);
    Utils::DebuggerLanguageChooser *debuggerLanguageChooser = new Utils::DebuggerLanguageChooser(config);

183
    form->addRow(tr("Main QML File:"), m_fileListCombo.data());
184 185 186 187
    form->addRow(debuggerLabel, debuggerLanguageChooser);

    debuggerLanguageChooser->setCppChecked(useCppDebugger());
    debuggerLanguageChooser->setQmlChecked(useQmlDebugger());
188
    debuggerLanguageChooser->setQmlDebugServerPort(qmlDebugServerPort());
189 190 191 192 193

    connect(debuggerLanguageChooser, SIGNAL(cppLanguageToggled(bool)),
            this, SLOT(useCppDebuggerToggled(bool)));
    connect(debuggerLanguageChooser, SIGNAL(qmlLanguageToggled(bool)),
            this, SLOT(useQmlDebuggerToggled(bool)));
194 195
    connect(debuggerLanguageChooser, SIGNAL(qmlDebugServerPortChanged(uint)),
            this, SLOT(qmlDebugServerPortChanged(uint)));
Kai Koehne's avatar
Kai Koehne committed
196 197 198 199

    return config;
}

200

Kai Koehne's avatar
Kai Koehne committed
201 202
QString QmlProjectRunConfiguration::mainScript() const
{
203 204
    if (m_usingCurrentFile)
        return m_currentFileFilename;
Kai Koehne's avatar
Kai Koehne committed
205

206
    return m_mainScriptFilename;
Kai Koehne's avatar
Kai Koehne committed
207 208
}

209 210 211 212 213 214 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
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
241 242 243
void QmlProjectRunConfiguration::setMainScript(const QString &scriptFile)
{
    m_scriptFile = scriptFile;
244 245 246
    // replace with locale-agnostic string
    if (m_scriptFile == CURRENT_FILE)
        m_scriptFile = M_CURRENT_FILE;
247

248
    if (m_scriptFile.isEmpty() || m_scriptFile == M_CURRENT_FILE) {
249 250 251 252 253
        m_usingCurrentFile = true;
        changeCurrentFile(Core::EditorManager::instance()->currentEditor());
    } else {
        m_usingCurrentFile = false;
        m_mainScriptFilename = qmlTarget()->qmlProject()->projectDir().absoluteFilePath(scriptFile);
254
        updateEnabled();
255
    }
Kai Koehne's avatar
Kai Koehne committed
256 257
}

258
void QmlProjectRunConfiguration::onViewerChanged()
Kai Koehne's avatar
Kai Koehne committed
259 260 261 262
{
    if (Utils::PathChooser *chooser = qobject_cast<Utils::PathChooser *>(sender())) {
        m_qmlViewerCustomPath = chooser->path();
    }
263 264 265
    if (!m_qmlViewerExecutable.isNull()) {
        m_qmlViewerExecutable.data()->setText(viewerPath() + " " + m_qmlViewerArgs);
    }
Kai Koehne's avatar
Kai Koehne committed
266 267
}

268
void QmlProjectRunConfiguration::onViewerArgsChanged()
Kai Koehne's avatar
Kai Koehne committed
269 270 271
{
    if (QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender()))
        m_qmlViewerArgs = lineEdit->text();
272 273 274 275

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

278 279 280 281 282 283 284 285 286 287
void QmlProjectRunConfiguration::useCppDebuggerToggled(bool toggled)
{
    setUseCppDebugger(toggled);
}

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

288 289 290 291
void QmlProjectRunConfiguration::qmlDebugServerPortChanged(uint port)
{
    setQmlDebugServerPort(port);
}
292

Kai Koehne's avatar
Kai Koehne committed
293 294 295 296 297 298 299 300 301 302 303 304 305 306
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();
307
    m_scriptFile = map.value(QLatin1String(Constants::QML_MAINSCRIPT_KEY), M_CURRENT_FILE).toString();
308
    setMainScript(m_scriptFile);
Kai Koehne's avatar
Kai Koehne committed
309 310 311 312

    return RunConfiguration::fromMap(map);
}

313 314 315 316 317 318
void QmlProjectRunConfiguration::changeCurrentFile(Core::IEditor * /*editor*/)
{
    updateEnabled();
}

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

                if (!filename.isEmpty() && fi.baseName()[0].isLower()
335
                    && Core::ICore::instance()->mimeDatabase()->findByFile(fi).type() == QLatin1String("application/x-qml"))
336 337
                {
                    m_currentFileFilename = filename;
338
                    qmlFileFound = true;
339 340 341 342
                    break;
                }

            }
343
        }
344 345 346 347 348
    } else { // use default one
        qmlFileFound = !m_mainScriptFilename.isEmpty();
    }

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

350 351 352
    if (m_isEnabled != newValue) {
        m_isEnabled = newValue;
        emit isEnabledChanged(m_isEnabled);
353 354 355
    }
}

356
QString QmlProjectRunConfiguration::viewerDefaultPath() const
357
{
358 359
    QString path;

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
    // 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

380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
    // 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;
405 406
}

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