qt4project.cpp 53.2 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
hjk's avatar
hjk committed
3
4
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** 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.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30
#include "qt4project.h"
hjk's avatar
hjk committed
31

Tobias Hunger's avatar
Tobias Hunger committed
32
#include "qt4projectmanager.h"
con's avatar
con committed
33
34
#include "makestep.h"
#include "qmakestep.h"
Tobias Hunger's avatar
Tobias Hunger committed
35
#include "qmakerunconfigurationfactory.h"
con's avatar
con committed
36
#include "qt4nodes.h"
37
#include "qt4projectconfigwidget.h"
con's avatar
con committed
38
#include "qt4projectmanagerconstants.h"
dt's avatar
dt committed
39
#include "qt4buildconfiguration.h"
40
#include "findqt4profiles.h"
41
#include "buildconfigurationinfo.h"
42

43
#include <coreplugin/icore.h>
44
#include <coreplugin/idocument.h>
45
#include <coreplugin/icontext.h>
con's avatar
con committed
46
47
#include <coreplugin/messagemanager.h>
#include <coreplugin/coreconstants.h>
dt's avatar
dt committed
48
#include <coreplugin/progressmanager/progressmanager.h>
49
#include <coreplugin/documentmanager.h>
50
#include <coreplugin/variablemanager.h>
51
#include <extensionsystem/pluginmanager.h>
52
#include <cpptools/ModelManagerInterface.h>
53
#include <qmljs/qmljsmodelmanagerinterface.h>
54
55
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/deploymentdata.h>
56
#include <projectexplorer/toolchain.h>
57
#include <projectexplorer/headerpath.h>
58
#include <projectexplorer/target.h>
Tobias Hunger's avatar
Tobias Hunger committed
59
#include <projectexplorer/kitinformation.h>
60
#include <projectexplorer/projectexplorer.h>
61
#include <projectexplorer/projectexplorerconstants.h>
62
#include <utils/qtcassert.h>
63
#include <qtsupport/customexecutablerunconfiguration.h>
64
65
66
#include <qtsupport/qmldumptool.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/profilereader.h>
Tobias Hunger's avatar
Tobias Hunger committed
67
#include <qtsupport/qtkitinformation.h>
68
#include <qtsupport/qtsupportconstants.h>
69
#include <qtsupport/qtversionmanager.h>
70
#include <utils/QtConcurrentTools>
71
#include <utils/stringutils.h>
con's avatar
con committed
72

73
74
75
76
77
#include <QDebug>
#include <QDir>
#include <QFileSystemWatcher>
#include <QFileDialog>
#include <QInputDialog>
con's avatar
con committed
78
79
80
81
82

using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;
using namespace ProjectExplorer;

hjk's avatar
hjk committed
83
enum { debug = 0 };
con's avatar
con committed
84

Tobias Hunger's avatar
Tobias Hunger committed
85
86
87
88
89
90
91
92
93
94
// -----------------------------------------------------------------------
// Helpers:
// -----------------------------------------------------------------------

namespace {

Qt4BuildConfiguration *enableActiveQt4BuildConfiguration(ProjectExplorer::Target *t, bool enabled)
{
    if (!t)
        return 0;
95
    Qt4BuildConfiguration *bc = static_cast<Qt4BuildConfiguration *>(t->activeBuildConfiguration());
Tobias Hunger's avatar
Tobias Hunger committed
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    if (!bc)
        return 0;
    bc->setEnabled(enabled);
    return bc;
}

QString sanitize(const QString &input)
{
    QString result;
    result.reserve(input.size());
    foreach (const QChar &qc, input) {
        const char c = qc.toLatin1();
        if ((c >= 'a' && c <='z')
                || (c >= 'A' && c <= 'Z')
                || (c >= '0' && c <= '9')
                || c == '-'
                || c == '_')
            result.append(qc);
        else
            result.append(QLatin1Char('_'));
    }
    return result;
}

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
class Qt4ProjectExpander : public Utils::AbstractQtcMacroExpander
{
public:
    Qt4ProjectExpander(const QString &proFilePath, const Kit *k, const QString &bcName) :
        m_proFile(proFilePath), m_kit(k), m_bcName(bcName)
    { }

    bool resolveMacro(const QString &name, QString *ret)
    {
        QString result;
        bool found = false;
        if (name == QLatin1String(ProjectExplorer::Constants::VAR_CURRENTPROJECT_NAME)) {
            result = m_proFile.baseName();
            found = true;
        } else if (name == QLatin1String(ProjectExplorer::Constants::VAR_CURRENTPROJECT_PATH)) {
            result = m_proFile.absolutePath();
            found = true;
        } else if (name == QLatin1String(ProjectExplorer::Constants::VAR_CURRENTPROJECT_FILEPATH)) {
            result = m_proFile.absoluteFilePath();
            found = true;
        } else if (m_kit && name == QLatin1String(ProjectExplorer::Constants::VAR_CURRENTKIT_NAME)) {
            result = m_kit->displayName();
            found = true;
        } else if (m_kit && name == QLatin1String(ProjectExplorer::Constants::VAR_CURRENTKIT_FILESYSTEMNAME)) {
            result = m_kit->fileSystemFriendlyName();
            found = true;
        } else if (m_kit && name == QLatin1String(ProjectExplorer::Constants::VAR_CURRENTKIT_ID)) {
            result = m_kit->id().toString();
            found = true;
        } else if (name == QLatin1String(ProjectExplorer::Constants::VAR_CURRENTBUILD_NAME)) {
            result = m_bcName;
            found = true;
        } else {
            result = Core::VariableManager::instance()->value(name.toUtf8(), &found);
        }
        if (ret)
            *ret = result;
        return found;
    }

private:
    QFileInfo m_proFile;
    const Kit *m_kit;
    QString m_bcName;
    Utils::AbstractMacroExpander *m_expander;
};

Tobias Hunger's avatar
Tobias Hunger committed
167
168
} // namespace

