2009-02-25 09:02:17 +01:00
|
|
|
/**************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
**
|
2009-02-25 09:02:17 +01:00
|
|
|
** Copyright (c) 2009 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 "proeditormodel.h"
|
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"
|
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>
|
2009-03-26 17:36:58 +01:00
|
|
|
#include <projectexplorer/filewatcher.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
#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>
|
|
|
|
#include <QtCore/QTimer>
|
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>
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\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)),
|
2008-12-09 17:17:12 +01:00
|
|
|
m_projectDir(QFileInfo(filePath).absolutePath()),
|
2009-03-26 17:36:58 +01:00
|
|
|
m_fileWatcher(new ProjectExplorer::FileWatcher(this))
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2008-12-17 15:51:48 +01:00
|
|
|
Q_ASSERT(project);
|
2009-03-20 16:13:46 +01:00
|
|
|
setFolderName(QFileInfo(filePath).completeBaseName());
|
2009-01-27 12:40:49 +01:00
|
|
|
|
|
|
|
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);
|
2008-12-09 17:17:12 +01:00
|
|
|
m_fileWatcher->addFile(filePath);
|
|
|
|
connect(m_fileWatcher, SIGNAL(fileChanged(QString)),
|
|
|
|
this, SLOT(scheduleUpdate()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4PriFileNode::scheduleUpdate()
|
|
|
|
{
|
|
|
|
m_qt4ProFileNode->scheduleUpdate();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2009-08-17 17:59:57 +02:00
|
|
|
namespace Qt4ProjectManager {
|
|
|
|
namespace Internal {
|
|
|
|
struct InternalNode
|
|
|
|
{
|
|
|
|
QMap<QString, InternalNode*> subnodes;
|
|
|
|
QStringList files;
|
|
|
|
ProjectExplorer::FileType type;
|
|
|
|
QString fullName;
|
|
|
|
QIcon icon;
|
|
|
|
|
2009-08-25 15:39:31 +02:00
|
|
|
InternalNode()
|
|
|
|
{
|
|
|
|
type = ProjectExplorer::UnknownFileType;
|
|
|
|
}
|
|
|
|
|
2009-08-17 17:59:57 +02:00
|
|
|
~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.keys().at(0);
|
|
|
|
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;
|
2009-12-04 15:57:28 +01:00
|
|
|
typedef QPair<InternalNode *, FolderNode *> NodePair;
|
|
|
|
QList<NodePair> nodesToUpdate;
|
2009-08-17 17:59:57 +02:00
|
|
|
|
|
|
|
// 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)->name() < newNodeIter.key()) {
|
|
|
|
foldersToRemove << *existingNodeIter;
|
|
|
|
++existingNodeIter;
|
|
|
|
} else if ((*existingNodeIter)->name() > 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;
|
2009-12-04 15:57:28 +01:00
|
|
|
nodesToUpdate << NodePair(newNodeIter.value(), newNode);
|
2009-08-17 17:59:57 +02:00
|
|
|
++newNodeIter;
|
|
|
|
} else { // *existingNodeIter->path() == *newPathIter
|
2009-12-04 15:57:28 +01:00
|
|
|
nodesToUpdate << NodePair(newNodeIter.value(), *existingNodeIter);
|
2009-08-17 17:59:57 +02:00
|
|
|
++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;
|
2009-12-04 15:57:28 +01:00
|
|
|
nodesToUpdate << NodePair(newNodeIter.value(), newNode);
|
2009-08-17 17:59:57 +02:00
|
|
|
++newNodeIter;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!foldersToRemove.isEmpty())
|
|
|
|
projectNode->removeFolderNodes(foldersToRemove, folder);
|
|
|
|
if (!foldersToAdd.isEmpty())
|
|
|
|
projectNode->addFolderNodes(foldersToAdd, folder);
|
|
|
|
|
2009-12-04 15:57:28 +01:00
|
|
|
foreach (const NodePair &np, nodesToUpdate)
|
|
|
|
np.first->updateSubFolders(projectNode, np.second);
|
2009-08-17 17:59:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
|
|
|
|
{
|
2008-12-17 15:51:48 +01:00
|
|
|
Q_ASSERT(includeFile);
|
|
|
|
Q_ASSERT(reader);
|
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);
|
|
|
|
|
|
|
|
static QList<FileType> fileTypes =
|
|
|
|
(QList<FileType>() << ProjectExplorer::HeaderType
|
|
|
|
<< ProjectExplorer::SourceType
|
|
|
|
<< ProjectExplorer::FormType
|
|
|
|
<< ProjectExplorer::ResourceType
|
|
|
|
<< ProjectExplorer::UnknownFileType);
|
2009-08-17 17:59:57 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-07-10 13:37:02 +02:00
|
|
|
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();
|
|
|
|
|
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) {
|
|
|
|
FileType type = fileTypes.at(i);
|
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) {
|
|
|
|
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();
|
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;
|
|
|
|
subfolder->icon = fileTypeIcons.at(i);
|
2009-09-22 13:32:21 +02:00
|
|
|
subfolder->fullName = m_projectDir + '#' + fileTypeNames.at(i);
|
2009-08-17 17:59:57 +02:00
|
|
|
contents.subnodes.insert(fileTypeNames.at(i), subfolder);
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Qt4PriFileNode::saveModifiedEditors(const QString &path)
|
|
|
|
{
|
|
|
|
QList<Core::IFile*> allFileHandles;
|
|
|
|
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
|
|
|
|
|
|
|
foreach (Core::IFile *file, core->fileManager()->managedFiles(path)) {
|
2008-12-02 12:01:29 +01:00
|
|
|
allFileHandles << file;
|
|
|
|
}
|
|
|
|
|
2008-12-05 14:29:18 +01:00
|
|
|
foreach (Core::IEditor *editor, core->editorManager()->editorsForFileName(path)) {
|
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,
|
2008-12-02 12:01:29 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Qt4PriFileNode::changeFiles(const FileType fileType,
|
|
|
|
const QStringList &filePaths,
|
|
|
|
QStringList *notChanged,
|
|
|
|
ChangeType change)
|
|
|
|
{
|
|
|
|
if (filePaths.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2008-12-05 14:29:18 +01:00
|
|
|
ProFileReader *reader = m_qt4ProFileNode->createProFileReader();
|
|
|
|
if (!reader->readProFile(m_qt4ProFileNode->path())) {
|
|
|
|
m_project->proFileParseError(tr("Error while parsing file %1. Giving up.").arg(m_projectFilePath));
|
|
|
|
delete reader;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ProFile *includeFile = reader->proFileFor(m_projectFilePath);
|
2008-12-09 11:07:24 +01:00
|
|
|
if (!includeFile) {
|
2008-12-05 14:29:18 +01:00
|
|
|
m_project->proFileParseError(tr("Error while changing pro file %1.").arg(m_projectFilePath));
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
*notChanged = filePaths;
|
|
|
|
|
|
|
|
// Check for modified editors
|
2009-12-04 21:18:30 +01:00
|
|
|
if (!saveModifiedEditors(m_projectFilePath)) {
|
|
|
|
delete reader;
|
2008-12-02 12:01:29 +01:00
|
|
|
return;
|
2009-12-04 21:18:30 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
// Check if file is readonly
|
|
|
|
ProEditorModel proModel;
|
2008-12-05 14:29:18 +01:00
|
|
|
proModel.setProFiles(QList<ProFile*>() << includeFile);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
const QStringList vars = varNames(fileType);
|
|
|
|
QDir priFileDir = QDir(m_projectDir);
|
|
|
|
|
|
|
|
if (change == AddToProFile) {
|
|
|
|
// root item "<Global Scope>"
|
|
|
|
const QModelIndex root = proModel.index(0, 0);
|
|
|
|
|
|
|
|
// Check if variable item exists as child of root item
|
|
|
|
ProVariable *proVar = 0;
|
|
|
|
int row = 0;
|
|
|
|
for (; row < proModel.rowCount(root); ++row) {
|
|
|
|
if ((proVar = proModel.proVariable(root.child(row, 0)))) {
|
|
|
|
if (vars.contains(proVar->variable())
|
|
|
|
&& proVar->variableOperator() != ProVariable::RemoveOperator
|
|
|
|
&& proVar->variableOperator() != ProVariable::ReplaceOperator)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
proVar = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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(), proModel.proBlock(root));
|
|
|
|
proVar->setVariableOperator(ProVariable::AddOperator);
|
|
|
|
proModel.insertItem(proVar, row, root);
|
|
|
|
}
|
|
|
|
const QModelIndex varIndex = root.child(row, 0);
|
|
|
|
|
2009-07-09 14:51:56 +10:00
|
|
|
const QString &proFilePath = includeFile->fileName();
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const QString &filePath, filePaths) {
|
2009-07-09 14:51:56 +10:00
|
|
|
if (filePath == proFilePath)
|
|
|
|
continue;
|
2008-12-02 12:01:29 +01:00
|
|
|
const QString &relativeFilePath = priFileDir.relativeFilePath(filePath);
|
|
|
|
proModel.insertItem(new ProValue(relativeFilePath, proVar),
|
|
|
|
proModel.rowCount(varIndex), varIndex);
|
|
|
|
notChanged->removeOne(filePath);
|
|
|
|
}
|
|
|
|
} else { // RemoveFromProFile
|
|
|
|
QList<QModelIndex> proVarIndexes = proModel.findVariables(vars);
|
|
|
|
QList<QModelIndex> toRemove;
|
|
|
|
|
|
|
|
QStringList relativeFilePaths;
|
|
|
|
foreach (const QString &absoluteFilePath, filePaths)
|
|
|
|
relativeFilePaths << priFileDir.relativeFilePath(absoluteFilePath);
|
|
|
|
|
|
|
|
foreach (const QModelIndex &proVarIndex, proVarIndexes) {
|
|
|
|
ProVariable *proVar = proModel.proVariable(proVarIndex);
|
|
|
|
|
|
|
|
if (proVar->variableOperator() != ProVariable::RemoveOperator
|
|
|
|
&& proVar->variableOperator() != ProVariable::ReplaceOperator) {
|
|
|
|
|
|
|
|
for (int row = proModel.rowCount(proVarIndex) - 1; row >= 0; --row) {
|
|
|
|
QModelIndex itemIndex = proModel.index(row, 0, proVarIndex);
|
|
|
|
ProItem *item = proModel.proItem(itemIndex);
|
|
|
|
|
|
|
|
if (item->kind() == ProItem::ValueKind) {
|
|
|
|
ProValue *val = static_cast<ProValue *>(item);
|
|
|
|
int index = relativeFilePaths.indexOf(val->value());
|
|
|
|
if (index != -1) {
|
|
|
|
toRemove.append(itemIndex);
|
|
|
|
notChanged->removeAt(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (const QModelIndex &index, toRemove) {
|
|
|
|
proModel.removeItem(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// save file
|
2008-12-05 14:29:18 +01:00
|
|
|
save(includeFile);
|
|
|
|
delete reader;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
2008-12-05 14:29:18 +01:00
|
|
|
void Qt4PriFileNode::save(ProFile *includeFile)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-01-20 11:52:04 +01:00
|
|
|
Core::ICore *core = Core::ICore::instance();
|
2008-12-05 14:29:18 +01:00
|
|
|
Core::FileManager *fileManager = core->fileManager();
|
|
|
|
QList<Core::IFile *> allFileHandles = fileManager->managedFiles(includeFile->fileName());
|
2008-12-02 18:14:06 +01:00
|
|
|
Core::IFile *modifiedFileHandle = 0;
|
2008-12-09 11:07:24 +01:00
|
|
|
foreach (Core::IFile *file, allFileHandles)
|
2008-12-05 14:29:18 +01:00
|
|
|
if (file->fileName() == includeFile->fileName())
|
2008-12-02 18:14:06 +01:00
|
|
|
modifiedFileHandle = file;
|
|
|
|
|
|
|
|
if (modifiedFileHandle)
|
|
|
|
fileManager->blockFileChange(modifiedFileHandle);
|
|
|
|
ProWriter pw;
|
2008-12-05 14:29:18 +01:00
|
|
|
const bool ok = pw.write(includeFile, includeFile->fileName());
|
2008-12-03 15:04:51 +01:00
|
|
|
Q_UNUSED(ok)
|
2008-12-05 14:29:18 +01:00
|
|
|
includeFile->setModified(false);
|
|
|
|
m_project->qt4ProjectManager()->notifyChanged(includeFile->fileName());
|
2008-12-02 18:14:06 +01:00
|
|
|
if (modifiedFileHandle)
|
|
|
|
fileManager->unblockFileChange(modifiedFileHandle);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
Core::IFile::ReloadBehavior tempBehavior =
|
|
|
|
Core::IFile::ReloadAll;
|
2008-12-02 18:14:06 +01:00
|
|
|
foreach (Core::IFile *file, allFileHandles)
|
2008-12-02 12:01:29 +01:00
|
|
|
file->modified(&tempBehavior);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Deletes all subprojects/files/virtual folders
|
|
|
|
*/
|
|
|
|
void Qt4PriFileNode::clear()
|
|
|
|
{
|
|
|
|
// delete files && folders && projects
|
|
|
|
if (!fileNodes().isEmpty())
|
|
|
|
removeFileNodes(fileNodes(), this);
|
|
|
|
if (!subProjectNodes().isEmpty())
|
|
|
|
removeProjectNodes(subProjectNodes());
|
|
|
|
if (!subFolderNodes().isEmpty())
|
|
|
|
removeFolderNodes(subFolderNodes(), this);
|
|
|
|
}
|
|
|
|
|
|
|
|
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-04-28 14:30:17 +02:00
|
|
|
Qt4PriFileNode *Qt4PriFileNode::findProFileFor(const QString &fileName)
|
|
|
|
{
|
|
|
|
if (fileName == path())
|
|
|
|
return this;
|
|
|
|
foreach (ProjectNode *pn, subProjectNodes())
|
|
|
|
if (Qt4PriFileNode *qt4PriFileNode = qobject_cast<Qt4PriFileNode *>(pn))
|
|
|
|
if (Qt4PriFileNode *result = qt4PriFileNode->findProFileFor(fileName))
|
|
|
|
return result;
|
|
|
|
return 0;
|
|
|
|
}
|
2009-01-14 17:13:17 +01:00
|
|
|
|
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),
|
2008-12-02 12:01:29 +01:00
|
|
|
// own stuff
|
2009-07-27 12:50:42 +02:00
|
|
|
m_projectType(InvalidProject)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
if (parent)
|
|
|
|
setParent(parent);
|
|
|
|
|
2008-12-09 17:17:12 +01:00
|
|
|
m_updateTimer.setInterval(100);
|
|
|
|
m_updateTimer.setSingleShot(true);
|
|
|
|
|
|
|
|
connect(&m_updateTimer, SIGNAL(timeout()),
|
|
|
|
this, SLOT(update()));
|
2009-01-14 17:13:17 +01:00
|
|
|
|
|
|
|
connect(ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager(), SIGNAL(buildStateChanged(ProjectExplorer::Project*)),
|
|
|
|
this, SLOT(buildStateChanged(ProjectExplorer::Project*)));
|
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();
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-12-09 17:17:12 +01:00
|
|
|
void Qt4ProFileNode::scheduleUpdate()
|
|
|
|
{
|
|
|
|
m_updateTimer.start();
|
|
|
|
}
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void Qt4ProFileNode::update()
|
|
|
|
{
|
2008-12-05 14:29:18 +01:00
|
|
|
ProFileReader *reader = createProFileReader();
|
|
|
|
if (!reader->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));
|
2008-12-05 14:29:18 +01:00
|
|
|
delete reader;
|
2008-12-02 12:01:29 +01:00
|
|
|
invalidate();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
qDebug() << "Qt4ProFileNode - updating files for file " << m_projectFilePath;
|
|
|
|
|
|
|
|
Qt4ProjectType projectType = InvalidProject;
|
2008-12-05 14:29:18 +01:00
|
|
|
switch (reader->templateType()) {
|
2008-12-02 12:01:29 +01:00
|
|
|
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) {
|
2008-12-05 14:29:18 +01:00
|
|
|
foreach (const QString &subDirProject, subDirsPaths(reader))
|
2008-12-02 12:01:29 +01:00
|
|
|
newProjectFiles << subDirProject;
|
|
|
|
}
|
|
|
|
|
2008-12-05 14:29:18 +01:00
|
|
|
foreach (ProFile *includeFile, reader->includeFiles()) {
|
2008-12-02 12:01:29 +01:00
|
|
|
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
|
2008-12-05 14:29:18 +01:00
|
|
|
= new Qt4PriFileNode(m_project, this,
|
2008-12-02 12:01:29 +01:00
|
|
|
*newProjectFileIter);
|
2008-12-05 14:29:18 +01:00
|
|
|
priFileNode->update(file, reader);
|
2008-12-02 12:01:29 +01:00
|
|
|
toAdd << priFileNode;
|
|
|
|
} else {
|
|
|
|
toAdd << createSubProFileNode(*newProjectFileIter);
|
|
|
|
}
|
|
|
|
++newProjectFileIter;
|
|
|
|
} else { // *existingNodeIter->path() == *newProjectFileIter
|
|
|
|
if (ProFile *file = includeFiles.value(*newProjectFileIter)) {
|
|
|
|
Qt4PriFileNode *priFileNode = static_cast<Qt4PriFileNode*>(*existingNodeIter);
|
2008-12-05 14:29:18 +01:00
|
|
|
priFileNode->update(file, reader);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
++existingNodeIter;
|
|
|
|
++newProjectFileIter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (existingNodeIter != existingProjectNodes.constEnd()) {
|
|
|
|
toRemove << *existingNodeIter;
|
|
|
|
++existingNodeIter;
|
|
|
|
}
|
|
|
|
while (newProjectFileIter != newProjectFiles.constEnd()) {
|
|
|
|
if (ProFile *file = includeFiles.value(*newProjectFileIter)) {
|
|
|
|
Qt4PriFileNode *priFileNode
|
2008-12-05 14:29:18 +01:00
|
|
|
= new Qt4PriFileNode(m_project, this,
|
2008-12-02 12:01:29 +01:00
|
|
|
*newProjectFileIter);
|
2008-12-05 14:29:18 +01:00
|
|
|
priFileNode->update(file, reader);
|
2008-12-02 12:01:29 +01:00
|
|
|
toAdd << priFileNode;
|
|
|
|
} else {
|
|
|
|
toAdd << createSubProFileNode(*newProjectFileIter);
|
|
|
|
}
|
|
|
|
++newProjectFileIter;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!toRemove.isEmpty())
|
|
|
|
removeProjectNodes(toRemove);
|
|
|
|
if (!toAdd.isEmpty())
|
|
|
|
addProjectNodes(toAdd);
|
|
|
|
|
2008-12-05 14:29:18 +01:00
|
|
|
Qt4PriFileNode::update(fileForCurrentProject, reader);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
// update other variables
|
|
|
|
QHash<Qt4Variable, QStringList> newVarValues;
|
2009-02-26 17:19:46 +01:00
|
|
|
|
2008-12-05 14:29:18 +01:00
|
|
|
newVarValues[DefinesVar] = reader->values(QLatin1String("DEFINES"));
|
|
|
|
newVarValues[IncludePathVar] = includePaths(reader);
|
|
|
|
newVarValues[UiDirVar] = uiDirPaths(reader);
|
|
|
|
newVarValues[MocDirVar] = mocDirPaths(reader);
|
2009-05-13 18:09:47 +02:00
|
|
|
newVarValues[PkgConfigVar] = reader->values(QLatin1String("PKGCONFIG"));
|
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
|
|
|
|
|
|
|
delete reader;
|
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
|
|
|
}
|
|
|
|
|
2008-12-05 14:29:18 +01:00
|
|
|
ProFileReader *Qt4PriFileNode::createProFileReader() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2008-12-02 18:14:06 +01:00
|
|
|
ProFileReader *reader = new ProFileReader();
|
2009-01-20 11:52:04 +01:00
|
|
|
connect(reader, SIGNAL(errorFound(QString)),
|
|
|
|
m_project, SLOT(proFileParseError(QString)));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-11-26 14:43:27 +01:00
|
|
|
Qt4BuildConfiguration *qt4bc = m_project->activeQt4BuildConfiguration();
|
2009-11-25 18:50:20 +01:00
|
|
|
|
|
|
|
QtVersion *version = qt4bc->qtVersion();
|
2009-01-20 11:52:04 +01:00
|
|
|
if (version->isValid())
|
2008-12-02 12:01:29 +01:00
|
|
|
reader->setQtVersion(version);
|
|
|
|
|
2009-01-14 17:46:44 +01:00
|
|
|
reader->setOutputDir(m_qt4ProFileNode->buildDir());
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
return reader;
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt4ProFileNode *Qt4ProFileNode::createSubProFileNode(const QString &path)
|
|
|
|
{
|
|
|
|
Qt4ProFileNode *subProFileNode = new Qt4ProFileNode(m_project, path);
|
|
|
|
subProFileNode->update();
|
|
|
|
return subProFileNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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()) {
|
|
|
|
info.setFile(m_projectDir + "/" + realDir);
|
2008-12-03 13:25:19 +01:00
|
|
|
realDir = m_projectDir + "/" + 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()) {
|
2008-12-02 12:01:29 +01:00
|
|
|
realFile = QString("%1/%2.pro").arg(realDir, info.fileName());
|
|
|
|
if (!QFile::exists(realFile)) {
|
|
|
|
// parse directory for pro files - if there is only one, use that
|
|
|
|
QDir dir(realDir);
|
|
|
|
QStringList files = dir.entryList(QStringList() << "*.pro", QDir::Files);
|
|
|
|
if (files.size() == 1) {
|
|
|
|
realFile = QString("%1/%2").arg(realDir, files.first());
|
|
|
|
} else {
|
|
|
|
m_project->proFileParseError(tr("Could not find .pro file for sub dir '%1' in '%2'")
|
|
|
|
.arg(subDirVar).arg(realDir));
|
|
|
|
realFile = QString::null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
realFile = realDir;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!realFile.isEmpty() && !subProjectPaths.contains(realFile))
|
|
|
|
subProjectPaths << realFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
return subProjectPaths;
|
|
|
|
}
|
|
|
|
|
2008-12-05 14:29:18 +01:00
|
|
|
QString Qt4PriFileNode::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);
|
2009-11-25 18:50:20 +01:00
|
|
|
return QDir(m_project->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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-05 11:06:05 +02:00
|
|
|
void Qt4ProFileNode::updateCodeModelSupportFromEditor(const QString &uiFileName, Designer::FormWindowEditor *fw)
|
2009-05-12 14:12:20 +02:00
|
|
|
{
|
|
|
|
QMap<QString, Qt4UiCodeModelSupport *>::const_iterator it;
|
|
|
|
it = m_uiCodeModelSupport.constFind(uiFileName);
|
|
|
|
if (it != m_uiCodeModelSupport.constEnd()) {
|
|
|
|
it.value()->updateFromEditor(fw);
|
|
|
|
}
|
|
|
|
foreach (ProjectExplorer::ProjectNode *pro, subProjectNodes())
|
|
|
|
if (Qt4ProFileNode *qt4proFileNode = qobject_cast<Qt4ProFileNode *>(pro))
|
|
|
|
qt4proFileNode->updateCodeModelSupportFromEditor(uiFileName, fw);
|
|
|
|
}
|
|
|
|
|
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());
|
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
}
|