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

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

namespace QmlProjectManager {

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

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

83 84 85 86
bool QmlProjectRunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *bc) const
{
    Q_UNUSED(bc);

87
    return m_isEnabled;
88 89
}

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

96 97 98 99
    Core::EditorManager *em = Core::EditorManager::instance();
    connect(em, SIGNAL(currentEditorChanged(Core::IEditor*)),
            this, SLOT(changeCurrentFile(Core::IEditor*)));

100
    Qt4ProjectManager::QtVersionManager *qtVersions = Qt4ProjectManager::QtVersionManager::instance();
101
    connect(qtVersions, SIGNAL(qtVersionsChanged(QList<int>)), this, SLOT(updateQtVersions()));
102

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

QmlProjectRunConfiguration::~QmlProjectRunConfiguration()
{
}

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

115
QString QmlProjectRunConfiguration::viewerPath() const
116
{
117 118
    Qt4ProjectManager::QtVersion *version = qtVersion();
    if (!version) {
119
        return QString();
120 121 122
    } else {
        return version->qmlviewerCommand();
    }
123 124
}

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

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

    // arguments in .user file
    if (!m_qmlViewerArgs.isEmpty())
141
        args.append(m_qmlViewerArgs.split(QLatin1Char(' ')));
Kai Koehne's avatar
Kai Koehne committed
142 143

    // arguments from .qmlproject file
144
    foreach (const QString &importPath, qmlTarget()->qmlProject()->importPaths()) {
145
        args.append(QLatin1String("-I"));
146
        args.append(importPath);
Kai Koehne's avatar
Kai Koehne committed
147 148 149 150 151 152 153 154 155 156 157 158 159 160
    }

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

161 162 163 164 165 166 167 168 169 170 171 172
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;
}

173 174 175 176 177
static bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
{
    return s1.toLower() < s2.toLower();
}

178
QWidget *QmlProjectRunConfiguration::createConfigurationWidget()
Kai Koehne's avatar
Kai Koehne committed
179
{
180 181 182 183 184 185 186
    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
187

188 189 190
    m_fileListCombo = new QComboBox;
    m_fileListCombo.data()->setModel(m_fileListModel);
    updateFileComboBox();
Kai Koehne's avatar
Kai Koehne committed
191

192 193
    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
194

195 196 197
    m_qtVersionComboBox = new QComboBox;
    m_qtVersionComboBox.data()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    connect(m_qtVersionComboBox.data(), SIGNAL(activated(int)), this, SLOT(onQtVersionSelectionChanged()));
198

199 200 201
    QPushButton *pushButton = new QPushButton;
    pushButton->setText(tr("Manage Qt versions"));
    connect(pushButton, SIGNAL(clicked()), this, SLOT(manageQtVersions()));
Kai Koehne's avatar
Kai Koehne committed
202

203 204 205
    QHBoxLayout *qtVersionLayout = new QHBoxLayout;
    qtVersionLayout->addWidget(m_qtVersionComboBox.data());
    qtVersionLayout->addWidget(pushButton);
206

Kai Koehne's avatar
Kai Koehne committed
207 208
    QLineEdit *qmlViewerArgs = new QLineEdit;
    qmlViewerArgs->setText(m_qmlViewerArgs);
209
    connect(qmlViewerArgs, SIGNAL(textChanged(QString)), this, SLOT(onViewerArgsChanged()));
Kai Koehne's avatar
Kai Koehne committed
210

211
    form->addRow(tr("Qt version:"), qtVersionLayout);
212
    form->addRow(tr("Arguments:"), qmlViewerArgs);
Kai Koehne's avatar
Kai Koehne committed
213

214 215 216 217 218 219 220 221 222
    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);

223
    Utils::DebuggerLanguageChooser *debuggerLanguageChooser = new Utils::DebuggerLanguageChooser(formWidget);
224

Leena Miettinen's avatar
Leena Miettinen committed
225
    form->addRow(tr("Main QML file:"), m_fileListCombo.data());
226
    form->addRow(debuggerLabelWidget, debuggerLanguageChooser);
227 228 229

    debuggerLanguageChooser->setCppChecked(useCppDebugger());
    debuggerLanguageChooser->setQmlChecked(useQmlDebugger());
230
    debuggerLanguageChooser->setQmlDebugServerPort(qmlDebugServerPort());
231 232 233 234 235

    connect(debuggerLanguageChooser, SIGNAL(cppLanguageToggled(bool)),
            this, SLOT(useCppDebuggerToggled(bool)));
    connect(debuggerLanguageChooser, SIGNAL(qmlLanguageToggled(bool)),
            this, SLOT(useQmlDebuggerToggled(bool)));
236 237
    connect(debuggerLanguageChooser, SIGNAL(qmlDebugServerPortChanged(uint)),
            this, SLOT(qmlDebugServerPortChanged(uint)));
Kai Koehne's avatar
Kai Koehne committed
238

239 240 241
    updateQtVersions();
    updateEnabled();

242
    return detailsWidget;
Kai Koehne's avatar
Kai Koehne committed
243 244
}

245