con's avatar
con committed
169
170
171
namespace Qt4ProjectManager {
namespace Internal {

172
class Qt4ProjectFile : public Core::IDocument
173
174
175
176
{
    Q_OBJECT

public:
Tobias Hunger's avatar
Tobias Hunger committed
177
    Qt4ProjectFile(const QString &filePath, QObject *parent = 0);
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

    bool save(QString *errorString, const QString &fileName, bool autoSave);
    QString fileName() const;
    virtual void rename(const QString &newName);

    QString defaultPath() const;
    QString suggestedFileName() const;
    virtual QString mimeType() const;

    bool isModified() const;
    bool isSaveAsAllowed() const;

    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
    bool reload(QString *errorString, ReloadFlag flag, ChangeType type);

private:
    const QString m_mimeType;
    QString m_filePath;
};

/// Watches folders for Qt4PriFile nodes
/// use one file system watcher to watch all folders
/// such minimizing system ressouce usage

class CentralizedFolderWatcher : public QObject
{
    Q_OBJECT
public:
    CentralizedFolderWatcher(QObject *parent);
    ~CentralizedFolderWatcher();
208
209
    void watchFolders(const QList<QString> &folders, Qt4ProjectManager::Qt4PriFileNode *node);
    void unwatchFolders(const QList<QString> &folders, Qt4ProjectManager::Qt4PriFileNode *node);
210
211
212
213
214
215
216
217
218

private slots:
    void folderChanged(const QString &folder);
    void onTimer();
    void delayedFolderChanged(const QString &folder);

private:
    QSet<QString> recursiveDirs(const QString &folder);
    QFileSystemWatcher m_watcher;
219
    QMultiMap<QString, Qt4ProjectManager::Qt4PriFileNode *> m_map;
220
221
222
223
224
225

    QSet<QString> m_recursiveWatchedFolders;
    QTimer m_compressTimer;
    QSet<QString> m_changedFolders;
};

con's avatar
con committed
226
// Qt4ProjectFiles: Struct for (Cached) lists of files in a project
Tobias Hunger's avatar
Tobias Hunger committed
227
228
class Qt4ProjectFiles {
public:
con's avatar
con committed
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
    void clear();
    bool equals(const Qt4ProjectFiles &f) const;

    QStringList files[ProjectExplorer::FileTypeSize];
    QStringList generatedFiles[ProjectExplorer::FileTypeSize];
    QStringList proFiles;
};

void Qt4ProjectFiles::clear()
{
    for (int i = 0; i < FileTypeSize; ++i) {
        files[i].clear();
        generatedFiles[i].clear();
    }
    proFiles.clear();
}

bool Qt4ProjectFiles::equals(const Qt4ProjectFiles &f) const
{
    for (int i = 0; i < FileTypeSize; ++i)
        if (files[i] != f.files[i] || generatedFiles[i] != f.generatedFiles[i])
            return false;
    if (proFiles != f.proFiles)
        return false;
    return true;
}

inline bool operator==(const Qt4ProjectFiles &f1, const Qt4ProjectFiles &f2)
{       return f1.equals(f2); }

inline bool operator!=(const Qt4ProjectFiles &f1, const Qt4ProjectFiles &f2)
{       return !f1.equals(f2); }

QDebug operator<<(QDebug d, const  Qt4ProjectFiles &f)
{
    QDebug nsp = d.nospace();
    nsp << "Qt4ProjectFiles: proFiles=" <<  f.proFiles << '\n';
    for (int i = 0; i < FileTypeSize; ++i)
        nsp << "Type " << i << " files=" << f.files[i] <<  " generated=" << f.generatedFiles[i] << '\n';
    return d;
}

// A visitor to collect all files of a project in a Qt4ProjectFiles struct
class ProjectFilesVisitor : public ProjectExplorer::NodesVisitor
{
    ProjectFilesVisitor(Qt4ProjectFiles *files);
hjk's avatar
hjk committed
275

con's avatar
con committed
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
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
public:

    static void findProjectFiles(Qt4ProFileNode *rootNode, Qt4ProjectFiles *files);

