qbsproject.cpp 22.7 KB
Newer Older
Tobias Hunger's avatar
Tobias Hunger committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qbsproject.h"

#include "qbsbuildconfiguration.h"
33
#include "qbslogsink.h"
Tobias Hunger's avatar
Tobias Hunger committed
34
35
36
37
38
39
40
41
42
43
44
45
#include "qbsprojectfile.h"
#include "qbsprojectmanagerconstants.h"
#include "qbsnodes.h"

#include <coreplugin/documentmanager.h>
#include <utils/qtcassert.h>

#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/id.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/mimedatabase.h>
46
#include <cpptools/cppmodelmanagerinterface.h>
Tobias Hunger's avatar
Tobias Hunger committed
47
#include <projectexplorer/buildenvironmentwidget.h>
48
49
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/deploymentdata.h>
Tobias Hunger's avatar
Tobias Hunger committed
50
51
52
53
54
55
#include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <projectexplorer/taskhub.h>
56
#include <projectexplorer/toolchain.h>
57
#include <projectexplorer/headerpath.h>
Tobias Hunger's avatar
Tobias Hunger committed
58
#include <qtsupport/qtkitinformation.h>
Tobias Hunger's avatar
Tobias Hunger committed
59
#include <qtsupport/uicodemodelsupport.h>
60
#include <qmljstools/qmljsmodelmanager.h>
Tobias Hunger's avatar
Tobias Hunger committed
61
62
63
64
65
66
67

#include <qmljs/qmljsmodelmanagerinterface.h>

#include <qbs.h>

#include <QFileInfo>

68
using namespace Core;
69
70
using namespace ProjectExplorer;
using namespace Utils;
71
72
73
74