Kai Koehne's avatar
Kai Koehne committed
246 247
QString QmlProjectRunConfiguration::mainScript() const
{
248 249
    if (m_usingCurrentFile)
        return m_currentFileFilename;
Kai Koehne's avatar
Kai Koehne committed
250

251
    return m_mainScriptFilename;
Kai Koehne's avatar
Kai Koehne committed
252 253
}

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
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
286 287 288
void QmlProjectRunConfiguration::setMainScript(const QString &scriptFile)
{
    m_scriptFile = scriptFile;
289 290 291
    // replace with locale-agnostic string
    if (m_scriptFile == CURRENT_FILE)
        m_scriptFile = M_CURRENT_FILE;
292

293
    if (m_scriptFile.isEmpty() || m_scriptFile == M_CURRENT_FILE) {
294 295 296 297 298
        m_usingCurrentFile = true;
        changeCurrentFile(Core::EditorManager::instance()->currentEditor());
    } else {
        m_usingCurrentFile = false;
        m_mainScriptFilename = qmlTarget()->qmlProject()->projectDir().absoluteFilePath(scriptFile);
299
        updateEnabled();
300
    }
Kai Koehne's avatar
Kai Koehne committed
301 302
}

303
void QmlProjectRunConfiguration::onQtVersionSelectionChanged()
Kai Koehne's avatar
Kai Koehne committed
304
{
305 306 307 308
    QVariant data = m_qtVersionComboBox.data()->itemData(m_qtVersionComboBox.data()->currentIndex());
    QTC_ASSERT(data.isValid() && data.canConvert(QVariant::Int), return)
    m_qtVersionId = data.toInt();
    updateEnabled();
Kai Koehne's avatar
Kai Koehne committed
309 310
}

311
void QmlProjectRunConfiguration::onViewerArgsChanged()
Kai Koehne's avatar
Kai Koehne committed
312 313 314 315 316
{
    if (QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender()))
        m_qmlViewerArgs = lineEdit->text();
}

317 318 319 320 321 322 323 324 325 326
void QmlProjectRunConfiguration::useCppDebuggerToggled(bool toggled)
{
    setUseCppDebugger(toggled);
}

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

327 328 329 330
void QmlProjectRunConfiguration::qmlDebugServerPortChanged(uint port)
{
    setQmlDebugServerPort(port);
}
331

Kai Koehne's avatar
Kai Koehne committed
332 333 334 335
QVariantMap QmlProjectRunConfiguration::toMap() const
{
    QVariantMap map(ProjectExplorer::RunConfiguration::toMap());

336
    map.insert(QLatin1String(Constants::QML_VIEWER_QT_KEY), m_qtVersionId);
Kai Koehne's avatar
Kai Koehne committed
337 338 339 340 341 342 343
    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)
{
344
    m_qtVersionId = map.value(QLatin1String(Constants::QML_VIEWER_QT_KEY), -1).toInt();
Kai Koehne's avatar
Kai Koehne committed
345
    m_qmlViewerArgs = map.value(QLatin1String(Constants::QML_VIEWER_ARGUMENTS_KEY)).toString();
346
    m_scriptFile = map.value(QLatin1String(Constants::QML_MAINSCRIPT_KEY), M_CURRENT_FILE).toString();
347 348

    updateQtVersions();
349
    setMainScript(m_scriptFile);
Kai Koehne's avatar
Kai Koehne committed
350 351 352 353

    return RunConfiguration::fromMap(map);
}

354 355 356 357 358 359
void QmlProjectRunConfiguration::changeCurrentFile(Core::IEditor * /*editor*/)
{
    updateEnabled();
}

void QmlProjectRunConfiguration::updateEnabled()
360
{
361
    bool qmlFileFound = false;
362
    if (m_usingCurrentFile) {
363
        Core::IEditor *editor = Core::EditorManager::instance()->currentEditor();
364 365
        if (editor) {
            m_currentFileFilename = editor->file()->fileName();
366
            if (Core::ICore::instance()->mimeDatabase()->findByFile(mainScript()).type() == QLatin1String("application/x-qml"))
367
                qmlFileFound = true;
368 369 370
        }
        if (!editor
            || Core::ICore::instance()->mimeDatabase()->findByFile(mainScript()).type() == QLatin1String("application/x-qmlproject")) {
371
            // find a qml file with lowercase filename. This is slow but only done in initialization/other border cases.
372
            foreach(const QString &filename, m_projectTarget->qmlProject()->files()) {
373 374 375
                const QFileInfo fi(filename);

                if (!filename.isEmpty() && fi.baseName()[0].isLower()
376
                    && Core::ICore::instance()->mimeDatabase()->findByFile(fi).type() == QLatin1String("application/x-qml"))
377 378
                {
                    m_currentFileFilename = filename;
379
                    qmlFileFound = true;
380 381 382 383
                    break;
                }

            }
384
        }
385 386 387 388
    } else { // use default one
        qmlFileFound = !m_mainScriptFilename.isEmpty();
    }

389 390
    bool newValue = (QFileInfo(viewerPath()).exists()
                    || QFileInfo(observerPath()).exists()) && qmlFileFound;
391

392 393 394 395

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

398
void QmlProjectRunConfiguration::updateQtVersions()
399
{
400
    Qt4ProjectManager::QtVersionManager *qtVersions = Qt4ProjectManager::QtVersionManager::instance();
401 402 403 404 405 406 407 408 409 410 411

    //
    // update m_qtVersionId
    //
    if (!qtVersions->isValidId(m_qtVersionId)
            || !isValidVersion(qtVersions->version(m_qtVersionId))) {
        m_qtVersionId = -1;
        // take first one you find
        foreach (Qt4ProjectManager::QtVersion *version, qtVersions->validVersions()) {
            if (isValidVersion(version)) {
                m_qtVersionId = version->uniqueId();
412 413
                break;
            }
414 415 416
        }
    }

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
    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
            && version->supportsTargetId(Qt4ProjectManager::Constants::DESKTOP_TARGET_ID)
            && !version->qmlviewerCommand().isEmpty()) {
        return true;
    }
    return false;
459 460
}

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