    void visitProjectNode(ProjectNode *projectNode);
    void visitFolderNode(FolderNode *folderNode);

private:
    Qt4ProjectFiles *m_files;
};

ProjectFilesVisitor::ProjectFilesVisitor(Qt4ProjectFiles *files) :
    m_files(files)
{
}

void ProjectFilesVisitor::findProjectFiles(Qt4ProFileNode *rootNode, Qt4ProjectFiles *files)
{
    files->clear();
    ProjectFilesVisitor visitor(files);
    rootNode->accept(&visitor);
    for (int i = 0; i < FileTypeSize; ++i) {
        qSort(files->files[i]);
        qSort(files->generatedFiles[i]);
    }
    qSort(files->proFiles);
}

void ProjectFilesVisitor::visitProjectNode(ProjectNode *projectNode)
{
    const QString path = projectNode->path();
    if (!m_files->proFiles.contains(path))
        m_files->proFiles.append(path);
    visitFolderNode(projectNode);
}

void ProjectFilesVisitor::visitFolderNode(FolderNode *folderNode)
{
    foreach (FileNode *fileNode, folderNode->fileNodes()) {
        const QString path = fileNode->path();
        const int type = fileNode->fileType();
        QStringList &targetList = fileNode->isGenerated() ? m_files->generatedFiles[type] : m_files->files[type];
        if (!targetList.contains(path))
            targetList.push_back(path);
    }
}

}

// ----------- Qt4ProjectFile
Friedemann Kleint's avatar
Friedemann Kleint committed
326
namespace Internal {
Tobias Hunger's avatar
Tobias Hunger committed
327
Qt4ProjectFile::Qt4ProjectFile(const QString &filePath, QObject *parent)
328
    : Core::IDocument(parent),
con's avatar
con committed
329
330
331
332
333
      m_mimeType(QLatin1String(Qt4ProjectManager::Constants::PROFILE_MIMETYPE)),
      m_filePath(filePath)
{
}

334
bool Qt4ProjectFile::save(QString *, const QString &, bool)
con's avatar
con committed
335
{
336
337
    // This is never used
    return false;
con's avatar
con committed
338
339
}

dt's avatar
dt committed
340
341
342
343
344
345
346
void Qt4ProjectFile::rename(const QString &newName)
{
    // Can't happen
    Q_UNUSED(newName);
    Q_ASSERT(false);
}

con's avatar
con committed
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
QString Qt4ProjectFile::fileName() const
{
    return m_filePath;
}

QString Qt4ProjectFile::defaultPath() const
{
    return QString();
}

QString Qt4ProjectFile::suggestedFileName() const
{
    return QString();
}

QString Qt4ProjectFile::mimeType() const
{
    return m_mimeType;
}

bool Qt4ProjectFile::isModified() const
{
369
    return false; // we save after changing anyway
con's avatar
con committed
370
371
372
373
374
375
376
}

bool Qt4ProjectFile::isSaveAsAllowed() const
{
    return false;
}

377
Core::IDocument::ReloadBehavior Qt4ProjectFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
con's avatar
con committed
378
{
379
380
381
382
383
    Q_UNUSED(state)
    Q_UNUSED(type)
    return BehaviorSilent;
}

384
bool Qt4ProjectFile::reload(QString *errorString, ReloadFlag flag, ChangeType type)
385
{
386
    Q_UNUSED(errorString)
387
388
    Q_UNUSED(flag)
    Q_UNUSED(type)
389
    return true;
con's avatar
con committed
390
391
}

392
} // namespace Internal
393

con's avatar
con committed
394
/*!
395
  \class Qt4Project
con's avatar
con committed
396
397
398
399
400
401

  Qt4Project manages information about an individual Qt 4 (.pro) project file.
  */

Qt4Project::Qt4Project(Qt4Manager *manager, const QString& fileName) :
    m_manager(manager),
dt's avatar
dt committed
402
    m_rootProjectNode(0),
con's avatar
con committed
403
    m_nodesWatcher(new Internal::Qt4NodesWatcher(this)),
Tobias Hunger's avatar
Tobias Hunger committed
404
    m_fileInfo(new Qt4ProjectFile(fileName, this)),
405
    m_projectFiles(new Qt4ProjectFiles),
406
    m_qmakeGlobals(0),
dt's avatar
dt committed
407
408
409
    m_asyncUpdateFutureInterface(0),
    m_pendingEvaluateFuturesCount(0),
    m_asyncUpdateState(NoState),
410
    m_cancelEvaluate(false),
411
412
    m_centralizedFolderWatcher(0),
    m_activeTarget(0)
con's avatar
con committed
413
{
414
415
416
    setProjectContext(Core::Context(Qt4ProjectManager::Constants::PROJECT_ID));
    setProjectLanguage(Core::Context(ProjectExplorer::Constants::LANG_CXX));

dt's avatar
dt committed
417
418
419
    m_asyncUpdateTimer.setSingleShot(true);
    m_asyncUpdateTimer.setInterval(3000);
    connect(&m_asyncUpdateTimer, SIGNAL(timeout()), this, SLOT(asyncUpdate()));
con's avatar
con committed
420
421
422
423
}

Qt4Project::~Qt4Project()
{
424
    m_codeModelFuture.cancel();
425
    m_asyncUpdateState = ShuttingDown;
dt's avatar
dt committed
426
    m_manager->unregisterProject(this);
con's avatar
con committed
427
    delete m_projectFiles;
428
    m_cancelEvaluate = true;
429
430
431
432
433
    // Deleting the root node triggers a few things, make sure rootProjectNode
    // returns 0 already
    Qt4ProFileNode *root = m_rootProjectNode;
    m_rootProjectNode = 0;
    delete root;
con's avatar
con committed
434
435
436
437
438
439
440
441
442
443
444
445
446
447
}

void Qt4Project::updateFileList()
{
    Qt4ProjectFiles newFiles;
    ProjectFilesVisitor::findProjectFiles(m_rootProjectNode, &newFiles);
    if (newFiles != *m_projectFiles) {
        *m_projectFiles = newFiles;
        emit fileListChanged();
        if (debug)
            qDebug() << Q_FUNC_INFO << *m_projectFiles;
    }
}

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
bool Qt4Project::setupTarget(ProjectExplorer::Target *t)
{
    QList<BuildConfigurationInfo> infoList
            = Qt4BuildConfigurationFactory::availableBuildConfigurations(t->kit(), m_fileInfo->fileName());
    setupTarget(t, infoList);
    return true;
}

void Qt4Project::setupTarget(ProjectExplorer::Target *t, const QList<BuildConfigurationInfo> &infoList)
{
    // Build Configurations:
    foreach (const BuildConfigurationInfo &info, infoList) {
        QString name = info.buildConfig & QtSupport::BaseQtVersion::DebugBuild
                ? tr("Debug") : tr("Release");
        Qt4BuildConfiguration *bc
                = Qt4BuildConfiguration::setup(t, name, name,
                                               info.buildConfig, info.additionalArguments,
                                               info.directory, info.importing);
        t->addBuildConfiguration(bc);
    }

    // Deploy Configurations:
    t->updateDefaultDeployConfigurations();
    // Do not create Run Configurations: Those will be generated later anyway.
}

474
bool Qt4Project::fromMap(const QVariantMap &map)
con's avatar
con committed
475
{
476
477
    if (!Project::fromMap(map))
        return false;
con's avatar
con committed
478

Tobias Hunger's avatar
Tobias Hunger committed
479
480
    // Prune targets without buildconfigurations:
    // This can happen esp. when updating from a old version of Qt Creator
dt's avatar
dt committed
481
    QList<Target *>ts = targets();
Tobias Hunger's avatar
Tobias Hunger committed
482
    foreach (Target *t, ts) {
483
        if (t->buildConfigurations().isEmpty()) {
484
            qWarning() << "Removing" << t->id().name() << "since it has no buildconfigurations!";
Tobias Hunger's avatar
Tobias Hunger committed
485
            removeTarget(t);
486
        }
Tobias Hunger's avatar
Tobias Hunger committed
487
488
    }

dt's avatar
dt committed
489
490
491
492
493
    m_manager->registerProject(this);

    m_rootProjectNode = new Qt4ProFileNode(this, m_fileInfo->fileName(), this);
    m_rootProjectNode->registerWatcher(m_nodesWatcher);

Tobias Hunger's avatar
Tobias Hunger committed
494
495
    update();
    updateFileList();
496
497
    // This might be incorrect, need a full update
    updateCodeModels();
498

Tobias Hunger's avatar
Tobias Hunger committed
499
    // We have the profile nodes now, so we know the runconfigs!
500
501
    connect(m_nodesWatcher, SIGNAL(proFileUpdated(Qt4ProjectManager::Qt4ProFileNode*,bool,bool)),
            this, SIGNAL(proFileUpdated(Qt4ProjectManager::Qt4ProFileNode*,bool,bool)));
502

503
    // Now we emit update once :)
Daniel Teske's avatar
Daniel Teske committed
504
    m_rootProjectNode->emitProFileUpdatedRecursive();
505

506
507
508
509
510
511
    // On active buildconfiguration changes, reevaluate the .pro files
    m_activeTarget = activeTarget();
    if (m_activeTarget)
        connect(m_activeTarget, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
                this, SLOT(scheduleAsyncUpdate()));

Tobias Hunger's avatar
Tobias Hunger committed
512
513
514
    connect(this, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
            this, SLOT(activeTargetWasChanged()));

dt's avatar
dt committed
515
    return true;
con's avatar
con committed
516
517
}

dt's avatar
dt committed
518
519
520
521
522
523
524
525
526
527
528
529
530
/// equalFileList compares two file lists ignoring
/// <configuration> without generating temporary lists

bool Qt4Project::equalFileList(const QStringList &a, const QStringList &b)
{
    if (abs(a.length() - b.length()) > 1)
        return false;
    QStringList::const_iterator ait = a.constBegin();
    QStringList::const_iterator bit = b.constBegin();
    QStringList::const_iterator aend = a.constEnd();
    QStringList::const_iterator bend = b.constEnd();

    while (ait != aend && bit != bend) {
531
        if (*ait == CPlusPlus::CppModelManagerInterface::configurationFileName())
dt's avatar
dt committed
532
            ++ait;
533
        else if (*bit == CPlusPlus::CppModelManagerInterface::configurationFileName())
dt's avatar
dt committed
534
535
536
537
538
539
540
            ++bit;
        else if (*ait == *bit)
            ++ait, ++bit;
        else
           return false;
    }
    return (ait == aend && bit == bend);
Tobias Hunger's avatar
Tobias Hunger committed
541
542
}

543
void Qt4Project::updateCodeModels()
con's avatar
con committed
544
545
546
547
{
    if (debug)
        qDebug()<<"Qt4Project::updateCodeModel()";

548
    if (activeTarget() && !activeTarget()->activeBuildConfiguration())
Tobias Hunger's avatar
Tobias Hunger committed
549
550
        return;

551
552
553
554
555
556
    updateCppCodeModel();
    updateQmlJSCodeModel();
}

void Qt4Project::updateCppCodeModel()
{
557
558
    typedef CPlusPlus::CppModelManagerInterface::ProjectPart ProjectPart;

Tobias Hunger's avatar
Tobias Hunger committed
559
    Kit *k = 0;
560
561
    QtSupport::BaseQtVersion *qtVersion = 0;
    ToolChain *tc = 0;
Tobias Hunger's avatar
Tobias Hunger committed
562
    if (ProjectExplorer::Target *target = activeTarget())
Tobias Hunger's avatar
Tobias Hunger committed
563
        k = target->kit();
Tobias Hunger's avatar
Tobias Hunger committed
564
    else
Tobias Hunger's avatar
Tobias Hunger committed
565
566
567
        k = KitManager::instance()->defaultKit();
    qtVersion = QtSupport::QtKitInformation::qtVersion(k);
    tc = ToolChainKitInformation::toolChain(k);
568

569
    CPlusPlus::CppModelManagerInterface *modelmanager =
570
        CPlusPlus::CppModelManagerInterface::instance();
con's avatar
con committed
571

572
    if (!modelmanager)
con's avatar
con committed
573
574
        return;

575
576
    FindQt4ProFiles findQt4ProFiles;
    QList<Qt4ProFileNode *> proFiles = findQt4ProFiles(rootProjectNode());
con's avatar
con committed
577

578
579
580
581
582
583
584
585
586
    CPlusPlus::CppModelManagerInterface::ProjectInfo pinfo = modelmanager->projectInfo(this);
    pinfo.clearProjectParts();
    ProjectPart::QtVersion qtVersionForPart = ProjectPart::NoQt;
    if (qtVersion) {
        if (qtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0))
            qtVersionForPart = ProjectPart::Qt4;
        else
            qtVersionForPart = ProjectPart::Qt5;
    }
587

588
589
590
    QStringList allFiles;
    foreach (Qt4ProFileNode *pro, proFiles) {
        ProjectPart::Ptr part(new ProjectPart);
591
592
593
594
595

        if (pro->variableValue(ConfigVar).contains(QLatin1String("qt")))
            part->qtVersion = qtVersionForPart;
        else
            part->qtVersion = ProjectPart::NoQt;
596

597
598
        QStringList cxxflags = pro->variableValue(CppFlagsVar);

599
600
        // part->defines
        if (tc)
601
            part->defines = tc->predefinedMacros(cxxflags);
602
603
604
605
606
607
608
        part->defines += pro->cxxDefines();

        // part->includePaths
        part->includePaths.append(pro->variableValue(IncludePathVar));

        QList<HeaderPath> headers;
        if (tc)
609
            headers = tc->systemHeaderPaths(cxxflags, SysRootKitInformation::sysRoot(k));
610
        if (qtVersion) {
Tobias Hunger's avatar
Tobias Hunger committed
611
            headers.append(qtVersion->systemHeaderPathes(k));
612
613
        }

614
        foreach (const HeaderPath &headerPath, headers) {
dt's avatar
dt committed
615
            if (headerPath.kind() == HeaderPath::FrameworkHeaderPath)
616
                part->frameworkPaths.append(headerPath.path());
dt's avatar
dt committed
617
            else
618
                part->includePaths.append(headerPath.path());
con's avatar
con committed
619
620
        }

621
622
623
        if (qtVersion) {
            if (!qtVersion->frameworkInstallPath().isEmpty())
                part->frameworkPaths.append(qtVersion->frameworkInstallPath());
624

625
        }
626
627
        if (Qt4ProFileNode *node = rootQt4ProjectNode())
            part->includePaths.append(node->resolvedMkspecPath());
con's avatar
con committed
628

629
630
        // part->precompiledHeaders
        part->precompiledHeaders.append(pro->variableValue(PrecompiledHeaderVar));
dt's avatar
dt committed
631

632
633
        // part->language
        if (tc)
634
635
            part->language = tc->compilerFlags(pro->variableValue(CppFlagsVar)) == ToolChain::STD_CXX11 ? ProjectPart::CXX11 : ProjectPart::CXX;
        else
636
            part->language = CPlusPlus::CppModelManagerInterface::ProjectPart::CXX11;
637

638
        part->sourceFiles = pro->variableValue(CppSourceVar);
639
640
        part->headerFiles += pro->variableValue(CppHeaderVar);
        part->headerFiles += pro->uiFiles();
641
        part->sourceFiles.prepend(CPlusPlus::CppModelManagerInterface::configurationFileName());
642
        part->objcSourceFiles = pro->variableValue(ObjCSourceVar);
643
        pinfo.appendProjectPart(part);
con's avatar
con committed
644

645
        allFiles += part->headerFiles;
646
        allFiles += part->sourceFiles;
647
        allFiles += part->objcSourceFiles;
con's avatar
con committed
648
    }
649
650
651

