qmlprojectrunconfiguration.cpp 16 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
#include <utils/qtcassert.h>
46
#include <utils/qtcprocess.h>
47 48
#include <qt4projectmanager/qtversionmanager.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
49
#include <qt4projectmanager/qmlobservertool.h>
50
#include <qt4projectmanager/qtoutputformatter.h>
Kai Koehne's avatar
Kai Koehne committed
51 52 53 54

#include <QFormLayout>
#include <QComboBox>
#include <QLineEdit>
55
#include <QPushButton>
56
#include <QStringListModel>
Kai Koehne's avatar
Kai Koehne committed
57 58 59 60 61 62 63 64

using Core::EditorManager;
using Core::ICore;
using Core::IEditor;
using Utils::DebuggerLanguageChooser;
using Qt4ProjectManager::QtVersionManager;

using namespace QmlProjectManager::Internal;
Kai Koehne's avatar
Kai Koehne committed
65 66 67

namespace QmlProjectManager {

Kai Koehne's avatar
Kai Koehne committed
68 69 70 71
const char * const CURRENT_FILE  = QT_TRANSLATE_NOOP("QmlManager", "<Current File>");
const char * const M_CURRENT_FILE  = "CurrentFile";

QmlProjectRunConfiguration::QmlProjectRunConfiguration(QmlProjectTarget *parent) :
Kai Koehne's avatar
Kai Koehne committed
72
    ProjectExplorer::RunConfiguration(parent, QLatin1String(Constants::QML_RC_ID)),
73
    m_qtVersionId(-1),
74
    m_fileListModel(new QStringListModel(this)),
75
    m_projectTarget(parent),
76
    m_usingCurrentFile(true),
77
    m_isEnabled(false)
Kai Koehne's avatar
Kai Koehne committed
78 79
{
    ctor();
80
    updateQtVersions();
Kai Koehne's avatar
Kai Koehne committed
81 82
}

Kai Koehne's avatar
Kai Koehne committed
83 84
QmlProjectRunConfiguration::QmlProjectRunConfiguration(QmlProjectTarget *parent,
                                                       QmlProjectRunConfiguration *source) :
Kai Koehne's avatar
Kai Koehne committed
85
    ProjectExplorer::RunConfiguration(parent, source),
86
    m_qtVersionId(source->m_qtVersionId),
87
    m_qmlViewerArgs(source->m_qmlViewerArgs),
88
    m_fileListModel(new QStringListModel(this)),
89
    m_projectTarget(parent)
Kai Koehne's avatar
Kai Koehne committed
90
{
91 92
    ctor();
    setMainScript(source->m_scriptFile);
93
    updateQtVersions();
Kai Koehne's avatar
Kai Koehne committed
94 95
}

96 97 98 99
bool QmlProjectRunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *bc) const
{
    Q_UNUSED(bc);

100
    return m_isEnabled;
101 102
}

Kai Koehne's avatar
Kai Koehne committed
103 104
void QmlProjectRunConfiguration::ctor()
{
105 106 107 108
    // reset default settings in constructor
    setUseCppDebugger(false);
    setUseQmlDebugger(true);

Kai Koehne's avatar
Kai Koehne committed
109
    EditorManager *em = Core::EditorManager::instance();
110 111 112
    connect(em, SIGNAL(currentEditorChanged(Core::IEditor*)),
            this, SLOT(changeCurrentFile(Core::IEditor*)));

Kai Koehne's avatar
Kai Koehne committed
113
    QtVersionManager *qtVersions = QtVersionManager::instance();
114
    connect(qtVersions, SIGNAL(qtVersionsChanged(QList<int>)), this, SLOT(updateQtVersions()));
115

116
    setDisplayName(tr("QML Viewer", "QMLRunConfiguration display name."));
Kai Koehne's avatar
Kai Koehne committed
117 118 119 120 121 122
}

QmlProjectRunConfiguration::~QmlProjectRunConfiguration()
{
}

Kai Koehne's avatar
Kai Koehne committed
123
QmlProjectTarget *QmlProjectRunConfiguration::qmlTarget() const
Kai Koehne's avatar
Kai Koehne committed
124
{
Kai Koehne's avatar
Kai Koehne committed
125
    return static_cast<QmlProjectTarget *>(target());
Kai Koehne's avatar
Kai Koehne committed
126 127
}

128
QString QmlProjectRunConfiguration::viewerPath() const
129
{
130 131
    Qt4ProjectManager::QtVersion *version = qtVersion();
    if (!version) {
132
        return QString();
133 134 135
    } else {
        return version->qmlviewerCommand();
    }
136 137
}