namespace QbsProjectManager {
namespace Internal {

Tobias Hunger's avatar
Tobias Hunger committed
75
76
77
78
// --------------------------------------------------------------------
// Constants:
// --------------------------------------------------------------------

79
80
static const char CONFIG_CPP_MODULE[] = "cpp";
static const char CONFIG_CXXFLAGS[] = "cxxflags";
81
static const char CONFIG_CFLAGS[] = "cflags";
82
83
84
85
static const char CONFIG_DEFINES[] = "defines";
static const char CONFIG_INCLUDEPATHS[] = "includePaths";
static const char CONFIG_FRAMEWORKPATHS[] = "frameworkPaths";
static const char CONFIG_PRECOMPILEDHEADER[] = "precompiledHeader";
Tobias Hunger's avatar
Tobias Hunger committed
86
87
88
89
90
91
92
static const char CONFIGURATION_PATH[] = "<configuration>";

// --------------------------------------------------------------------
// QbsProject:
// --------------------------------------------------------------------

QbsProject::QbsProject(QbsManager *manager, const QString &fileName) :
93
94
95
    m_manager(manager),
    m_projectName(QFileInfo(fileName).completeBaseName()),
    m_fileName(fileName),
96
    m_rootProjectNode(0),
Tobias Hunger's avatar
Tobias Hunger committed
97
98
    m_qbsSetupProjectJob(0),
    m_qbsUpdateFutureInterface(0),
99
100
    m_currentProgressBase(0),
    m_forceParsing(false),
Tobias Hunger's avatar
Tobias Hunger committed
101
102
    m_currentBc(0)
{
103
    m_parsingDelay.setInterval(1000); // delay parsing by 1s.
104

105
106
    setProjectContext(Context(Constants::PROJECT_ID));
    setProjectLanguages(Context(ProjectExplorer::Constants::LANG_CXX));
Tobias Hunger's avatar
Tobias Hunger committed
107
108
109
110
111

    connect(this, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
            this, SLOT(changeActiveTarget(ProjectExplorer::Target*)));
    connect(this, SIGNAL(addedTarget(ProjectExplorer::Target*)),
            this, SLOT(targetWasAdded(ProjectExplorer::Target*)));
112
113
114
    connect(this, SIGNAL(environmentChanged()), this, SLOT(delayParsing()));

    connect(&m_parsingDelay, SIGNAL(timeout()), this, SLOT(parseCurrentBuildConfiguration()));
Tobias Hunger's avatar
Tobias Hunger committed
115

116
    updateDocuments(QSet<QString>() << fileName);
117
    m_rootProjectNode = new QbsProjectNode(this); // needs documents to be initialized!
Tobias Hunger's avatar
Tobias Hunger committed
118
119
120
121
122
}

QbsProject::~QbsProject()
{
    m_codeModelFuture.cancel();
123
124
125
126
127
    if (m_qbsSetupProjectJob) {
        m_qbsSetupProjectJob->disconnect(this);
        m_qbsSetupProjectJob->cancel();
        delete m_qbsSetupProjectJob;
    }
Tobias Hunger's avatar
Tobias Hunger committed
128
129
130
131
132
133
134
}

QString QbsProject::displayName() const
{
    return m_projectName;
}

135
Id QbsProject::id() const
Tobias Hunger's avatar
Tobias Hunger committed
136
{
137
    return Constants::PROJECT_ID;
Tobias Hunger's avatar
Tobias Hunger committed
138
139
}

140
IDocument *QbsProject::document() const
Tobias Hunger's avatar
Tobias Hunger committed
141
{
142
    foreach (IDocument *doc, m_qbsDocuments) {
143
        if (doc->filePath() == m_fileName)
Tobias Hunger's avatar
Tobias Hunger committed
144
145
146
147
148
149
150
151
152
153
            return doc;
    }
    QTC_ASSERT(false, return 0);
}

QbsManager *QbsProject::projectManager() const
{
    return m_manager;
}

154
ProjectNode *QbsProject::rootProjectNode() const
Tobias Hunger's avatar
Tobias Hunger committed
155
156
157
158
{
    return m_rootProjectNode;
}

159
QStringList QbsProject::files(Project::FilesMode fileMode) const
Tobias Hunger's avatar
Tobias Hunger committed
160
161
{
    Q_UNUSED(fileMode);
162
    QSet<QString> result;
163
164
    if (m_rootProjectNode && m_rootProjectNode->qbsProjectData().isValid()) {
        foreach (const qbs::ProductData &prd, m_rootProjectNode->qbsProjectData().allProducts()) {
165
166
167
            foreach (const qbs::GroupData &grp, prd.groups()) {
                foreach (const QString &file, grp.allFilePaths())
                    result.insert(file);
168
                result.insert(grp.location().fileName());
169
            }
170
            result.insert(prd.location().fileName());
171
        }
172
        result.insert(m_rootProjectNode->qbsProjectData().location().fileName());
Tobias Hunger's avatar
Tobias Hunger committed
173
    }
174
    return result.toList();
Tobias Hunger's avatar
Tobias Hunger committed
175
176
177
178
179
180
181
}

void QbsProject::invalidate()
{
    prepareForParsing();
}

182
qbs::BuildJob *QbsProject::build(const qbs::BuildOptions &opts, QStringList productNames)
Tobias Hunger's avatar
Tobias Hunger committed
183
{
184
    if (!qbsProject().isValid() || isParsing())
Tobias Hunger's avatar
Tobias Hunger committed
185
        return 0;
186
    if (productNames.isEmpty()) {
187
        return qbsProject().buildAllProducts(opts);
188
189
190
191
    } else {
        QList<qbs::ProductData> products;
        foreach (const QString &productName, productNames) {
            bool found = false;
192
            foreach (const qbs::ProductData &data, qbsProjectData().allProducts()) {
193
194
195
196
197
198
199
200
201
202
                if (data.name() == productName) {
                    found = true;
                    products.append(data);
                    break;
                }
            }
            if (!found)
                return 0;
        }

203
        return qbsProject().buildSomeProducts(products, opts);
204
    }
Tobias Hunger's avatar
Tobias Hunger committed
205
206
}

207
qbs::CleanJob *QbsProject::clean(const qbs::CleanOptions &opts)
Tobias Hunger's avatar
Tobias Hunger committed
208
{
209
    if (!qbsProject().isValid())
Tobias Hunger's avatar
Tobias Hunger committed
210
        return 0;
211
    return qbsProject().cleanAllProducts(opts);
Tobias Hunger's avatar
Tobias Hunger committed
212
213
}

Tobias Hunger's avatar
Tobias Hunger committed
214
215
qbs::InstallJob *QbsProject::install(const qbs::InstallOptions &opts)
{
216
    if (!qbsProject().isValid())
Tobias Hunger's avatar
Tobias Hunger committed
217
        return 0;
218
    return qbsProject().installAllProducts(opts);
Tobias Hunger's avatar
Tobias Hunger committed
219
220
}

221
QString QbsProject::profileForTarget(const Target *t) const
Tobias Hunger's avatar
Tobias Hunger committed
222
223
224
225
226
227
228
229
230
231
232
{
    return m_manager->profileForKit(t->kit());
}

bool QbsProject::isParsing() const
{
    return m_qbsUpdateFutureInterface;
}

bool QbsProject::hasParseResult() const
{
233
    return qbsProject().isValid();
Tobias Hunger's avatar
Tobias Hunger committed
234
235
}

236
FileName QbsProject::defaultBuildDirectory() const
Tobias Hunger's avatar
Tobias Hunger committed
237
{
238
239
240
241
242
243
    return defaultBuildDirectory(m_fileName);
}

Utils::FileName QbsProject::defaultBuildDirectory(const QString &path)
{
    QFileInfo fi(path);
Tobias Hunger's avatar
Tobias Hunger committed
244
    const QString buildDir = QDir(fi.canonicalPath()).absoluteFilePath(QString::fromLatin1("../%1-build").arg(fi.baseName()));
245
    return FileName::fromString(buildDir);
Tobias Hunger's avatar
Tobias Hunger committed
246
247
}

248
qbs::Project QbsProject::qbsProject() const
249
250
{
    if (!m_rootProjectNode)
251
        return qbs::Project();
252
    return m_rootProjectNode->qbsProject();
253
254
}

255
const qbs::ProjectData QbsProject::qbsProjectData() const
256
257
{
    if (!m_rootProjectNode)
258
        return qbs::ProjectData();
259
    return m_rootProjectNode->qbsProjectData();
260
261
}

262
263
264
265
266
bool QbsProject::needsSpecialDeployment() const
{
    return true;
}

Tobias Hunger's avatar
Tobias Hunger committed
267
268
269
270
271
void QbsProject::handleQbsParsingDone(bool success)
{
    QTC_ASSERT(m_qbsSetupProjectJob, return);
    QTC_ASSERT(m_qbsUpdateFutureInterface, return);

272
    qbs::Project project;
Tobias Hunger's avatar
Tobias Hunger committed
273
    if (success) {
274
        project = m_qbsSetupProjectJob->project();
Tobias Hunger's avatar
Tobias Hunger committed
275
276
277
278
279
280
281
282
283
284
285
286
287
    } else {
        generateErrors(m_qbsSetupProjectJob->error());
        m_qbsUpdateFutureInterface->reportCanceled();
    }
    m_qbsSetupProjectJob->deleteLater();
    m_qbsSetupProjectJob = 0;

    m_qbsUpdateFutureInterface->reportFinished();
    delete m_qbsUpdateFutureInterface;
    m_qbsUpdateFutureInterface = 0;

    m_rootProjectNode->update(project);

288
    updateDocuments(project.isValid() ? project.buildSystemFiles() : QSet<QString>() << m_fileName);
Tobias Hunger's avatar
Tobias Hunger committed
289

290
291
    updateCppCodeModel(m_rootProjectNode->qbsProjectData());
    updateQmlJsCodeModel(m_rootProjectNode->qbsProjectData());
292
293
    updateApplicationTargets(m_rootProjectNode->qbsProjectData());
    updateDeploymentInfo(m_rootProjectNode->qbsProject());
Tobias Hunger's avatar
Tobias Hunger committed
294

295
    foreach (Target *t, targets())
Tobias Hunger's avatar
Tobias Hunger committed
296
297
        t->updateDefaultRunConfigurations();

298
    emit fileListChanged();
Tobias Hunger's avatar
Tobias Hunger committed
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
    emit projectParsingDone(success);
}

void QbsProject::handleQbsParsingProgress(int progress)
{
    if (m_qbsUpdateFutureInterface)
        m_qbsUpdateFutureInterface->setProgressValue(m_currentProgressBase + progress);
}

void QbsProject::handleQbsParsingTaskSetup(const QString &description, int maximumProgressValue)
{
    Q_UNUSED(description);
    if (m_qbsUpdateFutureInterface) {
        m_currentProgressBase = m_qbsUpdateFutureInterface->progressValue();
        m_qbsUpdateFutureInterface->setProgressRange(0, m_currentProgressBase + maximumProgressValue);
    }
}

317
void QbsProject::targetWasAdded(Target *t)
Tobias Hunger's avatar
Tobias Hunger committed
318
319
{
    connect(t, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
320
321
            this, SLOT(delayForcedParsing()));
    connect(t, SIGNAL(buildDirectoryChanged()), this, SLOT(delayForcedParsing()));
Tobias Hunger's avatar
Tobias Hunger committed
322
323
}

324
void QbsProject::changeActiveTarget(Target *t)
Tobias Hunger's avatar
Tobias Hunger committed
325
{
326
    BuildConfiguration *bc = 0;
Tobias Hunger's avatar
Tobias Hunger committed
327
328
329
330
331
    if (t && t->kit())
        bc = t->activeBuildConfiguration();
    buildConfigurationChanged(bc);
}

332
void QbsProject::buildConfigurationChanged(BuildConfiguration *bc)
Tobias Hunger's avatar
Tobias Hunger committed
333
334
{
    if (m_currentBc)
335
        disconnect(m_currentBc, SIGNAL(qbsConfigurationChanged()), this, SLOT(delayParsing()));
Tobias Hunger's avatar
Tobias Hunger committed
336
337
338

    m_currentBc = qobject_cast<QbsBuildConfiguration *>(bc);
    if (m_currentBc) {
339
340
        connect(m_currentBc, SIGNAL(qbsConfigurationChanged()), this, SLOT(delayParsing()));
        delayParsing();
Tobias Hunger's avatar
Tobias Hunger committed
341
342
343
344
345
    } else {
        invalidate();
    }
}

346
347
348
349
350
void QbsProject::delayParsing()
{
    m_parsingDelay.start();
}

351
352
353
354
355
356
void QbsProject::delayForcedParsing()
{
    m_forceParsing = true;
    delayParsing();
}

Tobias Hunger's avatar
Tobias Hunger committed
357
358
void QbsProject::parseCurrentBuildConfiguration()
{
359
360
    m_parsingDelay.stop();

Tobias Hunger's avatar
Tobias Hunger committed
361
362
363
364
365
    if (!activeTarget())
        return;
    QbsBuildConfiguration *bc = qobject_cast<QbsBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
    if (!bc)
        return;
366
    parse(bc->qbsConfiguration(), bc->environment(), bc->buildDirectory().toString());
Tobias Hunger's avatar
Tobias Hunger committed
367
368
369
370
371
372
373
}

bool QbsProject::fromMap(const QVariantMap &map)
{
    if (!Project::fromMap(map))
        return false;

374
    Kit *defaultKit = KitManager::defaultKit();
375
    if (!activeTarget() && defaultKit) {
376
        Target *t = new Target(this, defaultKit);
Tobias Hunger's avatar
Tobias Hunger committed
377
378
379
380
381
382
383
384
385
        t->updateDefaultBuildConfigurations();
        t->updateDefaultDeployConfigurations();
        t->updateDefaultRunConfigurations();
        addTarget(t);
    }

    return true;
}

386
void QbsProject::generateErrors(const qbs::ErrorInfo &e)
Tobias Hunger's avatar
Tobias Hunger committed
387
{
388
    foreach (const qbs::ErrorItem &item, e.items())
389
390
391
392
393
        TaskHub::addTask(Task::Error, item.description(),
                         ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM,
                         FileName::fromString(item.codeLocation().fileName()),
                         item.codeLocation().line());

Tobias Hunger's avatar
Tobias Hunger committed
394
395
}

396
void QbsProject::parse(const QVariantMap &config, const Environment &env, const QString &dir)
Tobias Hunger's avatar
Tobias Hunger committed
397
398
{
    QTC_ASSERT(!dir.isNull(), return);
399

Tobias Hunger's avatar
Tobias Hunger committed
400
    qbs::SetupProjectParameters params;
401
    params.setBuildConfiguration(config);
402
    qbs::ErrorInfo err = params.expandBuildConfiguration(m_manager->settings());
Tobias Hunger's avatar
Tobias Hunger committed
403
    if (err.hasError()) {
404
405
406
407
408
        generateErrors(err);
        return;
    }

    // Avoid useless reparsing:
409
    const qbs::Project &currentProject = qbsProject();
410
    if (!m_forceParsing
411
412
413
            && currentProject.isValid()
            && currentProject.projectConfiguration() == params.buildConfiguration()) {
        QHash<QString, QString> usedEnv = currentProject.usedEnvironment();
414
415
416
417
418
419
420
421
422
423
424
425
        bool canSkip = true;
        for (QHash<QString, QString>::const_iterator i = usedEnv.constBegin();
             i != usedEnv.constEnd(); ++i) {
            if (env.value(i.key()) != i.value()) {
                canSkip = false;
                break;
            }
        }
        if (canSkip)
            return;
    }

426
    params.setBuildRoot(dir);
Christian Kandeler's avatar
Christian Kandeler committed
427
428
    params.setProjectFilePath(m_fileName);
    params.setIgnoreDifferentProjectFilePath(false);
Tobias Hunger's avatar
Tobias Hunger committed
429
    params.setEnvironment(env.toProcessEnvironment());
430
    qbs::Preferences *prefs = QbsManager::preferences();
431
432
433
    const QString qbsDir = qbsDirectory();
    params.setSearchPaths(prefs->searchPaths(qbsDir));
    params.setPluginPaths(prefs->pluginPaths(qbsDir));
Tobias Hunger's avatar
Tobias Hunger committed
434

435
436
437
438
    // Do the parsing:
    prepareForParsing();
    QTC_ASSERT(!m_qbsSetupProjectJob, return);

Tobias Hunger's avatar
Tobias Hunger committed
439
    m_qbsSetupProjectJob
440
            = qbs::Project::setupProject(params, m_manager->logSink(), 0);
Tobias Hunger's avatar
Tobias Hunger committed
441
442
443
444
445
446
447

    connect(m_qbsSetupProjectJob, SIGNAL(finished(bool,qbs::AbstractJob*)),
            this, SLOT(handleQbsParsingDone(bool)));
    connect(m_qbsSetupProjectJob, SIGNAL(taskStarted(QString,int,qbs::AbstractJob*)),
            this, SLOT(handleQbsParsingTaskSetup(QString,int)));
    connect(m_qbsSetupProjectJob, SIGNAL(taskProgress(int,qbs::AbstractJob*)),
            this, SLOT(handleQbsParsingProgress(int)));
448
449

    emit projectParsingStarted();
Tobias Hunger's avatar
Tobias Hunger committed
450
451
452
453
}

void QbsProject::prepareForParsing()
{
454
455
    m_forceParsing = false;

456
    TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
Tobias Hunger's avatar
Tobias Hunger committed
457
458
459
460
461
    if (m_qbsUpdateFutureInterface)
        m_qbsUpdateFutureInterface->reportCanceled();
    delete m_qbsUpdateFutureInterface;
    m_qbsUpdateFutureInterface = 0;

462
463
464
465
466
467
    if (m_qbsSetupProjectJob) {
        m_qbsSetupProjectJob->disconnect(this);
        m_qbsSetupProjectJob->cancel();
        m_qbsSetupProjectJob->deleteLater();
        m_qbsSetupProjectJob = 0;
    }
Tobias Hunger's avatar
Tobias Hunger committed
468
469
470
471

    m_currentProgressBase = 0;
    m_qbsUpdateFutureInterface = new QFutureInterface<void>();
    m_qbsUpdateFutureInterface->setProgressRange(0, 0);
472
473
    ProgressManager::addTask(m_qbsUpdateFutureInterface->future(),
        tr("Evaluating"), "Qbs.QbsEvaluate");
Tobias Hunger's avatar
Tobias Hunger committed
474
475
476
    m_qbsUpdateFutureInterface->reportStarted();
}

477
void QbsProject::updateDocuments(const QSet<QString> &files)
Tobias Hunger's avatar
Tobias Hunger committed
478
479
{
    // Update documents:
480
481
    QSet<QString> newFiles = files;
    QTC_ASSERT(!newFiles.isEmpty(), newFiles << m_fileName);
Tobias Hunger's avatar
Tobias Hunger committed
482
    QSet<QString> oldFiles;
483
    foreach (IDocument *doc, m_qbsDocuments)
484
        oldFiles.insert(doc->filePath());
Tobias Hunger's avatar
Tobias Hunger committed
485
486
487
488
489
490

    QSet<QString> filesToAdd = newFiles;
    filesToAdd.subtract(oldFiles);
    QSet<QString> filesToRemove = oldFiles;
    filesToRemove.subtract(newFiles);

491
492
    QSet<IDocument *> currentDocuments = m_qbsDocuments;
    foreach (IDocument *doc, currentDocuments) {
493
        if (filesToRemove.contains(doc->filePath())) {
Tobias Hunger's avatar
Tobias Hunger committed
494
495
496
497
            m_qbsDocuments.remove(doc);
            delete doc;
        }
    }
498
    QSet<IDocument *> toAdd;
Tobias Hunger's avatar
Tobias Hunger committed
499
500
501
    foreach (const QString &f, filesToAdd)
        toAdd.insert(new QbsProjectFile(this, f));

502
    DocumentManager::addDocuments(toAdd.toList());
Tobias Hunger's avatar
Tobias Hunger committed
503
504
505
    m_qbsDocuments.unite(toAdd);
}

506
void QbsProject::updateCppCodeModel(const qbs::ProjectData &prj)
Tobias Hunger's avatar
Tobias Hunger committed
507
{
508
    if (!prj.isValid())
Tobias Hunger's avatar
Tobias Hunger committed
509
510
        return;

511
    Kit *k = 0;
Tobias Hunger's avatar
Tobias Hunger committed
512
    QtSupport::BaseQtVersion *qtVersion = 0;
513
    if (Target *target = activeTarget())
Tobias Hunger's avatar
Tobias Hunger committed
514
515
        k = target->kit();
    else
516
        k = KitManager::defaultKit();
Tobias Hunger's avatar
Tobias Hunger committed
517
518
    qtVersion = QtSupport::QtKitInformation::qtVersion(k);

519
520
    CppTools::CppModelManagerInterface *modelmanager =
        CppTools::CppModelManagerInterface::instance();
Tobias Hunger's avatar
Tobias Hunger committed
521
522
523
524

    if (!modelmanager)
        return;

525
    CppTools::CppModelManagerInterface::ProjectInfo pinfo = modelmanager->projectInfo(this);
Tobias Hunger's avatar
Tobias Hunger committed
526
    pinfo.clearProjectParts();
527
528
    CppTools::ProjectPart::QtVersion qtVersionForPart
            = CppTools::ProjectPart::NoQt;
Tobias Hunger's avatar
Tobias Hunger committed
529
530
    if (qtVersion) {
        if (qtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0))
531
            qtVersionForPart = CppTools::ProjectPart::Qt4;
Tobias Hunger's avatar
Tobias Hunger committed
532
        else
533
            qtVersionForPart = CppTools::ProjectPart::Qt5;
Tobias Hunger's avatar
Tobias Hunger committed
534
535
    }

Tobias Hunger's avatar
Tobias Hunger committed
536
    QHash<QString, QString> uiFiles;
Tobias Hunger's avatar
Tobias Hunger committed
537
    QStringList allFiles;
538
    foreach (const qbs::ProductData &prd, prj.allProducts()) {
Tobias Hunger's avatar
Tobias Hunger committed
539
        foreach (const qbs::GroupData &grp, prd.groups()) {
540
            const qbs::PropertyMap &props = grp.properties();
Tobias Hunger's avatar
Tobias Hunger committed
541

542
543
544
            const QStringList cxxFlags = props.getModulePropertiesAsStringList(
                        QLatin1String(CONFIG_CPP_MODULE),
                        QLatin1String(CONFIG_CXXFLAGS));
Tobias Hunger's avatar
Tobias Hunger committed
545

546
547
548
549
            const QStringList cFlags = props.getModulePropertiesAsStringList(
                        QLatin1String(CONFIG_CPP_MODULE),
                        QLatin1String(CONFIG_CFLAGS));

550
551
552
            QStringList list = props.getModulePropertiesAsStringList(
                        QLatin1String(CONFIG_CPP_MODULE),
                        QLatin1String(CONFIG_DEFINES));
553
            QByteArray grpDefines;
554
555
556
557
558
559
560
            foreach (const QString &def, list) {
                QByteArray data = def.toUtf8();
                int pos = data.indexOf('=');
                if (pos >= 0)
                    data[pos] = ' ';
                grpDefines += (QByteArray("#define ") + data + '\n');
            }
Tobias Hunger's avatar
Tobias Hunger committed
561

562
563
            list = props.getModulePropertiesAsStringList(QLatin1String(CONFIG_CPP_MODULE),
                                                         QLatin1String(CONFIG_INCLUDEPATHS));
564
            QStringList grpIncludePaths;
Tobias Hunger's avatar
Tobias Hunger committed
565
            foreach (const QString &p, list) {
566
                const QString cp = FileName::fromUserInput(p).toString();
Tobias Hunger's avatar
Tobias Hunger committed
567
568
569
                grpIncludePaths.append(cp);
            }

570
571
            list = props.getModulePropertiesAsStringList(QLatin1String(CONFIG_CPP_MODULE),
                                                         QLatin1String(CONFIG_FRAMEWORKPATHS));
572
            QStringList grpFrameworkPaths;
Tobias Hunger's avatar
Tobias Hunger committed
573
            foreach (const QString &p, list) {
574
                const QString cp = FileName::fromUserInput(p).toString();
Tobias Hunger's avatar
Tobias Hunger committed
575
576
577
                grpFrameworkPaths.append(cp);
            }

578
579
            const QString pch = props.getModuleProperty(QLatin1String(CONFIG_CPP_MODULE),
                    QLatin1String(CONFIG_PRECOMPILEDHEADER)).toString();
Tobias Hunger's avatar
Tobias Hunger committed
580

581
            CppTools::ProjectPart::Ptr part(new CppTools::ProjectPart);
582
583
584
585
586
587
            part->project = this;
            part->displayName = grp.name();
            part->projectFile = QString::fromLatin1("%1:%2:%3")
                    .arg(grp.location().fileName())
                    .arg(grp.location().line())
                    .arg(grp.location().column());
588
            part->evaluateToolchain(ToolChainKitInformation::toolChain(k),
589
                                    cxxFlags,
590
                                    cFlags,
591
                                    SysRootKitInformation::sysRoot(k));
592

593
            CppTools::ProjectFileAdder adder(part->files);
Tobias Hunger's avatar
Tobias Hunger committed
594
595
596
            foreach (const QString &file, grp.allFilePaths()) {
                if (file.endsWith(QLatin1String(".ui"))) {
                    QStringList generated = m_rootProjectNode->qbsProject()
597
                            .generatedFiles(prd, file, QStringList(QLatin1String("hpp")));
Tobias Hunger's avatar
Tobias Hunger committed
598
599
600
                    if (generated.count() == 1)
                        uiFiles.insert(file, generated.at(0));
                }
601
602
                if (adder.maybeAdd(file))
                    allFiles.append(file);
Tobias Hunger's avatar
Tobias Hunger committed
603
            }
604
605
            part->files << CppTools::ProjectFile(QLatin1String(CONFIGURATION_PATH),
                                                  CppTools::ProjectFile::CXXHeader);
606
607

            part->qtVersion = qtVersionForPart;
608
609
            part->includePaths += grpIncludePaths;
            part->frameworkPaths += grpFrameworkPaths;
610
            part->precompiledHeaders = QStringList(pch);
611
            part->defines += grpDefines;
612
            pinfo.appendProjectPart(part);
Tobias Hunger's avatar
Tobias Hunger committed
613
614
615
        }
    }

616
617
    setProjectLanguage(ProjectExplorer::Constants::LANG_CXX, !allFiles.isEmpty());

Tobias Hunger's avatar
Tobias Hunger committed
618
619
620
    if (pinfo.projectParts().isEmpty())
        return;

Tobias Hunger's avatar
Tobias Hunger committed
621
622
    QtSupport::UiCodeModelManager::update(this, uiFiles);

Tobias Hunger's avatar
Tobias Hunger committed
623
    // Register update the code model:
624
    m_codeModelFuture = modelmanager->updateProjectInfo(pinfo);
Tobias Hunger's avatar
Tobias Hunger committed
625
626
}

627
void QbsProject::updateQmlJsCodeModel(const qbs::ProjectData &prj)
Tobias Hunger's avatar
Tobias Hunger committed
628
629
{
    Q_UNUSED(prj);
630
631
632
633
    QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
    if (!modelManager)
        return;

634
635
    QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
            QmlJSTools::defaultProjectInfoForProject(this);
636
637

    setProjectLanguage(ProjectExplorer::Constants::LANG_QMLJS, !projectInfo.sourceFiles.isEmpty());
Tobias Hunger's avatar
Tobias Hunger committed
638
639
640
    modelManager->updateProjectInfo(projectInfo);
}

641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
void QbsProject::updateApplicationTargets(const qbs::ProjectData &projectData)
{
    ProjectExplorer::BuildTargetInfoList applications;
    foreach (const qbs::ProductData &productData, projectData.allProducts()) {
        foreach (const qbs::TargetArtifact &ta, productData.targetArtifacts()) {
            QTC_ASSERT(ta.isValid(), continue);
            if (!ta.isExecutable())
                continue;
            applications.list << ProjectExplorer::BuildTargetInfo(Utils::FileName::fromString(ta.filePath()),
                    Utils::FileName::fromString(productData.location().fileName()));
        }
    }
    activeTarget()->setApplicationTargets(applications);
}

656
void QbsProject::updateDeploymentInfo(const qbs::Project &project)
657
658
{
    ProjectExplorer::DeploymentData deploymentData;
659
    if (project.isValid()) {
660
661
662
        qbs::InstallOptions installOptions;
        installOptions.setInstallRoot(QLatin1String("/"));
        foreach (const qbs::InstallableFile &f,
663
                 project.installableFilesForProject(project.projectData(), installOptions)) {
664
665
666
667
668
669
670
671
            deploymentData.addFile(f.sourceFilePath(), f.targetDirectory(), f.isExecutable()
                                   ? ProjectExplorer::DeployableFile::TypeExecutable
                                   : ProjectExplorer::DeployableFile::TypeNormal);
        }
    }
    activeTarget()->setDeploymentData(deploymentData);
}

672
QString QbsProject::qbsDirectory() const
673
{
674
675
676
677
    const QString qbsInstallDir = QLatin1String(QBS_INSTALL_DIR);
    if (!qbsInstallDir.isEmpty())
        return qbsInstallDir;
    return ICore::resourcePath() + QLatin1String("/qbs");
678
679
}

Tobias Hunger's avatar
Tobias Hunger committed
680
681
} // namespace Internal
} // namespace QbsProjectManager