2009-02-25 09:02:17 +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:02:17 +01:00
|
|
|
** Commercial Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:02:17 +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:02:17 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:02:17 +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:02:17 +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:02:17 +01:00
|
|
|
**************************************************************************/
|
2008-12-02 16:19:05 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "profilereader.h"
|
2008-12-03 09:39:11 +01:00
|
|
|
#include "prowriter.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "qt4nodes.h"
|
|
|
|
#include "qt4project.h"
|
|
|
|
#include "qt4projectmanager.h"
|
2010-01-20 14:47:08 +01:00
|
|
|
#include "qt4projectmanagerconstants.h"
|
2009-05-12 14:12:20 +02:00
|
|
|
#include "qtuicodemodelsupport.h"
|
2009-11-25 18:50:20 +01:00
|
|
|
#include "qt4buildconfiguration.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
#include <projectexplorer/nodesvisitor.h>
|
|
|
|
|
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2009-10-01 16:38:08 +02:00
|
|
|
#include <coreplugin/editormanager/ieditor.h>
|
2009-01-27 12:40:49 +01:00
|
|
|
#include <coreplugin/fileiconprovider.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <coreplugin/filemanager.h>
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
#include <coreplugin/iversioncontrol.h>
|
|
|
|
#include <coreplugin/vcsmanager.h>
|
|
|
|
|
|
|
|
#include <cpptools/cppmodelmanagerinterface.h>
|
2009-01-14 17:13:17 +01:00
|
|
|
#include <cplusplus/CppDocument.h>
|
2009-01-19 12:39:20 +01:00
|
|
|
#include <extensionsystem/pluginmanager.h>
|
2009-04-28 14:30:17 +02:00
|
|
|
#include <projectexplorer/projectexplorer.h>
|
|
|
|
#include <projectexplorer/buildmanager.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2008-12-09 15:25:01 +01:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <QtCore/QDebug>
|
|
|
|
#include <QtCore/QDir>
|
|
|
|
#include <QtCore/QFile>
|
|
|
|
#include <QtCore/QFileInfo>
|
2010-03-17 17:45:33 +01:00
|
|
|
#include <QtCore/QCoreApplication>
|
2008-12-09 15:25:01 +01:00
|
|
|
|
2009-01-27 12:40:49 +01:00
|
|
|
#include <QtGui/QPainter>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <QtGui/QMainWindow>
|
|
|
|
#include <QtGui/QMessageBox>
|
|
|
|
#include <QtGui/QPushButton>
|
2010-03-10 16:55:37 +01:00
|
|
|
#include <qtconcurrent/QtConcurrentTools>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-12 12:40:32 +01:00
|
|
|
// Static cached data in struct Qt4NodeStaticData providing information and icons
|
|
|
|
// for file types and the project. Do some magic via qAddPostRoutine()
|
|
|
|
// to make sure the icons do not outlive QApplication, triggering warnings on X11.
|
|
|
|
|
|
|
|
struct FileTypeDataStorage {
|
|
|
|
ProjectExplorer::FileType type;
|
|
|
|
const char *typeName;
|
|
|
|
const char *icon;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const FileTypeDataStorage fileTypeDataStorage[] = {
|
|
|
|
{ ProjectExplorer::HeaderType,
|
|
|
|
QT_TRANSLATE_NOOP("Qt4ProjectManager::Internal::Qt4PriFileNode", "Headers"),
|
|
|
|
":/qt4projectmanager/images/headers.png" },
|
|
|
|
{ ProjectExplorer::SourceType,
|
|
|
|
QT_TRANSLATE_NOOP("Qt4ProjectManager::Internal::Qt4PriFileNode", "Sources"),
|
|
|
|
":/qt4projectmanager/images/sources.png" },
|
|
|
|
{ ProjectExplorer::FormType,
|
|
|
|
QT_TRANSLATE_NOOP("Qt4ProjectManager::Internal::Qt4PriFileNode", "Forms"),
|
|
|
|
":/qt4projectmanager/images/forms.png" },
|
|
|
|
{ ProjectExplorer::ResourceType,
|
|
|
|
QT_TRANSLATE_NOOP("Qt4ProjectManager::Internal::Qt4PriFileNode", "Resources"),
|
|
|
|
":/qt4projectmanager/images/qt_qrc.png" },
|
|
|
|
{ ProjectExplorer::UnknownFileType,
|
|
|
|
QT_TRANSLATE_NOOP("Qt4ProjectManager::Internal::Qt4PriFileNode", "Other files"),
|
|
|
|
":/qt4projectmanager/images/unknown.png" }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Qt4NodeStaticData {
|
|
|
|
struct FileTypeData {
|
|
|
|
FileTypeData(ProjectExplorer::FileType t = ProjectExplorer::UnknownFileType,
|
|
|
|
const QString &tN = QString(),
|
|
|
|
const QIcon &i = QIcon()) :
|
|
|
|
type(t), typeName(tN), icon(i) { }
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-02-12 12:40:32 +01:00
|
|
|
ProjectExplorer::FileType type;
|
|
|
|
QString typeName;
|
|
|
|
QIcon icon;
|
|
|
|
};
|
|
|
|
|
|
|
|
QVector<FileTypeData> fileTypeData;
|
|
|
|
QIcon projectIcon;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void clearQt4NodeStaticData();
|
|
|
|
|
|
|
|
Q_GLOBAL_STATIC_WITH_INITIALIZER(Qt4NodeStaticData, qt4NodeStaticData, {
|
|
|
|
// File type data
|
|
|
|
const unsigned count = sizeof(fileTypeDataStorage)/sizeof(FileTypeDataStorage);
|
|
|
|
x->fileTypeData.reserve(count);
|
|
|
|
|
|
|
|
// Overlay the SP_DirIcon with the custom icons
|
|
|
|
const QSize desiredSize = QSize(16, 16);
|
|
|
|
|
|
|
|
for (unsigned i = 0 ; i < count; i++) {
|
|
|
|
const QIcon overlayIcon = QIcon(QLatin1String(fileTypeDataStorage[i].icon));
|
|
|
|
const QPixmap folderPixmap =
|
|
|
|
Core::FileIconProvider::overlayIcon(QStyle::SP_DirIcon,
|
|
|
|
overlayIcon, desiredSize);
|
|
|
|
QIcon folderIcon;
|
|
|
|
folderIcon.addPixmap(folderPixmap);
|
|
|
|
const QString desc = Qt4ProjectManager::Internal::Qt4PriFileNode::tr(fileTypeDataStorage[i].typeName);
|
|
|
|
x->fileTypeData.push_back(Qt4NodeStaticData::FileTypeData(fileTypeDataStorage[i].type,
|
|
|
|
desc, folderIcon));
|
|
|
|
}
|
|
|
|
// Project icon
|
|
|
|
const QIcon projectBaseIcon(QLatin1String(":/qt4projectmanager/images/qt_project.png"));
|
|
|
|
const QPixmap projectPixmap = Core::FileIconProvider::overlayIcon(QStyle::SP_DirIcon,
|
|
|
|
projectBaseIcon,
|
|
|
|
desiredSize);
|
|
|
|
x->projectIcon.addPixmap(projectPixmap);
|
|
|
|
|
|
|
|
qAddPostRoutine(clearQt4NodeStaticData);
|
|
|
|
});
|
|
|
|
|
|
|
|
static void clearQt4NodeStaticData()
|
|
|
|
{
|
|
|
|
qt4NodeStaticData()->fileTypeData.clear();
|
|
|
|
qt4NodeStaticData()->projectIcon = QIcon();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-02-12 12:40:32 +01:00
|
|
|
enum { debug = 0 };
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
namespace {
|
|
|
|
// sorting helper function
|
|
|
|
bool sortProjectFilesByPath(ProFile *f1, ProFile *f2)
|
|
|
|
{
|
|
|
|
return f1->fileName() < f2->fileName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-12 12:40:32 +01:00
|
|
|
namespace Qt4ProjectManager {
|
|
|
|
namespace Internal {
|
2010-01-20 14:47:08 +01:00
|
|
|
|
|
|
|
Qt4PriFile::Qt4PriFile(Qt4PriFileNode *qt4PriFile)
|
|
|
|
: IFile(qt4PriFile), m_priFile(qt4PriFile)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFile::save(const QString &fileName)
|
|
|
|
{
|
|
|
|
Q_UNUSED(fileName);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Qt4PriFile::fileName() const
|
|
|
|
{
|
|
|
|
return m_priFile->path();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Qt4PriFile::defaultPath() const
|
|
|
|
{
|
2010-02-02 17:09:41 +01:00
|
|
|
return QString();
|
2010-01-20 14:47:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Qt4PriFile::suggestedFileName() const
|
|
|
|
{
|
2010-02-02 17:09:41 +01:00
|
|
|
return QString();
|
2010-01-20 14:47:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Qt4PriFile::mimeType() const
|
|
|
|
{
|
|
|
|
return Qt4ProjectManager::Constants::PROFILE_MIMETYPE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFile::isModified() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFile::isReadOnly() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFile::isSaveAsAllowed() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-03-19 10:28:05 +01:00
|
|
|
Core::IFile::ReloadBehavior Qt4PriFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
|
2010-01-20 14:47:08 +01:00
|
|
|
{
|
2010-03-19 10:28:05 +01:00
|
|
|
Q_UNUSED(state)
|
|
|
|
Q_UNUSED(type)
|
|
|
|
return BehaviorSilent;
|
2010-01-20 14:47:08 +01:00
|
|
|
}
|
|
|
|
|
2010-03-19 10:28:05 +01:00
|
|
|
void Qt4PriFile::reload(ReloadFlag flag, ChangeType type)
|
|
|
|
{
|
|
|
|
Q_UNUSED(flag)
|
|
|
|
Q_UNUSED(type)
|
|
|
|
if (type == TypePermissions)
|
|
|
|
return;
|
|
|
|
m_priFile->scheduleUpdate();
|
|
|
|
}
|
2010-01-20 14:47:08 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
\class Qt4PriFileNode
|
|
|
|
Implements abstract ProjectNode class
|
|
|
|
*/
|
|
|
|
|
2008-12-05 14:29:18 +01:00
|
|
|
Qt4PriFileNode::Qt4PriFileNode(Qt4Project *project, Qt4ProFileNode* qt4ProFileNode, const QString &filePath)
|
2008-12-02 12:01:29 +01:00
|
|
|
: ProjectNode(filePath),
|
|
|
|
m_project(project),
|
2008-12-05 14:29:18 +01:00
|
|
|
m_qt4ProFileNode(qt4ProFileNode),
|
2008-12-04 11:10:56 +01:00
|
|
|
m_projectFilePath(QDir::fromNativeSeparators(filePath)),
|
2010-01-20 14:47:08 +01:00
|
|
|
m_projectDir(QFileInfo(filePath).absolutePath())
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2008-12-17 15:51:48 +01:00
|
|
|
Q_ASSERT(project);
|
2010-01-22 16:49:57 +01:00
|
|
|
m_qt4PriFile = new Qt4PriFile(this);
|
|
|
|
Core::ICore::instance()->fileManager()->addFile(m_qt4PriFile);
|
2010-01-20 14:47:08 +01:00
|
|
|
|
2010-02-24 15:03:54 +01:00
|
|
|
setDisplayName(QFileInfo(filePath).completeBaseName());
|
2009-01-27 12:40:49 +01:00
|
|
|
|
2010-02-12 12:40:32 +01:00
|
|
|
setIcon(qt4NodeStaticData()->projectIcon);
|
2008-12-09 17:17:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4PriFileNode::scheduleUpdate()
|
|
|
|
{
|
2009-12-07 22:58:47 +01:00
|
|
|
ProFileCacheManager::instance()->discardFile(m_projectFilePath);
|
2008-12-09 17:17:12 +01:00
|
|
|
m_qt4ProFileNode->scheduleUpdate();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-02-12 12:40:32 +01:00
|
|
|
struct InternalNode
|
2010-02-26 12:55:17 +01:00
|
|
|
{
|
|
|
|
QMap<QString, InternalNode*> subnodes;
|
|
|
|
QStringList files;
|
|
|
|
ProjectExplorer::FileType type;
|
|
|
|
QString fullPath;
|
|
|
|
QIcon icon;
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
InternalNode()
|
|
|
|
{
|
|
|
|
type = ProjectExplorer::UnknownFileType;
|
|
|
|
}
|
2009-08-25 15:39:31 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
~InternalNode()
|
|
|
|
{
|
|
|
|
qDeleteAll(subnodes);
|
|
|
|
}
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
// Creates a tree structure from a list of absolute file paths.
|
|
|
|
// Empty directories are compressed into a single entry with a longer path.
|
|
|
|
// * project
|
|
|
|
// * /absolute/path
|
|
|
|
// * file1
|
|
|
|
// * relative
|
|
|
|
// * path1
|
|
|
|
// * file1
|
|
|
|
// * file2
|
|
|
|
// * path2
|
|
|
|
// * file1
|
|
|
|
// The method first creates a tree that looks like the directory structure, i.e.
|
|
|
|
// * /
|
|
|
|
// * absolute
|
|
|
|
// * path
|
|
|
|
// ...
|
|
|
|
// and afterwards calls compress() which merges directory nodes with single children, i.e. to
|
|
|
|
// * /absolute/path
|
|
|
|
void create(const QString &projectDir, const QStringList &newFilePaths, ProjectExplorer::FileType type)
|
|
|
|
{
|
|
|
|
static const QChar separator = QChar('/');
|
|
|
|
const QString projectDirWithSeparator = projectDir + separator;
|
|
|
|
int projectDirWithSeparatorLength = projectDirWithSeparator.length();
|
|
|
|
foreach (const QString &file, newFilePaths) {
|
|
|
|
QString fileWithoutPrefix;
|
|
|
|
bool isRelative;
|
|
|
|
if (file.startsWith(projectDirWithSeparator)) {
|
|
|
|
isRelative = true;
|
|
|
|
fileWithoutPrefix = file.mid(projectDirWithSeparatorLength);
|
|
|
|
} else {
|
|
|
|
isRelative = false;
|
|
|
|
fileWithoutPrefix = file;
|
|
|
|
}
|
|
|
|
QStringList parts = fileWithoutPrefix.split(separator, QString::SkipEmptyParts);
|
2010-02-24 15:03:54 +01:00
|
|
|
#ifndef Q_OS_WIN
|
2010-02-26 12:55:17 +01:00
|
|
|
if (!isRelative && parts.count() > 0)
|
|
|
|
parts[0].prepend(separator);
|
2010-02-24 15:03:54 +01:00
|
|
|
#endif
|
2010-02-26 12:55:17 +01:00
|
|
|
QStringListIterator it(parts);
|
|
|
|
InternalNode *currentNode = this;
|
|
|
|
QString path = (isRelative ? projectDir : "");
|
|
|
|
while (it.hasNext()) {
|
|
|
|
const QString &key = it.next();
|
|
|
|
if (it.hasNext()) { // key is directory
|
|
|
|
path += key;
|
|
|
|
if (!currentNode->subnodes.contains(key)) {
|
|
|
|
InternalNode *val = new InternalNode;
|
|
|
|
val->type = type;
|
|
|
|
val->fullPath = path;
|
|
|
|
currentNode->subnodes.insert(key, val);
|
|
|
|
currentNode = val;
|
|
|
|
} else {
|
|
|
|
currentNode = currentNode->subnodes.value(key);
|
2009-08-17 17:59:57 +02:00
|
|
|
}
|
2010-02-26 12:55:17 +01:00
|
|
|
path += separator;
|
|
|
|
} else { // key is filename
|
|
|
|
currentNode->files.append(file);
|
2009-08-17 17:59:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-02-26 12:55:17 +01:00
|
|
|
this->compress();
|
|
|
|
}
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
// Removes folder nodes with only a single sub folder in it
|
|
|
|
void compress()
|
|
|
|
{
|
|
|
|
static const QChar separator = QDir::separator(); // it is used for the *keys* which will become display name
|
|
|
|
QMap<QString, InternalNode*> newSubnodes;
|
|
|
|
QMapIterator<QString, InternalNode*> i(subnodes);
|
|
|
|
while (i.hasNext()) {
|
|
|
|
i.next();
|
|
|
|
i.value()->compress();
|
|
|
|
if (i.value()->files.isEmpty() && i.value()->subnodes.size() == 1) {
|
|
|
|
QString key = i.value()->subnodes.begin().key();
|
|
|
|
newSubnodes.insert(i.key()+separator+key, i.value()->subnodes.value(key));
|
|
|
|
i.value()->subnodes.clear();
|
|
|
|
delete i.value();
|
|
|
|
} else {
|
|
|
|
newSubnodes.insert(i.key(), i.value());
|
2009-08-17 17:59:57 +02:00
|
|
|
}
|
|
|
|
}
|
2010-02-26 12:55:17 +01:00
|
|
|
subnodes = newSubnodes;
|
|
|
|
}
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
// Makes the projectNode's subtree below the given folder match this internal node's subtree
|
|
|
|
void updateSubFolders(Qt4PriFileNode *projectNode, ProjectExplorer::FolderNode *folder)
|
|
|
|
{
|
|
|
|
updateFiles(projectNode, folder, type);
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
// update folders
|
|
|
|
QList<FolderNode *> existingFolderNodes;
|
|
|
|
foreach (FolderNode *node, folder->subFolderNodes()) {
|
|
|
|
if (node->nodeType() != ProjectNodeType)
|
|
|
|
existingFolderNodes << node;
|
|
|
|
}
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
QList<FolderNode *> foldersToRemove;
|
|
|
|
QList<FolderNode *> foldersToAdd;
|
|
|
|
typedef QPair<InternalNode *, FolderNode *> NodePair;
|
|
|
|
QList<NodePair> nodesToUpdate;
|
|
|
|
|
|
|
|
// newFolders is already sorted
|
|
|
|
qSort(existingFolderNodes.begin(), existingFolderNodes.end(), ProjectNode::sortFolderNodesByName);
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
QList<FolderNode*>::const_iterator existingNodeIter = existingFolderNodes.constBegin();
|
|
|
|
QMap<QString, InternalNode*>::const_iterator newNodeIter = subnodes.constBegin();;
|
|
|
|
while (existingNodeIter != existingFolderNodes.constEnd()
|
|
|
|
&& newNodeIter != subnodes.constEnd()) {
|
|
|
|
if ((*existingNodeIter)->displayName() < newNodeIter.key()) {
|
2009-08-17 17:59:57 +02:00
|
|
|
foldersToRemove << *existingNodeIter;
|
|
|
|
++existingNodeIter;
|
2010-02-26 12:55:17 +01:00
|
|
|
} else if ((*existingNodeIter)->displayName() > newNodeIter.key()) {
|
2010-02-24 15:48:52 +01:00
|
|
|
FolderNode *newNode = new FolderNode(newNodeIter.value()->fullPath);
|
2010-02-24 15:03:54 +01:00
|
|
|
newNode->setDisplayName(newNodeIter.key());
|
2009-08-17 17:59:57 +02:00
|
|
|
if (!newNodeIter.value()->icon.isNull())
|
|
|
|
newNode->setIcon(newNodeIter.value()->icon);
|
|
|
|
foldersToAdd << newNode;
|
2009-12-04 15:57:28 +01:00
|
|
|
nodesToUpdate << NodePair(newNodeIter.value(), newNode);
|
2009-08-17 17:59:57 +02:00
|
|
|
++newNodeIter;
|
2010-02-26 12:55:17 +01:00
|
|
|
} else { // *existingNodeIter->path() == *newPathIter
|
|
|
|
nodesToUpdate << NodePair(newNodeIter.value(), *existingNodeIter);
|
|
|
|
++existingNodeIter;
|
|
|
|
++newNodeIter;
|
2009-08-17 17:59:57 +02:00
|
|
|
}
|
2010-02-26 12:55:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
while (existingNodeIter != existingFolderNodes.constEnd()) {
|
|
|
|
foldersToRemove << *existingNodeIter;
|
|
|
|
++existingNodeIter;
|
|
|
|
}
|
|
|
|
while (newNodeIter != subnodes.constEnd()) {
|
|
|
|
FolderNode *newNode = new FolderNode(newNodeIter.value()->fullPath);
|
|
|
|
newNode->setDisplayName(newNodeIter.key());
|
|
|
|
if (!newNodeIter.value()->icon.isNull())
|
|
|
|
newNode->setIcon(newNodeIter.value()->icon);
|
|
|
|
foldersToAdd << newNode;
|
|
|
|
nodesToUpdate << NodePair(newNodeIter.value(), newNode);
|
|
|
|
++newNodeIter;
|
|
|
|
}
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
if (!foldersToRemove.isEmpty())
|
|
|
|
projectNode->removeFolderNodes(foldersToRemove, folder);
|
|
|
|
if (!foldersToAdd.isEmpty())
|
|
|
|
projectNode->addFolderNodes(foldersToAdd, folder);
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
foreach (const NodePair &np, nodesToUpdate)
|
|
|
|
np.first->updateSubFolders(projectNode, np.second);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Makes the folder's files match this internal node's file list
|
|
|
|
void updateFiles(Qt4PriFileNode *projectNode, FolderNode *folder, FileType type)
|
|
|
|
{
|
|
|
|
QList<FileNode*> existingFileNodes;
|
|
|
|
foreach (FileNode *fileNode, folder->fileNodes()) {
|
|
|
|
if (fileNode->fileType() == type && !fileNode->isGenerated())
|
|
|
|
existingFileNodes << fileNode;
|
2009-08-17 17:59:57 +02:00
|
|
|
}
|
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
QList<FileNode*> filesToRemove;
|
|
|
|
QList<FileNode*> filesToAdd;
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
qSort(files);
|
|
|
|
qSort(existingFileNodes.begin(), existingFileNodes.end(), ProjectNode::sortNodesByPath);
|
|
|
|
|
|
|
|
QList<FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin();
|
|
|
|
QList<QString>::const_iterator newPathIter = files.constBegin();
|
|
|
|
while (existingNodeIter != existingFileNodes.constEnd()
|
|
|
|
&& newPathIter != files.constEnd()) {
|
|
|
|
if ((*existingNodeIter)->path() < *newPathIter) {
|
2009-08-17 17:59:57 +02:00
|
|
|
filesToRemove << *existingNodeIter;
|
|
|
|
++existingNodeIter;
|
2010-02-26 12:55:17 +01:00
|
|
|
} else if ((*existingNodeIter)->path() > *newPathIter) {
|
2009-08-17 17:59:57 +02:00
|
|
|
filesToAdd << new FileNode(*newPathIter, type, false);
|
|
|
|
++newPathIter;
|
2010-02-26 12:55:17 +01:00
|
|
|
} else { // *existingNodeIter->path() == *newPathIter
|
|
|
|
++existingNodeIter;
|
|
|
|
++newPathIter;
|
2009-08-17 17:59:57 +02:00
|
|
|
}
|
|
|
|
}
|
2010-02-26 12:55:17 +01:00
|
|
|
while (existingNodeIter != existingFileNodes.constEnd()) {
|
|
|
|
filesToRemove << *existingNodeIter;
|
|
|
|
++existingNodeIter;
|
|
|
|
}
|
|
|
|
while (newPathIter != files.constEnd()) {
|
|
|
|
filesToAdd << new FileNode(*newPathIter, type, false);
|
|
|
|
++newPathIter;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!filesToRemove.isEmpty())
|
|
|
|
projectNode->removeFileNodes(filesToRemove, folder);
|
|
|
|
if (!filesToAdd.isEmpty())
|
|
|
|
projectNode->addFileNodes(filesToAdd, folder);
|
|
|
|
}
|
|
|
|
};
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
|
|
|
|
QStringList Qt4PriFileNode::baseVPaths(ProFileReader *reader, const QString &projectDir)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-03-10 16:55:37 +01:00
|
|
|
QStringList result;
|
|
|
|
if (!reader)
|
|
|
|
return result;
|
|
|
|
result += reader->absolutePathValues("VPATH", projectDir);
|
|
|
|
result << projectDir; // QMAKE_ABSOLUTE_SOURCE_PATH
|
|
|
|
result += reader->absolutePathValues("DEPENDPATH", projectDir);
|
|
|
|
result.removeDuplicates();
|
|
|
|
return result;
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
QStringList Qt4PriFileNode::fullVPaths(const QStringList &baseVPaths, ProFileReader *reader, FileType type, const QString &qmakeVariable, const QString &projectDir)
|
|
|
|
{
|
|
|
|
QStringList vPaths;
|
|
|
|
if (!reader)
|
|
|
|
return vPaths;
|
|
|
|
if (type == ProjectExplorer::SourceType)
|
|
|
|
vPaths = reader->absolutePathValues("VPATH_" + qmakeVariable, projectDir);
|
|
|
|
vPaths += baseVPaths;
|
|
|
|
if (type == ProjectExplorer::HeaderType)
|
|
|
|
vPaths += reader->absolutePathValues("INCLUDEPATH", projectDir);
|
|
|
|
vPaths.removeDuplicates();
|
|
|
|
return vPaths;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Qt4PriFileNode::update(ProFile *includeFileExact, ProFileReader *readerExact, ProFile *includeFileCumlative, ProFileReader *readerCumulative)
|
|
|
|
{
|
2008-12-02 12:01:29 +01:00
|
|
|
// add project file node
|
|
|
|
if (m_fileNodes.isEmpty())
|
|
|
|
addFileNodes(QList<FileNode*>() << new FileNode(m_projectFilePath, ProjectFileType, false), this);
|
|
|
|
|
2009-07-10 13:37:02 +02:00
|
|
|
const QString &projectDir = m_qt4ProFileNode->m_projectDir;
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
QStringList baseVPathsExact = baseVPaths(readerExact, projectDir);
|
|
|
|
QStringList baseVPathsCumulative = baseVPaths(readerCumulative, projectDir);
|
2009-07-10 13:37:02 +02:00
|
|
|
|
2010-02-12 12:40:32 +01:00
|
|
|
const QVector<Qt4NodeStaticData::FileTypeData> &fileTypes = qt4NodeStaticData()->fileTypeData;
|
|
|
|
|
2009-08-17 17:59:57 +02:00
|
|
|
InternalNode contents;
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
// update files
|
2009-08-17 17:59:57 +02:00
|
|
|
for (int i = 0; i < fileTypes.size(); ++i) {
|
2010-02-12 12:40:32 +01:00
|
|
|
FileType type = fileTypes.at(i).type;
|
2008-12-02 12:01:29 +01:00
|
|
|
const QStringList qmakeVariables = varNames(type);
|
|
|
|
|
|
|
|
QStringList newFilePaths;
|
2009-07-10 13:37:02 +02:00
|
|
|
foreach (const QString &qmakeVariable, qmakeVariables) {
|
2010-03-10 16:55:37 +01:00
|
|
|
QStringList vPathsExact = fullVPaths(baseVPathsExact, readerExact, type, qmakeVariable, projectDir);
|
|
|
|
QStringList vPathsCumulative = fullVPaths(baseVPathsCumulative, readerCumulative, type, qmakeVariable, projectDir);
|
|
|
|
|
|
|
|
|
|
|
|
newFilePaths += readerExact->absoluteFileValues(qmakeVariable, projectDir, vPathsExact, includeFileExact);
|
|
|
|
if (readerCumulative)
|
|
|
|
newFilePaths += readerCumulative->absoluteFileValues(qmakeVariable, projectDir, vPathsCumulative, includeFileCumlative);
|
|
|
|
|
2009-07-10 13:37:02 +02:00
|
|
|
}
|
|
|
|
newFilePaths.removeDuplicates();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-08-17 17:59:57 +02:00
|
|
|
if (!newFilePaths.isEmpty()) {
|
|
|
|
InternalNode *subfolder = new InternalNode;
|
|
|
|
subfolder->type = type;
|
2010-02-12 12:40:32 +01:00
|
|
|
subfolder->icon = fileTypes.at(i).icon;
|
2010-03-15 13:27:23 +01:00
|
|
|
subfolder->fullPath = m_projectDir + "/#" + fileTypes.at(i).typeName;
|
2010-02-12 12:40:32 +01:00
|
|
|
contents.subnodes.insert(fileTypes.at(i).typeName, subfolder);
|
2009-08-17 17:59:57 +02:00
|
|
|
// create the hierarchy with subdirectories
|
|
|
|
subfolder->create(m_projectDir, newFilePaths, type);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
2009-08-17 17:59:57 +02:00
|
|
|
contents.updateSubFolders(this, this);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions() const
|
|
|
|
{
|
|
|
|
QList<ProjectAction> actions;
|
2008-12-05 14:29:18 +01:00
|
|
|
|
|
|
|
const FolderNode *folderNode = this;
|
|
|
|
const Qt4ProFileNode *proFileNode;
|
|
|
|
while (!(proFileNode = qobject_cast<const Qt4ProFileNode*>(folderNode)))
|
|
|
|
folderNode = folderNode->parentFolderNode();
|
2008-12-17 15:51:48 +01:00
|
|
|
Q_ASSERT(proFileNode);
|
2008-12-05 14:29:18 +01:00
|
|
|
|
|
|
|
switch (proFileNode->projectType()) {
|
|
|
|
case ApplicationTemplate:
|
|
|
|
case LibraryTemplate:
|
|
|
|
actions << AddFile << RemoveFile;
|
|
|
|
break;
|
|
|
|
case SubDirsTemplate:
|
|
|
|
actions << AddSubProject << RemoveSubProject;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
return actions;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFileNode::addSubProjects(const QStringList &proFilePaths)
|
|
|
|
{
|
2009-07-13 17:35:17 +02:00
|
|
|
Q_UNUSED(proFilePaths)
|
2008-12-05 14:29:18 +01:00
|
|
|
return false; //changeIncludes(m_includeFile, proFilePaths, AddToProFile);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFileNode::removeSubProjects(const QStringList &proFilePaths)
|
|
|
|
{
|
2009-07-13 17:35:17 +02:00
|
|
|
Q_UNUSED(proFilePaths)
|
2008-12-05 14:29:18 +01:00
|
|
|
return false; //changeIncludes(m_includeFile, proFilePaths, RemoveFromProFile);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFileNode::addFiles(const FileType fileType, const QStringList &filePaths,
|
|
|
|
QStringList *notAdded)
|
|
|
|
{
|
|
|
|
QStringList failedFiles;
|
|
|
|
|
|
|
|
changeFiles(fileType, filePaths, &failedFiles, AddToProFile);
|
|
|
|
if (notAdded)
|
|
|
|
*notAdded = failedFiles;
|
|
|
|
return failedFiles.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFileNode::removeFiles(const FileType fileType, const QStringList &filePaths,
|
|
|
|
QStringList *notRemoved)
|
|
|
|
{
|
|
|
|
QStringList failedFiles;
|
|
|
|
changeFiles(fileType, filePaths, &failedFiles, RemoveFromProFile);
|
|
|
|
if (notRemoved)
|
|
|
|
*notRemoved = failedFiles;
|
|
|
|
return failedFiles.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFileNode::renameFile(const FileType fileType, const QString &filePath,
|
|
|
|
const QString &newFilePath)
|
|
|
|
{
|
2008-12-05 14:29:18 +01:00
|
|
|
if (newFilePath.isEmpty())
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!QFile::rename(filePath, newFilePath))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QStringList dummy;
|
|
|
|
changeFiles(fileType, QStringList() << filePath, &dummy, RemoveFromProFile);
|
|
|
|
if (!dummy.isEmpty())
|
|
|
|
return false;
|
|
|
|
changeFiles(fileType, QStringList() << newFilePath, &dummy, AddToProFile);
|
|
|
|
if (!dummy.isEmpty())
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFileNode::changeIncludes(ProFile *includeFile, const QStringList &proFilePaths,
|
|
|
|
ChangeType change)
|
|
|
|
{
|
2009-07-13 17:35:17 +02:00
|
|
|
Q_UNUSED(includeFile)
|
|
|
|
Q_UNUSED(proFilePaths)
|
|
|
|
Q_UNUSED(change)
|
2008-12-02 12:01:29 +01:00
|
|
|
// TODO
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFileNode::priFileWritable(const QString &path)
|
|
|
|
{
|
|
|
|
const QString dir = QFileInfo(path).dir().path();
|
2009-01-20 11:52:04 +01:00
|
|
|
Core::ICore *core = Core::ICore::instance();
|
2008-12-05 14:29:18 +01:00
|
|
|
Core::IVersionControl *versionControl = core->vcsManager()->findVersionControlForDirectory(dir);
|
|
|
|
switch (Core::EditorManager::promptReadOnlyFile(path, versionControl, core->mainWindow(), false)) {
|
2008-12-03 15:04:51 +01:00
|
|
|
case Core::EditorManager::RO_OpenVCS:
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!versionControl->vcsOpen(path)) {
|
2008-12-05 14:29:18 +01:00
|
|
|
QMessageBox::warning(core->mainWindow(), tr("Failed!"), tr("Could not open the file for edit with SCC."));
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
2008-12-03 15:04:51 +01:00
|
|
|
case Core::EditorManager::RO_MakeWriteable: {
|
2008-12-02 12:01:29 +01:00
|
|
|
const bool permsOk = QFile::setPermissions(path, QFile::permissions(path) | QFile::WriteUser);
|
|
|
|
if (!permsOk) {
|
2008-12-05 14:29:18 +01:00
|
|
|
QMessageBox::warning(core->mainWindow(), tr("Failed!"), tr("Could not set permissions to writable."));
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2008-12-03 15:04:51 +01:00
|
|
|
case Core::EditorManager::RO_SaveAs:
|
|
|
|
case Core::EditorManager::RO_Cancel:
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
bool Qt4PriFileNode::saveModifiedEditors()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
QList<Core::IFile*> modifiedFileHandles;
|
|
|
|
|
2009-01-20 11:52:04 +01:00
|
|
|
Core::ICore *core = Core::ICore::instance();
|
2008-12-05 14:29:18 +01:00
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
foreach (Core::IEditor *editor, core->editorManager()->editorsForFileName(m_projectFilePath)) {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (Core::IFile *editorFile = editor->file()) {
|
|
|
|
if (editorFile->isModified())
|
|
|
|
modifiedFileHandles << editorFile;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!modifiedFileHandles.isEmpty()) {
|
|
|
|
bool cancelled;
|
2008-12-05 14:29:18 +01:00
|
|
|
core->fileManager()->saveModifiedFiles(modifiedFileHandles, &cancelled,
|
2010-01-22 16:49:57 +01:00
|
|
|
tr("There are unsaved changes for project file %1.").arg(m_projectFilePath));
|
2008-12-02 12:01:29 +01:00
|
|
|
if (cancelled)
|
|
|
|
return false;
|
2010-01-22 16:49:57 +01:00
|
|
|
// force instant reload of ourselves
|
|
|
|
ProFileCacheManager::instance()->discardFile(m_projectFilePath);
|
|
|
|
m_project->qt4ProjectManager()->notifyChanged(m_projectFilePath);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4PriFileNode::changeFiles(const FileType fileType,
|
|
|
|
const QStringList &filePaths,
|
|
|
|
QStringList *notChanged,
|
|
|
|
ChangeType change)
|
|
|
|
{
|
|
|
|
if (filePaths.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2010-01-14 21:39:31 +01:00
|
|
|
*notChanged = filePaths;
|
|
|
|
|
|
|
|
// Check for modified editors
|
2010-01-22 16:49:57 +01:00
|
|
|
if (!saveModifiedEditors())
|
2010-01-14 21:39:31 +01:00
|
|
|
return;
|
|
|
|
|
2010-01-14 22:58:55 +01:00
|
|
|
QStringList lines;
|
|
|
|
ProFile *includeFile;
|
|
|
|
{
|
|
|
|
QString contents;
|
|
|
|
{
|
|
|
|
QFile qfile(m_projectFilePath);
|
|
|
|
if (qfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
|
|
contents = QString::fromLatin1(qfile.readAll()); // yes, really latin1
|
|
|
|
qfile.close();
|
|
|
|
lines = contents.split(QLatin1Char('\n'));
|
2010-02-24 16:23:40 +01:00
|
|
|
while (!lines.isEmpty() && lines.last().isEmpty())
|
2010-01-14 22:58:55 +01:00
|
|
|
lines.removeLast();
|
|
|
|
} else {
|
|
|
|
m_project->proFileParseError(tr("Error while reading PRO file %1: %2")
|
|
|
|
.arg(m_projectFilePath, qfile.errorString()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ProFileReader *reader = m_project->createProFileReader(m_qt4ProFileNode);
|
|
|
|
includeFile = reader->parsedProFile(m_projectFilePath, contents);
|
|
|
|
m_project->destroyProFileReader(reader);
|
2008-12-05 14:29:18 +01:00
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
const QStringList vars = varNames(fileType);
|
2010-01-15 21:52:44 +01:00
|
|
|
QDir priFileDir = QDir(m_qt4ProFileNode->m_projectDir);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
if (change == AddToProFile) {
|
2010-01-14 22:58:55 +01:00
|
|
|
ProWriter::addFiles(includeFile, &lines, priFileDir, filePaths, vars);
|
|
|
|
notChanged->clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
} else { // RemoveFromProFile
|
2010-01-14 22:58:55 +01:00
|
|
|
*notChanged = ProWriter::removeFiles(includeFile, &lines, priFileDir, filePaths, vars);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// save file
|
2010-01-14 22:58:55 +01:00
|
|
|
save(lines);
|
2010-01-14 21:51:34 +01:00
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
// This is a hack
|
|
|
|
// We are savign twice in a very short timeframe, once the editor and once the ProFile
|
|
|
|
// So the modification time might not change between those two saves
|
|
|
|
// We manually tell each editor to reload it's file
|
|
|
|
// (The .pro files are notified by the file system watcher)
|
|
|
|
foreach (Core::IEditor *editor, Core::ICore::instance()->editorManager()->editorsForFileName(m_projectFilePath)) {
|
|
|
|
if (Core::IFile *editorFile = editor->file()) {
|
2010-03-19 10:28:05 +01:00
|
|
|
editorFile->reload(Core::IFile::FlagReload, Core::IFile::TypeContents);
|
2010-01-22 16:49:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-14 21:51:34 +01:00
|
|
|
includeFile->deref();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2010-01-14 22:58:55 +01:00
|
|
|
void Qt4PriFileNode::save(const QStringList &lines)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-01-14 22:58:55 +01:00
|
|
|
QFile qfile(m_projectFilePath);
|
|
|
|
if (qfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
|
|
foreach (const QString &str, lines) {
|
|
|
|
qfile.write(str.toLatin1()); // yes, really latin1
|
|
|
|
qfile.write("\n");
|
|
|
|
}
|
|
|
|
qfile.close();
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-01-22 16:49:57 +01:00
|
|
|
m_project->qt4ProjectManager()->notifyChanged(m_projectFilePath);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Deletes all subprojects/files/virtual folders
|
|
|
|
*/
|
|
|
|
void Qt4PriFileNode::clear()
|
|
|
|
{
|
|
|
|
// delete files && folders && projects
|
2009-12-04 16:32:49 +01:00
|
|
|
removeFileNodes(fileNodes(), this);
|
|
|
|
removeProjectNodes(subProjectNodes());
|
|
|
|
removeFolderNodes(subFolderNodes(), this);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QStringList Qt4PriFileNode::varNames(FileType type)
|
|
|
|
{
|
|
|
|
QStringList vars;
|
|
|
|
switch (type) {
|
|
|
|
case ProjectExplorer::HeaderType:
|
|
|
|
vars << QLatin1String("HEADERS");
|
2009-11-24 19:13:37 +01:00
|
|
|
vars << QLatin1String("OBJECTIVE_HEADERS");
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
case ProjectExplorer::SourceType:
|
|
|
|
vars << QLatin1String("SOURCES");
|
|
|
|
vars << QLatin1String("OBJECTIVE_SOURCES");
|
2009-06-16 14:41:25 +02:00
|
|
|
vars << QLatin1String("LEXSOURCES");
|
|
|
|
vars << QLatin1String("YACCSOURCES");
|
2008-12-02 12:01:29 +01:00
|
|
|
break;
|
|
|
|
case ProjectExplorer::ResourceType:
|
|
|
|
vars << QLatin1String("RESOURCES");
|
|
|
|
break;
|
|
|
|
case ProjectExplorer::FormType:
|
|
|
|
vars << QLatin1String("FORMS");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
vars << QLatin1String("OTHER_FILES");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return vars;
|
|
|
|
}
|
|
|
|
|
2009-12-04 19:22:12 +01:00
|
|
|
Qt4ProFileNode *Qt4ProFileNode::findProFileFor(const QString &fileName)
|
2009-04-28 14:30:17 +02:00
|
|
|
{
|
|
|
|
if (fileName == path())
|
|
|
|
return this;
|
|
|
|
foreach (ProjectNode *pn, subProjectNodes())
|
2009-12-04 19:22:12 +01:00
|
|
|
if (Qt4ProFileNode *qt4ProFileNode = qobject_cast<Qt4ProFileNode *>(pn))
|
|
|
|
if (Qt4ProFileNode *result = qt4ProFileNode->findProFileFor(fileName))
|
2009-04-28 14:30:17 +02:00
|
|
|
return result;
|
|
|
|
return 0;
|
|
|
|
}
|
2009-01-14 17:13:17 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
TargetInformation Qt4ProFileNode::targetInformation(const QString &fileName)
|
|
|
|
{
|
|
|
|
TargetInformation result;
|
|
|
|
Qt4ProFileNode *qt4ProFileNode = findProFileFor(fileName);
|
|
|
|
if (!qt4ProFileNode)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
return qt4ProFileNode->targetInformation();
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
\class Qt4ProFileNode
|
|
|
|
Implements abstract ProjectNode class
|
|
|
|
*/
|
|
|
|
Qt4ProFileNode::Qt4ProFileNode(Qt4Project *project,
|
|
|
|
const QString &filePath,
|
|
|
|
QObject *parent)
|
2008-12-05 14:29:18 +01:00
|
|
|
: Qt4PriFileNode(project, this, filePath),
|
2010-03-10 16:55:37 +01:00
|
|
|
m_projectType(InvalidProject),
|
|
|
|
m_readerExact(0),
|
|
|
|
m_readerCumulative(0)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-03-10 16:55:37 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
if (parent)
|
|
|
|
setParent(parent);
|
|
|
|
|
2009-01-14 17:13:17 +01:00
|
|
|
connect(ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager(), SIGNAL(buildStateChanged(ProjectExplorer::Project*)),
|
|
|
|
this, SLOT(buildStateChanged(ProjectExplorer::Project*)));
|
2010-03-10 16:55:37 +01:00
|
|
|
|
|
|
|
connect(&m_parseFutureWatcher, SIGNAL(finished()),
|
|
|
|
this, SLOT(applyAsyncEvaluate()));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2008-12-02 18:14:06 +01:00
|
|
|
Qt4ProFileNode::~Qt4ProFileNode()
|
|
|
|
{
|
2009-05-12 14:12:20 +02:00
|
|
|
CppTools::CppModelManagerInterface *modelManager
|
|
|
|
= ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
|
|
|
|
QMap<QString, Qt4UiCodeModelSupport *>::const_iterator it, end;
|
|
|
|
end = m_uiCodeModelSupport.constEnd();
|
|
|
|
for (it = m_uiCodeModelSupport.constBegin(); it != end; ++it) {
|
|
|
|
modelManager->removeEditorSupport(it.value());
|
|
|
|
delete it.value();
|
|
|
|
}
|
2010-03-10 16:55:37 +01:00
|
|
|
m_parseFutureWatcher.waitForFinished();
|
2010-03-11 17:01:06 +01:00
|
|
|
if (m_readerExact) {
|
|
|
|
// Oh we need to clean up
|
|
|
|
applyEvaluate(true, true);
|
|
|
|
m_project->decrementPendingEvaluateFutures();
|
|
|
|
}
|
2010-03-10 16:55:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4ProFileNode::isParent(Qt4ProFileNode *node)
|
|
|
|
{
|
2010-03-12 14:58:42 +01:00
|
|
|
while ((node = qobject_cast<Qt4ProFileNode *>(node->parentFolderNode()))) {
|
2010-03-10 16:55:37 +01:00
|
|
|
if (node == this)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2008-12-02 18:14:06 +01:00
|
|
|
}
|
|
|
|
|
2009-01-14 17:13:17 +01:00
|
|
|
void Qt4ProFileNode::buildStateChanged(ProjectExplorer::Project *project)
|
|
|
|
{
|
2009-05-12 14:12:20 +02:00
|
|
|
if (project == m_project && !ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager()->isBuilding(m_project)) {
|
|
|
|
QStringList filesToUpdate = updateUiFiles();
|
|
|
|
updateCodeModelSupportFromBuild(filesToUpdate);
|
|
|
|
}
|
2009-01-14 17:13:17 +01:00
|
|
|
}
|
|
|
|
|
2010-02-02 11:59:24 +01:00
|
|
|
bool Qt4ProFileNode::hasBuildTargets() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
return (projectType() == ApplicationTemplate) || (projectType() == LibraryTemplate);
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt4ProjectType Qt4ProFileNode::projectType() const
|
|
|
|
{
|
|
|
|
return m_projectType;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList Qt4ProFileNode::variableValue(const Qt4Variable var) const
|
|
|
|
{
|
|
|
|
return m_varValues.value(var);
|
|
|
|
}
|
|
|
|
|
2008-12-09 17:17:12 +01:00
|
|
|
void Qt4ProFileNode::scheduleUpdate()
|
|
|
|
{
|
2010-03-10 16:55:37 +01:00
|
|
|
m_project->scheduleAsyncUpdate(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4ProFileNode::asyncUpdate()
|
|
|
|
{
|
|
|
|
m_project->incrementPendingEvaluateFutures();
|
|
|
|
setupReader();
|
|
|
|
QFuture<bool> future = QtConcurrent::run(&Qt4ProFileNode::asyncEvaluate, this);
|
|
|
|
m_parseFutureWatcher.setFuture(future);
|
2008-12-09 17:17:12 +01:00
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void Qt4ProFileNode::update()
|
|
|
|
{
|
2010-03-10 16:55:37 +01:00
|
|
|
setupReader();
|
|
|
|
bool parserError = evaluate();
|
|
|
|
applyEvaluate(!parserError, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4ProFileNode::setupReader()
|
|
|
|
{
|
|
|
|
Q_ASSERT(!m_readerExact);
|
|
|
|
Q_ASSERT(!m_readerCumulative);
|
|
|
|
|
|
|
|
m_readerExact = m_project->createProFileReader(this);
|
|
|
|
m_readerExact->setCumulative(false);
|
|
|
|
|
|
|
|
m_readerCumulative = m_project->createProFileReader(this);
|
|
|
|
|
|
|
|
// Find out what flags we pass on to qmake
|
|
|
|
QStringList addedUserConfigArguments;
|
|
|
|
QStringList removedUserConfigArguments;
|
|
|
|
m_project->activeTarget()->activeBuildConfiguration()->getConfigCommandLineArguments(&addedUserConfigArguments, &removedUserConfigArguments);
|
|
|
|
|
|
|
|
m_readerExact->setConfigCommandLineArguments(addedUserConfigArguments, removedUserConfigArguments);
|
|
|
|
m_readerCumulative->setConfigCommandLineArguments(addedUserConfigArguments, removedUserConfigArguments);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4ProFileNode::evaluate()
|
|
|
|
{
|
|
|
|
bool parserError = false;
|
|
|
|
if (!m_readerExact->readProFile(m_projectFilePath)) {
|
2008-12-02 12:01:29 +01:00
|
|
|
m_project->proFileParseError(tr("Error while parsing file %1. Giving up.").arg(m_projectFilePath));
|
2010-03-10 16:55:37 +01:00
|
|
|
parserError = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_readerCumulative->readProFile(m_projectFilePath)) {
|
|
|
|
m_project->proFileParseError(tr("Error while parsing file %1. Giving up.").arg(m_projectFilePath));
|
|
|
|
parserError = true;
|
|
|
|
}
|
|
|
|
return parserError;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4ProFileNode::asyncEvaluate(QFutureInterface<bool> &fi)
|
|
|
|
{
|
|
|
|
bool parserError = evaluate();
|
|
|
|
fi.reportResult(!parserError);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4ProFileNode::applyAsyncEvaluate()
|
|
|
|
{
|
|
|
|
applyEvaluate(m_parseFutureWatcher.result(), true);
|
|
|
|
m_project->decrementPendingEvaluateFutures();
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt4ProjectType proFileTemplateTypeToProjectType(ProFileEvaluator::TemplateType type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case ProFileEvaluator::TT_Unknown:
|
|
|
|
case ProFileEvaluator::TT_Application:
|
|
|
|
return ApplicationTemplate;
|
|
|
|
case ProFileEvaluator::TT_Library:
|
|
|
|
return LibraryTemplate;
|
|
|
|
case ProFileEvaluator::TT_Script:
|
|
|
|
return ScriptTemplate;
|
|
|
|
case ProFileEvaluator::TT_Subdirs:
|
|
|
|
return SubDirsTemplate;
|
|
|
|
default:
|
|
|
|
return InvalidProject;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4ProFileNode::applyEvaluate(bool parseResult, bool async)
|
|
|
|
{
|
2010-03-11 17:01:06 +01:00
|
|
|
if (!m_readerExact)
|
|
|
|
return;
|
2010-03-10 16:55:37 +01:00
|
|
|
if (!parseResult || m_project->wasEvaluateCanceled()) {
|
2010-03-11 17:01:06 +01:00
|
|
|
m_project->destroyProFileReader(m_readerExact);
|
2010-03-10 16:55:37 +01:00
|
|
|
if (m_readerCumulative)
|
|
|
|
m_project->destroyProFileReader(m_readerCumulative);
|
|
|
|
m_readerExact = m_readerCumulative = 0;
|
|
|
|
if (!parseResult) // Invalidate
|
|
|
|
invalidate();
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
qDebug() << "Qt4ProFileNode - updating files for file " << m_projectFilePath;
|
|
|
|
|
|
|
|
Qt4ProjectType projectType = InvalidProject;
|
2010-03-10 16:55:37 +01:00
|
|
|
// Check that both are the same if we have both
|
|
|
|
if (m_readerExact->templateType() != m_readerCumulative->templateType()) {
|
|
|
|
// Now what. The only thing which could be reasonable is that someone
|
|
|
|
// changes between template app and library.
|
|
|
|
// Well, we are conservative here for now.
|
|
|
|
// Let's wait until someone complains and look at what they are doing.
|
|
|
|
m_project->destroyProFileReader(m_readerCumulative);
|
|
|
|
m_readerCumulative = 0;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-03-10 16:55:37 +01:00
|
|
|
|
|
|
|
projectType = proFileTemplateTypeToProjectType(m_readerExact->templateType());
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
if (projectType != m_projectType) {
|
|
|
|
Qt4ProjectType oldType = m_projectType;
|
|
|
|
// probably all subfiles/projects have changed anyway ...
|
|
|
|
clear();
|
|
|
|
m_projectType = projectType;
|
2010-03-10 16:55:37 +01:00
|
|
|
// really emit here? or at the end? Noone is connected to this signal at the moment
|
|
|
|
// so we kind of can ignore that question for now
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (NodesWatcher *watcher, watchers())
|
|
|
|
if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher))
|
|
|
|
emit qt4Watcher->projectTypeChanged(this, oldType, projectType);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Add/Remove pri files, sub projects
|
|
|
|
//
|
|
|
|
|
|
|
|
QList<ProjectNode*> existingProjectNodes = subProjectNodes();
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
QStringList newProjectFilesExact;
|
|
|
|
QHash<QString, ProFile*> includeFilesExact;
|
|
|
|
ProFile *fileForCurrentProjectExact = 0;
|
|
|
|
if (m_projectType == SubDirsTemplate)
|
|
|
|
newProjectFilesExact = subDirsPaths(m_readerExact);
|
|
|
|
foreach (ProFile *includeFile, m_readerExact->includeFiles()) {
|
|
|
|
if (includeFile->fileName() == m_projectFilePath) { // this file
|
|
|
|
fileForCurrentProjectExact = includeFile;
|
|
|
|
} else {
|
|
|
|
newProjectFilesExact << includeFile->fileName();
|
|
|
|
includeFilesExact.insert(includeFile->fileName(), includeFile);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-03-10 16:55:37 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
|
|
|
|
QStringList newProjectFilesCumlative;
|
|
|
|
QHash<QString, ProFile*> includeFilesCumlative;
|
|
|
|
ProFile *fileForCurrentProjectCumlative = 0;
|
|
|
|
if (m_readerCumulative) {
|
|
|
|
if (m_projectType == SubDirsTemplate)
|
|
|
|
newProjectFilesCumlative = subDirsPaths(m_readerCumulative);
|
|
|
|
foreach (ProFile *includeFile, m_readerCumulative->includeFiles()) {
|
|
|
|
if (includeFile->fileName() == m_projectFilePath) {
|
|
|
|
fileForCurrentProjectCumlative = includeFile;
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2010-03-10 16:55:37 +01:00
|
|
|
newProjectFilesCumlative << includeFile->fileName();
|
|
|
|
includeFilesCumlative.insert(includeFile->fileName(), includeFile);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qSort(existingProjectNodes.begin(), existingProjectNodes.end(),
|
|
|
|
sortNodesByPath);
|
2010-03-10 16:55:37 +01:00
|
|
|
qSort(newProjectFilesExact);
|
|
|
|
qSort(newProjectFilesCumlative);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
QList<ProjectNode*> toAdd;
|
|
|
|
QList<ProjectNode*> toRemove;
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
QList<ProjectNode*>::const_iterator existingIt = existingProjectNodes.constBegin();
|
|
|
|
QStringList::const_iterator newExactIt = newProjectFilesExact.constBegin();
|
|
|
|
QStringList::const_iterator newCumlativeIt = newProjectFilesCumlative.constBegin();
|
|
|
|
|
|
|
|
forever {
|
|
|
|
bool existingAtEnd = (existingIt == existingProjectNodes.constEnd());
|
|
|
|
bool newExactAtEnd = (newExactIt == newProjectFilesExact.constEnd());
|
|
|
|
bool newCumlativeAtEnd = (newCumlativeIt == newProjectFilesCumlative.constEnd());
|
|
|
|
|
|
|
|
if (existingAtEnd && newExactAtEnd && newCumlativeAtEnd)
|
|
|
|
break; // we are done, hurray!
|
|
|
|
|
|
|
|
// So this is one giant loop comparing 3 lists at once and sorting the comparision
|
|
|
|
// into mainly 2 buckets: toAdd and toRemove
|
|
|
|
// We need to distinguish between nodes that came from exact and cumalative
|
|
|
|
// parsing, since the update call is diffrent for them
|
|
|
|
// I believe this code to be correct, be careful in changing it
|
|
|
|
|
|
|
|
QString nodeToAdd;
|
|
|
|
if (! existingAtEnd
|
|
|
|
&& (newExactAtEnd || (*existingIt)->path() < *newExactIt)
|
|
|
|
&& (newCumlativeAtEnd || (*existingIt)->path() < *newCumlativeIt)) {
|
|
|
|
// Remove case
|
|
|
|
toRemove << *existingIt;
|
|
|
|
++existingIt;
|
|
|
|
} else if(! newExactAtEnd
|
|
|
|
&& (existingAtEnd || *newExactIt < (*existingIt)->path())
|
|
|
|
&& (newCumlativeAtEnd || *newExactIt < *newCumlativeIt)) {
|
|
|
|
// Mark node from exact for adding
|
|
|
|
nodeToAdd = *newExactIt;
|
|
|
|
++newExactIt;
|
|
|
|
} else if (! newCumlativeAtEnd
|
|
|
|
&& (existingAtEnd || *newCumlativeIt < (*existingIt)->path())
|
|
|
|
&& (newExactAtEnd || *newCumlativeIt < *newExactIt)) {
|
|
|
|
// Mark node from cumalative for adding
|
|
|
|
nodeToAdd = *newCumlativeIt;
|
|
|
|
++newCumlativeIt;
|
|
|
|
} else if (!newExactAtEnd
|
|
|
|
&& !newCumlativeAtEnd
|
|
|
|
&& (existingAtEnd || *newExactIt < (*existingIt)->path())
|
|
|
|
&& (existingAtEnd || *newCumlativeIt < (*existingIt)->path())) {
|
|
|
|
// Mark node from both for adding
|
|
|
|
nodeToAdd = *newExactIt;
|
|
|
|
++newExactIt;
|
|
|
|
++newCumlativeIt;
|
|
|
|
} else {
|
|
|
|
Q_ASSERT(!newExactAtEnd || !newCumlativeAtEnd);
|
|
|
|
// update case, figure out which case exactly
|
|
|
|
if (newExactAtEnd) {
|
|
|
|
++newCumlativeIt;
|
|
|
|
} else if (newCumlativeAtEnd) {
|
|
|
|
++newExactIt;
|
|
|
|
} else if(*newExactIt < *newCumlativeIt) {
|
|
|
|
++newExactIt;
|
|
|
|
} else if (*newCumlativeIt < *newExactIt) {
|
|
|
|
++newCumlativeIt;
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2010-03-10 16:55:37 +01:00
|
|
|
++newExactIt;
|
|
|
|
++newCumlativeIt;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-03-10 16:55:37 +01:00
|
|
|
// Update existingNodeIte
|
|
|
|
ProFile *fileExact = includeFilesCumlative.value((*existingIt)->path());
|
|
|
|
ProFile *fileCumlative = includeFilesCumlative.value((*existingIt)->path());
|
|
|
|
if (fileExact || fileCumlative) {
|
|
|
|
static_cast<Qt4PriFileNode *>(*existingIt)->update(fileExact, m_readerExact, fileCumlative, m_readerCumulative);
|
|
|
|
} else {
|
|
|
|
// We always parse exactly, because we later when async parsing don't know whether
|
|
|
|
// the .pro file is included in this .pro file
|
|
|
|
// So to compare that later parse with the sync one
|
|
|
|
if (async)
|
|
|
|
static_cast<Qt4ProFileNode *>(*existingIt)->asyncUpdate();
|
|
|
|
else
|
|
|
|
static_cast<Qt4ProFileNode *>(*existingIt)->update();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-03-10 16:55:37 +01:00
|
|
|
++existingIt;
|
|
|
|
// newCumalativeIt and newExactIt are already incremented
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
}
|
2010-03-10 16:55:37 +01:00
|
|
|
// If we found something to add do it
|
|
|
|
if (!nodeToAdd.isEmpty()) {
|
|
|
|
ProFile *fileExact = includeFilesCumlative.value(nodeToAdd);
|
|
|
|
ProFile *fileCumlative = includeFilesCumlative.value(nodeToAdd);
|
|
|
|
if (fileExact || fileCumlative) {
|
|
|
|
Qt4PriFileNode *qt4PriFileNode = new Qt4PriFileNode(m_project, this, nodeToAdd);
|
|
|
|
qt4PriFileNode->update(fileExact, m_readerExact, fileCumlative, m_readerCumulative);
|
|
|
|
toAdd << qt4PriFileNode;
|
|
|
|
} else {
|
|
|
|
Qt4ProFileNode *qt4ProFileNode = new Qt4ProFileNode(m_project, nodeToAdd);
|
|
|
|
if (async)
|
|
|
|
qt4ProFileNode->asyncUpdate();
|
|
|
|
else
|
|
|
|
qt4ProFileNode->update();
|
|
|
|
toAdd << qt4ProFileNode;
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2010-03-10 16:55:37 +01:00
|
|
|
} // for
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
if (!toRemove.isEmpty())
|
|
|
|
removeProjectNodes(toRemove);
|
|
|
|
if (!toAdd.isEmpty())
|
|
|
|
addProjectNodes(toAdd);
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
Qt4PriFileNode::update(fileForCurrentProjectExact, m_readerExact, fileForCurrentProjectCumlative, m_readerCumulative);
|
|
|
|
|
|
|
|
// update TargetInformation
|
|
|
|
m_qt4targetInformation = targetInformation(m_readerExact);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
// update other variables
|
|
|
|
QHash<Qt4Variable, QStringList> newVarValues;
|
2009-02-26 17:19:46 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
newVarValues[DefinesVar] = m_readerExact->values(QLatin1String("DEFINES"));
|
|
|
|
newVarValues[IncludePathVar] = includePaths(m_readerExact);
|
|
|
|
newVarValues[UiDirVar] = uiDirPaths(m_readerExact);
|
|
|
|
newVarValues[MocDirVar] = mocDirPaths(m_readerExact);
|
|
|
|
newVarValues[PkgConfigVar] = m_readerExact->values(QLatin1String("PKGCONFIG"));
|
2010-01-12 13:13:22 +01:00
|
|
|
newVarValues[PrecompiledHeaderVar] =
|
2010-03-10 16:55:37 +01:00
|
|
|
m_readerExact->absoluteFileValues(QLatin1String("PRECOMPILED_HEADER"),
|
|
|
|
m_projectDir,
|
|
|
|
QStringList() << m_projectDir,
|
|
|
|
0);
|
2010-03-29 15:17:04 +02:00
|
|
|
newVarValues[LibDirectoriesVar] = libDirectories(m_readerExact);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
if (m_varValues != newVarValues) {
|
|
|
|
m_varValues = newVarValues;
|
|
|
|
foreach (NodesWatcher *watcher, watchers())
|
|
|
|
if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher))
|
|
|
|
emit qt4Watcher->variablesChanged(this, m_varValues, newVarValues);
|
|
|
|
}
|
|
|
|
|
2009-05-12 14:12:20 +02:00
|
|
|
createUiCodeModelSupport();
|
2009-04-03 17:45:18 +02:00
|
|
|
updateUiFiles();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
foreach (NodesWatcher *watcher, watchers())
|
|
|
|
if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher))
|
|
|
|
emit qt4Watcher->proFileUpdated(this);
|
2008-12-05 14:29:18 +01:00
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
m_project->destroyProFileReader(m_readerExact);
|
|
|
|
if (m_readerCumulative)
|
|
|
|
m_project->destroyProFileReader(m_readerCumulative);
|
|
|
|
|
|
|
|
m_readerExact = 0;
|
|
|
|
m_readerCumulative = 0;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// find all ui files in project
|
|
|
|
class FindUiFileNodesVisitor : public ProjectExplorer::NodesVisitor {
|
|
|
|
public:
|
|
|
|
void visitProjectNode(ProjectNode *projectNode)
|
|
|
|
{
|
|
|
|
visitFolderNode(projectNode);
|
|
|
|
}
|
|
|
|
void visitFolderNode(FolderNode *folderNode)
|
|
|
|
{
|
|
|
|
foreach (FileNode *fileNode, folderNode->fileNodes()) {
|
|
|
|
if (fileNode->fileType() == ProjectExplorer::FormType)
|
|
|
|
uiFileNodes << fileNode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
QList<FileNode*> uiFileNodes;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2009-01-14 17:13:17 +01:00
|
|
|
// This function is triggered after a build, and updates the state ui files
|
|
|
|
// It does so by storing a modification time for each ui file we know about.
|
|
|
|
|
2009-01-15 12:45:53 +01:00
|
|
|
// TODO this function should also be called if the build directory is changed
|
2009-05-12 14:12:20 +02:00
|
|
|
QStringList Qt4ProFileNode::updateUiFiles()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-05-14 11:26:57 +02:00
|
|
|
// qDebug()<<"Qt4ProFileNode::updateUiFiles()";
|
2009-01-14 17:13:17 +01:00
|
|
|
// Only those two project types can have ui files for us
|
2008-12-02 12:01:29 +01:00
|
|
|
if (m_projectType != ApplicationTemplate
|
|
|
|
&& m_projectType != LibraryTemplate)
|
2009-05-12 14:12:20 +02:00
|
|
|
return QStringList();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-01-14 17:13:17 +01:00
|
|
|
// Find all ui files
|
2008-12-02 12:01:29 +01:00
|
|
|
FindUiFileNodesVisitor uiFilesVisitor;
|
|
|
|
this->accept(&uiFilesVisitor);
|
|
|
|
const QList<FileNode*> uiFiles = uiFilesVisitor.uiFileNodes;
|
|
|
|
|
2009-01-14 17:13:17 +01:00
|
|
|
// Find the UiDir, there can only ever be one
|
2009-04-02 15:40:47 +02:00
|
|
|
QString uiDir = buildDir();
|
2009-01-14 17:13:17 +01:00
|
|
|
QStringList tmp = m_varValues[UiDirVar];
|
|
|
|
if (tmp.size() != 0)
|
|
|
|
uiDir = tmp.first();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-01-14 17:13:17 +01:00
|
|
|
// Collect all existing generated files
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<FileNode*> existingFileNodes;
|
|
|
|
foreach (FileNode *file, fileNodes()) {
|
|
|
|
if (file->isGenerated())
|
|
|
|
existingFileNodes << file;
|
|
|
|
}
|
2008-12-09 17:17:12 +01:00
|
|
|
|
|
|
|
// Convert uiFile to uiHeaderFilePath, find all headers that correspond
|
2009-01-14 17:13:17 +01:00
|
|
|
// and try to find them in uiDir
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList newFilePaths;
|
2009-01-14 17:13:17 +01:00
|
|
|
foreach (FileNode *uiFile, uiFiles) {
|
|
|
|
const QString uiHeaderFilePath
|
2009-03-20 16:13:46 +01:00
|
|
|
= QString("%1/ui_%2.h").arg(uiDir, QFileInfo(uiFile->path()).completeBaseName());
|
2009-01-14 17:13:17 +01:00
|
|
|
if (QFileInfo(uiHeaderFilePath).exists())
|
|
|
|
newFilePaths << uiHeaderFilePath;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2009-01-14 17:13:17 +01:00
|
|
|
// Create a diff between those lists
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<FileNode*> toRemove;
|
|
|
|
QList<FileNode*> toAdd;
|
2009-01-14 17:13:17 +01:00
|
|
|
// The list of files for which we call updateSourceFile
|
|
|
|
QStringList toUpdate;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
qSort(newFilePaths);
|
|
|
|
qSort(existingFileNodes.begin(), existingFileNodes.end(), ProjectNode::sortNodesByPath);
|
|
|
|
|
|
|
|
QList<FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin();
|
|
|
|
QList<QString>::const_iterator newPathIter = newFilePaths.constBegin();
|
|
|
|
while (existingNodeIter != existingFileNodes.constEnd()
|
|
|
|
&& newPathIter != newFilePaths.constEnd()) {
|
|
|
|
if ((*existingNodeIter)->path() < *newPathIter) {
|
|
|
|
toRemove << *existingNodeIter;
|
|
|
|
++existingNodeIter;
|
|
|
|
} else if ((*existingNodeIter)->path() > *newPathIter) {
|
|
|
|
toAdd << new FileNode(*newPathIter, ProjectExplorer::HeaderType, true);
|
|
|
|
++newPathIter;
|
|
|
|
} else { // *existingNodeIter->path() == *newPathIter
|
2009-01-14 17:13:17 +01:00
|
|
|
QString fileName = (*existingNodeIter)->path();
|
|
|
|
QMap<QString, QDateTime>::const_iterator it = m_uitimestamps.find(fileName);
|
|
|
|
QDateTime lastModified = QFileInfo(fileName).lastModified();
|
|
|
|
if (it == m_uitimestamps.constEnd() || it.value() < lastModified) {
|
|
|
|
toUpdate << fileName;
|
|
|
|
m_uitimestamps[fileName] = lastModified;
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
++existingNodeIter;
|
|
|
|
++newPathIter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (existingNodeIter != existingFileNodes.constEnd()) {
|
|
|
|
toRemove << *existingNodeIter;
|
|
|
|
++existingNodeIter;
|
|
|
|
}
|
|
|
|
while (newPathIter != newFilePaths.constEnd()) {
|
|
|
|
toAdd << new FileNode(*newPathIter, ProjectExplorer::HeaderType, true);
|
|
|
|
++newPathIter;
|
|
|
|
}
|
|
|
|
|
2009-01-14 17:13:17 +01:00
|
|
|
// Update project tree
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!toRemove.isEmpty()) {
|
|
|
|
foreach (FileNode *file, toRemove)
|
2009-01-14 17:13:17 +01:00
|
|
|
m_uitimestamps.remove(file->path());
|
2008-12-02 12:01:29 +01:00
|
|
|
removeFileNodes(toRemove, this);
|
|
|
|
}
|
2009-01-14 17:13:17 +01:00
|
|
|
|
|
|
|
CppTools::CppModelManagerInterface *modelManager =
|
|
|
|
ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!toAdd.isEmpty()) {
|
2009-01-14 17:13:17 +01:00
|
|
|
foreach (FileNode *file, toAdd) {
|
|
|
|
m_uitimestamps.insert(file->path(), QFileInfo(file->path()).lastModified());
|
|
|
|
toUpdate << file->path();
|
|
|
|
|
2009-05-12 14:12:20 +02:00
|
|
|
// Also adding files depending on that
|
|
|
|
// We only need to do that for files that were newly created
|
2009-01-14 17:13:17 +01:00
|
|
|
QString fileName = QFileInfo(file->path()).fileName();
|
|
|
|
foreach (CPlusPlus::Document::Ptr doc, modelManager->snapshot()) {
|
|
|
|
if (doc->includedFiles().contains(fileName)) {
|
|
|
|
if (!toUpdate.contains(doc->fileName()))
|
|
|
|
toUpdate << doc->fileName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
addFileNodes(toAdd, this);
|
|
|
|
}
|
2009-05-12 14:12:20 +02:00
|
|
|
return toUpdate;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QStringList Qt4ProFileNode::uiDirPaths(ProFileReader *reader) const
|
|
|
|
{
|
|
|
|
QStringList candidates = reader->absolutePathValues(QLatin1String("UI_DIR"),
|
2009-07-10 13:37:02 +02:00
|
|
|
buildDir());
|
|
|
|
candidates.removeDuplicates();
|
2008-12-02 12:01:29 +01:00
|
|
|
return candidates;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList Qt4ProFileNode::mocDirPaths(ProFileReader *reader) const
|
|
|
|
{
|
|
|
|
QStringList candidates = reader->absolutePathValues(QLatin1String("MOC_DIR"),
|
2009-07-10 13:37:02 +02:00
|
|
|
buildDir());
|
|
|
|
candidates.removeDuplicates();
|
2008-12-02 12:01:29 +01:00
|
|
|
return candidates;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList Qt4ProFileNode::includePaths(ProFileReader *reader) const
|
|
|
|
{
|
|
|
|
QStringList paths;
|
|
|
|
paths = reader->absolutePathValues(QLatin1String("INCLUDEPATH"),
|
2009-07-10 13:37:02 +02:00
|
|
|
m_projectDir);
|
2008-12-02 12:01:29 +01:00
|
|
|
paths << uiDirPaths(reader) << mocDirPaths(reader);
|
|
|
|
paths.removeDuplicates();
|
|
|
|
return paths;
|
|
|
|
}
|
|
|
|
|
2010-03-29 15:17:04 +02:00
|
|
|
QStringList Qt4ProFileNode::libDirectories(ProFileReader *reader) const
|
|
|
|
{
|
|
|
|
QStringList result;
|
|
|
|
foreach (const QString &str, reader->values(QLatin1String("LIBS"))) {
|
|
|
|
if (str.startsWith("-L")) {
|
|
|
|
result.append(str.mid(2));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QStringList Qt4ProFileNode::subDirsPaths(ProFileReader *reader) const
|
|
|
|
{
|
|
|
|
QStringList subProjectPaths;
|
|
|
|
|
|
|
|
const QStringList subDirVars = reader->values(QLatin1String("SUBDIRS"));
|
|
|
|
|
|
|
|
foreach (const QString &subDirVar, subDirVars) {
|
|
|
|
// Special case were subdir is just an identifier:
|
|
|
|
// "SUBDIR = subid
|
|
|
|
// subid.subdir = realdir"
|
2009-03-12 14:57:37 +01:00
|
|
|
// or
|
|
|
|
// "SUBDIR = subid
|
|
|
|
// subid.file = realdir/realfile.pro"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
QString realDir;
|
|
|
|
const QString subDirKey = subDirVar + QLatin1String(".subdir");
|
2009-03-12 14:57:37 +01:00
|
|
|
const QString subDirFileKey = subDirVar + QLatin1String(".file");
|
2008-12-02 12:01:29 +01:00
|
|
|
if (reader->contains(subDirKey))
|
2008-12-03 13:25:19 +01:00
|
|
|
realDir = QFileInfo(reader->value(subDirKey)).filePath();
|
2009-03-12 14:57:37 +01:00
|
|
|
else if (reader->contains(subDirFileKey))
|
|
|
|
realDir = QFileInfo(reader->value(subDirFileKey)).filePath();
|
|
|
|
else
|
2008-12-02 12:01:29 +01:00
|
|
|
realDir = subDirVar;
|
|
|
|
QFileInfo info(realDir);
|
2009-07-27 12:50:42 +02:00
|
|
|
if (!info.isAbsolute()) {
|
2010-02-01 12:43:56 +01:00
|
|
|
info.setFile(m_projectDir + QLatin1Char('/') + realDir);
|
|
|
|
realDir = m_projectDir + QLatin1Char('/') + realDir;
|
2009-07-27 12:50:42 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-07-27 12:50:42 +02:00
|
|
|
QString realFile;
|
|
|
|
if (info.isDir()) {
|
2010-02-01 12:43:56 +01:00
|
|
|
realFile = QString::fromLatin1("%1/%2.pro").arg(realDir, info.fileName());
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
|
|
|
realFile = realDir;
|
|
|
|
}
|
|
|
|
|
2010-01-19 15:59:36 +01:00
|
|
|
if (QFile::exists(realFile)) {
|
|
|
|
if (!subProjectPaths.contains(realFile))
|
|
|
|
subProjectPaths << realFile;
|
|
|
|
} else {
|
|
|
|
m_project->proFileParseError(tr("Could not find .pro file for sub dir '%1' in '%2'")
|
|
|
|
.arg(subDirVar).arg(realDir));
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return subProjectPaths;
|
|
|
|
}
|
|
|
|
|
2010-03-10 16:55:37 +01:00
|
|
|
TargetInformation Qt4ProFileNode::targetInformation(ProFileReader *reader) const
|
|
|
|
{
|
|
|
|
TargetInformation result;
|
|
|
|
if (!reader)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
const QString baseDir = buildDir();
|
|
|
|
// qDebug() << "base build dir is:"<<baseDir;
|
|
|
|
|
|
|
|
// Working Directory
|
|
|
|
if (reader->contains("DESTDIR")) {
|
|
|
|
//qDebug() << "reader contains destdir:" << reader->value("DESTDIR");
|
|
|
|
result.workingDir = reader->value("DESTDIR");
|
|
|
|
if (QDir::isRelativePath(result.workingDir)) {
|
|
|
|
result.workingDir = baseDir + QLatin1Char('/') + result.workingDir;
|
|
|
|
//qDebug() << "was relative and expanded to" << result.workingDir;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//qDebug() << "reader didn't contain DESTDIR, setting to " << baseDir;
|
|
|
|
result.workingDir = baseDir;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.target = reader->value("TARGET");
|
|
|
|
if (result.target.isEmpty())
|
|
|
|
result.target = QFileInfo(m_projectFilePath).baseName();
|
|
|
|
|
|
|
|
#if defined (Q_OS_MAC)
|
|
|
|
if (reader->values("CONFIG").contains("app_bundle")) {
|
|
|
|
result.workingDir += QLatin1Char('/')
|
|
|
|
+ result.target
|
|
|
|
+ QLatin1String(".app/Contents/MacOS");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
result.workingDir = QDir::cleanPath(result.workingDir);
|
|
|
|
|
|
|
|
QString wd = result.workingDir;
|
|
|
|
if (!reader->contains("DESTDIR")
|
|
|
|
&& reader->values("CONFIG").contains("debug_and_release")
|
|
|
|
&& reader->values("CONFIG").contains("debug_and_release_target")) {
|
|
|
|
// If we don't have a destdir and debug and release is set
|
|
|
|
// then the executable is in a debug/release folder
|
|
|
|
//qDebug() << "reader has debug_and_release_target";
|
|
|
|
|
|
|
|
// Hmm can we find out whether it's debug or release in a saner way?
|
|
|
|
// Theoretically it's in CONFIG
|
|
|
|
QString qmakeBuildConfig = "release";
|
|
|
|
if (m_project->activeTarget()->activeBuildConfiguration()->qmakeBuildConfiguration() & QtVersion::DebugBuild)
|
|
|
|
qmakeBuildConfig = "debug";
|
|
|
|
wd += QLatin1Char('/') + qmakeBuildConfig;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.executable = QDir::cleanPath(wd + QLatin1Char('/') + result.target);
|
|
|
|
//qDebug() << "##### updateTarget sets:" << result.workingDir << result.executable;
|
|
|
|
|
|
|
|
#if defined (Q_OS_WIN)
|
|
|
|
result.executable += QLatin1String(".exe");
|
|
|
|
#endif
|
|
|
|
result.valid = true;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
TargetInformation Qt4ProFileNode::targetInformation()
|
|
|
|
{
|
|
|
|
return m_qt4targetInformation;
|
|
|
|
}
|
|
|
|
|
2009-12-04 19:22:12 +01:00
|
|
|
QString Qt4ProFileNode::buildDir() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
const QDir srcDirRoot = QFileInfo(m_project->rootProjectNode()->path()).absoluteDir();
|
|
|
|
const QString relativeDir = srcDirRoot.relativeFilePath(m_projectDir);
|
2010-02-08 15:50:06 +01:00
|
|
|
return QDir(m_project->activeTarget()->activeBuildConfiguration()->buildDirectory()).absoluteFilePath(relativeDir);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Sets project type to InvalidProject & deletes all subprojects/files/virtual folders
|
|
|
|
*/
|
|
|
|
void Qt4ProFileNode::invalidate()
|
|
|
|
{
|
|
|
|
if (m_projectType == InvalidProject)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clear();
|
|
|
|
|
|
|
|
// change project type
|
|
|
|
Qt4ProjectType oldType = m_projectType;
|
|
|
|
m_projectType = InvalidProject;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (NodesWatcher *watcher, watchers())
|
|
|
|
if (Qt4NodesWatcher *qt4Watcher = qobject_cast<Qt4NodesWatcher*>(watcher))
|
|
|
|
emit qt4Watcher->projectTypeChanged(this, oldType, InvalidProject);
|
|
|
|
}
|
|
|
|
|
2009-05-12 14:12:20 +02:00
|
|
|
void Qt4ProFileNode::updateCodeModelSupportFromBuild(const QStringList &files)
|
|
|
|
{
|
|
|
|
foreach (const QString &file, files) {
|
|
|
|
QMap<QString, Qt4UiCodeModelSupport *>::const_iterator it, end;
|
|
|
|
end = m_uiCodeModelSupport.constEnd();
|
|
|
|
for (it = m_uiCodeModelSupport.constBegin(); it != end; ++it) {
|
|
|
|
if (it.value()->fileName() == file)
|
|
|
|
it.value()->updateFromBuild();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-26 14:55:25 +01:00
|
|
|
void Qt4ProFileNode::updateCodeModelSupportFromEditor(const QString &uiFileName,
|
|
|
|
const QString &contents)
|
2009-05-12 14:12:20 +02:00
|
|
|
{
|
2010-02-26 14:55:25 +01:00
|
|
|
const QMap<QString, Qt4UiCodeModelSupport *>::const_iterator it =
|
|
|
|
m_uiCodeModelSupport.constFind(uiFileName);
|
|
|
|
if (it != m_uiCodeModelSupport.constEnd())
|
|
|
|
it.value()->updateFromEditor(contents);
|
2009-05-12 14:12:20 +02:00
|
|
|
foreach (ProjectExplorer::ProjectNode *pro, subProjectNodes())
|
|
|
|
if (Qt4ProFileNode *qt4proFileNode = qobject_cast<Qt4ProFileNode *>(pro))
|
2010-02-26 14:55:25 +01:00
|
|
|
qt4proFileNode->updateCodeModelSupportFromEditor(uiFileName, contents);
|
2009-05-12 14:12:20 +02:00
|
|
|
}
|
|
|
|
|
2009-12-03 16:23:15 +01:00
|
|
|
QString Qt4ProFileNode::uiDirectory() const
|
|
|
|
{
|
|
|
|
const Qt4VariablesHash::const_iterator it = m_varValues.constFind(UiDirVar);
|
|
|
|
if (it != m_varValues.constEnd() && !it.value().isEmpty())
|
|
|
|
return it.value().front();
|
|
|
|
return buildDir();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Qt4ProFileNode::uiHeaderFile(const QString &uiDir, const QString &formFile)
|
|
|
|
{
|
|
|
|
QString uiHeaderFilePath = uiDir;
|
|
|
|
uiHeaderFilePath += QLatin1String("/ui_");
|
|
|
|
uiHeaderFilePath += QFileInfo(formFile).completeBaseName();
|
|
|
|
uiHeaderFilePath += QLatin1String(".h");
|
|
|
|
return QDir::cleanPath(uiHeaderFilePath);
|
|
|
|
}
|
|
|
|
|
2009-05-12 14:12:20 +02:00
|
|
|
void Qt4ProFileNode::createUiCodeModelSupport()
|
|
|
|
{
|
2009-05-14 11:26:57 +02:00
|
|
|
// qDebug()<<"creatUiCodeModelSupport()";
|
2009-05-12 14:12:20 +02:00
|
|
|
CppTools::CppModelManagerInterface *modelManager
|
|
|
|
= ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
|
|
|
|
|
|
|
|
// First move all to
|
|
|
|
QMap<QString, Qt4UiCodeModelSupport *> oldCodeModelSupport;
|
|
|
|
oldCodeModelSupport = m_uiCodeModelSupport;
|
|
|
|
m_uiCodeModelSupport.clear();
|
|
|
|
|
|
|
|
// Only those two project types can have ui files for us
|
|
|
|
if (m_projectType == ApplicationTemplate || m_projectType == LibraryTemplate) {
|
|
|
|
// Find all ui files
|
|
|
|
FindUiFileNodesVisitor uiFilesVisitor;
|
|
|
|
this->accept(&uiFilesVisitor);
|
|
|
|
const QList<FileNode*> uiFiles = uiFilesVisitor.uiFileNodes;
|
|
|
|
|
|
|
|
// Find the UiDir, there can only ever be one
|
2009-12-03 16:23:15 +01:00
|
|
|
const QString uiDir = uiDirectory();
|
|
|
|
foreach (const FileNode *uiFile, uiFiles) {
|
|
|
|
const QString uiHeaderFilePath = uiHeaderFile(uiDir, uiFile->path());
|
2009-05-14 11:26:57 +02:00
|
|
|
// qDebug()<<"code model support for "<<uiFile->path()<<" "<<uiHeaderFilePath;
|
2009-05-12 14:12:20 +02:00
|
|
|
QMap<QString, Qt4UiCodeModelSupport *>::iterator it = oldCodeModelSupport.find(uiFile->path());
|
|
|
|
if (it != oldCodeModelSupport.end()) {
|
2009-05-14 11:26:57 +02:00
|
|
|
// qDebug()<<"updated old codemodelsupport";
|
2009-05-12 14:12:20 +02:00
|
|
|
Qt4UiCodeModelSupport *cms = it.value();
|
|
|
|
cms->setFileName(uiHeaderFilePath);
|
|
|
|
m_uiCodeModelSupport.insert(it.key(), cms);
|
|
|
|
oldCodeModelSupport.erase(it);
|
|
|
|
} else {
|
2009-05-14 11:26:57 +02:00
|
|
|
// qDebug()<<"adding new codemodelsupport";
|
2009-05-12 14:12:20 +02:00
|
|
|
Qt4UiCodeModelSupport *cms = new Qt4UiCodeModelSupport(modelManager, m_project, uiFile->path(), uiHeaderFilePath);
|
|
|
|
m_uiCodeModelSupport.insert(uiFile->path(), cms);
|
|
|
|
modelManager->addEditorSupport(cms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Remove old
|
|
|
|
QMap<QString, Qt4UiCodeModelSupport *>::const_iterator it, end;
|
|
|
|
end = oldCodeModelSupport.constEnd();
|
|
|
|
for (it = oldCodeModelSupport.constBegin(); it!=end; ++it) {
|
|
|
|
modelManager->removeEditorSupport(it.value());
|
|
|
|
delete it.value();
|
|
|
|
}
|
|
|
|
}
|
2008-12-02 18:14:06 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
Qt4NodesWatcher::Qt4NodesWatcher(QObject *parent)
|
|
|
|
: NodesWatcher(parent)
|
|
|
|
{
|
|
|
|
}
|
2010-02-12 12:40:32 +01:00
|
|
|
|
2010-02-26 12:55:17 +01:00
|
|
|
} // namespace Internal
|
|
|
|
} // namespace Qt4ProjectManager
|