138
QString QmlProjectRunConfiguration::observerPath() const
Kai Koehne's avatar
Kai Koehne committed
139
{
140 141
    Qt4ProjectManager::QtVersion *version = qtVersion();
    if (!version) {
142
        return QString();
143 144 145
    } else {
        return version->qmlObserverTool();
    }
Kai Koehne's avatar
Kai Koehne committed
146 147
}

148
QString QmlProjectRunConfiguration::viewerArguments() const
Kai Koehne's avatar
Kai Koehne committed
149 150
{
    // arguments in .user file
151
    QString args = m_qmlViewerArgs;
Kai Koehne's avatar
Kai Koehne committed
152 153

    // arguments from .qmlproject file
154
    foreach (const QString &importPath, qmlTarget()->qmlProject()->importPaths()) {
155 156
        Utils::QtcProcess::addArg(&args, "-I");
        Utils::QtcProcess::addArg(&args, importPath);
Kai Koehne's avatar
Kai Koehne committed
157 158
    }

159 160 161
    const QString &s = mainScript();
    if (!s.isEmpty())
        Utils::QtcProcess::addArg(&args, s);
Kai Koehne's avatar
Kai Koehne committed
162 163 164 165 166 167 168 169 170
    return args;
}

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

171 172 173 174 175
int QmlProjectRunConfiguration::qtVersionId() const
{
    return m_qtVersionId;
}

176 177 178 179 180 181 182 183 184
void QmlProjectRunConfiguration::setQtVersionId(int id)
{
    if (m_qtVersionId == id)
        return;

    m_qtVersionId = id;
    qmlTarget()->qmlProject()->refresh(QmlProject::Configuration);
}

185 186 187 188 189
Qt4ProjectManager::QtVersion *QmlProjectRunConfiguration::qtVersion() const
{
    if (m_qtVersionId == -1)
        return 0;

Kai Koehne's avatar
Kai Koehne committed
190
    QtVersionManager *versionManager = QtVersionManager::instance();
191 192 193 194 195 196
    Qt4ProjectManager::QtVersion *version = versionManager->version(m_qtVersionId);
    QTC_ASSERT(version, return 0);

    return version;
}

197 198 199 200 201
static bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
{
    return s1.toLower() < s2.toLower();
}

202
QWidget *QmlProjectRunConfiguration::createConfigurationWidget()
Kai Koehne's avatar
Kai Koehne committed
203
{
204 205 206 207 208 209 210
    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
211

212 213 214
    m_fileListCombo = new QComboBox;
    m_fileListCombo.data()->setModel(m_fileListModel);
    updateFileComboBox();
Kai Koehne's avatar
Kai Koehne committed
215

Kai Koehne's avatar
Kai Koehne committed
216 217 218 219
    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
220

221 222
    m_qtVersionComboBox = new QComboBox;
    m_qtVersionComboBox.data()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
Kai Koehne's avatar
Kai Koehne committed
223 224
    connect(m_qtVersionComboBox.data(), SIGNAL(activated(int)),
            this, SLOT(onQtVersionSelectionChanged()));
225

226 227 228
    QPushButton *pushButton = new QPushButton;
    pushButton->setText(tr("Manage Qt versions"));
    connect(pushButton, SIGNAL(clicked()), this, SLOT(manageQtVersions()));
Kai Koehne's avatar
Kai Koehne committed
229

230 231 232
    QHBoxLayout *qtVersionLayout = new QHBoxLayout;
    qtVersionLayout->addWidget(m_qtVersionComboBox.data());
    qtVersionLayout->addWidget(pushButton);
233

Kai Koehne's avatar
Kai Koehne committed
234 235
    QLineEdit *qmlViewerArgs = new QLineEdit;
    qmlViewerArgs->setText(m_qmlViewerArgs);
236
    connect(qmlViewerArgs, SIGNAL(textChanged(QString)), this, SLOT(onViewerArgsChanged()));
Kai Koehne's avatar
Kai Koehne committed
237

238
    form->addRow(tr("Qt version:"), qtVersionLayout);
239
    form->addRow(tr("Arguments:"), qmlViewerArgs);
Kai Koehne's avatar
Kai Koehne committed
240

241 242 243 244 245 246 247 248 249
    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);

Kai Koehne's avatar
Kai Koehne committed
250
    DebuggerLanguageChooser *debuggerLanguageChooser = new DebuggerLanguageChooser(formWidget);
251

Leena Miettinen's avatar
Leena Miettinen committed
252
    form->addRow(tr("Main QML file:"), m_fileListCombo.data());
253
    form->addRow(debuggerLabelWidget, debuggerLanguageChooser);
