Newer
Older
/**************************************************************************
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
** 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.
** 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.
** If you are unsure which license is appropriate for your use, please
**************************************************************************/
#include "qt4nodes.h"
#include "qt4project.h"
#include "qt4projectmanager.h"
#include "qt4projectmanagerconstants.h"
#include "qt4buildconfiguration.h"
#include <projectexplorer/nodesvisitor.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/filemanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/buildmanager.h>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QTimer>
#include <QtGui/QMainWindow>
#include <QtGui/QMessageBox>
#include <QtGui/QPushButton>
using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;
namespace {
bool debug = false;
}
namespace {
// sorting helper function
bool sortProjectFilesByPath(ProFile *f1, ProFile *f2)
{
return f1->fileName() < f2->fileName();
}
}
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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
{
return QString::null;
}
QString Qt4PriFile::suggestedFileName() const
{
return QString::null;
}
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;
}
void Qt4PriFile::modified(Core::IFile::ReloadBehavior *behavior)
{
Q_UNUSED(behavior);
m_priFile->scheduleUpdate();
}
/*!
\class Qt4PriFileNode
Implements abstract ProjectNode class
*/
Qt4PriFileNode::Qt4PriFileNode(Qt4Project *project, Qt4ProFileNode* qt4ProFileNode, const QString &filePath)
m_projectFilePath(QDir::fromNativeSeparators(filePath)),
m_projectDir(QFileInfo(filePath).absolutePath())
Qt4PriFile *qt4PriFile = new Qt4PriFile(this);
Core::ICore::instance()->fileManager()->addFile(qt4PriFile);
setFolderName(QFileInfo(filePath).completeBaseName());
static QIcon dirIcon;
if (dirIcon.isNull()) {
// Create a custom Qt dir icon based on the system icon
Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
QPixmap dirIconPixmap = iconProvider->overlayIcon(QStyle::SP_DirIcon,
QIcon(":/qt4projectmanager/images/qt_project.png"),
QSize(16, 16));
dirIcon.addPixmap(dirIconPixmap);
}
setIcon(dirIcon);
}
void Qt4PriFileNode::scheduleUpdate()
{
ProFileCacheManager::instance()->discardFile(m_projectFilePath);
m_qt4ProFileNode->scheduleUpdate();
namespace Qt4ProjectManager {
namespace Internal {
struct InternalNode
{
QMap<QString, InternalNode*> subnodes;
QStringList files;
ProjectExplorer::FileType type;
QString fullName;
QIcon icon;
InternalNode()
{
type = ProjectExplorer::UnknownFileType;
}
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
~InternalNode()
{
qDeleteAll(subnodes);
}
// 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
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);
if (!isRelative && parts.count() > 0)
parts[0].prepend(separator);
QStringListIterator it(parts);
InternalNode *currentNode = this;
QString path = (isRelative ? projectDir : "");
while (it.hasNext()) {
const QString &key = it.next();
path += separator + key;
if (it.hasNext()) { // key is directory
if (!currentNode->subnodes.contains(key)) {
InternalNode *val = new InternalNode;
val->type = type;
val->fullName = path;
currentNode->subnodes.insert(key, val);
currentNode = val;
} else {
currentNode = currentNode->subnodes.value(key);
}
} else { // key is filename
currentNode->files.append(file);
}
}
}
this->compress();
}
// Removes folder nodes with only a single sub folder in it
void compress()
{
static const QChar separator = QChar('/');
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());
}
}
subnodes = newSubnodes;
}
// 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);
// update folders
QList<FolderNode *> existingFolderNodes;
foreach (FolderNode *node, folder->subFolderNodes()) {
if (node->nodeType() != ProjectNodeType)
existingFolderNodes << node;
}
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);
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()) {
foldersToRemove << *existingNodeIter;
++existingNodeIter;
} else if ((*existingNodeIter)->displayName() > newNodeIter.key()) {
FolderNode *newNode = new FolderNode(newNodeIter.value()->fullName);
newNode->setFolderName(newNodeIter.key());
if (!newNodeIter.value()->icon.isNull())
newNode->setIcon(newNodeIter.value()->icon);
foldersToAdd << newNode;
nodesToUpdate << NodePair(newNodeIter.value(), newNode);
++newNodeIter;
} else { // *existingNodeIter->path() == *newPathIter
nodesToUpdate << NodePair(newNodeIter.value(), *existingNodeIter);
++existingNodeIter;
++newNodeIter;
}
}
while (existingNodeIter != existingFolderNodes.constEnd()) {
foldersToRemove << *existingNodeIter;
++existingNodeIter;
}
while (newNodeIter != subnodes.constEnd()) {
FolderNode *newNode = new FolderNode(newNodeIter.value()->fullName);
newNode->setFolderName(newNodeIter.key());
if (!newNodeIter.value()->icon.isNull())
newNode->setIcon(newNodeIter.value()->icon);
foldersToAdd << newNode;
nodesToUpdate << NodePair(newNodeIter.value(), newNode);
++newNodeIter;
}
if (!foldersToRemove.isEmpty())
projectNode->removeFolderNodes(foldersToRemove, folder);
if (!foldersToAdd.isEmpty())
projectNode->addFolderNodes(foldersToAdd, folder);
foreach (const NodePair &np, nodesToUpdate)
np.first->updateSubFolders(projectNode, np.second);
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
}
// 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;
}
QList<FileNode*> filesToRemove;
QList<FileNode*> filesToAdd;
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) {
filesToRemove << *existingNodeIter;
++existingNodeIter;
} else if ((*existingNodeIter)->path() > *newPathIter) {
filesToAdd << new FileNode(*newPathIter, type, false);
++newPathIter;
} else { // *existingNodeIter->path() == *newPathIter
++existingNodeIter;
++newPathIter;
}
}
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);
}
};
} // Internal namespace
} // namespace
void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
{
Q_ASSERT(includeFile);
Q_ASSERT(reader);
// add project file node
if (m_fileNodes.isEmpty())
addFileNodes(QList<FileNode*>() << new FileNode(m_projectFilePath, ProjectFileType, false), this);
static QList<FileType> fileTypes =
(QList<FileType>() << ProjectExplorer::HeaderType
<< ProjectExplorer::SourceType
<< ProjectExplorer::FormType
<< ProjectExplorer::ResourceType
<< ProjectExplorer::UnknownFileType);
static QStringList fileTypeNames =
QStringList() << tr("Headers")
<< tr("Sources")
<< tr("Forms")
<< tr("Resources")
<< tr("Other files");
static QList<QIcon> fileTypeIcons;
if (fileTypeIcons.isEmpty()) {
QStringList iconPaths;
iconPaths << ":/qt4projectmanager/images/headers.png"
<< ":/qt4projectmanager/images/sources.png"
<< ":/qt4projectmanager/images/forms.png"
<< ":/qt4projectmanager/images/qt_qrc.png"
<< ":/qt4projectmanager/images/unknown.png";
foreach (const QString &iconPath, iconPaths) {
QIcon dirIcon;
Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
QPixmap dirIconPixmap = iconProvider->overlayIcon(QStyle::SP_DirIcon,
QIcon(iconPath),
QSize(16, 16));
dirIcon.addPixmap(dirIconPixmap);
fileTypeIcons.append(dirIcon);
}
}
const QString &projectDir = m_qt4ProFileNode->m_projectDir;
QStringList baseVPaths;
baseVPaths += reader->absolutePathValues("VPATH", projectDir);
baseVPaths << projectDir; // QMAKE_ABSOLUTE_SOURCE_PATH
baseVPaths += reader->absolutePathValues("DEPENDPATH", projectDir);
baseVPaths.removeDuplicates();
InternalNode contents;
for (int i = 0; i < fileTypes.size(); ++i) {
FileType type = fileTypes.at(i);
const QStringList qmakeVariables = varNames(type);
QStringList newFilePaths;
foreach (const QString &qmakeVariable, qmakeVariables) {
QStringList vPaths;
if (type == ProjectExplorer::SourceType)
vPaths = reader->absolutePathValues("VPATH_" + qmakeVariable, projectDir);
vPaths += baseVPaths;
if (type == ProjectExplorer::HeaderType)
vPaths += reader->absolutePathValues("INCLUDEPATH", projectDir);
vPaths.removeDuplicates();
newFilePaths += reader->absoluteFileValues(qmakeVariable, projectDir, vPaths, includeFile);
}
newFilePaths.removeDuplicates();
if (!newFilePaths.isEmpty()) {
InternalNode *subfolder = new InternalNode;
subfolder->type = type;
subfolder->icon = fileTypeIcons.at(i);
subfolder->fullName = m_projectDir + '#' + fileTypeNames.at(i);
contents.subnodes.insert(fileTypeNames.at(i), subfolder);
// create the hierarchy with subdirectories
subfolder->create(m_projectDir, newFilePaths, type);
contents.updateSubFolders(this, this);
}
QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions() const
{
QList<ProjectAction> actions;
const FolderNode *folderNode = this;
const Qt4ProFileNode *proFileNode;
while (!(proFileNode = qobject_cast<const Qt4ProFileNode*>(folderNode)))
folderNode = folderNode->parentFolderNode();
switch (proFileNode->projectType()) {
case ApplicationTemplate:
case LibraryTemplate:
actions << AddFile << RemoveFile;
break;
case SubDirsTemplate:
actions << AddSubProject << RemoveSubProject;
break;
default:
break;
}
return actions;
}
bool Qt4PriFileNode::addSubProjects(const QStringList &proFilePaths)
{
Q_UNUSED(proFilePaths)
return false; //changeIncludes(m_includeFile, proFilePaths, AddToProFile);
}
bool Qt4PriFileNode::removeSubProjects(const QStringList &proFilePaths)
{
Q_UNUSED(proFilePaths)
return false; //changeIncludes(m_includeFile, proFilePaths, RemoveFromProFile);
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
}
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)
{
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)
{
Q_UNUSED(includeFile)
Q_UNUSED(proFilePaths)
Q_UNUSED(change)
// TODO
return false;
}
bool Qt4PriFileNode::priFileWritable(const QString &path)
{
const QString dir = QFileInfo(path).dir().path();
Core::ICore *core = Core::ICore::instance();
Core::IVersionControl *versionControl = core->vcsManager()->findVersionControlForDirectory(dir);
switch (Core::EditorManager::promptReadOnlyFile(path, versionControl, core->mainWindow(), false)) {
case Core::EditorManager::RO_OpenVCS:
QMessageBox::warning(core->mainWindow(), tr("Failed!"), tr("Could not open the file for edit with SCC."));
case Core::EditorManager::RO_MakeWriteable: {
const bool permsOk = QFile::setPermissions(path, QFile::permissions(path) | QFile::WriteUser);
if (!permsOk) {
QMessageBox::warning(core->mainWindow(), tr("Failed!"), tr("Could not set permissions to writable."));
case Core::EditorManager::RO_SaveAs:
case Core::EditorManager::RO_Cancel:
return false;
}
return true;
}
bool Qt4PriFileNode::saveModifiedEditors(const QString &path)
{
QList<Core::IFile*> allFileHandles;
QList<Core::IFile*> modifiedFileHandles;
Core::ICore *core = Core::ICore::instance();
foreach (Core::IFile *file, core->fileManager()->managedFiles(path)) {
foreach (Core::IEditor *editor, core->editorManager()->editorsForFileName(path)) {
if (Core::IFile *editorFile = editor->file()) {
if (editorFile->isModified())
modifiedFileHandles << editorFile;
}
}
if (!modifiedFileHandles.isEmpty()) {
bool cancelled;
core->fileManager()->saveModifiedFiles(modifiedFileHandles, &cancelled,
tr("There are unsaved changes for project file %1.").arg(path));
if (cancelled)
return false;
// force instant reload
foreach (Core::IFile *fileHandle, allFileHandles) {
Core::IFile::ReloadBehavior reload = Core::IFile::ReloadAll;
fileHandle->modified(&reload);
}
}
return true;
}
static void findProVariables(ProBlock *block, const QStringList &vars,
QList<ProVariable *> *proVars)
{
foreach (ProItem *item, block->items()) {
if (item->kind() == ProItem::BlockKind) {
ProBlock *subBlock = static_cast<ProBlock *>(item);
if (subBlock->blockKind() == ProBlock::VariableKind) {
ProVariable *proVar = static_cast<ProVariable*>(subBlock);
if (vars.contains(proVar->variable()))
*proVars << proVar;
} else {
findProVariables(subBlock, vars, proVars);
}
}
}
}
void Qt4PriFileNode::changeFiles(const FileType fileType,
const QStringList &filePaths,
QStringList *notChanged,
ChangeType change)
{
if (filePaths.isEmpty())
return;
*notChanged = filePaths;
// Check for modified editors
if (!saveModifiedEditors(m_projectFilePath))
return;
ProFileReader *reader = m_project->createProFileReader(m_qt4ProFileNode);
ProFile *includeFile = reader->parsedProFile(m_projectFilePath);
m_project->destroyProFileReader(reader);
m_project->proFileParseError(tr("Error while changing pro file %1.").arg(m_projectFilePath));
QDir priFileDir = QDir(m_qt4ProFileNode->m_projectDir);
ProVariable *proVar = 0;
foreach (ProItem *item, includeFile->items()) {
if (item->kind() == ProItem::BlockKind) {
ProBlock *block = static_cast<ProBlock *>(item);
if (block->blockKind() == ProBlock::VariableKind) {
proVar = static_cast<ProVariable*>(block);
if (vars.contains(proVar->variable())
&& proVar->variableOperator() != ProVariable::RemoveOperator
&& proVar->variableOperator() != ProVariable::ReplaceOperator)
break;
}
}
if (!proVar) {
// Create & append new variable item
// TODO: This will always store e.g. a source file in SOURCES and not OBJECTIVE_SOURCES
proVar = new ProVariable(vars.first(), includeFile);
includeFile->appendItem(proVar);

Stian Sandvik Thomassen
committed
const QString &proFilePath = includeFile->fileName();

Stian Sandvik Thomassen
committed
if (filePath == proFilePath)
continue;
const QString &relativeFilePath = priFileDir.relativeFilePath(filePath);
proVar->appendItem(new ProValue(relativeFilePath, proVar));
notChanged->removeOne(filePath);
}
} else { // RemoveFromProFile
QList<ProVariable *> proVars;
findProVariables(includeFile, vars, &proVars);
QStringList relativeFilePaths;
foreach (const QString &absoluteFilePath, filePaths)
relativeFilePaths << priFileDir.relativeFilePath(absoluteFilePath);
foreach (ProVariable *proVar, proVars) {
if (proVar->variableOperator() != ProVariable::RemoveOperator
&& proVar->variableOperator() != ProVariable::ReplaceOperator) {
QList<ProItem *> values = proVar->items();
for (int i = values.count(); --i >= 0; ) {
ProItem *item = values.at(i);
if (item->kind() == ProItem::ValueKind) {
ProValue *val = static_cast<ProValue *>(item);
if (relativeFilePaths.contains(val->value())) {
notChanged->removeOne(priFileDir.absoluteFilePath(val->value()));
delete values.takeAt(i);
proVar->setItems(values);
includeFile->deref();
void Qt4PriFileNode::save(ProFile *includeFile)
Core::ICore *core = Core::ICore::instance();
Core::FileManager *fileManager = core->fileManager();
QList<Core::IFile *> allFileHandles = fileManager->managedFiles(includeFile->fileName());
if (file->fileName() == includeFile->fileName())
modifiedFileHandle = file;
if (modifiedFileHandle)
fileManager->blockFileChange(modifiedFileHandle);
ProWriter pw;
const bool ok = pw.write(includeFile, includeFile->fileName());
Q_UNUSED(ok)
m_project->qt4ProjectManager()->notifyChanged(includeFile->fileName());
if (modifiedFileHandle)
fileManager->unblockFileChange(modifiedFileHandle);
Core::IFile::ReloadBehavior tempBehavior =
Core::IFile::ReloadAll;
foreach (Core::IFile *file, allFileHandles)
file->modified(&tempBehavior);
}
/*
Deletes all subprojects/files/virtual folders
*/
void Qt4PriFileNode::clear()
{
// delete files && folders && projects
removeFileNodes(fileNodes(), this);
removeProjectNodes(subProjectNodes());
removeFolderNodes(subFolderNodes(), this);
}
QStringList Qt4PriFileNode::varNames(FileType type)
{
QStringList vars;
switch (type) {
case ProjectExplorer::HeaderType:
vars << QLatin1String("HEADERS");
vars << QLatin1String("OBJECTIVE_HEADERS");
break;
case ProjectExplorer::SourceType:
vars << QLatin1String("SOURCES");
vars << QLatin1String("OBJECTIVE_SOURCES");
vars << QLatin1String("LEXSOURCES");
vars << QLatin1String("YACCSOURCES");
break;
case ProjectExplorer::ResourceType:
vars << QLatin1String("RESOURCES");
break;
case ProjectExplorer::FormType:
vars << QLatin1String("FORMS");
break;
default:
vars << QLatin1String("OTHER_FILES");
break;
}
return vars;
}
Qt4ProFileNode *Qt4ProFileNode::findProFileFor(const QString &fileName)
{
if (fileName == path())
return this;
foreach (ProjectNode *pn, subProjectNodes())
if (Qt4ProFileNode *qt4ProFileNode = qobject_cast<Qt4ProFileNode *>(pn))
if (Qt4ProFileNode *result = qt4ProFileNode->findProFileFor(fileName))
return result;
return 0;
}
/*!
\class Qt4ProFileNode
Implements abstract ProjectNode class
*/
Qt4ProFileNode::Qt4ProFileNode(Qt4Project *project,
const QString &filePath,
QObject *parent)
: Qt4PriFileNode(project, this, filePath),
m_updateTimer.setInterval(100);
m_updateTimer.setSingleShot(true);
connect(&m_updateTimer, SIGNAL(timeout()),
this, SLOT(update()));
connect(ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager(), SIGNAL(buildStateChanged(ProjectExplorer::Project*)),
this, SLOT(buildStateChanged(ProjectExplorer::Project*)));
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();
}
void Qt4ProFileNode::buildStateChanged(ProjectExplorer::Project *project)
{
if (project == m_project && !ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager()->isBuilding(m_project)) {
QStringList filesToUpdate = updateUiFiles();
updateCodeModelSupportFromBuild(filesToUpdate);
}
bool Qt4ProFileNode::hasTargets() const
{
return (projectType() == ApplicationTemplate) || (projectType() == LibraryTemplate);
}
Qt4ProjectType Qt4ProFileNode::projectType() const
{
return m_projectType;
}
QStringList Qt4ProFileNode::variableValue(const Qt4Variable var) const
{
return m_varValues.value(var);
}
void Qt4ProFileNode::scheduleUpdate()
{
m_updateTimer.start();
}
ProFileReader *reader = m_project->createProFileReader(this);
if (!reader->readProFile(m_projectFilePath)) {
m_project->proFileParseError(tr("Error while parsing file %1. Giving up.").arg(m_projectFilePath));
m_project->destroyProFileReader(reader);
invalidate();
return;
}
if (debug)
qDebug() << "Qt4ProFileNode - updating files for file " << m_projectFilePath;
Qt4ProjectType projectType = InvalidProject;
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
case ProFileEvaluator::TT_Unknown:
case ProFileEvaluator::TT_Application: {
projectType = ApplicationTemplate;
break;
}
case ProFileEvaluator::TT_Library: {
projectType = LibraryTemplate;
break;
}
case ProFileEvaluator::TT_Script: {
projectType = ScriptTemplate;
break;
}
case ProFileEvaluator::TT_Subdirs:
projectType = SubDirsTemplate;
break;
}
if (projectType != m_projectType) {
Qt4ProjectType oldType = m_projectType;
// probably all subfiles/projects have changed anyway ...
clear();
m_projectType = projectType;
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();
QList<QString> newProjectFiles;
QHash<QString, ProFile*> includeFiles;
ProFile *fileForCurrentProject = 0;
{
if (projectType == SubDirsTemplate) {
foreach (const QString &subDirProject, subDirsPaths(reader))
foreach (ProFile *includeFile, reader->includeFiles()) {
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
if (includeFile->fileName() == m_projectFilePath) { // this file
fileForCurrentProject = includeFile;
} else {
newProjectFiles << includeFile->fileName();
includeFiles.insert(includeFile->fileName(), includeFile);
}
}
}
qSort(existingProjectNodes.begin(), existingProjectNodes.end(),
sortNodesByPath);
qSort(newProjectFiles.begin(), newProjectFiles.end());
QList<ProjectNode*> toAdd;
QList<ProjectNode*> toRemove;
QList<ProjectNode*>::const_iterator existingNodeIter = existingProjectNodes.constBegin();
QList<QString>::const_iterator newProjectFileIter = newProjectFiles.constBegin();
while (existingNodeIter != existingProjectNodes.constEnd()
&& newProjectFileIter != newProjectFiles.constEnd()) {
if ((*existingNodeIter)->path() < *newProjectFileIter) {
toRemove << *existingNodeIter;
++existingNodeIter;
} else if ((*existingNodeIter)->path() > *newProjectFileIter) {
if (ProFile *file = includeFiles.value(*newProjectFileIter)) {
Qt4PriFileNode *priFileNode
toAdd << priFileNode;
} else {
toAdd << createSubProFileNode(*newProjectFileIter);
}
++newProjectFileIter;
} else { // *existingNodeIter->path() == *newProjectFileIter
if (ProFile *file = includeFiles.value(*newProjectFileIter)) {
Qt4PriFileNode *priFileNode = static_cast<Qt4PriFileNode*>(*existingNodeIter);
}
++existingNodeIter;
++newProjectFileIter;
}
}
while (existingNodeIter != existingProjectNodes.constEnd()) {
toRemove << *existingNodeIter;
++existingNodeIter;
}
while (newProjectFileIter != newProjectFiles.constEnd()) {
if (ProFile *file = includeFiles.value(*newProjectFileIter)) {
Qt4PriFileNode *priFileNode
toAdd << priFileNode;
} else {
toAdd << createSubProFileNode(*newProjectFileIter);
}
++newProjectFileIter;
}
if (!toRemove.isEmpty())
removeProjectNodes(toRemove);
if (!toAdd.isEmpty())
addProjectNodes(toAdd);
Qt4PriFileNode::update(fileForCurrentProject, reader);
// update other variables
QHash<Qt4Variable, QStringList> newVarValues;
newVarValues[DefinesVar] = reader->values(QLatin1String("DEFINES"));
newVarValues[IncludePathVar] = includePaths(reader);
newVarValues[UiDirVar] = uiDirPaths(reader);
newVarValues[MocDirVar] = mocDirPaths(reader);
newVarValues[PkgConfigVar] = reader->values(QLatin1String("PKGCONFIG"));
newVarValues[PrecompiledHeaderVar] =
reader->absoluteFileValues(QLatin1String("PRECOMPILED_HEADER"),
m_projectDir,
QStringList() << m_projectDir,
0);