qmlprojectrunconfiguration.cpp 15.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"
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 55

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

namespace QmlProjectManager {

QmlProjectRunConfiguration::QmlProjectRunConfiguration(Internal::QmlProjectTarget *parent) :
    ProjectExplorer::RunConfiguration(parent, QLatin1String(Constants::QML_RC_ID)),
65
    m_qtVersionId(-1),
66
    m_fileListModel(new QStringListModel(this)),
67
    m_projectTarget(parent),
68
    m_usingCurrentFile(true),
69
    m_isEnabled(false)
Kai Koehne's avatar
Kai Koehne committed
70 71
{
    ctor();
72
    updateQtVersions();
Kai Koehne's avatar
Kai Koehne committed
73 74 75 76
}

QmlProjectRunConfiguration::QmlProjectRunConfiguration(Internal::QmlProjectTarget *parent, QmlProjectRunConfiguration *source) :
    ProjectExplorer::RunConfiguration(parent, source),
77
    m_qtVersionId(source->m_qtVersionId),
78
    m_qmlViewerArgs(source->m_qmlViewerArgs),
79
    m_fileListModel(new QStringListModel(this)),
80
    m_projectTarget(parent)
Kai Koehne's avatar
Kai Koehne committed
81
{
82 83
    ctor();
    setMainScript(source->m_scriptFile);
84
    updateQtVersions();
Kai Koehne's avatar
Kai Koehne committed
85 86
}

87 88 89 90
bool QmlProjectRunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *bc) const
{
    Q_UNUSED(bc);

91
    return m_isEnabled;
92 93
}

Kai Koehne's avatar
Kai Koehne committed
94 95
void QmlProjectRunConfiguration::ctor()
{
96 97 98 99
    // reset default settings in constructor
    setUseCppDebugger(false);
    setUseQmlDebugger(true);

100 101 102 103
    Core::EditorManager *em = Core::EditorManager::instance();
    connect(em, SIGNAL(currentEditorChanged(Core::IEditor*)),
            this, SLOT(changeCurrentFile(Core::IEditor*)));

104
    Qt4ProjectManager::QtVersionManager *qtVersions = Qt4ProjectManager::QtVersionManager::instance();
105
    connect(qtVersions, SIGNAL(qtVersionsChanged(QList<int>)), this, SLOT(updateQtVersions()));
106

107
    setDisplayName(tr("QML Viewer", "QMLRunConfiguration display name."));
Kai Koehne's avatar
Kai Koehne committed
108 109 110 111 112 113 114 115 116 117 118
}

QmlProjectRunConfiguration::~QmlProjectRunConfiguration()
{
}

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

119
QString QmlProjectRunConfiguration::viewerPath() const
120
{
121 122
    Qt4ProjectManager::QtVersion *version = qtVersion();
    if (!version) {
123
        return QString();
124 125 126
    } else {
        return version->qmlviewerCommand();
    }
127 128
}

129
QString QmlProjectRunConfiguration::observerPath() const
Kai Koehne's avatar
Kai Koehne committed
130
{
131 132
    Qt4ProjectManager::QtVersion *version = qtVersion();
    if (!version) {
133
        return QString();
134 135 136
    } else {
        return version->qmlObserverTool();
    }
Kai Koehne's avatar
Kai Koehne committed
137 138
}

139
QString QmlProjectRunConfiguration::viewerArguments() const
Kai Koehne's avatar
Kai Koehne committed
140 141
{
    // arguments in .user file
142
    QString args = m_qmlViewerArgs;
Kai Koehne's avatar
Kai Koehne committed
143 144

    // arguments from .qmlproject file
145
    foreach (const QString &importPath, qmlTarget()->qmlProject()->importPaths()) {
146 147
        Utils::QtcProcess::addArg(&args, "-I");
        Utils::QtcProcess::addArg(&args, importPath);
Kai Koehne's avatar
Kai Koehne committed
148 149
    }

150 151 152
    const QString &s = mainScript();
    if (!s.isEmpty())
        Utils::QtcProcess::addArg(&args, s);
Kai Koehne's avatar
Kai Koehne committed
153 154 155 156 157 158 159 160 161
    return args;
}

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

162 163 164 165 166
int QmlProjectRunConfiguration::qtVersionId() const
{
    return m_qtVersionId;
}