    modelmanager->updateProjectInfo(pinfo);
    m_codeModelFuture = modelmanager->updateSourceFiles(allFiles);
652
653
}

654
655
void Qt4Project::updateQmlJSCodeModel()
{
656
    QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
657
658
659
    if (!modelManager)
        return;

660
    QmlJS::ModelManagerInterface::ProjectInfo projectInfo = modelManager->projectInfo(this);
661
    projectInfo.sourceFiles = m_projectFiles->files[QMLType];
662
663
664
665

    FindQt4ProFiles findQt4ProFiles;
    QList<Qt4ProFileNode *> proFiles = findQt4ProFiles(rootProjectNode());

666
    projectInfo.importPaths.clear();
667
668
669
    foreach (Qt4ProFileNode *node, proFiles) {
        projectInfo.importPaths.append(node->variableValue(QmlImportPathVar));
    }
670

671
    bool preferDebugDump = false;
672
    projectInfo.tryQmlDump = false;
673

Tobias Hunger's avatar
Tobias Hunger committed
674
    ProjectExplorer::Target *t = activeTarget();
Tobias Hunger's avatar
Tobias Hunger committed
675
676
    ProjectExplorer::Kit *k = t ? t->kit() : ProjectExplorer::KitManager::instance()->defaultKit();
    QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k);
