2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2014-01-07 13:27:11 +01:00
|
|
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
2012-10-02 09:12:39 +02:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02: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.
|
|
|
|
**
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 16:19:05 +01:00
|
|
|
|
2013-10-16 12:10:22 +02:00
|
|
|
#include "qmakeproject.h"
|
2008-12-02 16:19:05 +01:00
|
|
|
|
2013-10-16 12:10:22 +02:00
|
|
|
#include "qmakeprojectmanager.h"
|
2013-08-13 10:52:57 +02:00
|
|
|
#include "qmakeprojectimporter.h"
|
|
|
|
#include "qmakebuildinfo.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "qmakestep.h"
|
2013-10-16 12:10:22 +02:00
|
|
|
#include "qmakenodes.h"
|
|
|
|
#include "qmakeprojectmanagerconstants.h"
|
|
|
|
#include "qmakebuildconfiguration.h"
|
|
|
|
#include "findqmakeprofiles.h"
|
|
|
|
#include "wizards/abstractmobileapp.h"
|
|
|
|
#include "wizards/qtquickapp.h"
|
2009-06-22 14:32:54 +02:00
|
|
|
|
2014-06-04 13:11:25 +02:00
|
|
|
#include <utils/algorithm.h>
|
2011-04-12 12:17:19 +02:00
|
|
|
#include <coreplugin/icontext.h>
|
2014-03-11 18:09:23 +01:00
|
|
|
#include <coreplugin/icore.h>
|
2010-03-10 16:55:37 +01:00
|
|
|
#include <coreplugin/progressmanager/progressmanager.h>
|
2012-10-05 21:34:09 +10:00
|
|
|
#include <coreplugin/documentmanager.h>
|
2014-09-15 00:12:27 +02:00
|
|
|
#include <cpptools/cppmodelmanager.h>
|
2014-07-24 11:48:30 +02:00
|
|
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
2013-05-29 20:18:51 +02:00
|
|
|
#include <projectexplorer/buildmanager.h>
|
2012-08-20 12:41:52 +02:00
|
|
|
#include <projectexplorer/buildtargetinfo.h>
|
|
|
|
#include <projectexplorer/deploymentdata.h>
|
2010-11-01 14:14:17 +01:00
|
|
|
#include <projectexplorer/toolchain.h>
|
2011-02-28 16:50:14 +01:00
|
|
|
#include <projectexplorer/headerpath.h>
|
2011-08-18 16:46:44 +02:00
|
|
|
#include <projectexplorer/target.h>
|
2010-09-27 17:22:57 +02:00
|
|
|
#include <projectexplorer/projectexplorer.h>
|
2013-01-17 15:03:41 +01:00
|
|
|
#include <projectexplorer/projectmacroexpander.h>
|
2013-05-29 20:18:51 +02:00
|
|
|
#include <proparser/qmakevfs.h>
|
2011-05-20 21:40:53 +02:00
|
|
|
#include <qtsupport/profilereader.h>
|
2012-09-03 18:31:44 +02:00
|
|
|
#include <qtsupport/qtkitinformation.h>
|
2013-07-11 16:24:51 +02:00
|
|
|
#include <qtsupport/uicodemodelsupport.h>
|
2014-06-06 15:34:38 +02:00
|
|
|
#include <resourceeditor/resourcenode.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDebug>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QFileSystemWatcher>
|
2013-04-17 12:33:56 +02:00
|
|
|
#include <QMessageBox>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-10-16 11:02:37 +02:00
|
|
|
using namespace QmakeProjectManager;
|
|
|
|
using namespace QmakeProjectManager::Internal;
|
2008-12-02 12:01:29 +01:00
|
|
|
using namespace ProjectExplorer;
|
2014-06-04 12:50:10 +02:00
|
|
|
using namespace Utils;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-09-19 09:15:52 +02:00
|
|
|
enum { debug = 0 };
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-04-24 15:49:09 +02:00
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
// Helpers:
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2013-10-16 14:00:45 +02:00
|
|
|
QmakeBuildConfiguration *enableActiveQmakeBuildConfiguration(ProjectExplorer::Target *t, bool enabled)
|
2012-04-24 15:49:09 +02:00
|
|
|
{
|
|
|
|
if (!t)
|
|
|
|
return 0;
|
2013-10-16 14:00:45 +02:00
|
|
|
QmakeBuildConfiguration *bc = static_cast<QmakeBuildConfiguration *>(t->activeBuildConfiguration());
|
2012-04-24 15:49:09 +02:00
|
|
|
if (!bc)
|
|
|
|
return 0;
|
|
|
|
bc->setEnabled(enabled);
|
|
|
|
return bc;
|
|
|
|
}
|
|
|
|
|
2013-04-17 12:33:56 +02:00
|
|
|
void updateBoilerPlateCodeFiles(const AbstractMobileApp *app, const QString &proFile)
|
|
|
|
{
|
2013-11-27 13:02:15 +01:00
|
|
|
const QList<AbstractGeneratedFileInfo> updates = app->fileUpdates(proFile);
|
|
|
|
const QString nativeProFile = QDir::toNativeSeparators(proFile);
|
2013-04-17 12:33:56 +02:00
|
|
|
if (!updates.empty()) {
|
2013-10-29 15:15:10 +01:00
|
|
|
const QString title = QmakeManager::tr("Update of Generated Files");
|
2013-04-17 12:33:56 +02:00
|
|
|
QStringList fileNames;
|
|
|
|
foreach (const AbstractGeneratedFileInfo &info, updates)
|
|
|
|
fileNames.append(QDir::toNativeSeparators(info.fileInfo.fileName()));
|
|
|
|
const QString message =
|
2013-10-29 15:15:10 +01:00
|
|
|
QmakeManager::tr("In project<br><br>%1<br><br>The following files are either "
|
2013-04-17 12:33:56 +02:00
|
|
|
"outdated or have been modified:<br><br>%2<br><br>Do you want "
|
|
|
|
"Qt Creator to update the files? Any changes will be lost.")
|
2013-11-27 13:02:15 +01:00
|
|
|
.arg(nativeProFile, fileNames.join(QLatin1String(", ")));
|
2014-03-11 18:09:23 +01:00
|
|
|
if (QMessageBox::question(Core::ICore::dialogParent(), title, message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
2013-04-17 12:33:56 +02:00
|
|
|
QString error;
|
|
|
|
if (!app->updateFiles(updates, error))
|
|
|
|
QMessageBox::critical(0, title, error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-11 16:24:51 +02:00
|
|
|
|
2012-04-24 15:49:09 +02:00
|
|
|
} // namespace
|
|
|
|
|
2013-10-16 11:02:37 +02:00
|
|
|
namespace QmakeProjectManager {
|
2008-12-02 12:01:29 +01:00
|
|
|
namespace Internal {
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
class QmakeProjectFile : public Core::IDocument
|
2011-08-18 16:46:44 +02:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
2013-10-29 14:22:31 +01:00
|
|
|
QmakeProjectFile(const QString &filePath, QObject *parent = 0);
|
2011-08-18 16:46:44 +02:00
|
|
|
|
|
|
|
bool save(QString *errorString, const QString &fileName, bool autoSave);
|
|
|
|
|
|
|
|
QString defaultPath() const;
|
|
|
|
QString suggestedFileName() const;
|
|
|
|
|
|
|
|
bool isModified() const;
|
|
|
|
bool isSaveAsAllowed() const;
|
|
|
|
|
|
|
|
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
|
|
|
|
bool reload(QString *errorString, ReloadFlag flag, ChangeType type);
|
|
|
|
};
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
/// Watches folders for QmakePriFile nodes
|
2011-08-18 16:46:44 +02:00
|
|
|
/// use one file system watcher to watch all folders
|
|
|
|
/// such minimizing system ressouce usage
|
|
|
|
|
|
|
|
class CentralizedFolderWatcher : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
2013-10-29 14:22:31 +01:00
|
|
|
CentralizedFolderWatcher(QmakeProject *parent);
|
2011-08-18 16:46:44 +02:00
|
|
|
~CentralizedFolderWatcher();
|
2014-02-26 10:36:29 +02:00
|
|
|
void watchFolders(const QList<QString> &folders, QmakePriFileNode *node);
|
|
|
|
void unwatchFolders(const QList<QString> &folders, QmakePriFileNode *node);
|
2011-08-18 16:46:44 +02:00
|
|
|
|
|
|
|
private slots:
|
|
|
|
void folderChanged(const QString &folder);
|
|
|
|
void onTimer();
|
|
|
|
void delayedFolderChanged(const QString &folder);
|
|
|
|
|
|
|
|
private:
|
2013-10-29 14:22:31 +01:00
|
|
|
QmakeProject *m_project;
|
2011-08-18 16:46:44 +02:00
|
|
|
QSet<QString> recursiveDirs(const QString &folder);
|
|
|
|
QFileSystemWatcher m_watcher;
|
2014-02-26 10:36:29 +02:00
|
|
|
QMultiMap<QString, QmakePriFileNode *> m_map;
|
2011-08-18 16:46:44 +02:00
|
|
|
|
|
|
|
QSet<QString> m_recursiveWatchedFolders;
|
|
|
|
QTimer m_compressTimer;
|
|
|
|
QSet<QString> m_changedFolders;
|
|
|
|
};
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
// QmakeProjectFiles: Struct for (Cached) lists of files in a project
|
|
|
|
class QmakeProjectFiles {
|
2012-04-24 15:49:09 +02:00
|
|
|
public:
|
2008-12-02 12:01:29 +01:00
|
|
|
void clear();
|
2013-10-29 14:22:31 +01:00
|
|
|
bool equals(const QmakeProjectFiles &f) const;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
QStringList files[ProjectExplorer::FileTypeSize];
|
|
|
|
QStringList generatedFiles[ProjectExplorer::FileTypeSize];
|
|
|
|
QStringList proFiles;
|
|
|
|
};
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProjectFiles::clear()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < FileTypeSize; ++i) {
|
|
|
|
files[i].clear();
|
|
|
|
generatedFiles[i].clear();
|
|
|
|
}
|
|
|
|
proFiles.clear();
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProjectFiles::equals(const QmakeProjectFiles &f) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
inline bool operator==(const QmakeProjectFiles &f1, const QmakeProjectFiles &f2)
|
2008-12-02 12:01:29 +01:00
|
|
|
{ return f1.equals(f2); }
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
inline bool operator!=(const QmakeProjectFiles &f1, const QmakeProjectFiles &f2)
|
2008-12-02 12:01:29 +01:00
|
|
|
{ return !f1.equals(f2); }
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QDebug operator<<(QDebug d, const QmakeProjectFiles &f)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
QDebug nsp = d.nospace();
|
2013-10-29 14:22:31 +01:00
|
|
|
nsp << "QmakeProjectFiles: proFiles=" << f.proFiles << '\n';
|
2008-12-02 12:01:29 +01:00
|
|
|
for (int i = 0; i < FileTypeSize; ++i)
|
|
|
|
nsp << "Type " << i << " files=" << f.files[i] << " generated=" << f.generatedFiles[i] << '\n';
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
// A visitor to collect all files of a project in a QmakeProjectFiles struct
|
2008-12-02 12:01:29 +01:00
|
|
|
class ProjectFilesVisitor : public ProjectExplorer::NodesVisitor
|
|
|
|
{
|
2013-10-29 14:22:31 +01:00
|
|
|
ProjectFilesVisitor(QmakeProjectFiles *files);
|
2011-07-13 18:02:35 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
public:
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
static void findProjectFiles(QmakeProFileNode *rootNode, QmakeProjectFiles *files);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
void visitProjectNode(ProjectNode *projectNode);
|
|
|
|
void visitFolderNode(FolderNode *folderNode);
|
|
|
|
|
|
|
|
private:
|
2013-10-29 14:22:31 +01:00
|
|
|
QmakeProjectFiles *m_files;
|
2008-12-02 12:01:29 +01:00
|
|
|
};
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
ProjectFilesVisitor::ProjectFilesVisitor(QmakeProjectFiles *files) :
|
2008-12-02 12:01:29 +01:00
|
|
|
m_files(files)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-09-04 16:09:41 +02:00
|
|
|
namespace {
|
|
|
|
// uses std::unique, so takes a sorted list
|
|
|
|
void unique(QStringList &list)
|
|
|
|
{
|
|
|
|
list.erase(std::unique(list.begin(), list.end()), list.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void ProjectFilesVisitor::findProjectFiles(QmakeProFileNode *rootNode, QmakeProjectFiles *files)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
files->clear();
|
|
|
|
ProjectFilesVisitor visitor(files);
|
|
|
|
rootNode->accept(&visitor);
|
|
|
|
for (int i = 0; i < FileTypeSize; ++i) {
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(files->files[i]);
|
2014-09-04 16:09:41 +02:00
|
|
|
unique(files->files[i]);
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(files->generatedFiles[i]);
|
2014-09-04 16:09:41 +02:00
|
|
|
unique(files->generatedFiles[i]);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(files->proFiles);
|
2014-09-04 16:09:41 +02:00
|
|
|
unique(files->proFiles);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProjectFilesVisitor::visitProjectNode(ProjectNode *projectNode)
|
|
|
|
{
|
|
|
|
const QString path = projectNode->path();
|
2014-09-04 16:09:41 +02:00
|
|
|
m_files->proFiles.append(path);
|
2008-12-02 12:01:29 +01:00
|
|
|
visitFolderNode(projectNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProjectFilesVisitor::visitFolderNode(FolderNode *folderNode)
|
|
|
|
{
|
2014-06-06 15:34:38 +02:00
|
|
|
if (qobject_cast<ResourceEditor::ResourceTopLevelNode *>(folderNode))
|
|
|
|
m_files->files[ResourceType].push_back(folderNode->path());
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
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];
|
2014-09-04 16:09:41 +02:00
|
|
|
targetList.push_back(path);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
// ----------- QmakeProjectFile
|
2011-08-18 16:55:45 +02:00
|
|
|
namespace Internal {
|
2013-10-29 14:22:31 +01:00
|
|
|
QmakeProjectFile::QmakeProjectFile(const QString &filePath, QObject *parent)
|
2014-06-26 02:15:34 +02:00
|
|
|
: Core::IDocument(parent)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2014-03-05 15:58:12 +01:00
|
|
|
setId("Qmake.ProFile");
|
2014-06-26 02:15:34 +02:00
|
|
|
setMimeType(QLatin1String(QmakeProjectManager::Constants::PROFILE_MIMETYPE));
|
2013-07-04 13:30:26 +02:00
|
|
|
setFilePath(filePath);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProjectFile::save(QString *, const QString &, bool)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2008-12-05 14:29:18 +01:00
|
|
|
// This is never used
|
|
|
|
return false;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QString QmakeProjectFile::defaultPath() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QString QmakeProjectFile::suggestedFileName() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProjectFile::isModified() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2008-12-05 14:29:18 +01:00
|
|
|
return false; // we save after changing anyway
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProjectFile::isSaveAsAllowed() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
Core::IDocument::ReloadBehavior QmakeProjectFile::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;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProjectFile::reload(QString *errorString, ReloadFlag flag, ChangeType type)
|
2010-03-19 10:28:05 +01:00
|
|
|
{
|
2011-04-04 15:24:13 +02:00
|
|
|
Q_UNUSED(errorString)
|
2010-03-19 10:28:05 +01:00
|
|
|
Q_UNUSED(flag)
|
|
|
|
Q_UNUSED(type)
|
2011-04-04 15:24:13 +02:00
|
|
|
return true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2011-08-18 16:46:44 +02:00
|
|
|
} // namespace Internal
|
2012-07-17 15:56:43 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2013-10-29 14:22:31 +01:00
|
|
|
\class QmakeProject
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QmakeProject manages information about an individual Qt 4 (.pro) project file.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
2013-10-29 15:15:10 +01:00
|
|
|
QmakeProject::QmakeProject(QmakeManager *manager, const QString &fileName) :
|
2008-12-02 12:01:29 +01:00
|
|
|
m_manager(manager),
|
2009-03-12 15:01:01 +01:00
|
|
|
m_rootProjectNode(0),
|
2013-10-29 14:22:31 +01:00
|
|
|
m_nodesWatcher(new Internal::QmakeNodesWatcher(this)),
|
|
|
|
m_fileInfo(new QmakeProjectFile(fileName, this)),
|
|
|
|
m_projectFiles(new QmakeProjectFiles),
|
2013-05-29 20:18:51 +02:00
|
|
|
m_qmakeVfs(new QMakeVfs),
|
2012-05-02 15:20:08 +02:00
|
|
|
m_qmakeGlobals(0),
|
2010-03-10 16:55:37 +01:00
|
|
|
m_asyncUpdateFutureInterface(0),
|
|
|
|
m_pendingEvaluateFuturesCount(0),
|
|
|
|
m_asyncUpdateState(NoState),
|
2011-05-30 13:11:31 +02:00
|
|
|
m_cancelEvaluate(false),
|
2012-07-17 15:56:43 +02:00
|
|
|
m_centralizedFolderWatcher(0),
|
|
|
|
m_activeTarget(0)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-10-30 13:34:46 +01:00
|
|
|
setId(Constants::QMAKEPROJECT_ID);
|
2013-10-16 11:02:37 +02:00
|
|
|
setProjectContext(Core::Context(QmakeProjectManager::Constants::PROJECT_ID));
|
2013-05-28 13:19:32 +02:00
|
|
|
setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX));
|
2014-07-23 09:09:20 +02:00
|
|
|
setRequiredKitMatcher(QtSupport::QtKitInformation::qtVersionMatcher());
|
2011-04-12 12:17:19 +02: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()));
|
2013-05-29 20:18:51 +02:00
|
|
|
|
2013-09-05 14:36:20 +02:00
|
|
|
connect(BuildManager::instance(), SIGNAL(buildQueueFinished(bool)),
|
2013-05-29 20:18:51 +02:00
|
|
|
SLOT(buildFinished(bool)));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QmakeProject::~QmakeProject()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-04-22 18:57:43 +02:00
|
|
|
m_codeModelFuture.cancel();
|
2010-03-11 17:01:06 +01:00
|
|
|
m_asyncUpdateState = ShuttingDown;
|
2008-12-02 18:14:06 +01:00
|
|
|
m_manager->unregisterProject(this);
|
2013-05-29 20:18:51 +02:00
|
|
|
delete m_qmakeVfs;
|
2008-12-02 12:01:29 +01:00
|
|
|
delete m_projectFiles;
|
2010-03-11 17:01:06 +01:00
|
|
|
m_cancelEvaluate = true;
|
2011-12-07 17:51:24 +01:00
|
|
|
// Deleting the root node triggers a few things, make sure rootProjectNode
|
|
|
|
// returns 0 already
|
2013-10-29 14:22:31 +01:00
|
|
|
QmakeProFileNode *root = m_rootProjectNode;
|
2011-12-07 17:51:24 +01:00
|
|
|
m_rootProjectNode = 0;
|
|
|
|
delete root;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::updateFileList()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-10-29 14:22:31 +01:00
|
|
|
QmakeProjectFiles newFiles;
|
2008-12-02 12:01:29 +01:00
|
|
|
ProjectFilesVisitor::findProjectFiles(m_rootProjectNode, &newFiles);
|
|
|
|
if (newFiles != *m_projectFiles) {
|
|
|
|
*m_projectFiles = newFiles;
|
|
|
|
emit fileListChanged();
|
|
|
|
if (debug)
|
|
|
|
qDebug() << Q_FUNC_INFO << *m_projectFiles;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProject::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
|
2010-12-06 16:24:29 +01:00
|
|
|
QList<Target *>ts = targets();
|
2010-02-08 15:50:06 +01:00
|
|
|
foreach (Target *t, ts) {
|
2010-02-18 18:37:11 +01:00
|
|
|
if (t->buildConfigurations().isEmpty()) {
|
2012-03-15 17:17:40 +01:00
|
|
|
qWarning() << "Removing" << t->id().name() << "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
|
|
|
}
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
m_manager->registerProject(this);
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
m_rootProjectNode = new QmakeProFileNode(this, m_fileInfo->filePath(), this);
|
2010-03-10 16:55:37 +01:00
|
|
|
m_rootProjectNode->registerWatcher(m_nodesWatcher);
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
update();
|
|
|
|
updateFileList();
|
2011-09-15 12:15:10 +02:00
|
|
|
// This might be incorrect, need a full update
|
|
|
|
updateCodeModels();
|
2010-06-10 14:48:59 +02:00
|
|
|
|
2012-04-24 15:49:09 +02:00
|
|
|
// We have the profile nodes now, so we know the runconfigs!
|
2013-10-29 14:22:31 +01:00
|
|
|
connect(m_nodesWatcher, SIGNAL(proFileUpdated(QmakeProjectManager::QmakeProFileNode*,bool,bool)),
|
|
|
|
this, SIGNAL(proFileUpdated(QmakeProjectManager::QmakeProFileNode*,bool,bool)));
|
2009-12-03 18:37:27 +01:00
|
|
|
|
2010-11-02 16:39:45 +01:00
|
|
|
// Now we emit update once :)
|
2011-09-12 12:40:53 +02:00
|
|
|
m_rootProjectNode->emitProFileUpdatedRecursive();
|
2010-11-02 16:39:45 +01:00
|
|
|
|
2012-07-17 15:56:43 +02:00
|
|
|
// On active buildconfiguration changes, reevaluate the .pro files
|
|
|
|
m_activeTarget = activeTarget();
|
|
|
|
if (m_activeTarget)
|
|
|
|
connect(m_activeTarget, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
|
|
|
|
this, SLOT(scheduleAsyncUpdate()));
|
|
|
|
|
2010-02-08 15:50:06 +01:00
|
|
|
connect(this, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
|
|
|
|
this, SLOT(activeTargetWasChanged()));
|
|
|
|
|
2013-04-17 12:33:56 +02:00
|
|
|
// // Update boiler plate code for subprojects.
|
|
|
|
QtQuickApp qtQuickApp;
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
foreach (QmakeProFileNode *node, applicationProFiles(QmakeProject::ExactAndCumulativeParse)) {
|
2013-04-17 12:33:56 +02:00
|
|
|
const QString path = node->path();
|
|
|
|
|
2013-11-06 16:42:25 +01:00
|
|
|
foreach (TemplateInfo info, QtQuickApp::templateInfos()) {
|
|
|
|
qtQuickApp.setTemplateInfo(info);
|
|
|
|
updateBoilerPlateCodeFiles(&qtQuickApp, path);
|
|
|
|
}
|
2013-04-17 12:33:56 +02:00
|
|
|
}
|
2009-07-03 16:46:01 +02:00
|
|
|
return true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
/// equalFileList compares two file lists ignoring
|
|
|
|
/// <configuration> without generating temporary lists
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProject::equalFileList(const QStringList &a, const QStringList &b)
|
2010-03-10 16:55:37 +01:00
|
|
|
{
|
|
|
|
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) {
|
2014-09-15 00:12:27 +02:00
|
|
|
if (*ait == CppTools::CppModelManager::configurationFileName())
|
2010-03-10 16:55:37 +01:00
|
|
|
++ait;
|
2014-09-15 00:12:27 +02:00
|
|
|
else if (*bit == CppTools::CppModelManager::configurationFileName())
|
2010-03-10 16:55:37 +01:00
|
|
|
++bit;
|
|
|
|
else if (*ait == *bit)
|
|
|
|
++ait, ++bit;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return (ait == aend && bit == bend);
|
2010-02-08 15:50:06 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::updateCodeModels()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
if (debug)
|
2013-10-29 14:22:31 +01:00
|
|
|
qDebug() << "QmakeProject::updateCodeModel()";
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-10-28 10:15:04 +00:00
|
|
|
if (activeTarget() && !activeTarget()->activeBuildConfiguration())
|
2010-02-08 15:50:06 +01:00
|
|
|
return;
|
|
|
|
|
2010-09-21 14:28:55 +02:00
|
|
|
updateCppCodeModel();
|
|
|
|
updateQmlJSCodeModel();
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::updateCppCodeModel()
|
2010-09-21 14:28:55 +02:00
|
|
|
{
|
2013-04-02 11:28:11 +02:00
|
|
|
typedef CppTools::ProjectPart ProjectPart;
|
|
|
|
typedef CppTools::ProjectFile ProjectFile;
|
2012-02-16 15:09:56 +01:00
|
|
|
|
2012-09-03 18:31:44 +02:00
|
|
|
Kit *k = 0;
|
2011-10-28 10:15:04 +00:00
|
|
|
QtSupport::BaseQtVersion *qtVersion = 0;
|
2012-04-24 15:49:09 +02:00
|
|
|
if (ProjectExplorer::Target *target = activeTarget())
|
2012-09-03 18:31:44 +02:00
|
|
|
k = target->kit();
|
2012-04-24 15:49:09 +02:00
|
|
|
else
|
2013-08-21 12:48:46 +02:00
|
|
|
k = KitManager::defaultKit();
|
2012-09-03 18:31:44 +02:00
|
|
|
qtVersion = QtSupport::QtKitInformation::qtVersion(k);
|
2009-11-25 18:50:20 +01:00
|
|
|
|
2014-09-15 00:12:27 +02:00
|
|
|
CppTools::CppModelManager *modelmanager =
|
|
|
|
CppTools::CppModelManager::instance();
|
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;
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
FindQmakeProFiles findQmakeProFiles;
|
|
|
|
QList<QmakeProFileNode *> proFiles = findQmakeProFiles(rootProjectNode());
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-07-30 17:13:45 +02:00
|
|
|
CppTools::ProjectInfo pinfo = modelmanager->projectInfo(this);
|
2012-02-16 15:09:56 +01:00
|
|
|
pinfo.clearProjectParts();
|
|
|
|
ProjectPart::QtVersion qtVersionForPart = ProjectPart::NoQt;
|
|
|
|
if (qtVersion) {
|
|
|
|
if (qtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0))
|
|
|
|
qtVersionForPart = ProjectPart::Qt4;
|
|
|
|
else
|
|
|
|
qtVersionForPart = ProjectPart::Qt5;
|
|
|
|
}
|
2010-10-18 17:12:44 +02:00
|
|
|
|
2013-07-11 16:24:51 +02:00
|
|
|
QHash<QString, QString> uiCodeModelData;
|
2012-02-16 15:09:56 +01:00
|
|
|
QStringList allFiles;
|
2013-10-29 14:22:31 +01:00
|
|
|
foreach (QmakeProFileNode *pro, proFiles) {
|
2014-08-19 12:01:08 +02:00
|
|
|
ProjectPart::Ptr templatePart(new ProjectPart);
|
|
|
|
templatePart->project = this;
|
|
|
|
templatePart->displayName = pro->displayName();
|
|
|
|
templatePart->projectFile = pro->path();
|
2012-12-08 23:38:26 +04:00
|
|
|
|
|
|
|
if (pro->variableValue(ConfigVar).contains(QLatin1String("qt")))
|
2014-08-19 12:01:08 +02:00
|
|
|
templatePart->qtVersion = qtVersionForPart;
|
2012-12-08 23:38:26 +04:00
|
|
|
else
|
2014-08-19 12:01:08 +02:00
|
|
|
templatePart->qtVersion = ProjectPart::NoQt;
|
2011-02-01 18:36:00 +01:00
|
|
|
|
2012-02-16 15:09:56 +01:00
|
|
|
// part->defines
|
2014-08-19 12:01:08 +02:00
|
|
|
templatePart->projectDefines += pro->cxxDefines();
|
2012-02-16 15:09:56 +01:00
|
|
|
|
2014-06-25 17:23:19 +02:00
|
|
|
// part->headerPaths
|
|
|
|
foreach (const QString &inc, pro->variableValue(IncludePathVar))
|
2014-08-19 12:01:08 +02:00
|
|
|
templatePart->headerPaths += ProjectPart::HeaderPath(inc, ProjectPart::HeaderPath::IncludePath);
|
2012-02-16 15:09:56 +01:00
|
|
|
|
|
|
|
if (qtVersion) {
|
2013-04-28 16:59:44 +04:00
|
|
|
foreach (const HeaderPath &header, qtVersion->systemHeaderPathes(k)) {
|
2014-06-25 17:23:19 +02:00
|
|
|
ProjectPart::HeaderPath::Type type = ProjectPart::HeaderPath::IncludePath;
|
2013-04-28 16:59:44 +04:00
|
|
|
if (header.kind() == HeaderPath::FrameworkHeaderPath)
|
2014-06-25 17:23:19 +02:00
|
|
|
type = ProjectPart::HeaderPath::FrameworkPath;
|
2014-08-19 12:01:08 +02:00
|
|
|
templatePart->headerPaths += ProjectPart::HeaderPath(header.path(), type);
|
2014-06-25 17:23:19 +02:00
|
|
|
}
|
|
|
|
if (!qtVersion->frameworkInstallPath().isEmpty()) {
|
2014-08-19 12:01:08 +02:00
|
|
|
templatePart->headerPaths += ProjectPart::HeaderPath(
|
2014-06-25 17:23:19 +02:00
|
|
|
qtVersion->frameworkInstallPath(),
|
|
|
|
ProjectPart::HeaderPath::FrameworkPath);
|
2013-04-28 16:59:44 +04:00
|
|
|
}
|
2009-05-04 18:22:40 +02:00
|
|
|
}
|
2013-04-28 16:59:44 +04:00
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
if (QmakeProFileNode *node = rootQmakeProjectNode())
|
2014-08-19 12:01:08 +02:00
|
|
|
templatePart->headerPaths += ProjectPart::HeaderPath(node->resolvedMkspecPath(),
|
2014-06-25 17:23:19 +02:00
|
|
|
ProjectPart::HeaderPath::IncludePath);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-16 15:09:56 +01:00
|
|
|
// part->precompiledHeaders
|
2014-08-19 12:01:08 +02:00
|
|
|
templatePart->precompiledHeaders.append(pro->variableValue(PrecompiledHeaderVar));
|
|
|
|
|
|
|
|
ProjectPart::Ptr cppPart = templatePart->copy();
|
|
|
|
{ // C++ files:
|
|
|
|
// part->files
|
|
|
|
foreach (const QString &file, pro->variableValue(CppSourceVar)) {
|
|
|
|
allFiles << file;
|
|
|
|
cppPart->files << ProjectFile(file, ProjectFile::CXXSource);
|
|
|
|
}
|
|
|
|
foreach (const QString &file, pro->variableValue(CppHeaderVar)) {
|
|
|
|
allFiles << file;
|
|
|
|
cppPart->files << ProjectFile(file, ProjectFile::CXXHeader);
|
|
|
|
}
|
2008-12-08 12:44:28 +01:00
|
|
|
|
2014-08-19 12:01:08 +02:00
|
|
|
// Ui Files:
|
|
|
|
QHash<QString, QString> uiData = pro->uiFiles();
|
|
|
|
for (QHash<QString, QString>::const_iterator i = uiData.constBegin(); i != uiData.constEnd(); ++i) {
|
|
|
|
allFiles << i.value();
|
|
|
|
cppPart->files << ProjectFile(i.value(), ProjectFile::CXXHeader);
|
|
|
|
}
|
|
|
|
uiCodeModelData.unite(uiData);
|
|
|
|
|
2014-09-15 00:12:27 +02:00
|
|
|
cppPart->files.prepend(ProjectFile(CppTools::CppModelManager::configurationFileName(),
|
2014-08-19 12:01:08 +02:00
|
|
|
ProjectFile::CXXSource));
|
|
|
|
const QStringList cxxflags = pro->variableValue(CppFlagsVar);
|
|
|
|
cppPart->evaluateToolchain(ToolChainKitInformation::toolChain(k),
|
|
|
|
cxxflags,
|
|
|
|
SysRootKitInformation::sysRoot(k));
|
|
|
|
|
|
|
|
if (!cppPart->files.isEmpty()) {
|
|
|
|
pinfo.appendProjectPart(cppPart);
|
|
|
|
setProjectLanguage(ProjectExplorer::Constants::LANG_CXX, true);
|
|
|
|
}
|
2013-03-04 01:30:46 +04:00
|
|
|
}
|
2013-07-11 16:24:51 +02:00
|
|
|
|
2014-08-19 12:01:08 +02:00
|
|
|
ProjectPart::Ptr objcppPart = templatePart->copy();
|
|
|
|
{ // ObjC++ files:
|
|
|
|
foreach (const QString &file, pro->variableValue(ObjCSourceVar)) {
|
|
|
|
allFiles << file;
|
|
|
|
// Although the enum constant is called ObjCSourceVar, it actually is ObjC++ source
|
|
|
|
// code, as qmake does not handle C (and ObjC).
|
|
|
|
objcppPart->files << ProjectFile(file, ProjectFile::ObjCXXSource);
|
|
|
|
}
|
|
|
|
foreach (const QString &file, pro->variableValue(ObjCHeaderVar)) {
|
|
|
|
allFiles << file;
|
|
|
|
objcppPart->files << ProjectFile(file, ProjectFile::ObjCXXHeader);
|
|
|
|
}
|
2013-03-21 22:10:38 +04:00
|
|
|
|
2014-08-19 12:01:08 +02:00
|
|
|
const QStringList cxxflags = pro->variableValue(CppFlagsVar);
|
|
|
|
objcppPart->evaluateToolchain(ToolChainKitInformation::toolChain(k),
|
|
|
|
cxxflags,
|
|
|
|
SysRootKitInformation::sysRoot(k));
|
2014-03-31 11:28:56 +02:00
|
|
|
|
2014-08-19 12:01:08 +02:00
|
|
|
if (!objcppPart->files.isEmpty()) {
|
|
|
|
pinfo.appendProjectPart(objcppPart);
|
|
|
|
// TODO: there is no LANG_OBJCXX, so:
|
|
|
|
setProjectLanguage(ProjectExplorer::Constants::LANG_CXX, true);
|
|
|
|
}
|
|
|
|
}
|
2012-02-16 15:09:56 +01:00
|
|
|
|
2014-08-19 12:01:08 +02:00
|
|
|
if (!objcppPart->files.isEmpty())
|
|
|
|
cppPart->displayName += QLatin1String(" (C++)");
|
|
|
|
if (!cppPart->files.isEmpty())
|
|
|
|
objcppPart->displayName += QLatin1String(" (ObjC++)");
|
|
|
|
}
|
2014-09-12 14:14:18 +02:00
|
|
|
pinfo.finish();
|
2013-04-10 14:45:47 +02:00
|
|
|
|
2013-07-11 16:24:51 +02:00
|
|
|
// Also update Ui Code Model Support:
|
2013-08-02 11:55:18 +02:00
|
|
|
QtSupport::UiCodeModelManager::update(this, uiCodeModelData);
|
2013-07-11 16:24:51 +02:00
|
|
|
|
2013-07-16 12:08:39 +02:00
|
|
|
m_codeModelFuture = modelmanager->updateProjectInfo(pinfo);
|
2009-05-04 18:22:40 +02:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::updateQmlJSCodeModel()
|
2010-09-21 14:28:55 +02:00
|
|
|
{
|
2010-09-27 11:16:43 +01:00
|
|
|
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
2010-09-21 14:28:55 +02:00
|
|
|
if (!modelManager)
|
|
|
|
return;
|
|
|
|
|
2012-12-06 17:20:58 +01:00
|
|
|
QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
|
2014-07-24 11:48:30 +02:00
|
|
|
modelManager->defaultProjectInfoForProject(this);
|
2010-09-21 14:28:55 +02:00
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
FindQmakeProFiles findQt4ProFiles;
|
|
|
|
QList<QmakeProFileNode *> proFiles = findQt4ProFiles(rootProjectNode());
|
2010-09-21 14:28:55 +02:00
|
|
|
|
2011-06-23 15:09:38 +02:00
|
|
|
projectInfo.importPaths.clear();
|
2012-11-21 16:18:53 +01:00
|
|
|
|
|
|
|
bool hasQmlLib = false;
|
2013-10-29 14:22:31 +01:00
|
|
|
foreach (QmakeProFileNode *node, proFiles) {
|
2014-07-22 19:06:44 +02:00
|
|
|
foreach (const QString &path, node->variableValue(QmlImportPathVar))
|
|
|
|
projectInfo.importPaths.maybeInsert(Utils::FileName::fromString(path),
|
|
|
|
QmlJS::Dialect::Qml);
|
2013-05-21 11:35:15 +02:00
|
|
|
projectInfo.activeResourceFiles.append(node->variableValue(ExactResourceVar));
|
|
|
|
projectInfo.allResourceFiles.append(node->variableValue(ResourceVar));
|
2012-11-21 16:18:53 +01:00
|
|
|
if (!hasQmlLib) {
|
|
|
|
QStringList qtLibs = node->variableValue(QtVar);
|
|
|
|
hasQmlLib = qtLibs.contains(QLatin1String("declarative")) ||
|
|
|
|
qtLibs.contains(QLatin1String("qml")) ||
|
|
|
|
qtLibs.contains(QLatin1String("quick"));
|
|
|
|
}
|
2010-09-21 14:28:55 +02:00
|
|
|
}
|
2011-09-21 15:54:07 +02:00
|
|
|
|
2013-05-28 13:19:32 +02:00
|
|
|
// If the project directory has a pro/pri file that includes a qml or quick or declarative
|
|
|
|
// library then chances of the project being a QML project is quite high.
|
|
|
|
// This assumption fails when there are no QDeclarativeEngine/QDeclarativeView (QtQuick 1)
|
|
|
|
// or QQmlEngine/QQuickView (QtQuick 2) instances.
|
|
|
|
Core::Context pl(ProjectExplorer::Constants::LANG_CXX);
|
|
|
|
if (hasQmlLib)
|
|
|
|
pl.add(ProjectExplorer::Constants::LANG_QMLJS);
|
|
|
|
setProjectLanguages(pl);
|
|
|
|
|
2013-05-21 11:35:15 +02:00
|
|
|
projectInfo.activeResourceFiles.removeDuplicates();
|
|
|
|
projectInfo.allResourceFiles.removeDuplicates();
|
2010-09-21 14:28:55 +02:00
|
|
|
|
2013-04-10 14:45:47 +02:00
|
|
|
setProjectLanguage(ProjectExplorer::Constants::LANG_QMLJS, !projectInfo.sourceFiles.isEmpty());
|
|
|
|
|
2014-01-23 14:28:31 +01:00
|
|
|
modelManager->updateProjectInfo(projectInfo, this);
|
2010-09-21 14:28:55 +02:00
|
|
|
}
|
|
|
|
|
2008-12-09 17:17:12 +01:00
|
|
|
///*!
|
|
|
|
// Updates complete project
|
|
|
|
// */
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::update()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
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-10-27 16:27:22 +02:00
|
|
|
|
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;
|
2013-10-16 14:00:45 +02:00
|
|
|
enableActiveQmakeBuildConfiguration(activeTarget(), true);
|
2012-08-20 12:41:52 +02:00
|
|
|
updateBuildSystemData();
|
2013-11-04 17:02:30 +01:00
|
|
|
if (activeTarget())
|
|
|
|
activeTarget()->updateDefaultDeployConfigurations();
|
2012-07-17 15:56:43 +02:00
|
|
|
updateRunConfigurations();
|
|
|
|
emit proFilesEvaluated();
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::updateRunConfigurations()
|
2012-07-17 15:56:43 +02:00
|
|
|
{
|
2013-06-19 12:17:59 +02:00
|
|
|
if (activeTarget())
|
|
|
|
activeTarget()->updateDefaultRunConfigurations();
|
2010-03-10 16:55:37 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::scheduleAsyncUpdate(QmakeProFileNode *node)
|
2010-03-10 16:55:37 +01:00
|
|
|
{
|
2010-10-25 17:26:41 +02:00
|
|
|
if (m_asyncUpdateState == ShuttingDown)
|
|
|
|
return;
|
2010-10-27 16:27:22 +02:00
|
|
|
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
2011-09-12 12:40:53 +02:00
|
|
|
qDebug()<<"schduleAsyncUpdate (node)"<<node->path();
|
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;
|
|
|
|
}
|
|
|
|
|
2013-10-16 14:00:45 +02:00
|
|
|
enableActiveQmakeBuildConfiguration(activeTarget(), false);
|
2011-01-19 15:46:01 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
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;
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QList<QmakeProFileNode *>::iterator it;
|
2010-03-10 16:55:37 +01:00
|
|
|
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
|
2011-09-12 12:40:53 +02:00
|
|
|
it = m_partialEvaluate.erase(it);
|
|
|
|
} else if ((*it)->isParent(node)) { // The node is the parent of a child already in the list
|
2010-03-10 16:55:37 +01:00
|
|
|
add = false;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (add)
|
|
|
|
m_partialEvaluate.append(node);
|
|
|
|
// and start the timer anew
|
|
|
|
m_asyncUpdateTimer.start();
|
2012-09-04 11:02:11 +02:00
|
|
|
|
|
|
|
// Cancel running code model update
|
|
|
|
m_codeModelFuture.cancel();
|
2010-03-10 16:55:37 +01:00
|
|
|
} 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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::scheduleAsyncUpdate()
|
2010-03-10 16:55:37 +01:00
|
|
|
{
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<"scheduleAsyncUpdate";
|
2010-10-25 17:26:41 +02:00
|
|
|
if (m_asyncUpdateState == ShuttingDown)
|
|
|
|
return;
|
2010-10-27 16:27:22 +02:00
|
|
|
|
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;
|
2013-10-16 14:00:45 +02:00
|
|
|
enableActiveQmakeBuildConfiguration(activeTarget(), false);
|
2011-09-12 12:40:53 +02:00
|
|
|
m_rootProjectNode->setParseInProgressRecursive(true);
|
2010-03-10 16:55:37 +01:00
|
|
|
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();
|
2013-10-16 14:00:45 +02:00
|
|
|
enableActiveQmakeBuildConfiguration(activeTarget(), false);
|
2011-09-12 12:40:53 +02:00
|
|
|
m_rootProjectNode->setParseInProgressRecursive(true);
|
2010-03-10 16:55:37 +01:00
|
|
|
m_asyncUpdateState = AsyncFullUpdatePending;
|
|
|
|
m_asyncUpdateTimer.start();
|
2010-04-22 18:57:43 +02:00
|
|
|
|
|
|
|
// Cancel running code model update
|
|
|
|
m_codeModelFuture.cancel();
|
2010-03-10 16:55:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::incrementPendingEvaluateFutures()
|
2010-03-10 16:55:37 +01:00
|
|
|
{
|
|
|
|
++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);
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::decrementPendingEvaluateFutures()
|
2010-03-10 16:55:37 +01:00
|
|
|
{
|
|
|
|
--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";
|
2012-10-08 14:33:33 +02:00
|
|
|
|
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){
|
2010-10-30 21:54:23 +02:00
|
|
|
// After being done, we need to call:
|
2011-09-12 13:25:12 +02:00
|
|
|
m_asyncUpdateState = Base;
|
2013-10-16 14:00:45 +02:00
|
|
|
enableActiveQmakeBuildConfiguration(activeTarget(), true);
|
2010-03-11 17:01:06 +01:00
|
|
|
updateFileList();
|
2011-09-15 12:15:10 +02:00
|
|
|
updateCodeModels();
|
2012-08-20 12:41:52 +02:00
|
|
|
updateBuildSystemData();
|
2012-07-17 15:56:43 +02:00
|
|
|
updateRunConfigurations();
|
|
|
|
emit proFilesEvaluated();
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<" Setting state to Base";
|
2010-03-10 16:55:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProject::wasEvaluateCanceled()
|
2010-03-10 16:55:37 +01:00
|
|
|
{
|
|
|
|
return m_cancelEvaluate;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::asyncUpdate()
|
2010-03-10 16:55:37 +01:00
|
|
|
{
|
2010-03-12 15:12:46 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug()<<"async update, timer expired, doing now";
|
2013-05-29 20:18:51 +02:00
|
|
|
|
|
|
|
m_qmakeVfs->invalidateCache();
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
Q_ASSERT(!m_asyncUpdateFutureInterface);
|
|
|
|
m_asyncUpdateFutureInterface = new QFutureInterface<void>();
|
|
|
|
|
2010-04-13 16:32:01 +02:00
|
|
|
m_asyncUpdateFutureInterface->setProgressRange(0, 0);
|
2014-04-17 15:14:14 +02:00
|
|
|
Core::ProgressManager::addTask(m_asyncUpdateFutureInterface->future(),
|
|
|
|
tr("Reading Project \"%1\"").arg(displayName()),
|
|
|
|
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";
|
2013-10-29 14:22:31 +01:00
|
|
|
foreach (QmakeProFileNode *node, m_partialEvaluate)
|
2010-03-10 16:55:37 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::buildFinished(bool success)
|
2013-05-29 20:18:51 +02:00
|
|
|
{
|
|
|
|
if (success)
|
|
|
|
m_qmakeVfs->invalidateContents();
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
ProjectExplorer::IProjectManager *QmakeProject::projectManager() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
return m_manager;
|
|
|
|
}
|
|
|
|
|
2013-10-29 17:37:39 +01:00
|
|
|
QmakeManager *QmakeProject::qmakeProjectManager() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
return m_manager;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProject::supportsKit(Kit *k, QString *errorMessage) const
|
2012-04-24 15:49:09 +02:00
|
|
|
{
|
2012-09-09 20:41:30 +03:00
|
|
|
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
|
2012-09-20 11:16:47 +02:00
|
|
|
if (!version && errorMessage)
|
|
|
|
*errorMessage = tr("No Qt version set in kit.");
|
2012-04-24 15:49:09 +02:00
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QString QmakeProject::displayName() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2014-05-02 12:22:58 +02:00
|
|
|
return projectFilePath().toFileInfo().completeBaseName();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
Core::IDocument *QmakeProject::document() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
return m_fileInfo;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QStringList QmakeProject::files(FilesMode fileMode) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
QStringList files;
|
|
|
|
for (int i = 0; i < FileTypeSize; ++i) {
|
|
|
|
files += m_projectFiles->files[i];
|
|
|
|
if (fileMode == AllFiles)
|
|
|
|
files += m_projectFiles->generatedFiles[i];
|
|
|
|
}
|
2014-01-23 17:01:43 +01:00
|
|
|
|
|
|
|
files.removeDuplicates();
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
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)
|
|
|
|
{
|
2012-11-28 20:44:03 +02:00
|
|
|
foreach (FileNode *fn, in->fileNodes())
|
2009-12-03 16:23:15 +01:00
|
|
|
if (fn->fileType() == fileType && fn->path() == fileName)
|
|
|
|
return in;
|
2012-11-28 20:44:03 +02:00
|
|
|
foreach (FolderNode *folder, in->subFolderNodes())
|
2009-12-03 16:23:15 +01:00
|
|
|
if (FolderNode *pn = folderOf(folder, fileType, fileName))
|
|
|
|
return pn;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-29 18:24:57 +01:00
|
|
|
// Find the QmakeProFileNode that contains a file of a certain type.
|
2009-12-03 16:23:15 +01:00
|
|
|
// First recurse down to folder, then find the pro-file.
|
2013-10-29 14:22:31 +01:00
|
|
|
static QmakeProFileNode *proFileNodeOf(QmakeProFileNode *in, FileType fileType, const QString &fileName)
|
2009-12-03 16:23:15 +01:00
|
|
|
{
|
|
|
|
for (FolderNode *folder = folderOf(in, fileType, fileName); folder; folder = folder->parentFolderNode())
|
2013-10-29 14:22:31 +01:00
|
|
|
if (QmakeProFileNode *proFile = qobject_cast<QmakeProFileNode *>(folder))
|
2009-12-03 16:23:15 +01:00
|
|
|
return proFile;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QString QmakeProject::generatedUiHeader(const QString &formFile) const
|
2009-12-03 16:23:15 +01:00
|
|
|
{
|
|
|
|
// Look in sub-profiles as SessionManager::projectForFile returns
|
|
|
|
// the top-level project only.
|
|
|
|
if (m_rootProjectNode)
|
2013-10-29 14:22:31 +01:00
|
|
|
if (const QmakeProFileNode *pro = proFileNodeOf(m_rootProjectNode, FormType, formFile))
|
2014-09-05 16:13:21 +02:00
|
|
|
return QmakeProFileNode::uiHeaderFile(pro->uiDirectory(pro->buildDir()), formFile);
|
2009-12-03 16:23:15 +01:00
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::proFileParseError(const QString &errorMessage)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-09-05 01:52:17 +02:00
|
|
|
Core::MessageManager::write(errorMessage);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QtSupport::ProFileReader *QmakeProject::createProFileReader(const QmakeProFileNode *qmakeProFileNode, QmakeBuildConfiguration *bc)
|
2009-12-07 20:49:39 +01:00
|
|
|
{
|
2012-05-02 15:20:08 +02:00
|
|
|
if (!m_qmakeGlobals) {
|
2012-08-28 18:18:07 +02:00
|
|
|
m_qmakeGlobals = new ProFileGlobals;
|
2012-05-02 15:20:08 +02:00
|
|
|
m_qmakeGlobalsRefCnt = 0;
|
2009-12-07 20:49:39 +01:00
|
|
|
|
2012-09-03 18:31:44 +02:00
|
|
|
Kit *k;
|
2011-10-28 10:15:04 +00:00
|
|
|
Utils::Environment env = Utils::Environment::systemEnvironment();
|
|
|
|
QStringList qmakeArgs;
|
2012-06-24 20:30:02 +03:00
|
|
|
if (!bc)
|
2013-10-16 14:00:45 +02:00
|
|
|
bc = activeTarget() ? static_cast<QmakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration()) : 0;
|
2012-06-24 20:30:02 +03:00
|
|
|
|
|
|
|
if (bc) {
|
2012-09-03 18:31:44 +02:00
|
|
|
k = bc->target()->kit();
|
2012-06-24 20:30:02 +03:00
|
|
|
env = bc->environment();
|
2012-08-15 18:17:26 +02:00
|
|
|
if (bc->qmakeStep())
|
2012-06-24 20:30:02 +03:00
|
|
|
qmakeArgs = bc->qmakeStep()->parserArguments();
|
2012-08-15 18:17:26 +02:00
|
|
|
else
|
2011-10-28 10:15:04 +00:00
|
|
|
qmakeArgs = bc->configCommandLineArguments();
|
|
|
|
} else {
|
2013-08-21 12:48:46 +02:00
|
|
|
k = KitManager::defaultKit();
|
2009-12-07 20:49:39 +01:00
|
|
|
}
|
2009-12-07 22:58:47 +01:00
|
|
|
|
2012-09-03 18:31:44 +02:00
|
|
|
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k);
|
|
|
|
QString systemRoot = SysRootKitInformation::hasSysRoot(k)
|
|
|
|
? SysRootKitInformation::sysRoot(k).toString() : QString();
|
2012-04-24 15:49:09 +02:00
|
|
|
|
2012-06-18 18:16:50 +02:00
|
|
|
if (qtVersion && qtVersion->isValid()) {
|
|
|
|
m_qmakeGlobals->qmake_abslocation = QDir::cleanPath(qtVersion->qmakeCommand().toString());
|
2012-06-18 17:42:20 +02:00
|
|
|
m_qmakeGlobals->setProperties(qtVersion->versionInfo());
|
2012-06-18 18:16:50 +02:00
|
|
|
}
|
2012-07-25 19:10:07 +02:00
|
|
|
m_qmakeGlobals->setDirectories(m_rootProjectNode->sourceDir(), m_rootProjectNode->buildDir());
|
2012-05-02 15:20:08 +02:00
|
|
|
m_qmakeGlobals->sysroot = systemRoot;
|
2011-10-28 10:15:04 +00:00
|
|
|
|
|
|
|
Utils::Environment::const_iterator eit = env.constBegin(), eend = env.constEnd();
|
|
|
|
for (; eit != eend; ++eit)
|
2012-05-02 15:20:08 +02:00
|
|
|
m_qmakeGlobals->environment.insert(env.key(eit), env.value(eit));
|
2011-10-28 10:15:04 +00:00
|
|
|
|
2012-08-15 18:11:54 +02:00
|
|
|
m_qmakeGlobals->setCommandLineArguments(m_rootProjectNode->buildDir(), qmakeArgs);
|
2011-10-28 10:15:04 +00:00
|
|
|
|
2011-05-20 21:40:53 +02:00
|
|
|
QtSupport::ProFileCacheManager::instance()->incRefCount();
|
2014-04-02 03:16:09 +02:00
|
|
|
|
|
|
|
// On ios, qmake is called recursively, and the second call with a different
|
|
|
|
// spec.
|
|
|
|
// macx-ios-clang just creates supporting makefiles, and to avoid being
|
|
|
|
// slow does not evaluate everything, and contains misleading information
|
|
|
|
// (that is never used).
|
|
|
|
// macx-xcode correctly evaluates the variables and generates the xcodeproject
|
|
|
|
// that is actually used to build the application.
|
|
|
|
//
|
|
|
|
// It is important to override the spec file only for the creator evaluator,
|
|
|
|
// and not the qmake buildstep used to build the app (as we use the makefiles).
|
|
|
|
const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; // from Ios::Constants
|
2014-04-03 10:16:48 +02:00
|
|
|
if (qtVersion && qtVersion->type() == QLatin1String(IOSQT))
|
2014-04-02 03:16:09 +02:00
|
|
|
m_qmakeGlobals->xqmakespec = QLatin1String("macx-xcode");
|
2009-12-07 20:49:39 +01:00
|
|
|
}
|
2012-05-02 15:20:08 +02:00
|
|
|
++m_qmakeGlobalsRefCnt;
|
2009-12-07 20:49:39 +01:00
|
|
|
|
2013-05-29 20:18:51 +02:00
|
|
|
QtSupport::ProFileReader *reader = new QtSupport::ProFileReader(m_qmakeGlobals, m_qmakeVfs);
|
2009-12-07 20:49:39 +01:00
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
reader->setOutputDir(qmakeProFileNode->buildDir());
|
2009-12-07 20:49:39 +01:00
|
|
|
|
|
|
|
return reader;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
ProFileGlobals *QmakeProject::qmakeGlobals()
|
2011-10-07 15:40:38 +02:00
|
|
|
{
|
2012-05-02 15:20:08 +02:00
|
|
|
return m_qmakeGlobals;
|
2011-10-07 15:40:38 +02:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::destroyProFileReader(QtSupport::ProFileReader *reader)
|
2009-12-07 20:49:39 +01:00
|
|
|
{
|
|
|
|
delete reader;
|
2012-05-02 15:20:08 +02:00
|
|
|
if (!--m_qmakeGlobalsRefCnt) {
|
2013-07-04 13:30:26 +02:00
|
|
|
QString dir = QFileInfo(m_fileInfo->filePath()).absolutePath();
|
2009-12-07 22:58:47 +01:00
|
|
|
if (!dir.endsWith(QLatin1Char('/')))
|
|
|
|
dir += QLatin1Char('/');
|
2011-05-20 21:40:53 +02:00
|
|
|
QtSupport::ProFileCacheManager::instance()->discardFiles(dir);
|
|
|
|
QtSupport::ProFileCacheManager::instance()->decRefCount();
|
2009-12-07 22:58:47 +01:00
|
|
|
|
2012-05-02 15:20:08 +02:00
|
|
|
delete m_qmakeGlobals;
|
|
|
|
m_qmakeGlobals = 0;
|
2009-12-07 20:49:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
ProjectExplorer::ProjectNode *QmakeProject::rootProjectNode() const
|
2011-08-18 16:46:44 +02:00
|
|
|
{
|
|
|
|
return m_rootProjectNode;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QmakeProFileNode *QmakeProject::rootQmakeProjectNode() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
return m_rootProjectNode;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProject::validParse(const QString &proFilePath) const
|
2010-10-27 16:27:22 +02:00
|
|
|
{
|
2010-10-29 12:15:30 +02:00
|
|
|
if (!m_rootProjectNode)
|
|
|
|
return false;
|
2013-10-29 14:22:31 +01:00
|
|
|
const QmakeProFileNode *node = m_rootProjectNode->findProFileFor(proFilePath);
|
2010-10-27 16:27:22 +02:00
|
|
|
return node && node->validParse();
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProject::parseInProgress(const QString &proFilePath) const
|
2011-06-10 15:37:10 +02:00
|
|
|
{
|
|
|
|
if (!m_rootProjectNode)
|
|
|
|
return false;
|
2013-10-29 14:22:31 +01:00
|
|
|
const QmakeProFileNode *node = m_rootProjectNode->findProFileFor(proFilePath);
|
2011-06-10 15:37:10 +02:00
|
|
|
return node && node->parseInProgress();
|
|
|
|
}
|
|
|
|
|
2014-06-04 12:50:10 +02:00
|
|
|
void QmakeProject::collectAllProFiles(QList<QmakeProFileNode *> &list, QmakeProFileNode *node, Parsing parse,
|
|
|
|
const QList<QmakeProjectType> &projectTypes)
|
2010-07-23 16:37:10 +02:00
|
|
|
{
|
2013-06-18 19:12:48 +02:00
|
|
|
if (parse == ExactAndCumulativeParse || node->includedInExactParse())
|
2014-06-04 12:50:10 +02:00
|
|
|
if (projectTypes.isEmpty() || projectTypes.contains(node->projectType()))
|
2013-06-18 19:12:48 +02:00
|
|
|
list.append(node);
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (ProjectNode *n, node->subProjectNodes()) {
|
2013-10-29 17:37:39 +01:00
|
|
|
QmakeProFileNode *qmakeProFileNode = qobject_cast<QmakeProFileNode *>(n);
|
|
|
|
if (qmakeProFileNode)
|
2014-06-04 12:50:10 +02:00
|
|
|
collectAllProFiles(list, qmakeProFileNode, parse, projectTypes);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-04 12:50:10 +02:00
|
|
|
QList<QmakeProFileNode *> QmakeProject::applicationProFiles(Parsing parse) const
|
2010-07-23 16:37:10 +02:00
|
|
|
{
|
2014-06-04 12:50:10 +02:00
|
|
|
return allProFiles(QList<QmakeProjectType>() << ApplicationTemplate << ScriptTemplate, parse);
|
2010-07-23 16:37:10 +02:00
|
|
|
}
|
|
|
|
|
2014-06-04 12:50:10 +02:00
|
|
|
QList<QmakeProFileNode *> QmakeProject::allProFiles(const QList<QmakeProjectType> &projectTypes, Parsing parse) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-10-29 14:22:31 +01:00
|
|
|
QList<QmakeProFileNode *> list;
|
2010-02-08 15:50:06 +01:00
|
|
|
if (!rootProjectNode())
|
|
|
|
return list;
|
2014-06-04 12:50:10 +02:00
|
|
|
collectAllProFiles(list, rootQmakeProjectNode(), parse, projectTypes);
|
2008-12-02 12:01:29 +01:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProject::hasApplicationProFile(const QString &path) const
|
2010-01-19 13:41:02 +01:00
|
|
|
{
|
|
|
|
if (path.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QList<QmakeProFileNode *> list = applicationProFiles();
|
|
|
|
foreach (QmakeProFileNode * node, list)
|
2010-01-19 13:41:02 +01:00
|
|
|
if (node->path() == path)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-06-12 16:24:52 +02:00
|
|
|
QList<QmakeProFileNode *> QmakeProject::nodesWithQtcRunnable(QList<QmakeProFileNode *> nodes)
|
|
|
|
{
|
|
|
|
std::function<bool (QmakeProFileNode *)> hasQtcRunnable = [](QmakeProFileNode *node) {
|
|
|
|
return node->isQtcRunnable();
|
|
|
|
};
|
|
|
|
|
|
|
|
if (anyOf(nodes, hasQtcRunnable))
|
|
|
|
erase(nodes, std::not1(hasQtcRunnable));
|
|
|
|
return nodes;
|
|
|
|
}
|
|
|
|
|
2014-07-01 11:08:26 +02:00
|
|
|
QList<Core::Id> QmakeProject::idsForNodes(Core::Id base, const QList<QmakeProFileNode *> &nodes)
|
2010-01-19 13:41:02 +01:00
|
|
|
{
|
2014-06-04 13:11:25 +02:00
|
|
|
return Utils::transform(nodes, [&base](QmakeProFileNode *node) {
|
|
|
|
return base.withSuffix(node->path());
|
|
|
|
});
|
2010-01-19 13:41:02 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::activeTargetWasChanged()
|
2010-02-08 15:50:06 +01:00
|
|
|
{
|
2012-08-27 15:11:28 +02:00
|
|
|
if (m_activeTarget) {
|
|
|
|
disconnect(m_activeTarget, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
|
|
|
|
this, SLOT(scheduleAsyncUpdate()));
|
|
|
|
}
|
2012-07-17 15:56:43 +02:00
|
|
|
|
|
|
|
m_activeTarget = activeTarget();
|
|
|
|
|
|
|
|
if (!m_activeTarget)
|
2010-02-08 15:50:06 +01:00
|
|
|
return;
|
|
|
|
|
2012-07-17 15:56:43 +02:00
|
|
|
connect(m_activeTarget, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
|
|
|
|
this, SLOT(scheduleAsyncUpdate()));
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
scheduleAsyncUpdate();
|
2010-02-08 15:50:06 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProject::hasSubNode(QmakePriFileNode *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()) {
|
2013-10-29 14:22:31 +01:00
|
|
|
if (qobject_cast<QmakeProFileNode *>(fn)) {
|
2008-12-05 14:29:18 +01:00
|
|
|
// we aren't interested in pro file nodes
|
2013-10-29 14:22:31 +01:00
|
|
|
} else if (QmakePriFileNode *qt4prifilenode = qobject_cast<QmakePriFileNode *>(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
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::findProFile(const QString& fileName, QmakeProFileNode *root, QList<QmakeProFileNode *> &list)
|
2008-12-02 18:14:06 +01:00
|
|
|
{
|
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())
|
2013-10-29 14:22:31 +01:00
|
|
|
if (QmakeProFileNode *qt4proFileNode = qobject_cast<QmakeProFileNode *>(fn))
|
2008-12-02 18:14:06 +01:00
|
|
|
findProFile(fileName, qt4proFileNode, list);
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::notifyChanged(const QString &name)
|
2008-12-02 18:14:06 +01:00
|
|
|
{
|
2013-10-29 14:22:31 +01:00
|
|
|
if (files(QmakeProject::ExcludeGeneratedFiles).contains(name)) {
|
|
|
|
QList<QmakeProFileNode *> list;
|
|
|
|
findProFile(name, rootQmakeProjectNode(), list);
|
|
|
|
foreach (QmakeProFileNode *node, list) {
|
2011-05-20 21:40:53 +02:00
|
|
|
QtSupport::ProFileCacheManager::instance()->discardFile(name);
|
2008-12-05 14:29:18 +01:00
|
|
|
node->update();
|
2009-12-07 22:58:47 +01:00
|
|
|
}
|
2011-05-25 12:54:14 +02:00
|
|
|
updateFileList();
|
2008-12-05 14:29:18 +01:00
|
|
|
}
|
2008-12-02 18:14:06 +01:00
|
|
|
}
|
2009-03-19 15:04:43 +01:00
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::watchFolders(const QStringList &l, QmakePriFileNode *node)
|
2011-08-18 16:46:44 +02:00
|
|
|
{
|
|
|
|
if (l.isEmpty())
|
|
|
|
return;
|
|
|
|
if (!m_centralizedFolderWatcher)
|
|
|
|
m_centralizedFolderWatcher = new Internal::CentralizedFolderWatcher(this);
|
|
|
|
m_centralizedFolderWatcher->watchFolders(l, node);
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::unwatchFolders(const QStringList &l, QmakePriFileNode *node)
|
2010-08-10 16:27:35 +02:00
|
|
|
{
|
2011-08-18 16:46:44 +02:00
|
|
|
if (m_centralizedFolderWatcher && !l.isEmpty())
|
|
|
|
m_centralizedFolderWatcher->unwatchFolders(l, node);
|
2010-08-10 16:27:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////
|
|
|
|
/// Centralized Folder Watcher
|
|
|
|
////////////
|
|
|
|
|
|
|
|
// All the folder have a trailing slash!
|
|
|
|
|
|
|
|
namespace {
|
2013-05-05 22:43:52 +03:00
|
|
|
bool debugCFW = false;
|
2010-08-10 16:27:35 +02:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
CentralizedFolderWatcher::CentralizedFolderWatcher(QmakeProject *parent)
|
2013-07-01 11:35:38 +02:00
|
|
|
: QObject(parent), m_project(parent)
|
2010-08-10 16:27:35 +02:00
|
|
|
{
|
2010-10-13 15:33:51 +02:00
|
|
|
m_compressTimer.setSingleShot(true);
|
|
|
|
m_compressTimer.setInterval(200);
|
|
|
|
connect(&m_compressTimer, SIGNAL(timeout()),
|
|
|
|
this, SLOT(onTimer()));
|
2010-08-10 16:27:35 +02:00
|
|
|
connect (&m_watcher, SIGNAL(directoryChanged(QString)),
|
|
|
|
this, SLOT(folderChanged(QString)));
|
|
|
|
}
|
|
|
|
|
|
|
|
CentralizedFolderWatcher::~CentralizedFolderWatcher()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
QSet<QString> CentralizedFolderWatcher::recursiveDirs(const QString &folder)
|
|
|
|
{
|
|
|
|
QSet<QString> result;
|
|
|
|
QDir dir(folder);
|
|
|
|
QStringList list = dir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot);
|
|
|
|
foreach (const QString &f, list) {
|
2012-01-13 14:20:45 +01:00
|
|
|
const QString a = folder + f + QLatin1Char('/');
|
2011-02-25 15:27:13 +01:00
|
|
|
result.insert(a);
|
|
|
|
result += recursiveDirs(a);
|
2010-08-10 16:27:35 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-02-26 10:36:29 +02:00
|
|
|
void CentralizedFolderWatcher::watchFolders(const QList<QString> &folders, QmakePriFileNode *node)
|
2010-08-10 16:27:35 +02:00
|
|
|
{
|
|
|
|
if (debugCFW)
|
|
|
|
qDebug()<<"CFW::watchFolders()"<<folders<<"for node"<<node->path();
|
|
|
|
m_watcher.addPaths(folders);
|
|
|
|
|
2012-01-13 14:20:45 +01:00
|
|
|
const QChar slash = QLatin1Char('/');
|
2010-08-10 16:27:35 +02:00
|
|
|
foreach (const QString &f, folders) {
|
|
|
|
QString folder = f;
|
2012-01-13 14:20:45 +01:00
|
|
|
if (!folder.endsWith(slash))
|
|
|
|
folder.append(slash);
|
2010-08-10 16:27:35 +02:00
|
|
|
m_map.insert(folder, node);
|
|
|
|
|
|
|
|
// Support for recursive watching
|
|
|
|
// we add the recursive directories we find
|
|
|
|
QSet<QString> tmp = recursiveDirs(folder);
|
2010-08-12 13:38:21 +02:00
|
|
|
if (!tmp.isEmpty())
|
|
|
|
m_watcher.addPaths(tmp.toList());
|
2010-08-10 16:27:35 +02:00
|
|
|
m_recursiveWatchedFolders += tmp;
|
|
|
|
|
|
|
|
if (debugCFW)
|
|
|
|
qDebug()<<"adding recursive dirs for"<< folder<<":"<<tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-26 10:36:29 +02:00
|
|
|
void CentralizedFolderWatcher::unwatchFolders(const QList<QString> &folders, QmakePriFileNode *node)
|
2010-08-10 16:27:35 +02:00
|
|
|
{
|
|
|
|
if (debugCFW)
|
|
|
|
qDebug()<<"CFW::unwatchFolders()"<<folders<<"for node"<<node->path();
|
2012-01-13 14:20:45 +01:00
|
|
|
const QChar slash = QLatin1Char('/');
|
2010-08-10 16:27:35 +02:00
|
|
|
foreach (const QString &f, folders) {
|
|
|
|
QString folder = f;
|
2012-01-13 14:20:45 +01:00
|
|
|
if (!folder.endsWith(slash))
|
|
|
|
folder.append(slash);
|
2010-08-10 16:27:35 +02:00
|
|
|
m_map.remove(folder, node);
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (!m_map.contains(folder))
|
2010-08-10 16:27:35 +02:00
|
|
|
m_watcher.removePath(folder);
|
|
|
|
|
|
|
|
// Figure out which recursive directories we can remove
|
2012-05-03 16:15:38 +02:00
|
|
|
// this might not scale. I'm pretty sure it doesn't
|
2010-08-10 16:27:35 +02:00
|
|
|
// A scaling implementation would need to save more information
|
|
|
|
// where a given directory watcher actual comes from...
|
|
|
|
|
|
|
|
QStringList toRemove;
|
|
|
|
foreach (const QString &rwf, m_recursiveWatchedFolders) {
|
|
|
|
if (rwf.startsWith(folder)) {
|
|
|
|
// So the rwf is a subdirectory of a folder we aren't watching
|
|
|
|
// but maybe someone else wants us to watch
|
|
|
|
bool needToWatch = false;
|
2014-02-26 10:36:29 +02:00
|
|
|
QMultiMap<QString, QmakePriFileNode *>::const_iterator it, end;
|
2010-08-10 16:27:35 +02:00
|
|
|
end = m_map.constEnd();
|
|
|
|
for (it = m_map.constEnd(); it != end; ++it) {
|
|
|
|
if (rwf.startsWith(it.key())) {
|
|
|
|
needToWatch = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!needToWatch) {
|
|
|
|
m_watcher.removePath(rwf);
|
|
|
|
toRemove << rwf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debugCFW)
|
|
|
|
qDebug()<<"removing recursive dirs for"<<folder<<":"<<toRemove;
|
|
|
|
|
|
|
|
foreach (const QString &tr, toRemove) {
|
|
|
|
m_recursiveWatchedFolders.remove(tr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CentralizedFolderWatcher::folderChanged(const QString &folder)
|
2010-10-13 15:33:51 +02:00
|
|
|
{
|
|
|
|
m_changedFolders.insert(folder);
|
|
|
|
m_compressTimer.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CentralizedFolderWatcher::onTimer()
|
|
|
|
{
|
2012-11-28 20:44:03 +02:00
|
|
|
foreach (const QString &folder, m_changedFolders)
|
2010-10-13 15:33:51 +02:00
|
|
|
delayedFolderChanged(folder);
|
|
|
|
m_changedFolders.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CentralizedFolderWatcher::delayedFolderChanged(const QString &folder)
|
2010-08-10 16:27:35 +02:00
|
|
|
{
|
|
|
|
if (debugCFW)
|
|
|
|
qDebug()<<"CFW::folderChanged"<<folder;
|
|
|
|
// Figure out whom to inform
|
|
|
|
|
2010-08-18 12:53:37 +02:00
|
|
|
QString dir = folder;
|
2012-01-13 14:20:45 +01:00
|
|
|
const QChar slash = QLatin1Char('/');
|
2013-07-01 11:35:38 +02:00
|
|
|
bool newOrRemovedFiles = false;
|
2010-08-10 16:27:35 +02:00
|
|
|
while (true) {
|
2012-01-13 14:20:45 +01:00
|
|
|
if (!dir.endsWith(slash))
|
|
|
|
dir.append(slash);
|
2014-02-26 10:36:29 +02:00
|
|
|
QList<QmakePriFileNode *> nodes = m_map.values(dir);
|
2013-07-01 11:35:38 +02:00
|
|
|
if (!nodes.isEmpty()) {
|
|
|
|
// Collect all the files
|
|
|
|
QSet<Utils::FileName> newFiles;
|
2013-10-29 14:22:31 +01:00
|
|
|
newFiles += QmakePriFileNode::recursiveEnumerate(folder);
|
2014-02-26 10:36:29 +02:00
|
|
|
foreach (QmakePriFileNode *node, nodes) {
|
2013-07-01 11:35:38 +02:00
|
|
|
newOrRemovedFiles = newOrRemovedFiles
|
|
|
|
|| node->folderChanged(folder, newFiles);
|
|
|
|
}
|
2010-08-10 16:27:35 +02:00
|
|
|
}
|
|
|
|
|
2010-08-18 12:53:37 +02:00
|
|
|
// Chop off last part, and break if there's nothing to chop off
|
|
|
|
//
|
|
|
|
if (dir.length() < 2)
|
2010-08-10 16:27:35 +02:00
|
|
|
break;
|
2010-08-18 12:53:37 +02:00
|
|
|
|
|
|
|
// We start before the last slash
|
2012-01-13 14:20:45 +01:00
|
|
|
const int index = dir.lastIndexOf(slash, dir.length() - 2);
|
2010-08-18 12:53:37 +02:00
|
|
|
if (index == -1)
|
|
|
|
break;
|
2012-01-13 14:20:45 +01:00
|
|
|
dir.truncate(index + 1);
|
2010-08-10 16:27:35 +02:00
|
|
|
}
|
|
|
|
|
2010-08-16 13:01:36 +02:00
|
|
|
QString folderWithSlash = folder;
|
2012-01-13 14:20:45 +01:00
|
|
|
if (!folder.endsWith(slash))
|
|
|
|
folderWithSlash.append(slash);
|
2010-08-16 13:01:36 +02:00
|
|
|
|
2010-08-10 16:27:35 +02:00
|
|
|
// If a subdirectory was added, watch it too
|
2010-08-16 13:01:36 +02:00
|
|
|
QSet<QString> tmp = recursiveDirs(folderWithSlash);
|
2010-08-10 16:27:35 +02:00
|
|
|
if (!tmp.isEmpty()) {
|
|
|
|
if (debugCFW)
|
|
|
|
qDebug()<<"found new recursive dirs"<<tmp;
|
2010-10-13 14:44:32 +02:00
|
|
|
|
|
|
|
QSet<QString> alreadyAdded = m_watcher.directories().toSet();
|
|
|
|
tmp.subtract(alreadyAdded);
|
|
|
|
if (!tmp.isEmpty())
|
|
|
|
m_watcher.addPaths(tmp.toList());
|
2010-08-10 16:27:35 +02:00
|
|
|
m_recursiveWatchedFolders += tmp;
|
|
|
|
}
|
2013-07-01 11:35:38 +02:00
|
|
|
|
|
|
|
if (newOrRemovedFiles) {
|
|
|
|
m_project->updateFileList();
|
|
|
|
m_project->updateCodeModels();
|
|
|
|
}
|
2010-08-10 16:27:35 +02:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
bool QmakeProject::needsConfiguration() const
|
2011-10-28 10:15:04 +00:00
|
|
|
{
|
|
|
|
return targets().isEmpty();
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::configureAsExampleProject(const QStringList &platforms)
|
2012-03-06 13:14:42 +01:00
|
|
|
{
|
2013-08-13 10:52:57 +02:00
|
|
|
QList<const BuildInfo *> infoList;
|
2014-09-12 01:08:28 +02:00
|
|
|
QList<Kit *> kits = KitManager::kits();
|
2012-09-03 18:31:44 +02:00
|
|
|
foreach (Kit *k, kits) {
|
|
|
|
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
|
2012-04-24 15:49:09 +02:00
|
|
|
if (!version)
|
|
|
|
continue;
|
|
|
|
if (!platforms.isEmpty() && !platforms.contains(version->platformName()))
|
|
|
|
continue;
|
|
|
|
|
2014-05-02 12:22:58 +02:00
|
|
|
IBuildConfigurationFactory *factory = IBuildConfigurationFactory::find(k, projectFilePath().toString());
|
2013-08-13 10:52:57 +02:00
|
|
|
if (!factory)
|
2012-04-24 15:49:09 +02:00
|
|
|
continue;
|
2014-05-02 12:22:58 +02:00
|
|
|
foreach (BuildInfo *info, factory->availableSetups(k, projectFilePath().toString()))
|
2013-08-13 10:52:57 +02:00
|
|
|
infoList << info;
|
2012-03-06 13:14:42 +01:00
|
|
|
}
|
2013-08-13 10:52:57 +02:00
|
|
|
setup(infoList);
|
|
|
|
qDeleteAll(infoList);
|
2014-09-12 01:08:28 +02:00
|
|
|
ProjectExplorerPlugin::requestProjectModeUpdate(this);
|
2012-03-06 13:14:42 +01:00
|
|
|
}
|
|
|
|
|
2014-07-11 12:04:30 +02:00
|
|
|
bool QmakeProject::requiresTargetPanel() const
|
2012-09-06 16:19:14 +02:00
|
|
|
{
|
2014-07-11 12:04:30 +02:00
|
|
|
return false;
|
2012-09-06 16:19:14 +02:00
|
|
|
}
|
|
|
|
|
2013-10-29 18:24:57 +01:00
|
|
|
// All the Qmake run configurations should share code.
|
2012-05-09 12:44:37 +02:00
|
|
|
// This is a rather suboptimal way to do that for disabledReason()
|
|
|
|
// but more pratical then duplicated the code everywhere
|
2013-10-29 14:22:31 +01:00
|
|
|
QString QmakeProject::disabledReasonForRunConfiguration(const QString &proFilePath)
|
2012-05-09 12:44:37 +02:00
|
|
|
{
|
|
|
|
if (!QFileInfo(proFilePath).exists())
|
2014-04-17 14:09:47 +02:00
|
|
|
return tr("The .pro file \"%1\" does not exist.")
|
2012-05-09 12:44:37 +02:00
|
|
|
.arg(QFileInfo(proFilePath).fileName());
|
|
|
|
|
2012-06-28 13:10:33 +02:00
|
|
|
if (!m_rootProjectNode) // Shutting down
|
|
|
|
return QString();
|
|
|
|
|
2012-05-09 12:44:37 +02:00
|
|
|
if (!m_rootProjectNode->findProFileFor(proFilePath))
|
2014-04-17 14:09:47 +02:00
|
|
|
return tr("The .pro file \"%1\" is not part of the project.")
|
2012-05-09 12:44:37 +02:00
|
|
|
.arg(QFileInfo(proFilePath).fileName());
|
|
|
|
|
2014-04-17 14:09:47 +02:00
|
|
|
return tr("The .pro file \"%1\" could not be parsed.")
|
2012-05-09 12:44:37 +02:00
|
|
|
.arg(QFileInfo(proFilePath).fileName());
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QString QmakeProject::shadowBuildDirectory(const QString &proFilePath, const Kit *k, const QString &suffix)
|
2012-04-24 15:49:09 +02:00
|
|
|
{
|
2012-11-16 19:11:36 +01:00
|
|
|
if (proFilePath.isEmpty())
|
2012-04-24 15:49:09 +02:00
|
|
|
return QString();
|
2012-11-16 19:11:36 +01:00
|
|
|
QFileInfo info(proFilePath);
|
2012-04-24 15:49:09 +02:00
|
|
|
|
2012-09-09 20:41:30 +03:00
|
|
|
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
|
2012-04-24 15:49:09 +02:00
|
|
|
if (version && !version->supportsShadowBuilds())
|
|
|
|
return info.absolutePath();
|
|
|
|
|
2013-01-17 15:03:41 +01:00
|
|
|
const QString projectName = QFileInfo(proFilePath).completeBaseName();
|
2013-03-15 15:38:28 +01:00
|
|
|
ProjectExplorer::ProjectMacroExpander expander(proFilePath, projectName, k, suffix);
|
2014-05-02 12:53:36 +02:00
|
|
|
QString projectDir = projectDirectory(Utils::FileName::fromString(proFilePath)).toString();
|
2012-11-16 19:11:36 +01:00
|
|
|
QString buildPath = Utils::expandMacros(Core::DocumentManager::buildDirectory(), &expander);
|
2014-04-11 17:45:11 +02:00
|
|
|
return Utils::FileUtils::resolvePath(projectDir, buildPath);
|
2012-04-24 15:49:09 +02:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QString QmakeProject::buildNameFor(const Kit *k)
|
2012-04-24 15:49:09 +02:00
|
|
|
{
|
2012-09-09 20:41:30 +03:00
|
|
|
if (!k)
|
2012-04-24 15:49:09 +02:00
|
|
|
return QLatin1String("unknown");
|
2012-10-04 14:40:29 +02:00
|
|
|
|
|
|
|
return k->fileSystemFriendlyName();
|
2012-04-24 15:49:09 +02:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::updateBuildSystemData()
|
2012-08-20 12:41:52 +02:00
|
|
|
{
|
|
|
|
Target * const target = activeTarget();
|
|
|
|
if (!target)
|
|
|
|
return;
|
2013-10-29 14:22:31 +01:00
|
|
|
const QmakeProFileNode * const rootNode = rootQmakeProjectNode();
|
2012-08-20 12:41:52 +02:00
|
|
|
if (!rootNode || rootNode->parseInProgress())
|
|
|
|
return;
|
|
|
|
|
|
|
|
DeploymentData deploymentData;
|
|
|
|
collectData(rootNode, deploymentData);
|
|
|
|
target->setDeploymentData(deploymentData);
|
|
|
|
|
|
|
|
BuildTargetInfoList appTargetList;
|
2014-08-07 15:53:54 +02:00
|
|
|
foreach (const QmakeProFileNode * const node, applicationProFiles()) {
|
|
|
|
appTargetList.list << BuildTargetInfo(node->targetInformation().target,
|
|
|
|
Utils::FileName::fromString(executableFor(node)),
|
|
|
|
Utils::FileName::fromString(node->path()));
|
|
|
|
}
|
2012-08-20 12:41:52 +02:00
|
|
|
target->setApplicationTargets(appTargetList);
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::collectData(const QmakeProFileNode *node, DeploymentData &deploymentData)
|
2012-08-20 12:41:52 +02:00
|
|
|
{
|
|
|
|
if (!node->isSubProjectDeployable(node->path()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
const InstallsList &installsList = node->installsList();
|
|
|
|
foreach (const InstallsItem &item, installsList.items) {
|
|
|
|
foreach (const QString &localFile, item.files)
|
|
|
|
deploymentData.addFile(localFile, item.path);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (node->projectType()) {
|
|
|
|
case ApplicationTemplate:
|
|
|
|
if (!installsList.targetPath.isEmpty())
|
2013-03-12 14:09:18 +01:00
|
|
|
collectApplicationData(node, deploymentData);
|
2012-08-20 12:41:52 +02:00
|
|
|
break;
|
|
|
|
case LibraryTemplate:
|
|
|
|
collectLibraryData(node, deploymentData);
|
|
|
|
break;
|
|
|
|
case SubDirsTemplate:
|
|
|
|
foreach (const ProjectNode * const subProject, node->subProjectNodesExact()) {
|
2013-10-29 14:22:31 +01:00
|
|
|
const QmakeProFileNode * const qt4SubProject
|
|
|
|
= qobject_cast<const QmakeProFileNode *>(subProject);
|
2012-08-20 12:41:52 +02:00
|
|
|
if (!qt4SubProject)
|
|
|
|
continue;
|
|
|
|
collectData(qt4SubProject, deploymentData);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::collectApplicationData(const QmakeProFileNode *node, DeploymentData &deploymentData)
|
2013-03-12 14:09:18 +01:00
|
|
|
{
|
|
|
|
QString executable = executableFor(node);
|
|
|
|
if (!executable.isEmpty())
|
|
|
|
deploymentData.addFile(executable, node->installsList().targetPath,
|
|
|
|
DeployableFile::TypeExecutable);
|
|
|
|
}
|
|
|
|
|
2014-04-08 17:28:39 +02:00
|
|
|
static QString destDirFor(const TargetInformation &ti)
|
|
|
|
{
|
|
|
|
if (ti.destDir.isEmpty())
|
|
|
|
return ti.buildDir;
|
|
|
|
if (QDir::isRelativePath(ti.destDir))
|
|
|
|
return QDir::cleanPath(ti.buildDir + QLatin1Char('/') + ti.destDir);
|
|
|
|
return ti.destDir;
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::collectLibraryData(const QmakeProFileNode *node, DeploymentData &deploymentData)
|
2012-08-20 12:41:52 +02:00
|
|
|
{
|
|
|
|
const QString targetPath = node->installsList().targetPath;
|
|
|
|
if (targetPath.isEmpty())
|
|
|
|
return;
|
2012-09-03 18:31:44 +02:00
|
|
|
const ProjectExplorer::Kit * const kit = activeTarget()->kit();
|
2012-08-20 12:41:52 +02:00
|
|
|
const ProjectExplorer::ToolChain * const toolchain
|
2012-09-03 18:31:44 +02:00
|
|
|
= ProjectExplorer::ToolChainKitInformation::toolChain(kit);
|
2012-08-20 12:41:52 +02:00
|
|
|
if (!toolchain)
|
|
|
|
return;
|
|
|
|
|
|
|
|
TargetInformation ti = node->targetInformation();
|
|
|
|
QString targetFileName = ti.target;
|
|
|
|
const QStringList config = node->variableValue(ConfigVar);
|
|
|
|
const bool isStatic = config.contains(QLatin1String("static"));
|
|
|
|
const bool isPlugin = config.contains(QLatin1String("plugin"));
|
|
|
|
switch (toolchain->targetAbi().os()) {
|
|
|
|
case ProjectExplorer::Abi::WindowsOS: {
|
|
|
|
QString targetVersionExt = node->singleVariableValue(TargetVersionExtVar);
|
|
|
|
if (targetVersionExt.isEmpty()) {
|
|
|
|
const QString version = node->singleVariableValue(VersionVar);
|
|
|
|
if (!version.isEmpty()) {
|
|
|
|
targetVersionExt = version.left(version.indexOf(QLatin1Char('.')));
|
|
|
|
if (targetVersionExt == QLatin1String("0"))
|
|
|
|
targetVersionExt.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
targetFileName += targetVersionExt + QLatin1Char('.');
|
|
|
|
targetFileName += QLatin1String(isStatic ? "lib" : "dll");
|
2013-03-12 14:09:18 +01:00
|
|
|
deploymentData.addFile(destDirFor(ti) + QLatin1Char('/') + targetFileName, targetPath);
|
2012-08-20 12:41:52 +02:00
|
|
|
break;
|
|
|
|
}
|
2013-03-12 14:09:18 +01:00
|
|
|
case ProjectExplorer::Abi::MacOS: {
|
|
|
|
QString destDir = destDirFor(ti);
|
2012-11-26 15:09:56 +02:00
|
|
|
if (config.contains(QLatin1String("lib_bundle"))) {
|
2013-03-12 14:09:18 +01:00
|
|
|
destDir.append(QLatin1Char('/')).append(ti.target)
|
2012-08-20 12:41:52 +02:00
|
|
|
.append(QLatin1String(".framework"));
|
|
|
|
} else {
|
|
|
|
targetFileName.prepend(QLatin1String("lib"));
|
|
|
|
if (!isPlugin) {
|
|
|
|
targetFileName += QLatin1Char('.');
|
|
|
|
const QString version = node->singleVariableValue(VersionVar);
|
|
|
|
QString majorVersion = version.left(version.indexOf(QLatin1Char('.')));
|
|
|
|
if (majorVersion.isEmpty())
|
|
|
|
majorVersion = QLatin1String("1");
|
|
|
|
targetFileName += majorVersion;
|
|
|
|
}
|
|
|
|
targetFileName += QLatin1Char('.');
|
|
|
|
targetFileName += node->singleVariableValue(isStatic
|
|
|
|
? StaticLibExtensionVar : ShLibExtensionVar);
|
|
|
|
}
|
2013-03-12 14:09:18 +01:00
|
|
|
deploymentData.addFile(destDir + QLatin1Char('/') + targetFileName, targetPath);
|
2012-08-20 12:41:52 +02:00
|
|
|
break;
|
2013-03-12 14:09:18 +01:00
|
|
|
}
|
2012-08-20 12:41:52 +02:00
|
|
|
case ProjectExplorer::Abi::LinuxOS:
|
|
|
|
case ProjectExplorer::Abi::BsdOS:
|
|
|
|
case ProjectExplorer::Abi::UnixOS:
|
|
|
|
targetFileName.prepend(QLatin1String("lib"));
|
|
|
|
targetFileName += QLatin1Char('.');
|
|
|
|
if (isStatic) {
|
|
|
|
targetFileName += QLatin1Char('a');
|
|
|
|
} else {
|
|
|
|
targetFileName += QLatin1String("so");
|
2013-03-12 14:09:18 +01:00
|
|
|
deploymentData.addFile(destDirFor(ti) + QLatin1Char('/') + targetFileName, targetPath);
|
2012-08-20 12:41:52 +02:00
|
|
|
if (!isPlugin) {
|
|
|
|
QString version = node->singleVariableValue(VersionVar);
|
|
|
|
if (version.isEmpty())
|
|
|
|
version = QLatin1String("1.0.0");
|
|
|
|
targetFileName += QLatin1Char('.');
|
|
|
|
while (true) {
|
2013-03-12 14:09:18 +01:00
|
|
|
deploymentData.addFile(destDirFor(ti) + QLatin1Char('/')
|
2012-08-20 12:41:52 +02:00
|
|
|
+ targetFileName + version, targetPath);
|
|
|
|
const QString tmpVersion = version.left(version.lastIndexOf(QLatin1Char('.')));
|
|
|
|
if (tmpVersion == version)
|
|
|
|
break;
|
|
|
|
version = tmpVersion;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
QString QmakeProject::executableFor(const QmakeProFileNode *node)
|
2013-03-12 14:09:18 +01:00
|
|
|
{
|
|
|
|
const ProjectExplorer::Kit * const kit = activeTarget()->kit();
|
|
|
|
const ProjectExplorer::ToolChain * const toolchain
|
|
|
|
= ProjectExplorer::ToolChainKitInformation::toolChain(kit);
|
|
|
|
if (!toolchain)
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
TargetInformation ti = node->targetInformation();
|
2013-12-23 15:01:10 +02:00
|
|
|
QString target;
|
2013-03-12 14:09:18 +01:00
|
|
|
|
|
|
|
switch (toolchain->targetAbi().os()) {
|
|
|
|
case ProjectExplorer::Abi::MacOS:
|
2013-12-23 15:01:10 +02:00
|
|
|
if (node->variableValue(ConfigVar).contains(QLatin1String("app_bundle"))) {
|
|
|
|
target = ti.target + QLatin1String(".app/Contents/MacOS/") + ti.target;
|
|
|
|
break;
|
|
|
|
}
|
2013-03-12 14:09:18 +01:00
|
|
|
// else fall through
|
|
|
|
case ProjectExplorer::Abi::WindowsOS:
|
|
|
|
case ProjectExplorer::Abi::LinuxOS:
|
|
|
|
case ProjectExplorer::Abi::BsdOS:
|
|
|
|
case ProjectExplorer::Abi::UnixOS: {
|
|
|
|
QString extension = node->singleVariableValue(TargetExtVar);
|
2013-12-23 15:01:10 +02:00
|
|
|
target = ti.target + extension;
|
|
|
|
break;
|
2013-03-12 14:09:18 +01:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
return QString();
|
|
|
|
}
|
2013-12-23 15:01:10 +02:00
|
|
|
return QDir(destDirFor(ti)).absoluteFilePath(target);
|
2013-03-12 14:09:18 +01:00
|
|
|
}
|
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
void QmakeProject::emitBuildDirectoryInitialized()
|
2012-07-13 17:14:42 +02:00
|
|
|
{
|
|
|
|
emit buildDirectoryInitialized();
|
|
|
|
}
|
2013-08-13 10:52:57 +02:00
|
|
|
|
2013-10-29 14:22:31 +01:00
|
|
|
ProjectImporter *QmakeProject::createProjectImporter() const
|
2013-08-13 10:52:57 +02:00
|
|
|
{
|
2014-05-02 12:22:58 +02:00
|
|
|
return new QmakeProjectImporter(projectFilePath().toString());
|
2013-08-13 10:52:57 +02:00
|
|
|
}
|
|
|
|
|
2013-10-16 11:02:37 +02:00
|
|
|
} // namespace QmakeProjectManager
|
2011-08-18 16:55:45 +02:00
|
|
|
|
2013-10-16 12:10:22 +02:00
|
|
|
#include "qmakeproject.moc"
|