167 168 169 170 171 172 173 174 175
void QmlProjectRunConfiguration::setQtVersionId(int id)
{
    if (m_qtVersionId == id)
        return;

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

176 177 178 179 180 181 182 183 184 185 186 187
Qt4ProjectManager::QtVersion *QmlProjectRunConfiguration::qtVersion() const
{
    if (m_qtVersionId == -1)
        return 0;

    Qt4ProjectManager::QtVersionManager *versionManager = Qt4ProjectManager::QtVersionManager::instance();
    Qt4ProjectManager::QtVersion *version = versionManager->version(m_qtVersionId);
    QTC_ASSERT(version, return 0);

    return version;
}

188 189 190 191 192
static bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
{
    return s1.toLower() < s2.toLower();
}

193
QWidget *QmlProjectRunConfiguration::createConfigurationWidget()
Kai Koehne's avatar
Kai Koehne committed
194
{
195 196 197 198 199 200 201
    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
202

203 204 205
    m_fileListCombo = new QComboBox;
    m_fileListCombo.data()->setModel(m_fileListModel);
    updateFileComboBox();
Kai Koehne's avatar
Kai Koehne committed
206

207 208
    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
209

210 211 212
    m_qtVersionComboBox = new QComboBox;
    m_qtVersionComboBox.data()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    connect(m_qtVersionComboBox.data(), SIGNAL(activated(int)), this, SLOT(onQtVersionSelectionChanged()));
213

214 215 216
    QPushButton *pushButton = new QPushButton;
    pushButton->setText(tr("Manage Qt versions"));
    connect(pushButton, SIGNAL(clicked()), this, SLOT(manageQtVersions()));
Kai Koehne's avatar
Kai Koehne committed
217

218 219 220
    QHBoxLayout *qtVersionLayout = new QHBoxLayout;
    qtVersionLayout->addWidget(m_qtVersionComboBox.data());
    qtVersionLayout->addWidget(pushButton);
221

Kai Koehne's avatar
Kai Koehne committed
222 223
    QLineEdit *qmlViewerArgs = new QLineEdit;
    qmlViewerArgs->setText(m_qmlViewerArgs);
224
    connect(qmlViewerArgs, SIGNAL(textChanged(QString)), this, SLOT(onViewerArgsChanged()));
Kai Koehne's avatar
Kai Koehne committed
225

226
    form->addRow(tr("Qt version:"), qtVersionLayout);
227
    form->addRow(tr("Arguments:"), qmlViewerArgs);
Kai Koehne's avatar
Kai Koehne committed
228

229 230 231 232 233 234 235 236 237
    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);

238
    Utils::DebuggerLanguageChooser *debuggerLanguageChooser = new Utils::DebuggerLanguageChooser(formWidget);
239

Leena Miettinen's avatar
Leena Miettinen committed
240
    form->addRow(tr("Main QML file:"), m_fileListCombo.data());
241
    form->addRow(debuggerLabelWidget, debuggerLanguageChooser);
242 243 244

    debuggerLanguageChooser->setCppChecked(useCppDebugger());
    debuggerLanguageChooser->setQmlChecked(useQmlDebugger());
245
    debuggerLanguageChooser->setQmlDebugServerPort(qmlDebugServerPort());
246 247 248 249 250

    connect(debuggerLanguageChooser, SIGNAL(cppLanguageToggled(bool)),
            this, SLOT(useCppDebuggerToggled(bool)));
    connect(debuggerLanguageChooser, SIGNAL(qmlLanguageToggled(bool)),
            this, SLOT(useQmlDebuggerToggled(bool)));
251 252
    connect(debuggerLanguageChooser, SIGNAL(qmlDebugServerPortChanged(uint)),
            this, SLOT(qmlDebugServerPortChanged(uint)));
Kai Koehne's avatar
Kai Koehne committed
253

254 255 256
    updateQtVersions();
    updateEnabled();

257
    return detailsWidget;
Kai Koehne's avatar
Kai Koehne committed
258 259
}

260 261 262 263
ProjectExplorer::OutputFormatter *QmlProjectRunConfiguration::createOutputFormatter() const
{
    return new Qt4ProjectManager::QtOutputFormatter(qmlTarget()->qmlProject());
}
264

Kai Koehne's avatar
Kai Koehne committed
265 266
QString QmlProjectRunConfiguration::mainScript() const
{
267 268
    if (m_usingCurrentFile)
        return m_currentFileFilename;
Kai Koehne's avatar
Kai Koehne committed
269

270
    return m_mainScriptFilename;
Kai Koehne's avatar
Kai Koehne committed
271 272
}

273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
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
305 306 307
void QmlProjectRunConfiguration::setMainScript(const QString &scriptFile)
{
    m_scriptFile = scriptFile;
308 309 310
    // replace with locale-agnostic string
    if (m_scriptFile == CURRENT_FILE)
        m_scriptFile = M_CURRENT_FILE;
311

312
    if (m_scriptFile.isEmpty() || m_scriptFile == M_CURRENT_FILE) {
313 314 315 316 317
        m_usingCurrentFile = true;
        changeCurrentFile(Core::EditorManager::instance()->currentEditor());
    } else {
        m_usingCurrentFile = false;
        m_mainScriptFilename = qmlTarget()->qmlProject()->projectDir().absoluteFilePath(scriptFile);
318
        updateEnabled();
319
    }
Kai Koehne's avatar
Kai Koehne committed
320 321
}

322
void QmlProjectRunConfiguration::onQtVersionSelectionChanged()
Kai Koehne's avatar
Kai Koehne committed
323
{
324 325
    QVariant data = m_qtVersionComboBox.data()->itemData(m_qtVersionComboBox.data()->currentIndex());
    QTC_ASSERT(data.isValid() && data.canConvert(QVariant::Int), return)
326
    setQtVersionId(data.toInt());
327
    updateEnabled();
Kai Koehne's avatar
Kai Koehne committed
328 329
}