Tobias Hunger's avatar
Tobias Hunger committed
677
678
679

    if (t) {
        if (Qt4BuildConfiguration *bc = qobject_cast<Qt4BuildConfiguration *>(t->activeBuildConfiguration()))
680
681
            preferDebugDump = bc->qmakeBuildConfiguration() & QtSupport::BaseQtVersion::DebugBuild;
    } else {
682
683
        if (qtVersion)
            preferDebugDump = qtVersion->defaultBuildConfig() & QtSupport::BaseQtVersion::DebugBuild;
684
    }
Tobias Hunger's avatar
Tobias Hunger committed
685
686
687
    if (qtVersion && qtVersion->isValid()) {
        projectInfo.tryQmlDump = qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT)
                || qtVersion->type() == QLatin1String(QtSupport::Constants::SIMULATORQT);
688
689
690
        projectInfo.qtQmlPath = qtVersion->qmakeProperty("QT_INSTALL_QML");
        if (!projectInfo.qtQmlPath.isEmpty())
            projectInfo.importPaths += projectInfo.qtQmlPath;
691
        projectInfo.qtImportsPath = qtVersion->qmakeProperty("QT_INSTALL_IMPORTS");
Tobias Hunger's avatar
Tobias Hunger committed
692
693
694
        if (!projectInfo.qtImportsPath.isEmpty())
            projectInfo.importPaths += projectInfo.qtImportsPath;
        projectInfo.qtVersionString = qtVersion->qtVersionString();
695
    }
696
697
    projectInfo.importPaths.removeDuplicates();

698
    if (projectInfo.tryQmlDump) {
Tobias Hunger's avatar
Tobias Hunger committed
699
        QtSupport::QmlDumpTool::pathAndEnvironment(this, qtVersion,
Tobias Hunger's avatar
Tobias Hunger committed
700
                                                   ToolChainKitInformation::toolChain(k),
Tobias Hunger's avatar
Tobias Hunger committed
701
702
                                                   preferDebugDump, &projectInfo.qmlDumpPath,
                                                   &projectInfo.qmlDumpEnvironment);
703
704
705
706
707
    } else {
        projectInfo.qmlDumpPath.clear();
        projectInfo.qmlDumpEnvironment.clear();
    }

708
    modelManager->updateProjectInfo(projectInfo);
709
710
}

711
712
713
///*!
//  Updates complete project
//  */
con's avatar
con committed
714
715
void Qt4Project::update()
{
dt's avatar
dt committed
716
717
    if (debug)
        qDebug()<<"Doing sync update";
con's avatar
con committed
718
    m_rootProjectNode->update();
719

dt's avatar
dt committed
720
721
    if (debug)
        qDebug()<<"State is now Base";
dt's avatar
dt committed
722
    m_asyncUpdateState = Base;
Tobias Hunger's avatar
Tobias Hunger committed
723
    enableActiveQt4BuildConfiguration(activeTarget(), true);
724
    updateBuildSystemData();
725
726
727
728
729
730
731
732
    updateRunConfigurations();
    emit proFilesEvaluated();
}