254 255 256

    debuggerLanguageChooser->setCppChecked(useCppDebugger());
    debuggerLanguageChooser->setQmlChecked(useQmlDebugger());
257
    debuggerLanguageChooser->setQmlDebugServerPort(qmlDebugServerPort());
258 259 260 261 262

    connect(debuggerLanguageChooser, SIGNAL(cppLanguageToggled(bool)),
            this, SLOT(useCppDebuggerToggled(bool)));
    connect(debuggerLanguageChooser, SIGNAL(qmlLanguageToggled(bool)),
            this, SLOT(useQmlDebuggerToggled(bool)));
263 264
    connect(debuggerLanguageChooser, SIGNAL(qmlDebugServerPortChanged(uint)),
            this, SLOT(qmlDebugServerPortChanged(uint)));
Kai Koehne's avatar
Kai Koehne committed
265

266 267 268
    updateQtVersions();
    updateEnabled();

269
    return detailsWidget;
Kai Koehne's avatar
Kai Koehne committed
270 271
}

272 273 274 275
ProjectExplorer::OutputFormatter *QmlProjectRunConfiguration::createOutputFormatter() const
{
    return new Qt4ProjectManager::QtOutputFormatter(qmlTarget()->qmlProject());
}
276

Kai Koehne's avatar
Kai Koehne committed
277 278
QString QmlProjectRunConfiguration::mainScript() const
{
279 280
    if (m_usingCurrentFile)
        return m_currentFileFilename;
Kai Koehne's avatar
Kai Koehne committed
281

282
    return m_mainScriptFilename;
Kai Koehne's avatar
Kai Koehne committed
283 284
}

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
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
317 318 319
void QmlProjectRunConfiguration::setMainScript(const QString &scriptFile)
{
    m_scriptFile = scriptFile;
320 321 322
    // replace with locale-agnostic string
    if (m_scriptFile == CURRENT_FILE)
        m_scriptFile = M_CURRENT_FILE;
323

324
    if (m_scriptFile.isEmpty() || m_scriptFile == M_CURRENT_FILE) {
325 326 327 328 329
        m_usingCurrentFile = true;
        changeCurrentFile(Core::EditorManager::instance()->currentEditor());
    } else {
        m_usingCurrentFile = false;
        m_mainScriptFilename = qmlTarget()->qmlProject()->projectDir().absoluteFilePath(scriptFile);
330
        updateEnabled();
331
    }
Kai Koehne's avatar
Kai Koehne committed
332 333
}

334
void QmlProjectRunConfiguration::onQtVersionSelectionChanged()
Kai Koehne's avatar
Kai Koehne committed
335
{
336 337
    QVariant data = m_qtVersionComboBox.data()->itemData(m_qtVersionComboBox.data()->currentIndex());
    QTC_ASSERT(data.isValid() && data.canConvert(QVariant::Int), return)
338
    setQtVersionId(data.toInt());
339
    updateEnabled();
Kai Koehne's avatar
Kai Koehne committed
340 341
}

342
void QmlProjectRunConfiguration::onViewerArgsChanged()
Kai Koehne's avatar
Kai Koehne committed
343 344 345 346 347
{
    if (QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender()))
        m_qmlViewerArgs = lineEdit->text();
}

348 349 350
void QmlProjectRunConfiguration::useCppDebuggerToggled(bool toggled)
{
    setUseCppDebugger(toggled);
351
    updateEnabled();
352 353 354 355 356
}

void QmlProjectRunConfiguration::useQmlDebuggerToggled(bool toggled)
{
    setUseQmlDebugger(toggled);
357
    updateEnabled();
358 359
}

360 361 362 363
void QmlProjectRunConfiguration::qmlDebugServerPortChanged(uint port)
{
    setQmlDebugServerPort(port);
}
364

Kai Koehne's avatar
Kai Koehne committed
365 366 367 368
QVariantMap QmlProjectRunConfiguration::toMap() const
{
    QVariantMap map(ProjectExplorer::RunConfiguration::toMap());

369
    map.insert(QLatin1String(Constants::QML_VIEWER_QT_KEY), m_qtVersionId);
Kai Koehne's avatar
Kai Koehne committed
370 371 372 373 374 375 376
    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)
{
377
    setQtVersionId(map.value(QLatin1String(Constants::QML_VIEWER_QT_KEY), -1).toInt());
Kai Koehne's avatar
Kai Koehne committed
378
    m_qmlViewerArgs = map.value(QLatin1String(Constants::QML_VIEWER_ARGUMENTS_KEY)).toString();
379
    m_scriptFile = map.value(QLatin1String(Constants::QML_MAINSCRIPT_KEY), M_CURRENT_FILE).toString();
380 381

    updateQtVersions();
382
    setMainScript(m_scriptFile);
Kai Koehne's avatar
Kai Koehne committed
383 384 385 386

    return RunConfiguration::fromMap(map);
}