330
void QmlProjectRunConfiguration::onViewerArgsChanged()
Kai Koehne's avatar
Kai Koehne committed
331 332 333 334 335
{
    if (QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender()))
        m_qmlViewerArgs = lineEdit->text();
}

336 337 338
void QmlProjectRunConfiguration::useCppDebuggerToggled(bool toggled)
{
    setUseCppDebugger(toggled);
339
    updateEnabled();
340 341 342 343 344
}

void QmlProjectRunConfiguration::useQmlDebuggerToggled(bool toggled)
{
    setUseQmlDebugger(toggled);
345
    updateEnabled();
346 347
}

348 349 350 351
void QmlProjectRunConfiguration::qmlDebugServerPortChanged(uint port)
{
    setQmlDebugServerPort(port);
}
352

Kai Koehne's avatar
Kai Koehne committed
353 354 355 356
QVariantMap QmlProjectRunConfiguration::toMap() const
{
    QVariantMap map(ProjectExplorer::RunConfiguration::toMap());

357
    map.insert(QLatin1String(Constants::QML_VIEWER_QT_KEY), m_qtVersionId);
Kai Koehne's avatar
Kai Koehne committed
358 359 360 361 362 363 364
    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)
{
365
    setQtVersionId(map.value(QLatin1String(Constants::QML_VIEWER_QT_KEY), -1).toInt());
Kai Koehne's avatar
Kai Koehne committed
366
    m_qmlViewerArgs = map.value(QLatin1String(Constants::QML_VIEWER_ARGUMENTS_KEY)).toString();
367
    m_scriptFile = map.value(QLatin1String(Constants::QML_MAINSCRIPT_KEY), M_CURRENT_FILE).toString();
368 369

    updateQtVersions();
370
    setMainScript(m_scriptFile);
Kai Koehne's avatar
Kai Koehne committed
371 372 373 374

    return RunConfiguration::fromMap(map);
}

375 376 377 378 379 380
void QmlProjectRunConfiguration::changeCurrentFile(Core::IEditor * /*editor*/)
{
    updateEnabled();
}

void QmlProjectRunConfiguration::updateEnabled()
381
{
382
    bool qmlFileFound = false;
383
    if (m_usingCurrentFile) {
384
        Core::IEditor *editor = Core::EditorManager::instance()->currentEditor();
385 386
        if (editor) {
            m_currentFileFilename = editor->file()->fileName();
387
            if (Core::ICore::instance()->mimeDatabase()->findByFile(mainScript()).type() == QLatin1String("application/x-qml"))
388
                qmlFileFound = true;
389 390 391
        }
        if (!editor
            || Core::ICore::instance()->mimeDatabase()->findByFile(mainScript()).type() == QLatin1String("application/x-qmlproject")) {
392
            // find a qml file with lowercase filename. This is slow but only done in initialization/other border cases.
393
            foreach(const QString &filename, m_projectTarget->qmlProject()->files()) {
394 395 396
                const QFileInfo fi(filename);

                if (!filename.isEmpty() && fi.baseName()[0].isLower()
397
                    && Core::ICore::instance()->mimeDatabase()->findByFile(fi).type() == QLatin1String("application/x-qml"))
398 399
                {
                    m_currentFileFilename = filename;
400
                    qmlFileFound = true;
401 402 403 404
                    break;
                }

            }
405
        }
406 407 408 409
    } else { // use default one
        qmlFileFound = !m_mainScriptFilename.isEmpty();
    }

410 411
    bool newValue = (QFileInfo(viewerPath()).exists()
                    || QFileInfo(observerPath()).exists()) && qmlFileFound;
412

413 414 415 416

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

419
void QmlProjectRunConfiguration::updateQtVersions()
420
{
421
    Qt4ProjectManager::QtVersionManager *qtVersions = Qt4ProjectManager::QtVersionManager::instance();
422 423 424 425 426 427

    //
    // update m_qtVersionId
    //
    if (!qtVersions->isValidId(m_qtVersionId)
            || !isValidVersion(qtVersions->version(m_qtVersionId))) {
428
        int newVersionId = -1;
429 430 431
        // take first one you find
        foreach (Qt4ProjectManager::QtVersion *version, qtVersions->validVersions()) {
            if (isValidVersion(version)) {
432
                newVersionId = version->uniqueId();
433 434
                break;
            }
435
        }
436
        setQtVersionId(newVersionId);
437 438
    }

439 440 441 442 443 444 445 446 447 448 449 450 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
    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()
{
    Core::ICore *core = Core::ICore::instance();
    core->showOptionsDialog(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY,
                            Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID);
}

bool QmlProjectRunConfiguration::isValidVersion(Qt4ProjectManager::QtVersion *version)
{
    if (version
476 477
            && (version->supportsTargetId(Qt4ProjectManager::Constants::DESKTOP_TARGET_ID)
                || version->supportsTargetId(Qt4ProjectManager::Constants::QT_SIMULATOR_TARGET_ID))
478 479 480 481
            && !version->qmlviewerCommand().isEmpty()) {
        return true;
    }
    return false;
482 483
}

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