void Qt4Project::updateRunConfigurations()
{
    foreach (Target *t, targets())
        t->updateDefaultRunConfigurations();
dt's avatar
dt committed
733
734
735
736
}

void Qt4Project::scheduleAsyncUpdate(Qt4ProFileNode *node)
{
dt's avatar
dt committed
737
738
    if (m_asyncUpdateState == ShuttingDown)
        return;
739

dt's avatar
dt committed
740
    if (debug)
Daniel Teske's avatar
Daniel Teske committed
741
        qDebug()<<"schduleAsyncUpdate (node)"<<node->path();
dt's avatar
dt committed
742
743
744
    Q_ASSERT(m_asyncUpdateState != NoState);

    if (m_cancelEvaluate) {
dt's avatar
dt committed
745
746
        if (debug)
            qDebug()<<"  Already canceling, nothing to do";
dt's avatar
dt committed
747
748
749
750
751
752
        // A cancel is in progress
        // That implies that a full update is going to happen afterwards
        // So we don't need to do anything
        return;
    }

Tobias Hunger's avatar
Tobias Hunger committed
753
    enableActiveQt4BuildConfiguration(activeTarget(), false);
754

dt's avatar
dt committed
755
756
    if (m_asyncUpdateState == AsyncFullUpdatePending) {
        // Just postpone
dt's avatar
dt committed
757
758
        if (debug)
            qDebug()<<"  full update pending, restarting timer";
dt's avatar
dt committed
759
760
761
        m_asyncUpdateTimer.start();
    } else if (m_asyncUpdateState == AsyncPartialUpdatePending
               || m_asyncUpdateState == Base) {
dt's avatar
dt committed
762
763
        if (debug)
            qDebug()<<"  adding node to async update list, setting state to AsyncPartialUpdatePending";
dt's avatar
dt committed
764
765
766
        // Add the node
        m_asyncUpdateState = AsyncPartialUpdatePending;

767
        QList<Qt4ProFileNode *>::iterator it;
dt's avatar
dt committed
768
        bool add = true;
dt's avatar
dt committed
769
770
        if (debug)
            qDebug()<<"scheduleAsyncUpdate();"<<m_partialEvaluate.size()<<"nodes";
dt's avatar
dt committed
771
772
773
774
775
776
        it = m_partialEvaluate.begin();
        while (it != m_partialEvaluate.end()) {
            if (*it == node) {
                add = false;
                break;
            } else if (node->isParent(*it)) { // We already have the parent in the list, nothing to do
Daniel Teske's avatar
Daniel Teske committed
777
778
                it = m_partialEvaluate.erase(it);
            } else if ((*it)->isParent(node)) { // The node is the parent of a child already in the list
dt's avatar
dt committed
779
780
781
782
783
784
785
786
787
788
789
                add = false;
                break;
            } else {
                ++it;
            }
        }

        if (add)
            m_partialEvaluate.append(node);
        // and start the timer anew
        m_asyncUpdateTimer.start();
790
791
792

        // Cancel running code model update
        m_codeModelFuture.cancel();
dt's avatar
dt committed
793
794
795
796
797
798
799
800
    } else if (m_asyncUpdateState == AsyncUpdateInProgress) {
        // A update is in progress
        // And this slot only gets called if a file changed on disc
        // So we'll play it safe and schedule a complete evaluate
        // This might trigger if due to version control a few files
        // change a partial update gets in progress and then another
        // batch of changes come in, which triggers a full update
        // even if that's not really needed
dt's avatar
dt committed
801
802
        if (debug)
            qDebug()<<"  Async update in progress, scheduling new one afterwards";
dt's avatar
dt committed
803
804
805
806
807
808
        scheduleAsyncUpdate();
    }
}

void Qt4Project::scheduleAsyncUpdate()
{
dt's avatar
dt committed
809
810
    if (debug)
        qDebug()<<"scheduleAsyncUpdate";
dt's avatar
dt committed
811
812
    if (m_asyncUpdateState == ShuttingDown)
        return;
813

dt's avatar
dt committed
814
815
816
    Q_ASSERT(m_asyncUpdateState != NoState);
    if (m_cancelEvaluate) { // we are in progress of canceling
                            // and will start the evaluation after that
dt's avatar
dt committed
817
818
        if (debug)
            qDebug()<<"  canceling is in progress, doing nothing";
dt's avatar
dt committed
819
820
821
        return;
    }
    if (m_asyncUpdateState == AsyncUpdateInProgress) {
dt's avatar
dt committed
822
823
        if (debug)
            qDebug()<<"  update in progress, canceling and setting state to full update pending";
dt's avatar
dt committed
824
825
        m_cancelEvaluate = true;
        m_asyncUpdateState = AsyncFullUpdatePending;
Tobias Hunger's avatar
Tobias Hunger committed
826
        enableActiveQt4BuildConfiguration(activeTarget(), false);
Daniel Teske's avatar
Daniel Teske committed
827
        m_rootProjectNode->setParseInProgressRecursive(true);
dt's avatar
dt committed
828
829
830
        return;
    }

dt's avatar
dt committed
831
832
    if (debug)
        qDebug()<<"  starting timer for full update, setting state to full update pending";
dt's avatar
dt committed
833
    m_partialEvaluate.clear();
Tobias Hunger's avatar
Tobias Hunger committed
834
    enableActiveQt4BuildConfiguration(activeTarget(), false);
Daniel Teske's avatar
Daniel Teske committed
835
    m_rootProjectNode->setParseInProgressRecursive(true);
dt's avatar
dt committed
836
837
    m_asyncUpdateState = AsyncFullUpdatePending;
    m_asyncUpdateTimer.start();
838
839
840

    // Cancel running code model update
    m_codeModelFuture.cancel();
dt's avatar
dt committed
841
842
843
844
845
846
}


