qmlprojectrunconfiguration.cpp 15.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"
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
{
    ctor();
70
    updateQtVersions();
Kai Koehne's avatar
Kai Koehne committed
71 72 73 74
}

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

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

89
    return m_isEnabled;
90 91
}

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

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

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

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

QmlProjectRunConfiguration::~QmlProjectRunConfiguration()
{
}

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

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

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

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

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

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

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

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

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

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

177 178 179 180 181 182 183 184 185 186 187 188
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;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

255 256 257
    updateQtVersions();
    updateEnabled();

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

261

Kai Koehne's avatar
Kai Koehne committed
262 263
QString QmlProjectRunConfiguration::mainScript() const
{
264 265
    if (m_usingCurrentFile)
        return m_currentFileFilename;
Kai Koehne's avatar
Kai Koehne committed
266

267
    return m_mainScriptFilename;
Kai Koehne's avatar
Kai Koehne committed
268 269
}

270 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
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
302 303 304
void QmlProjectRunConfiguration::setMainScript(const QString &scriptFile)
{
    m_scriptFile = scriptFile;
305 306 307
    // replace with locale-agnostic string
    if (m_scriptFile == CURRENT_FILE)
        m_scriptFile = M_CURRENT_FILE;
308

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

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

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

333 334 335 336 337 338 339 340 341 342
void QmlProjectRunConfiguration::useCppDebuggerToggled(bool toggled)
{
    setUseCppDebugger(toggled);
}

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

343 344 345 346
void QmlProjectRunConfiguration::qmlDebugServerPortChanged(uint port)
{
    setQmlDebugServerPort(port);
}
347

Kai Koehne's avatar
Kai Koehne committed
348 349 350 351
QVariantMap QmlProjectRunConfiguration::toMap() const
{
    QVariantMap map(ProjectExplorer::RunConfiguration::toMap());

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

    updateQtVersions();
365
    setMainScript(m_scriptFile);
Kai Koehne's avatar
Kai Koehne committed
366 367 368 369

    return RunConfiguration::fromMap(map);
}

370 371 372 373 374 375
void QmlProjectRunConfiguration::changeCurrentFile(Core::IEditor * /*editor*/)
{
    updateEnabled();
}

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

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

            }
400
        }
401 402 403 404
    } else { // use default one
        qmlFileFound = !m_mainScriptFilename.isEmpty();
    }

405 406
    bool newValue = (QFileInfo(viewerPath()).exists()
                    || QFileInfo(observerPath()).exists()) && qmlFileFound;
407

408 409 410 411

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

414
void QmlProjectRunConfiguration::updateQtVersions()
415
{
416
    Qt4ProjectManager::QtVersionManager *qtVersions = Qt4ProjectManager::QtVersionManager::instance();
417 418 419 420 421 422

    //
    // update m_qtVersionId
    //
    if (!qtVersions->isValidId(m_qtVersionId)
            || !isValidVersion(qtVersions->version(m_qtVersionId))) {
423
        int newVersionId = -1;
424 425 426
        // take first one you find
        foreach (Qt4ProjectManager::QtVersion *version, qtVersions->validVersions()) {
            if (isValidVersion(version)) {
427
                newVersionId = version->uniqueId();
428 429
                break;
            }
430
        }
431
        setQtVersionId(newVersionId);
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 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
            && version->supportsTargetId(Qt4ProjectManager::Constants::DESKTOP_TARGET_ID)
            && !version->qmlviewerCommand().isEmpty()) {
        return true;
    }
    return false;
476 477
}

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