2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
**
|
2010-03-05 11:25:49 +01:00
|
|
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-06-17 00:01:27 +10:00
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** Commercial Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** 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.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** 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.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** If you are unsure which license is appropriate for your use, please
|
2009-08-14 09:30:56 +02:00
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
**************************************************************************/
|
2008-12-02 16:19:05 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "qt4project.h"
|
2008-12-02 16:19:05 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "profilereader.h"
|
2010-02-08 15:50:06 +01:00
|
|
|
#include "qt4projectmanager.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "makestep.h"
|
|
|
|
#include "qmakestep.h"
|
|
|
|
#include "qt4runconfiguration.h"
|
|
|
|
#include "qt4nodes.h"
|
2009-04-20 17:21:31 +02:00
|
|
|
#include "qt4projectconfigwidget.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "qt4projectmanagerconstants.h"
|
|
|
|
#include "projectloadwizard.h"
|
2009-11-23 12:11:48 +01:00
|
|
|
#include "qt4buildconfiguration.h"
|
2009-06-22 14:32:54 +02:00
|
|
|
|
2009-01-20 11:52:04 +01:00
|
|
|
#include <coreplugin/icore.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <coreplugin/messagemanager.h>
|
|
|
|
#include <coreplugin/coreconstants.h>
|
2010-03-10 16:55:37 +01:00
|
|
|
#include <coreplugin/progressmanager/progressmanager.h>
|
2009-01-19 12:39:20 +01:00
|
|
|
#include <extensionsystem/pluginmanager.h>
|
2010-03-17 17:45:33 +01:00
|
|
|
#include <cpptools/cppmodelmanagerinterface.h>
|
2010-03-11 17:47:09 +01:00
|
|
|
#include <projectexplorer/buildenvironmentwidget.h>
|
2010-02-08 15:50:06 +01:00
|
|
|
#include <projectexplorer/customexecutablerunconfiguration.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <projectexplorer/nodesvisitor.h>
|
|
|
|
#include <projectexplorer/project.h>
|
2009-09-24 16:02:02 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
#include <QtCore/QDebug>
|
2009-01-19 12:39:20 +01:00
|
|
|
#include <QtCore/QDir>
|
|
|
|
#include <QtGui/QFileDialog>
|
2009-09-24 16:02:02 +02:00
|
|
|
#include <QtGui/QInputDialog>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
using namespace Qt4ProjectManager;
|
|
|
|
using namespace Qt4ProjectManager::Internal;
|
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
|
|
|
enum { debug = 0 };
|
|
|
|
|
|
|
|
namespace Qt4ProjectManager {
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
// Qt4ProjectFiles: Struct for (Cached) lists of files in a project
|
|
|
|
struct Qt4ProjectFiles {
|
|
|
|
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
|
|
|
|
{
|
|
|
|
Q_DISABLE_COPY(ProjectFilesVisitor)
|
|
|
|
ProjectFilesVisitor(Qt4ProjectFiles *files);
|
|
|
|
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
|
|
|
|
Qt4ProjectFile::Qt4ProjectFile(Qt4Project *project, const QString &filePath, QObject *parent)
|
|
|
|
: Core::IFile(parent),
|
|
|
|
m_mimeType(QLatin1String(Qt4ProjectManager::Constants::PROFILE_MIMETYPE)),
|
|
|
|
m_project(project),
|
|
|
|
m_filePath(filePath)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4ProjectFile::save(const QString &)
|
|
|
|
{
|
2008-12-05 14:29:18 +01:00
|
|
|
// This is never used
|
|
|
|
return false;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2008-12-05 14:29:18 +01:00
|
|
|
return false; // we save after changing anyway
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4ProjectFile::isReadOnly() const
|
|
|
|
{
|
2008-12-02 18:14:06 +01:00
|
|
|
QFileInfo fi(m_filePath);
|
|
|
|
return !fi.isWritable();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4ProjectFile::isSaveAsAllowed() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-03-19 10:28:05 +01:00
|
|
|
Core::IFile::ReloadBehavior Qt4ProjectFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-03-19 10:28:05 +01:00
|
|
|
Q_UNUSED(state)
|
|
|
|
Q_UNUSED(type)
|
|
|
|
return BehaviorSilent;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4ProjectFile::reload(ReloadFlag flag, ChangeType type)
|
|
|
|
{
|
|
|
|
Q_UNUSED(flag)
|
|
|
|
Q_UNUSED(type)
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2009-07-14 15:25:30 +02:00
|
|
|
\class Qt4Project
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
Qt4Project manages information about an individual Qt 4 (.pro) project file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
Qt4Project::Qt4Project(Qt4Manager *manager, const QString& fileName) :
|
|
|
|
m_manager(manager),
|
2009-03-12 15:01:01 +01:00
|
|
|
m_rootProjectNode(0),
|
2008-12-02 12:01:29 +01:00
|
|
|
m_nodesWatcher(new Internal::Qt4NodesWatcher(this)),
|
2010-02-08 15:50:06 +01:00
|
|
|
m_targetFactory(new Qt4TargetFactory(this)),
|
2008-12-02 12:01:29 +01:00
|
|
|
m_fileInfo(new Qt4ProjectFile(this, fileName, this)),
|
2009-12-03 18:37:27 +01:00
|
|
|
m_projectFiles(new Qt4ProjectFiles),
|
2010-03-10 16:55:37 +01:00
|
|
|
m_proFileOption(0),
|
|
|
|
m_asyncUpdateFutureInterface(0),
|
|
|
|
m_pendingEvaluateFuturesCount(0),
|
|
|
|
m_asyncUpdateState(NoState),
|
|
|
|
m_cancelEvaluate(false)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-03-10 16:55:37 +01:00
|
|
|
m_asyncUpdateTimer.setSingleShot(true);
|
|
|
|
m_asyncUpdateTimer.setInterval(3000);
|
|
|
|
connect(&m_asyncUpdateTimer, SIGNAL(timeout()), this, SLOT(asyncUpdate()));
|
2010-02-17 16:18:21 +01:00
|
|
|
|
|
|
|
setSupportedTargetIds(QtVersionManager::instance()->supportedTargetIds());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Qt4Project::~Qt4Project()
|
|
|
|
{
|
2010-03-11 17:01:06 +01:00
|
|
|
m_asyncUpdateState = ShuttingDown;
|
2008-12-02 18:14:06 +01:00
|
|
|
m_manager->unregisterProject(this);
|
2008-12-02 12:01:29 +01:00
|
|
|
delete m_projectFiles;
|
2010-03-11 17:01:06 +01:00
|
|
|
m_cancelEvaluate = true;
|
|
|
|
delete m_rootProjectNode;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-19 16:33:44 +01:00
|
|
|
bool Qt4Project::fromMap(const QVariantMap &map)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-01-19 16:33:44 +01:00
|
|
|
if (!Project::fromMap(map))
|
|
|
|
return false;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
// Prune targets without buildconfigurations:
|
|
|
|
// This can happen esp. when updating from a old version of Qt Creator
|
|
|
|
QList<Target *>ts(targets());
|
|
|
|
foreach (Target *t, ts) {
|
2010-02-18 18:37:11 +01:00
|
|
|
if (t->buildConfigurations().isEmpty()) {
|
|
|
|
qWarning() << "Removing" << t->id() << "since it has no buildconfigurations!";
|
2010-02-08 15:50:06 +01:00
|
|
|
removeTarget(t);
|
2010-02-18 18:37:11 +01:00
|
|
|
}
|
2010-02-08 15:50:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add buildconfigurations so we can parse the pro-files.
|
|
|
|
if (targets().isEmpty())
|
2009-10-15 19:06:51 +02:00
|
|
|
addDefaultBuild();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-19 11:07:15 +01:00
|
|
|
if (targets().isEmpty()) {
|
|
|
|
qWarning() << "Unable to create targets!";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
Q_ASSERT(activeTarget());
|
|
|
|
Q_ASSERT(activeTarget()->activeBuildConfiguration());
|
2009-10-06 17:16:18 +02:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
m_manager->registerProject(this);
|
|
|
|
|
|
|
|
m_rootProjectNode = new Qt4ProFileNode(this, m_fileInfo->fileName(), this);
|
|
|
|
m_rootProjectNode->registerWatcher(m_nodesWatcher);
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
update();
|
|
|
|
updateFileList();
|
|
|
|
// This might be incorrect, need a full update
|
2010-03-10 16:55:37 +01:00
|
|
|
updateCodeModel();
|
2010-04-07 13:41:46 +02:00
|
|
|
createApplicationProjects();
|
2009-03-12 15:01:01 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
foreach (Target *t, targets())
|
|
|
|
onAddedTarget(t);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
setSupportedTargetIds(QtVersionManager::instance()->supportedTargetIds());
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
// Setup Qt versions supported (== possible targets).
|
|
|
|
connect(this, SIGNAL(addedTarget(ProjectExplorer::Target*)),
|
|
|
|
this, SLOT(onAddedTarget(ProjectExplorer::Target*)));
|
|
|
|
|
|
|
|
connect(QtVersionManager::instance(), SIGNAL(qtVersionsChanged(QList<int>)),
|
|
|
|
this, SLOT(qtVersionsChanged()));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
connect(m_nodesWatcher, SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *)),
|
2009-12-03 18:37:27 +01:00
|
|
|
this, SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *)));
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
connect(this, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
|
|
|
|
this, SLOT(activeTargetWasChanged()));
|
|
|
|
|
2009-07-03 16:46:01 +02:00
|
|
|
return true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
Qt4TargetFactory *Qt4Project::targetFactory() const
|
2009-09-24 16:02:02 +02:00
|
|
|
{
|
2010-02-08 15:50:06 +01:00
|
|
|
return m_targetFactory;
|
2009-09-24 16:02:02 +02:00
|
|
|
}
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
Qt4Target *Qt4Project::activeTarget() const
|
2009-10-09 18:14:12 +02:00
|
|
|
{
|
2010-02-08 15:50:06 +01:00
|
|
|
return static_cast<Qt4Target *>(Project::activeTarget());
|
2009-10-09 18:14:12 +02:00
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
namespace {
|
|
|
|
class FindQt4ProFiles: protected ProjectExplorer::NodesVisitor {
|
|
|
|
QList<Qt4ProFileNode *> m_proFiles;
|
|
|
|
|
|
|
|
public:
|
|
|
|
QList<Qt4ProFileNode *> operator()(ProjectNode *root)
|
|
|
|
{
|
|
|
|
m_proFiles.clear();
|
|
|
|
root->accept(this);
|
|
|
|
return m_proFiles;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void visitProjectNode(ProjectNode *projectNode)
|
|
|
|
{
|
|
|
|
if (Qt4ProFileNode *pro = qobject_cast<Qt4ProFileNode *>(projectNode))
|
|
|
|
m_proFiles.append(pro);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
void Qt4Project::onAddedTarget(ProjectExplorer::Target *t)
|
|
|
|
{
|
|
|
|
Q_ASSERT(t);
|
2010-02-15 17:33:56 +01:00
|
|
|
Qt4Target *qt4target = qobject_cast<Qt4Target *>(t);
|
|
|
|
Q_ASSERT(qt4target);
|
|
|
|
connect(qt4target, SIGNAL(buildDirectoryInitialized()),
|
|
|
|
this, SIGNAL(buildDirectoryInitialized()));
|
2010-03-10 16:55:37 +01:00
|
|
|
connect(qt4target, SIGNAL(proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target*)),
|
|
|
|
this, SLOT(proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target*)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4Project::proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target *target)
|
|
|
|
{
|
|
|
|
if (activeTarget() == target)
|
|
|
|
scheduleAsyncUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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) {
|
|
|
|
if (*ait == QLatin1String("<configuration>"))
|
|
|
|
++ait;
|
|
|
|
else if (*bit == QLatin1String("<configuration>"))
|
|
|
|
++bit;
|
|
|
|
else if (*ait == *bit)
|
|
|
|
++ait, ++bit;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return (ait == aend && bit == bend);
|
2010-02-08 15:50:06 +01:00
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void Qt4Project::updateCodeModel()
|
|
|
|
{
|
|
|
|
if (debug)
|
|
|
|
qDebug()<<"Qt4Project::updateCodeModel()";
|
|
|
|
|
2010-03-02 12:51:47 +01:00
|
|
|
m_codeModelFuture.cancel();
|
2010-03-10 16:55:37 +01:00
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
if (!activeTarget() || !activeTarget()->activeBuildConfiguration())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Qt4BuildConfiguration *activeBC = activeTarget()->activeBuildConfiguration();
|
2009-11-25 18:50:20 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
CppTools::CppModelManagerInterface *modelmanager =
|
2009-01-20 15:31:33 +01:00
|
|
|
ExtensionSystem::PluginManager::instance()
|
|
|
|
->getObject<CppTools::CppModelManagerInterface>();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-01-20 15:31:33 +01:00
|
|
|
if (!modelmanager)
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
|
2010-01-12 12:15:06 +01:00
|
|
|
// Collect global headers/defines
|
2009-05-04 18:22:40 +02:00
|
|
|
QStringList predefinedIncludePaths;
|
|
|
|
QStringList predefinedFrameworkPaths;
|
|
|
|
QByteArray predefinedMacros;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-11-26 14:43:27 +01:00
|
|
|
ToolChain *tc = activeBC->toolChain();
|
2009-02-12 12:39:19 +01:00
|
|
|
if (tc) {
|
|
|
|
predefinedMacros = tc->predefinedMacros();
|
2010-02-08 15:50:06 +01:00
|
|
|
//qDebug()<<"Predefined Macros";
|
2009-02-12 16:09:23 +01:00
|
|
|
//qDebug()<<tc->predefinedMacros();
|
|
|
|
//qDebug()<<"";
|
|
|
|
//qDebug()<<"System Header Paths";
|
|
|
|
//foreach(const HeaderPath &hp, tc->systemHeaderPaths())
|
|
|
|
// qDebug()<<hp.path();
|
2009-05-04 18:22:40 +02:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
foreach (const HeaderPath &headerPath, tc->systemHeaderPaths()) {
|
|
|
|
if (headerPath.kind() == HeaderPath::FrameworkHeaderPath)
|
|
|
|
predefinedFrameworkPaths.append(headerPath.path());
|
|
|
|
else
|
|
|
|
predefinedIncludePaths.append(headerPath.path());
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2009-05-05 10:17:32 +02:00
|
|
|
FindQt4ProFiles findQt4ProFiles;
|
|
|
|
QList<Qt4ProFileNode *> proFiles = findQt4ProFiles(rootProjectNode());
|
2010-03-10 16:55:37 +01:00
|
|
|
QByteArray allDefinedMacros = predefinedMacros;
|
|
|
|
QStringList allIncludePaths;
|
2009-05-05 10:17:32 +02:00
|
|
|
QStringList allFrameworkPaths = predefinedFrameworkPaths;
|
2010-01-12 13:13:22 +01:00
|
|
|
QStringList allPrecompileHeaders;
|
2009-05-05 10:17:32 +02:00
|
|
|
|
2010-01-12 12:15:06 +01:00
|
|
|
// Collect per .pro file information
|
|
|
|
m_codeModelInfo.clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (Qt4ProFileNode *pro, proFiles) {
|
2009-05-04 18:22:40 +02:00
|
|
|
Internal::CodeModelInfo info;
|
|
|
|
info.defines = predefinedMacros;
|
|
|
|
info.frameworkPaths = predefinedFrameworkPaths;
|
|
|
|
|
2010-01-12 13:13:22 +01:00
|
|
|
info.precompiledHeader = pro->variableValue(PrecompiledHeaderVar);
|
|
|
|
|
|
|
|
allPrecompileHeaders.append(info.precompiledHeader);
|
|
|
|
|
2009-05-04 18:22:40 +02:00
|
|
|
// Add custom defines
|
2010-03-10 16:55:37 +01:00
|
|
|
|
2010-02-01 14:00:07 +01:00
|
|
|
foreach (const QString &def, pro->variableValue(DefinesVar)) {
|
2010-03-10 16:55:37 +01:00
|
|
|
allDefinedMacros += "#define ";
|
2009-05-04 18:22:40 +02:00
|
|
|
info.defines += "#define ";
|
2008-12-02 12:01:29 +01:00
|
|
|
const int index = def.indexOf(QLatin1Char('='));
|
|
|
|
if (index == -1) {
|
2010-03-10 16:55:37 +01:00
|
|
|
allDefinedMacros += def.toLatin1();
|
|
|
|
allDefinedMacros += " 1\n";
|
2009-05-04 18:22:40 +02:00
|
|
|
info.defines += def.toLatin1();
|
|
|
|
info.defines += " 1\n";
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
|
|
|
const QString name = def.left(index);
|
|
|
|
const QString value = def.mid(index + 1);
|
2010-03-10 16:55:37 +01:00
|
|
|
allDefinedMacros += name.toLatin1();
|
|
|
|
allDefinedMacros += ' ';
|
|
|
|
allDefinedMacros += value.toLocal8Bit();
|
|
|
|
allDefinedMacros += '\n';
|
2009-05-04 18:22:40 +02:00
|
|
|
info.defines += name.toLatin1();
|
|
|
|
info.defines += ' ';
|
|
|
|
info.defines += value.toLocal8Bit();
|
|
|
|
info.defines += '\n';
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const QStringList proIncludePaths = pro->variableValue(IncludePathVar);
|
2009-05-13 18:09:47 +02:00
|
|
|
foreach (const QString &includePath, proIncludePaths) {
|
2009-05-04 18:22:40 +02:00
|
|
|
if (!allIncludePaths.contains(includePath))
|
2009-11-04 12:51:02 +01:00
|
|
|
allIncludePaths.append(includePath);
|
2009-05-04 18:22:40 +02:00
|
|
|
if (!info.includes.contains(includePath))
|
2009-11-04 12:51:02 +01:00
|
|
|
info.includes.append(includePath);
|
2009-05-04 18:22:40 +02:00
|
|
|
}
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
#if 0 // Experimental PKGCONFIG support
|
2009-05-13 18:09:47 +02:00
|
|
|
{ // Pkg Config support
|
|
|
|
QStringList pkgConfig = pro->variableValue(PkgConfigVar);
|
|
|
|
if (!pkgConfig.isEmpty()) {
|
|
|
|
pkgConfig.prepend("--cflags-only-I");
|
|
|
|
QProcess process;
|
|
|
|
process.start("pkg-config", pkgConfig);
|
|
|
|
process.waitForFinished();
|
|
|
|
QString result = process.readAllStandardOutput();
|
|
|
|
foreach(const QString &part, result.trimmed().split(' ', QString::SkipEmptyParts)) {
|
2009-11-04 12:51:02 +01:00
|
|
|
info.includes.append(part.mid(2)); // Chop off "-I"
|
2009-05-13 18:09:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-01-12 12:15:06 +01:00
|
|
|
#endif
|
2009-05-13 18:09:47 +02:00
|
|
|
|
2009-05-04 18:22:40 +02:00
|
|
|
// Add mkspec directory
|
2009-11-26 14:43:27 +01:00
|
|
|
info.includes.append(activeBC->qtVersion()->mkspecPath());
|
2010-03-10 16:55:37 +01:00
|
|
|
info.includes.append(predefinedIncludePaths);
|
2009-05-04 18:22:40 +02:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
// qDebug()<<"Dumping code model information";
|
|
|
|
// qDebug()<<"for .pro file"<< pro->path();
|
|
|
|
// qDebug()<<info.defines;
|
|
|
|
// qDebug()<<info.includes;
|
|
|
|
// qDebug()<<info.frameworkPaths;
|
|
|
|
// qDebug()<<"\n";
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-12 12:15:06 +01:00
|
|
|
#if 0
|
|
|
|
//Disable for now, we need better .pro file parsing first, and code model
|
|
|
|
//support to access this information
|
|
|
|
|
|
|
|
// TODO this is wastefull
|
2010-02-01 12:43:56 +01:00
|
|
|
// only save it per .pro file, and on being asked
|
2010-01-12 12:15:06 +01:00
|
|
|
// search for the .pro file that has that file
|
2009-05-04 18:22:40 +02:00
|
|
|
foreach (FileNode *fileNode, pro->fileNodes()) {
|
|
|
|
const QString path = fileNode->path();
|
|
|
|
const int type = fileNode->fileType();
|
|
|
|
if (type == HeaderType || type == SourceType) {
|
|
|
|
m_codeModelInfo.insert(path, info);
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-01-12 12:15:06 +01:00
|
|
|
#endif
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2008-12-08 12:44:28 +01:00
|
|
|
// Add mkspec directory
|
2009-11-26 14:43:27 +01:00
|
|
|
allIncludePaths.append(activeBC->qtVersion()->mkspecPath());
|
2008-12-08 12:44:28 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
allIncludePaths.append(predefinedIncludePaths);
|
2009-05-04 18:22:40 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList files;
|
|
|
|
files += m_projectFiles->files[HeaderType];
|
|
|
|
files += m_projectFiles->generatedFiles[HeaderType];
|
|
|
|
files += m_projectFiles->files[SourceType];
|
|
|
|
files += m_projectFiles->generatedFiles[SourceType];
|
|
|
|
|
2008-12-08 10:44:56 +01:00
|
|
|
CppTools::CppModelManagerInterface::ProjectInfo pinfo = modelmanager->projectInfo(this);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-12 13:13:22 +01:00
|
|
|
//qDebug()<<"Using precompiled header"<<allPrecompileHeaders;
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
bool fileList = equalFileList(pinfo.sourceFiles, files);
|
|
|
|
|
|
|
|
if (pinfo.defines == allDefinedMacros
|
2010-01-12 13:13:22 +01:00
|
|
|
&& pinfo.includePaths == allIncludePaths
|
|
|
|
&& pinfo.frameworkPaths == allFrameworkPaths
|
2010-03-10 16:55:37 +01:00
|
|
|
&& fileList
|
2010-01-12 13:13:22 +01:00
|
|
|
&& pinfo.precompiledHeaders == allPrecompileHeaders) {
|
2009-10-26 15:31:43 +01:00
|
|
|
// Nothing to update...
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2010-03-10 16:55:37 +01:00
|
|
|
pinfo.sourceFiles.clear();
|
|
|
|
if (pinfo.defines != allDefinedMacros
|
|
|
|
|| pinfo.includePaths != allIncludePaths
|
|
|
|
|| pinfo.frameworkPaths != allFrameworkPaths
|
|
|
|
|| pinfo.precompiledHeaders != allPrecompileHeaders)
|
|
|
|
{
|
2009-05-04 18:22:40 +02:00
|
|
|
pinfo.sourceFiles.append(QLatin1String("<configuration>"));
|
|
|
|
}
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
//pinfo.defines = predefinedMacros;
|
|
|
|
pinfo.defines = allDefinedMacros;
|
2008-12-08 10:44:56 +01:00
|
|
|
pinfo.includePaths = allIncludePaths;
|
|
|
|
pinfo.frameworkPaths = allFrameworkPaths;
|
2010-03-10 16:55:37 +01:00
|
|
|
pinfo.sourceFiles += files;
|
2010-01-12 13:13:22 +01:00
|
|
|
pinfo.precompiledHeaders = allPrecompileHeaders;
|
2008-12-08 10:44:56 +01:00
|
|
|
|
|
|
|
modelmanager->updateProjectInfo(pinfo);
|
2010-03-02 12:51:47 +01:00
|
|
|
m_codeModelFuture = modelmanager->updateSourceFiles(pinfo.sourceFiles);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-05-04 18:22:40 +02:00
|
|
|
}
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
void Qt4Project::qtVersionsChanged()
|
|
|
|
{
|
|
|
|
setSupportedTargetIds(QtVersionManager::instance()->supportedTargetIds());
|
|
|
|
}
|
|
|
|
|
2009-05-04 18:22:40 +02:00
|
|
|
QByteArray Qt4Project::predefinedMacros(const QString &fileName) const
|
|
|
|
{
|
|
|
|
QMap<QString, CodeModelInfo>::const_iterator it = m_codeModelInfo.constFind(fileName);
|
|
|
|
if (it == m_codeModelInfo.constEnd())
|
|
|
|
return QByteArray();
|
|
|
|
else
|
|
|
|
return (*it).defines;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2009-05-04 18:22:40 +02:00
|
|
|
QStringList Qt4Project::includePaths(const QString &fileName) const
|
|
|
|
{
|
|
|
|
QMap<QString, CodeModelInfo>::const_iterator it = m_codeModelInfo.constFind(fileName);
|
|
|
|
if (it == m_codeModelInfo.constEnd())
|
|
|
|
return QStringList();
|
|
|
|
else
|
|
|
|
return (*it).includes;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList Qt4Project::frameworkPaths(const QString &fileName) const
|
|
|
|
{
|
|
|
|
QMap<QString, CodeModelInfo>::const_iterator it = m_codeModelInfo.constFind(fileName);
|
|
|
|
if (it == m_codeModelInfo.constEnd())
|
|
|
|
return QStringList();
|
|
|
|
else
|
|
|
|
return (*it).frameworkPaths;
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-09 17:17:12 +01:00
|
|
|
///*!
|
|
|
|
// Updates complete project
|
|
|
|
// */
|
2008-12-02 12:01:29 +01:00
|
|
|
void Qt4Project::update()
|
|
|
|
{
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<"Doing sync update";
|
2008-12-02 12:01:29 +01:00
|
|
|
m_rootProjectNode->update();
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<"State is now Base";
|
2010-03-10 16:55:37 +01:00
|
|
|
m_asyncUpdateState = Base;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4Project::scheduleAsyncUpdate(Qt4ProFileNode *node)
|
|
|
|
{
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<"schduleAsyncUpdate (node)";
|
2010-03-10 16:55:37 +01:00
|
|
|
Q_ASSERT(m_asyncUpdateState != NoState);
|
|
|
|
|
|
|
|
if (m_cancelEvaluate) {
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" Already canceling, nothing to do";
|
2010-03-10 16:55:37 +01:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_asyncUpdateState == AsyncFullUpdatePending) {
|
|
|
|
// Just postpone
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" full update pending, restarting timer";
|
2010-03-10 16:55:37 +01:00
|
|
|
m_asyncUpdateTimer.start();
|
|
|
|
} else if (m_asyncUpdateState == AsyncPartialUpdatePending
|
|
|
|
|| m_asyncUpdateState == Base) {
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" adding node to async update list, setting state to AsyncPartialUpdatePending";
|
2010-03-10 16:55:37 +01:00
|
|
|
// Add the node
|
|
|
|
m_asyncUpdateState = AsyncPartialUpdatePending;
|
|
|
|
|
|
|
|
QList<Internal::Qt4ProFileNode *>::iterator it;
|
|
|
|
bool add = true;
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<"scheduleAsyncUpdate();"<<m_partialEvaluate.size()<<"nodes";
|
2010-03-10 16:55:37 +01:00
|
|
|
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
|
|
|
|
add = false;
|
|
|
|
break;
|
|
|
|
} else if ((*it)->isParent(node)) { // The node is the parent of a child already in the list
|
|
|
|
it = m_partialEvaluate.erase(it);
|
|
|
|
} else {
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (add)
|
|
|
|
m_partialEvaluate.append(node);
|
|
|
|
// and start the timer anew
|
|
|
|
m_asyncUpdateTimer.start();
|
|
|
|
} 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
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" Async update in progress, scheduling new one afterwards";
|
2010-03-10 16:55:37 +01:00
|
|
|
scheduleAsyncUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4Project::scheduleAsyncUpdate()
|
|
|
|
{
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<"scheduleAsyncUpdate";
|
2010-03-10 16:55:37 +01:00
|
|
|
Q_ASSERT(m_asyncUpdateState != NoState);
|
|
|
|
if (m_cancelEvaluate) { // we are in progress of canceling
|
|
|
|
// and will start the evaluation after that
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" canceling is in progress, doing nothing";
|
2010-03-10 16:55:37 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (m_asyncUpdateState == AsyncUpdateInProgress) {
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" update in progress, canceling and setting state to full update pending";
|
2010-03-10 16:55:37 +01:00
|
|
|
m_cancelEvaluate = true;
|
|
|
|
m_asyncUpdateState = AsyncFullUpdatePending;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" starting timer for full update, setting state to full update pending";
|
2010-03-10 16:55:37 +01:00
|
|
|
m_partialEvaluate.clear();
|
|
|
|
m_asyncUpdateState = AsyncFullUpdatePending;
|
|
|
|
m_asyncUpdateTimer.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Qt4Project::incrementPendingEvaluateFutures()
|
|
|
|
{
|
|
|
|
++m_pendingEvaluateFuturesCount;
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<"incrementPendingEvaluateFutures to"<<m_pendingEvaluateFuturesCount;
|
2010-03-10 16:55:37 +01:00
|
|
|
|
|
|
|
m_asyncUpdateFutureInterface->setProgressRange(m_asyncUpdateFutureInterface->progressMinimum(),
|
|
|
|
m_asyncUpdateFutureInterface->progressMaximum() + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4Project::decrementPendingEvaluateFutures()
|
|
|
|
{
|
|
|
|
--m_pendingEvaluateFuturesCount;
|
|
|
|
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<"decrementPendingEvaluateFutures to"<<m_pendingEvaluateFuturesCount;
|
2010-03-10 16:55:37 +01:00
|
|
|
|
|
|
|
m_asyncUpdateFutureInterface->setProgressValue(m_asyncUpdateFutureInterface->progressValue() + 1);
|
|
|
|
if (m_pendingEvaluateFuturesCount == 0) {
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" WOHOO, no pending futures, cleaning up";
|
2010-03-10 16:55:37 +01:00
|
|
|
// We are done!
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" reporting finished";
|
2010-03-10 16:55:37 +01:00
|
|
|
m_asyncUpdateFutureInterface->reportFinished();
|
|
|
|
delete m_asyncUpdateFutureInterface;
|
|
|
|
m_asyncUpdateFutureInterface = 0;
|
|
|
|
m_cancelEvaluate = false;
|
|
|
|
|
|
|
|
// TODO clear the profile cache ?
|
|
|
|
if (m_asyncUpdateState == AsyncFullUpdatePending || m_asyncUpdateState == AsyncPartialUpdatePending) {
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" Oh update is pending start the timer";
|
2010-03-10 16:55:37 +01:00
|
|
|
m_asyncUpdateTimer.start();
|
2010-03-11 17:01:06 +01:00
|
|
|
} else if (m_asyncUpdateState != ShuttingDown){
|
|
|
|
// After beeing done, we need to call:
|
|
|
|
updateFileList();
|
|
|
|
updateCodeModel();
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" Setting state to Base";
|
2010-03-10 16:55:37 +01:00
|
|
|
m_asyncUpdateState = Base;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4Project::wasEvaluateCanceled()
|
|
|
|
{
|
|
|
|
return m_cancelEvaluate;
|
|
|
|
}
|
|
|
|
|
2010-03-25 11:55:29 +01:00
|
|
|
QString Qt4Project::defaultTopLevelBuildDirectory() const
|
|
|
|
{
|
|
|
|
QFileInfo info(file()->fileName());
|
2010-03-29 16:47:58 +02:00
|
|
|
return QDir(projectDirectory() + QLatin1String("/../") + info.baseName() + QLatin1String("-build")).absolutePath();
|
2010-03-25 11:55:29 +01:00
|
|
|
}
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
void Qt4Project::asyncUpdate()
|
|
|
|
{
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<"async update, timer expired, doing now";
|
2010-03-10 16:55:37 +01:00
|
|
|
Q_ASSERT(!m_asyncUpdateFutureInterface);
|
|
|
|
m_asyncUpdateFutureInterface = new QFutureInterface<void>();
|
|
|
|
|
|
|
|
Core::ProgressManager *progressManager = Core::ICore::instance()->progressManager();
|
|
|
|
|
2010-04-13 16:32:01 +02:00
|
|
|
m_asyncUpdateFutureInterface->setProgressRange(0, 0);
|
|
|
|
progressManager->addTask(m_asyncUpdateFutureInterface->future(), tr("Evaluating"), Constants::PROFILE_EVALUATE);
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" adding task";
|
2010-03-10 16:55:37 +01:00
|
|
|
|
|
|
|
m_asyncUpdateFutureInterface->reportStarted();
|
|
|
|
|
|
|
|
if (m_asyncUpdateState == AsyncFullUpdatePending) {
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" full update, starting with root node";
|
2010-03-10 16:55:37 +01:00
|
|
|
m_rootProjectNode->asyncUpdate();
|
|
|
|
} else {
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" partial update,"<<m_partialEvaluate.size()<<"nodes to update";
|
2010-03-10 16:55:37 +01:00
|
|
|
foreach(Qt4ProFileNode *node, m_partialEvaluate)
|
|
|
|
node->asyncUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_partialEvaluate.clear();
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" Setting state to AsyncUpdateInProgress";
|
2010-03-10 16:55:37 +01:00
|
|
|
m_asyncUpdateState = AsyncUpdateInProgress;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ProjectExplorer::IProjectManager *Qt4Project::projectManager() const
|
|
|
|
{
|
|
|
|
return m_manager;
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt4Manager *Qt4Project::qt4ProjectManager() const
|
|
|
|
{
|
|
|
|
return m_manager;
|
|
|
|
}
|
|
|
|
|
2010-01-07 18:17:24 +01:00
|
|
|
QString Qt4Project::displayName() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
return QFileInfo(file()->fileName()).completeBaseName();
|
|
|
|
}
|
|
|
|
|
2010-01-22 15:59:44 +01:00
|
|
|
QString Qt4Project::id() const
|
|
|
|
{
|
|
|
|
return QLatin1String("Qt4ProjectManager.Qt4Project");
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
Core::IFile *Qt4Project::file() const
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-12-03 16:23:15 +01:00
|
|
|
// Find the folder that contains a file a certain type (recurse down)
|
|
|
|
static FolderNode *folderOf(FolderNode *in, FileType fileType, const QString &fileName)
|
|
|
|
{
|
|
|
|
foreach(FileNode *fn, in->fileNodes())
|
|
|
|
if (fn->fileType() == fileType && fn->path() == fileName)
|
|
|
|
return in;
|
|
|
|
foreach(FolderNode *folder, in->subFolderNodes())
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<ProjectExplorer::Project*> Qt4Project::dependsOn()
|
|
|
|
{
|
|
|
|
// NBS implement dependsOn
|
|
|
|
return QList<Project *>();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4Project::addDefaultBuild()
|
|
|
|
{
|
2009-10-15 19:06:51 +02:00
|
|
|
// TODO this could probably refactored
|
|
|
|
// That is the ProjectLoadWizard divided into useful bits
|
|
|
|
// and this code then called here, instead of that strange forwarding
|
|
|
|
// to a wizard, which doesn't even show up
|
|
|
|
ProjectLoadWizard wizard(this);
|
|
|
|
wizard.execDialog();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4Project::proFileParseError(const QString &errorMessage)
|
|
|
|
{
|
2009-01-20 15:31:33 +01:00
|
|
|
Core::ICore::instance()->messageManager()->printToOutputPane(errorMessage);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2009-12-07 20:49:39 +01:00
|
|
|
ProFileReader *Qt4Project::createProFileReader(Qt4ProFileNode *qt4ProFileNode)
|
|
|
|
{
|
|
|
|
if (!m_proFileOption) {
|
|
|
|
m_proFileOption = new ProFileOption;
|
|
|
|
m_proFileOptionRefCnt = 0;
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
if (activeTarget() &&
|
|
|
|
activeTarget()->activeBuildConfiguration()) {
|
|
|
|
QtVersion *version = activeTarget()->activeBuildConfiguration()->qtVersion();
|
2009-12-07 20:49:39 +01:00
|
|
|
if (version->isValid())
|
|
|
|
m_proFileOption->properties = version->versionInfo();
|
|
|
|
}
|
2009-12-07 22:58:47 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
ProFileCacheManager::instance()->incRefCount();
|
2009-12-07 22:58:47 +01:00
|
|
|
m_proFileOption->cache = ProFileCacheManager::instance()->cache();
|
2009-12-07 20:49:39 +01:00
|
|
|
}
|
|
|
|
++m_proFileOptionRefCnt;
|
|
|
|
|
|
|
|
ProFileReader *reader = new ProFileReader(m_proFileOption);
|
|
|
|
connect(reader, SIGNAL(errorFound(QString)),
|
|
|
|
this, SLOT(proFileParseError(QString)));
|
|
|
|
|
|
|
|
reader->setOutputDir(qt4ProFileNode->buildDir());
|
|
|
|
|
|
|
|
return reader;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4Project::destroyProFileReader(ProFileReader *reader)
|
|
|
|
{
|
|
|
|
delete reader;
|
|
|
|
if (!--m_proFileOptionRefCnt) {
|
2009-12-07 22:58:47 +01:00
|
|
|
QString dir = QFileInfo(m_fileInfo->fileName()).absolutePath();
|
|
|
|
if (!dir.endsWith(QLatin1Char('/')))
|
|
|
|
dir += QLatin1Char('/');
|
|
|
|
m_proFileOption->cache->discardFiles(dir);
|
|
|
|
|
2009-12-07 20:49:39 +01:00
|
|
|
delete m_proFileOption;
|
|
|
|
m_proFileOption = 0;
|
2010-03-10 16:55:37 +01:00
|
|
|
ProFileCacheManager::instance()->decRefCount();
|
2009-12-07 20:49:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
Qt4ProFileNode *Qt4Project::rootProjectNode() const
|
|
|
|
{
|
|
|
|
return m_rootProjectNode;
|
|
|
|
}
|
|
|
|
|
2009-08-06 15:31:32 +02:00
|
|
|
BuildConfigWidget *Qt4Project::createConfigWidget()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-04-20 17:21:31 +02:00
|
|
|
return new Qt4ProjectConfigWidget(this);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2009-08-06 15:31:32 +02:00
|
|
|
QList<BuildConfigWidget*> Qt4Project::subConfigWidgets()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-08-06 15:31:32 +02:00
|
|
|
QList<BuildConfigWidget*> subWidgets;
|
2010-03-11 17:47:09 +01:00
|
|
|
subWidgets << new BuildEnvironmentWidget;
|
2008-12-02 12:01:29 +01:00
|
|
|
return subWidgets;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4Project::collectApplicationProFiles(QList<Qt4ProFileNode *> &list, Qt4ProFileNode *node)
|
|
|
|
{
|
|
|
|
if (node->projectType() == Internal::ApplicationTemplate
|
|
|
|
|| node->projectType() == Internal::ScriptTemplate) {
|
|
|
|
list.append(node);
|
|
|
|
}
|
|
|
|
foreach (ProjectNode *n, node->subProjectNodes()) {
|
|
|
|
Qt4ProFileNode *qt4ProFileNode = qobject_cast<Qt4ProFileNode *>(n);
|
|
|
|
if (qt4ProFileNode)
|
|
|
|
collectApplicationProFiles(list, qt4ProFileNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-07 13:41:46 +02:00
|
|
|
void Qt4Project::createApplicationProjects()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-04-07 13:41:46 +02:00
|
|
|
foreach (Target *target, targets()) {
|
|
|
|
if (target->runConfigurations().count()) {
|
|
|
|
// Remove all run configurations which the new project wizard created
|
|
|
|
QList<RunConfiguration*> toRemove;
|
|
|
|
foreach (RunConfiguration * rc, target->runConfigurations()) {
|
|
|
|
CustomExecutableRunConfiguration *cerc = qobject_cast<CustomExecutableRunConfiguration *>(rc);
|
|
|
|
if (cerc && !cerc->isConfigured())
|
|
|
|
toRemove.append(rc);
|
2010-03-30 19:14:26 +02:00
|
|
|
}
|
2010-04-07 13:41:46 +02:00
|
|
|
foreach (RunConfiguration *rc, toRemove)
|
|
|
|
target->removeRunConfiguration(rc);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-04-07 13:41:46 +02:00
|
|
|
// Only add new runconfigurations if there are none.
|
|
|
|
if (target->runConfigurations().isEmpty()) {
|
|
|
|
Qt4Target *qt4Target = static_cast<Qt4Target *>(target);
|
|
|
|
foreach (Qt4ProFileNode *qt4proFile, applicationProFiles()) {
|
|
|
|
qt4Target->addRunConfigurationForPath(qt4proFile->path());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
2010-04-07 13:41:46 +02:00
|
|
|
// Oh still none? Add a custom executable runconfiguration
|
2010-02-08 15:50:06 +01:00
|
|
|
if (target->runConfigurations().isEmpty()) {
|
|
|
|
target->addRunConfiguration(new ProjectExplorer::CustomExecutableRunConfiguration(target));
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<Qt4ProFileNode *> Qt4Project::applicationProFiles() const
|
|
|
|
{
|
|
|
|
QList<Qt4ProFileNode *> list;
|
2010-02-08 15:50:06 +01:00
|
|
|
if (!rootProjectNode())
|
|
|
|
return list;
|
2008-12-02 12:01:29 +01:00
|
|
|
collectApplicationProFiles(list, rootProjectNode());
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2010-01-19 13:41:02 +01:00
|
|
|
bool Qt4Project::hasApplicationProFile(const QString &path) const
|
|
|
|
{
|
|
|
|
if (path.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QList<Qt4ProFileNode *> list = applicationProFiles();
|
|
|
|
foreach (Qt4ProFileNode * node, list)
|
|
|
|
if (node->path() == path)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList Qt4Project::applicationProFilePathes(const QString &prepend) const
|
|
|
|
{
|
|
|
|
QStringList proFiles;
|
|
|
|
foreach (Qt4ProFileNode *node, applicationProFiles())
|
|
|
|
proFiles.append(prepend + node->path());
|
|
|
|
return proFiles;
|
|
|
|
}
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
void Qt4Project::activeTargetWasChanged()
|
|
|
|
{
|
|
|
|
if (!activeTarget())
|
|
|
|
return;
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
scheduleAsyncUpdate();
|
2010-02-08 15:50:06 +01:00
|
|
|
}
|
|
|
|
|
2008-12-05 14:29:18 +01:00
|
|
|
bool Qt4Project::hasSubNode(Qt4PriFileNode *root, const QString &path)
|
2008-12-02 18:14:06 +01:00
|
|
|
{
|
2008-12-05 14:29:18 +01:00
|
|
|
if (root->path() == path)
|
|
|
|
return true;
|
|
|
|
foreach (FolderNode *fn, root->subFolderNodes()) {
|
|
|
|
if (qobject_cast<Qt4ProFileNode *>(fn)) {
|
|
|
|
// we aren't interested in pro file nodes
|
2008-12-09 11:07:24 +01:00
|
|
|
} else if (Qt4PriFileNode *qt4prifilenode = qobject_cast<Qt4PriFileNode *>(fn)) {
|
2008-12-05 14:29:18 +01:00
|
|
|
if (hasSubNode(qt4prifilenode, path))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2008-12-02 18:14:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4Project::findProFile(const QString& fileName, Qt4ProFileNode *root, QList<Qt4ProFileNode *> &list)
|
|
|
|
{
|
2008-12-05 14:29:18 +01:00
|
|
|
if (hasSubNode(root, fileName))
|
2008-12-02 18:14:06 +01:00
|
|
|
list.append(root);
|
|
|
|
|
|
|
|
foreach (FolderNode *fn, root->subFolderNodes())
|
|
|
|
if (Qt4ProFileNode *qt4proFileNode = qobject_cast<Qt4ProFileNode *>(fn))
|
|
|
|
findProFile(fileName, qt4proFileNode, list);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4Project::notifyChanged(const QString &name)
|
|
|
|
{
|
2008-12-05 14:29:18 +01:00
|
|
|
if (files(Qt4Project::ExcludeGeneratedFiles).contains(name)) {
|
|
|
|
QList<Qt4ProFileNode *> list;
|
|
|
|
findProFile(name, rootProjectNode(), list);
|
2009-12-07 22:58:47 +01:00
|
|
|
foreach(Qt4ProFileNode *node, list) {
|
|
|
|
ProFileCacheManager::instance()->discardFile(name);
|
2008-12-05 14:29:18 +01:00
|
|
|
node->update();
|
2009-12-07 22:58:47 +01:00
|
|
|
}
|
2008-12-05 14:29:18 +01:00
|
|
|
}
|
2008-12-02 18:14:06 +01:00
|
|
|
}
|
2009-03-19 15:04:43 +01:00
|
|
|
|
|
|
|
/*!
|
|
|
|
Handle special case were a subproject of the qt directory is opened, and
|
|
|
|
qt was configured to be built as a shadow build -> also build in the sub-
|
|
|
|
project in the correct shadow build directory.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// TODO this function should be called on project first load
|
|
|
|
// and it should check against all configured qt versions ?
|
|
|
|
//void Qt4Project::detectQtShadowBuild(const QString &buildConfiguration) const
|
|
|
|
//{
|
|
|
|
// if (project()->activeBuildConfiguration() == buildConfiguration)
|
|
|
|
// return;
|
|
|
|
//
|
|
|
|
// const QString currentQtDir = static_cast<Qt4Project *>(project())->qtDir(buildConfiguration);
|
|
|
|
// const QString qtSourceDir = static_cast<Qt4Project *>(project())->qtVersion(buildConfiguration)->sourcePath();
|
|
|
|
//
|
|
|
|
// // if the project is a sub-project of Qt and Qt was shadow-built then automatically
|
|
|
|
// // adjust the build directory of the sub-project.
|
|
|
|
// if (project()->file()->fileName().startsWith(qtSourceDir) && qtSourceDir != currentQtDir) {
|
|
|
|
// project()->setValue(buildConfiguration, "useShadowBuild", true);
|
2010-03-25 13:19:27 +01:00
|
|
|
// QString buildDir = project()->projectDirectory();
|
2009-03-19 15:04:43 +01:00
|
|
|
// buildDir.replace(qtSourceDir, currentQtDir);
|
|
|
|
// project()->setValue(buildConfiguration, "buildDirectory", buildDir);
|
|
|
|
// project()->setValue(buildConfiguration, "autoShadowBuild", true);
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
|
|
|
|