void Qt4Project::incrementPendingEvaluateFutures()
{
    ++m_pendingEvaluateFuturesCount;
dt's avatar
dt committed
847
848
    if (debug)
        qDebug()<<"incrementPendingEvaluateFutures to"<<m_pendingEvaluateFuturesCount;
dt's avatar
dt committed
849
850
851
852
853
854
855
856
857

    m_asyncUpdateFutureInterface->setProgressRange(m_asyncUpdateFutureInterface->progressMinimum(),
                                                  m_asyncUpdateFutureInterface->progressMaximum() + 1);
}

void Qt4Project::decrementPendingEvaluateFutures()
{
    --m_pendingEvaluateFuturesCount;

dt's avatar
dt committed
858
859
    if (debug)
        qDebug()<<"decrementPendingEvaluateFutures to"<<m_pendingEvaluateFuturesCount;
dt's avatar
dt committed
860
861
862

    m_asyncUpdateFutureInterface->setProgressValue(m_asyncUpdateFutureInterface->progressValue() + 1);
    if (m_pendingEvaluateFuturesCount == 0) {
dt's avatar
dt committed
863
864
        if (debug)
            qDebug()<<"  WOHOO, no pending futures, cleaning up";
dt's avatar
dt committed
865
        // We are done!
dt's avatar
dt committed
866
867
        if (debug)
            qDebug()<<"  reporting finished";
868

dt's avatar
dt committed
869
870
871
872
873
874
875
        m_asyncUpdateFutureInterface->reportFinished();
        delete m_asyncUpdateFutureInterface;
        m_asyncUpdateFutureInterface = 0;
        m_cancelEvaluate = false;

        // TODO clear the profile cache ?
        if (m_asyncUpdateState == AsyncFullUpdatePending || m_asyncUpdateState == AsyncPartialUpdatePending) {
dt's avatar
dt committed
876
877
            if (debug)
                qDebug()<<"  Oh update is pending start the timer";
dt's avatar
dt committed
878
            m_asyncUpdateTimer.start();
879
        } else  if (m_asyncUpdateState != ShuttingDown){
Tobias Hunger's avatar
Tobias Hunger committed
880
            // After being done, we need to call:
881
            m_asyncUpdateState = Base;
Tobias Hunger's avatar
Tobias Hunger committed
882
            enableActiveQt4BuildConfiguration(activeTarget(), true);
883
            updateFileList();
884
            updateCodeModels();
885
            updateBuildSystemData();
886
887
            updateRunConfigurations();
            emit proFilesEvaluated();
dt's avatar
dt committed
888
889
            if (debug)
                qDebug()<<"  Setting state to Base";
dt's avatar
dt committed
890
891
892
893
894
895
896
897
898
899
900
        }
    }
}

bool Qt4Project::wasEvaluateCanceled()
{
    return m_cancelEvaluate;
}

void Qt4Project::asyncUpdate()
{
dt's avatar
dt committed
901
902
    if (debug)
        qDebug()<<"async update, timer expired, doing now";
dt's avatar
dt committed
903
904
905
    Q_ASSERT(!m_asyncUpdateFutureInterface);
    m_asyncUpdateFutureInterface = new QFutureInterface<void>();

hjk's avatar
hjk committed
906
    Core::ProgressManager *progressManager = Core::ICore::progressManager();
dt's avatar
dt committed
907

con's avatar
con committed
908
    m_asyncUpdateFutureInterface->setProgressRange(0, 0);
909
910
    progressManager->addTask(m_asyncUpdateFutureInterface->future(), tr("Evaluating"),
                             QLatin1String(Constants::PROFILE_EVALUATE));
dt's avatar
dt committed
911
912
    if (debug)
        qDebug()<<"  adding task";
dt's avatar
dt committed
913
914
915
916

    m_asyncUpdateFutureInterface->reportStarted();

    if (m_asyncUpdateState == AsyncFullUpdatePending) {
dt's avatar
dt committed
917
918
        if (debug)
            qDebug()<<"  full update, starting with root node";
dt's avatar
dt committed
919
920
        m_rootProjectNode->asyncUpdate();
    } else {
dt's avatar
dt committed
921
922
        if (debug)
            qDebug()<<"  partial update,"<<m_partialEvaluate.size()<<"nodes to update";
923
        foreach (Qt4ProFileNode *node, m_partialEvaluate)
dt's avatar
dt committed
924
925
926
927
            node->asyncUpdate();
    }

    m_partialEvaluate.clear();
dt's avatar
dt committed
928
929
    if (debug)
        qDebug()<<"  Setting state to AsyncUpdateInProgress";
dt's avatar
dt committed
930
    m_asyncUpdateState = AsyncUpdateInProgress;
con's avatar
con committed
931
932
933
934
935
936
937
938
939
940
941
942
}

ProjectExplorer::IProjectManager *Qt4Project::projectManager() const
{
    return m_manager;
}

Qt4Manager *Qt4Project::qt4ProjectManager() const
{
    return m_manager;
}

943
bool Qt4Project::supportsKit(Kit *k, QString *errorMessage) const
Tobias Hunger's avatar
Tobias Hunger committed
944
{
945
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
946
947
    if (!version && errorMessage)
        *errorMessage = tr("No Qt version set in kit.");
Tobias Hunger's avatar
Tobias Hunger committed
948
949
950
    return version;
}

951
QString Qt4Project::displayName() const
con's avatar
con committed
952
{
953
    return QFileInfo(document()->fileName()).completeBaseName();
con's avatar
con committed
954
955
}

956
Core::Id Qt4Project::id() const
Tobias Hunger's avatar
Tobias Hunger committed
957
{
958
    return Core::Id(Constants::QT4PROJECT_ID);
Tobias Hunger's avatar
Tobias Hunger committed
959
960
}

961
Core::IDocument *Qt4Project::document() const
con's avatar
con committed
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
{
    return m_fileInfo;
}

QStringList Qt4Project::files(FilesMode fileMode) const
{
    QStringList files;
    for (int i = 0; i < FileTypeSize; ++i) {
        files += m_projectFiles->files[i];
        if (fileMode == AllFiles)
            files += m_projectFiles->generatedFiles[i];
    }
    return files;
}