387 388 389 390 391 392
void QmlProjectRunConfiguration::changeCurrentFile(Core::IEditor * /*editor*/)
{
    updateEnabled();
}

void QmlProjectRunConfiguration::updateEnabled()
393
{
394
    bool qmlFileFound = false;
395
    if (m_usingCurrentFile) {
396
        Core::IEditor *editor = Core::EditorManager::instance()->currentEditor();
Kai Koehne's avatar
Kai Koehne committed
397
        Core::MimeDatabase *db = ICore::instance()->mimeDatabase();
398 399
        if (editor) {
            m_currentFileFilename = editor->file()->fileName();
Kai Koehne's avatar
Kai Koehne committed
400
            if (db->findByFile(mainScript()).type() == QLatin1String("application/x-qml"))
401
                qmlFileFound = true;
402 403
        }
        if (!editor
Kai Koehne's avatar
Kai Koehne committed
404 405 406
            || db->findByFile(mainScript()).type() == QLatin1String("application/x-qmlproject")) {
            // find a qml file with lowercase filename. This is slow, but only done
            // in initialization/other border cases.
407
            foreach(const QString &filename, m_projectTarget->qmlProject()->files()) {
408 409 410
                const QFileInfo fi(filename);

                if (!filename.isEmpty() && fi.baseName()[0].isLower()
Kai Koehne's avatar
Kai Koehne committed
411
                    && db->findByFile(fi).type() == QLatin1String("application/x-qml"))
412 413
                {
                    m_currentFileFilename = filename;
414
                    qmlFileFound = true;
415 416 417 418
                    break;
                }

            }
419
        }
420 421 422 423
    } else { // use default one
        qmlFileFound = !m_mainScriptFilename.isEmpty();
    }

424 425
    bool newValue = (QFileInfo(viewerPath()).exists()
                    || QFileInfo(observerPath()).exists()) && qmlFileFound;
426

427 428 429 430

    // Always emit change signal to force reevaluation of run/debug buttons
    m_isEnabled = newValue;
    emit isEnabledChanged(m_isEnabled);
431 432
}

433
void QmlProjectRunConfiguration::updateQtVersions()
434
{
Kai Koehne's avatar
Kai Koehne committed
435
    QtVersionManager *qtVersions = QtVersionManager::instance();
436 437 438 439 440 441

    //
    // update m_qtVersionId
    //
    if (!qtVersions->isValidId(m_qtVersionId)
            || !isValidVersion(qtVersions->version(m_qtVersionId))) {
442
        int newVersionId = -1;
443 444 445
        // take first one you find
        foreach (Qt4ProjectManager::QtVersion *version, qtVersions->validVersions()) {
            if (isValidVersion(version)) {
446
                newVersionId = version->uniqueId();
447 448
                break;
            }
449
        }
450
        setQtVersionId(newVersionId);
451 452
    }

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
    updateEnabled();

    if (!m_qtVersionComboBox)
        return;

    //
    // update combobox
    //
    m_qtVersionComboBox.data()->clear();

    foreach (Qt4ProjectManager::QtVersion *version, qtVersions->validVersions()) {
        if (isValidVersion(version)) {
            m_qtVersionComboBox.data()->addItem(version->displayName(), version->uniqueId());
        }
    }

    if (m_qtVersionId != -1) {
        int index = m_qtVersionComboBox.data()->findData(m_qtVersionId);
        QTC_ASSERT(index >= 0, return);
        m_qtVersionComboBox.data()->setCurrentIndex(index);
    } else {
        m_qtVersionComboBox.data()->addItem(tr("Invalid Qt version"), -1);
        m_qtVersionComboBox.data()->setCurrentIndex(0);
    }

}

void QmlProjectRunConfiguration::manageQtVersions()
{
Kai Koehne's avatar
Kai Koehne committed
482
    ICore *core = ICore::instance();
483 484 485 486 487 488 489
    core->showOptionsDialog(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY,
                            Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID);
}

bool QmlProjectRunConfiguration::isValidVersion(Qt4ProjectManager::QtVersion *version)
{
    if (version
490 491
            && (version->supportsTargetId(Qt4ProjectManager::Constants::DESKTOP_TARGET_ID)
                || version->supportsTargetId(Qt4ProjectManager::Constants::QT_SIMULATOR_TARGET_ID))
492 493 494 495
            && !version->qmlviewerCommand().isEmpty()) {
        return true;
    }
    return false;
496 497
}

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