977
978
979
// Find the folder that contains a file a certain type (recurse down)
static FolderNode *folderOf(FolderNode *in, FileType fileType, const QString &fileName)
{
980
    foreach (FileNode *fn, in->fileNodes())
981
982
        if (fn->fileType() == fileType && fn->path() == fileName)
            return in;
983
    foreach (FolderNode *folder, in->subFolderNodes())
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
        if (FolderNode *pn = folderOf(folder, fileType, fileName))
            return pn;
    return 0;
}

// Find the Qt4ProFileNode that contains a file of a certain type.
// First recurse down to folder, then find the pro-file.
static Qt4ProFileNode *proFileNodeOf(Qt4ProFileNode *in, FileType fileType, const QString &fileName)
{
    for (FolderNode *folder =  folderOf(in, fileType, fileName); folder; folder = folder->parentFolderNode())
        if (Qt4ProFileNode *proFile = qobject_cast<Qt4ProFileNode *>(folder))
            return proFile;
    return 0;
}

QString Qt4Project::generatedUiHeader(const QString &formFile) const
{
    // Look in sub-profiles as SessionManager::projectForFile returns
    // the top-level project only.
    if (m_rootProjectNode)
        if (const Qt4ProFileNode *pro = proFileNodeOf(m_rootProjectNode, FormType, formFile))
            return Qt4ProFileNode::uiHeaderFile(pro->uiDirectory(), formFile);
    return QString();
}

con's avatar
con committed
1009
1010
void Qt4Project::proFileParseError(const QString &errorMessage)
{
hjk's avatar
hjk committed
1011
    Core::ICore::messageManager()->printToOutputPanePopup(errorMessage);
con's avatar
con committed
1012
1013
}

1014
QtSupport::ProFileReader *Qt4Project::createProFileReader(const Qt4ProFileNode *qt4ProFileNode, Qt4BuildConfiguration *bc)
1015
{
1016
    if (!m_qmakeGlobals) {
1017
        m_qmakeGlobals = new ProFileGlobals;
1018
        m_qmakeGlobalsRefCnt = 0;
1019

Tobias Hunger's avatar
Tobias Hunger committed
1020
        Kit *k;
1021
1022
        Utils::Environment env = Utils::Environment::systemEnvironment();
        QStringList qmakeArgs;
Orgad Shaneh's avatar
Orgad Shaneh committed
1023
        if (!bc)
1024
            bc = activeTarget() ? static_cast<Qt4BuildConfiguration *>(activeTarget()->activeBuildConfiguration()) : 0;
Orgad Shaneh's avatar
Orgad Shaneh committed
1025
1026

        if (bc) {
Tobias Hunger's avatar
Tobias Hunger committed
1027
            k = bc->target()->kit();
Orgad Shaneh's avatar
Orgad Shaneh committed
1028
            env = bc->environment();
1029
            if (bc->qmakeStep())
Orgad Shaneh's avatar
Orgad Shaneh committed
1030
                qmakeArgs = bc->qmakeStep()->parserArguments();
1031
            else
1032
1033
                qmakeArgs = bc->configCommandLineArguments();
        } else {
Tobias Hunger's avatar
Tobias Hunger committed
1034
            k = KitManager::instance()->defaultKit();
1035
        }
1036

Tobias Hunger's avatar
Tobias Hunger committed
1037
1038
1039
        QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k);
        QString systemRoot = SysRootKitInformation::hasSysRoot(k)
                ? SysRootKitInformation::sysRoot(k).toString() : QString();
Tobias Hunger's avatar
Tobias Hunger committed
1040

1041
1042
        if (qtVersion && qtVersion->isValid()) {
            m_qmakeGlobals->qmake_abslocation = QDir::cleanPath(qtVersion->qmakeCommand().toString());
1043
            m_qmakeGlobals->setProperties(qtVersion->versionInfo());
1044
        }
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
1045
        m_qmakeGlobals->setDirectories(m_rootProjectNode->sourceDir(), m_rootProjectNode->buildDir());
1046
        m_qmakeGlobals->sysroot = systemRoot;
1047
1048
1049

        Utils::Environment::const_iterator eit = env.constBegin(), eend = env.constEnd();
        for (; eit != eend; ++eit)
1050
            m_qmakeGlobals->environment.insert(env.key(eit), env.value(eit));
1051

1052
        m_qmakeGlobals->setCommandLineArguments(m_rootProjectNode->buildDir(), qmakeArgs);
1053

1054
        QtSupport::ProFileCacheManager::instance()->incRefCount();
1055
    }
1056
    ++m_qmakeGlobalsRefCnt;
1057

1058
    QtSupport::ProFileReader *reader = new QtSupport::ProFileReader(m_qmakeGlobals);
1059
1060
1061
1062
1063
1064

    reader->setOutputDir(qt4ProFileNode->buildDir());

    return reader;
}

1065
ProFileGlobals *Qt4Project::qmakeGlobals()
1066
{
1067
    return m_qmakeGlobals;
1068
1069
}

1070
void Qt4Project::destroyProFileReader(QtSupport::ProFileReader *reader)
1071
1072
{
    delete reader;
1073
    if (!--m_qmakeGlobalsRefCnt) {
1074
1075
1076
        QString dir = QFileInfo(m_fileInfo->fileName()).absolutePath();
        if (!dir.endsWith(QLatin1Char('/')))
            dir += QLatin1Char('/');
1077
1078
        QtSupport::ProFileCacheManager::instance()->discardFiles(dir);
        QtSupport::ProFileCacheManager::instance()->decRefCount();
1079

1080
1081
        delete m_qmakeGlobals;
        m_qmakeGlobals = 0;
1082
1083
1084
    }
}

1085
1086
1087
1088
1089
1090
ProjectExplorer::ProjectNode *Qt4Project::rootProjectNode() const
{
    return m_rootProjectNode;
}

Qt4ProFileNode *Qt4Project::rootQt4ProjectNode() const