ProjectExplorer: Remove hack for virtual folders

Previously virtual folders, that is the "Sources", "Headers" folders used a
hack. This patch removes that hack, by introducing the following changes
- The FlatModel and the ProjectExplorer::Nodes now don't require path() to
  be unique. Thus allowing the virtual folders to all return the same for
  path(). [1]

- Introducing a new node type "VirtualFolder" which is sorted according to
  a priority.

- Introducing a few new virtuals for displayName and toolip(), which can
  be overriden.

[1] Note that all the project managers do require path() to be unique for
some types of nodes.

That also fixes:
Task-number: QTCREATORBUG-7100

Change-Id: I76b730f4c4254e2894467603bbe9a30e356a0bcc
Reviewed-by: Tobias Hunger <tobias.hunger@nokia.com>
Reviewed-by: Daniel Teske <daniel.teske@nokia.com>
This commit is contained in:
Daniel Teske
2012-05-04 11:49:37 +02:00
parent 3b4c6c0332
commit e8ee898864
7 changed files with 247 additions and 109 deletions

View File

@@ -376,13 +376,18 @@ void CMakeProject::gatherFileNodes(ProjectExplorer::FolderNode *parent, QList<Pr
list.append(file); list.append(file);
} }
bool sortNodesByPath(Node *a, Node *b)
{
return a->path() < b->path();
}
void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> newList) void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> newList)
{ {
// Gather old list // Gather old list
QList<ProjectExplorer::FileNode *> oldList; QList<ProjectExplorer::FileNode *> oldList;
gatherFileNodes(rootNode, oldList); gatherFileNodes(rootNode, oldList);
qSort(oldList.begin(), oldList.end(), ProjectExplorer::ProjectNode::sortNodesByPath); qSort(oldList.begin(), oldList.end(), sortNodesByPath);
qSort(newList.begin(), newList.end(), ProjectExplorer::ProjectNode::sortNodesByPath); qSort(newList.begin(), newList.end(), sortNodesByPath);
// generate added and deleted list // generate added and deleted list
QList<ProjectExplorer::FileNode *>::const_iterator oldIt = oldList.constBegin(); QList<ProjectExplorer::FileNode *>::const_iterator oldIt = oldList.constBegin();

View File

@@ -2567,12 +2567,11 @@ QString pathOrDirectoryFor(Node *node, bool dir)
QString path = node->path(); QString path = node->path();
QString location; QString location;
FolderNode *folder = qobject_cast<FolderNode *>(node); FolderNode *folder = qobject_cast<FolderNode *>(node);
const int hashPos = path.indexOf(QLatin1Char('#')); if (node->nodeType() == ProjectExplorer::VirtualFolderNodeType && folder) {
if (hashPos >= 0 && folder) {
// Virtual Folder case // Virtual Folder case
// If there are files directly below or no subfolders, take the folder path // If there are files directly below or no subfolders, take the folder path
if (!folder->fileNodes().isEmpty() || folder->subFolderNodes().isEmpty()) { if (!folder->fileNodes().isEmpty() || folder->subFolderNodes().isEmpty()) {
location = path.left(hashPos); location = path;
} else { } else {
// Otherwise we figure out a commonPath from the subfolders // Otherwise we figure out a commonPath from the subfolders
QStringList list; QStringList list;

View File

@@ -101,6 +101,29 @@ bool sortNodes(Node *n1, Node *n2)
if (n2Type == ProjectNodeType) if (n2Type == ProjectNodeType)
return false; return false;
if (n1Type == VirtualFolderNodeType) {
if (n2Type == VirtualFolderNodeType) {
VirtualFolderNode *folder1 = static_cast<VirtualFolderNode *>(n1);
VirtualFolderNode *folder2 = static_cast<VirtualFolderNode *>(n2);
if (folder1->priority() > folder2->priority())
return true;
if (folder1->priority() < folder2->priority())
return false;
int result = caseFriendlyCompare(folder1->path(), folder2->path());
if (result != 0)
return result < 0;
else
return folder1 < folder2;
} else {
return true; // virtual folder is before folder
}
}
if (n2Type == VirtualFolderNodeType)
return false;
if (n1Type == FolderNodeType) { if (n1Type == FolderNodeType) {
if (n2Type == FolderNodeType) { if (n2Type == FolderNodeType) {
FolderNode *folder1 = static_cast<FolderNode*>(n1); FolderNode *folder1 = static_cast<FolderNode*>(n1);
@@ -240,14 +263,11 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
switch (role) { switch (role) {
case Qt::DisplayRole: case Qt::DisplayRole:
case Qt::EditRole: { case Qt::EditRole: {
if (folderNode) result = node->displayName();
result = folderNode->displayName();
else
result = QFileInfo(node->path()).fileName(); //TODO cache that?
break; break;
} }
case Qt::ToolTipRole: { case Qt::ToolTipRole: {
result = QDir::toNativeSeparators(node->path()); result = node->tooltip();
break; break;
} }
case Qt::DecorationRole: { case Qt::DecorationRole: {

View File

@@ -102,6 +102,16 @@ QString Node::path() const
return m_path; return m_path;
} }
QString Node::displayName() const
{
return QFileInfo(path()).fileName();
}
QString Node::tooltip() const
{
return QDir::toNativeSeparators(path());
}
void Node::setNodeType(NodeType type) void Node::setNodeType(NodeType type)
{ {
m_nodeType = type; m_nodeType = type;
@@ -154,8 +164,8 @@ bool FileNode::isGenerated() const
\sa ProjectExplorer::FileNode, ProjectExplorer::ProjectNode \sa ProjectExplorer::FileNode, ProjectExplorer::ProjectNode
*/ */
FolderNode::FolderNode(const QString &folderPath) : FolderNode::FolderNode(const QString &folderPath, NodeType nodeType) :
Node(FolderNodeType, folderPath), Node(nodeType, folderPath),
m_displayName(QDir::toNativeSeparators(folderPath)) m_displayName(QDir::toNativeSeparators(folderPath))
{ {
} }
@@ -215,6 +225,31 @@ void FolderNode::setIcon(const QIcon &icon)
m_icon = icon; m_icon = icon;
} }
/*!
\class ProjectExplorer::VirtualFolderNode
In-memory presentation of a virtual folder.
Note that the node itself + all children (files and folders) are "managed" by the owning project.
A virtual folder does not correspond to a actual folder on the file system. See for example the
sources, headers and forms folder the qt4projectmanager creates
VirtualFolderNodes are always sorted before FolderNodes and are sorted according to their priority.
\sa ProjectExplorer::FileNode, ProjectExplorer::ProjectNode
*/
VirtualFolderNode::VirtualFolderNode(const QString &folderPath, int priority)
: FolderNode(folderPath, VirtualFolderNodeType), m_priority(priority)
{
}
VirtualFolderNode::~VirtualFolderNode()
{
}
int VirtualFolderNode::priority() const
{
return m_priority;
}
/*! /*!
\class ProjectExplorer::ProjectNode \class ProjectExplorer::ProjectNode
@@ -344,10 +379,8 @@ void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects)
m_subFolderNodes.append(project); m_subFolderNodes.append(project);
m_subProjectNodes.append(project); m_subProjectNodes.append(project);
} }
qSort(m_subFolderNodes.begin(), m_subFolderNodes.end(), qSort(m_subFolderNodes.begin(), m_subFolderNodes.end());
sortNodesByPath); qSort(m_subProjectNodes.begin(), m_subProjectNodes.end());
qSort(m_subProjectNodes.begin(), m_subProjectNodes.end(),
sortNodesByPath);
foreach (NodesWatcher *watcher, m_watchers) foreach (NodesWatcher *watcher, m_watchers)
emit watcher->foldersAdded(); emit watcher->foldersAdded();
@@ -366,7 +399,7 @@ void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects)
QList<FolderNode*> toRemove; QList<FolderNode*> toRemove;
foreach (ProjectNode *projectNode, subProjects) foreach (ProjectNode *projectNode, subProjects)
toRemove << projectNode; toRemove << projectNode;
qSort(toRemove.begin(), toRemove.end(), sortNodesByPath); qSort(toRemove.begin(), toRemove.end());
foreach (NodesWatcher *watcher, m_watchers) foreach (NodesWatcher *watcher, m_watchers)
emit watcher->foldersAboutToBeRemoved(this, toRemove); emit watcher->foldersAboutToBeRemoved(this, toRemove);
@@ -375,12 +408,12 @@ void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects)
QList<FolderNode*>::iterator folderIter = m_subFolderNodes.begin(); QList<FolderNode*>::iterator folderIter = m_subFolderNodes.begin();
QList<ProjectNode*>::iterator projectIter = m_subProjectNodes.begin(); QList<ProjectNode*>::iterator projectIter = m_subProjectNodes.begin();
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) { for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
while ((*projectIter)->path() != (*toRemoveIter)->path()) { while (*projectIter != *toRemoveIter) {
++projectIter; ++projectIter;
QTC_ASSERT(projectIter != m_subProjectNodes.end(), QTC_ASSERT(projectIter != m_subProjectNodes.end(),
qDebug("Project to remove is not part of specified folder!")); qDebug("Project to remove is not part of specified folder!"));
} }
while ((*folderIter)->path() != (*toRemoveIter)->path()) { while (*folderIter != *toRemoveIter) {
++folderIter; ++folderIter;
QTC_ASSERT(folderIter != m_subFolderNodes.end(), QTC_ASSERT(folderIter != m_subFolderNodes.end(),
qDebug("Project to remove is not part of specified folder!")); qDebug("Project to remove is not part of specified folder!"));
@@ -416,22 +449,17 @@ void ProjectNode::addFolderNodes(const QList<FolderNode*> &subFolders, FolderNod
folder->setProjectNode(this); folder->setProjectNode(this);
// Find the correct place to insert // Find the correct place to insert
if (parentFolder->m_subFolderNodes.count() == 0 || sortNodesByPath(parentFolder->m_subFolderNodes.last(), folder)) { if (parentFolder->m_subFolderNodes.count() == 0
|| parentFolder->m_subFolderNodes.last() < folder) {
// empty list or greater then last node // empty list or greater then last node
parentFolder->m_subFolderNodes.append(folder); parentFolder->m_subFolderNodes.append(folder);
} else { } else {
// Binary Search for insertion point // Binary Search for insertion point
int l = 0; QList<FolderNode*>::iterator it
int r = parentFolder->m_subFolderNodes.count(); = qLowerBound(parentFolder->m_subFolderNodes.begin(),
while (l != r) { parentFolder->m_subFolderNodes.end(),
int i = (l + r) / 2; folder);
if (sortNodesByPath(folder, parentFolder->m_subFolderNodes.at(i))) { parentFolder->m_subFolderNodes.insert(it, folder);
r = i;
} else {
l = i + 1;
}
}
parentFolder->m_subFolderNodes.insert(l, folder);
} }
// project nodes have to be added via addProjectNodes // project nodes have to be added via addProjectNodes
@@ -459,7 +487,7 @@ void ProjectNode::removeFolderNodes(const QList<FolderNode*> &subFolders,
const bool emitSignals = (parentFolder->projectNode() == this); const bool emitSignals = (parentFolder->projectNode() == this);
QList<FolderNode*> toRemove = subFolders; QList<FolderNode*> toRemove = subFolders;
qSort(toRemove.begin(), toRemove.end(), sortNodesByPath); qSort(toRemove.begin(), toRemove.end());
if (emitSignals) if (emitSignals)
foreach (NodesWatcher *watcher, m_watchers) foreach (NodesWatcher *watcher, m_watchers)
@@ -470,7 +498,7 @@ void ProjectNode::removeFolderNodes(const QList<FolderNode*> &subFolders,
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) { for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
QTC_ASSERT((*toRemoveIter)->nodeType() != ProjectNodeType, QTC_ASSERT((*toRemoveIter)->nodeType() != ProjectNodeType,
qDebug("project nodes have to be removed via removeProjectNodes")); qDebug("project nodes have to be removed via removeProjectNodes"));
while ((*folderIter)->path() != (*toRemoveIter)->path()) { while (*folderIter != *toRemoveIter) {
++folderIter; ++folderIter;
QTC_ASSERT(folderIter != parentFolder->m_subFolderNodes.end(), QTC_ASSERT(folderIter != parentFolder->m_subFolderNodes.end(),
qDebug("Folder to remove is not part of specified folder!")); qDebug("Folder to remove is not part of specified folder!"));
@@ -509,22 +537,16 @@ void ProjectNode::addFileNodes(const QList<FileNode*> &files, FolderNode *folder
file->setParentFolderNode(folder); file->setParentFolderNode(folder);
file->setProjectNode(this); file->setProjectNode(this);
// Now find the correct place to insert file // Now find the correct place to insert file
if (folder->m_fileNodes.count() == 0 || sortNodesByPath(folder->m_fileNodes.last(), file)) { if (folder->m_fileNodes.count() == 0
|| folder->m_fileNodes.last() < file) {
// empty list or greater then last node // empty list or greater then last node
folder->m_fileNodes.append(file); folder->m_fileNodes.append(file);
} else { } else {
// Binary Search for insertion point QList<FileNode *>::iterator it
int l = 0; = qLowerBound(folder->m_fileNodes.begin(),
int r = folder->m_fileNodes.count(); folder->m_fileNodes.end(),
while (l != r) { file);
int i = (l + r) / 2; folder->m_fileNodes.insert(it, file);
if (sortNodesByPath(file, folder->m_fileNodes.at(i))) {
r = i;
} else {
l = i + 1;
}
}
folder->m_fileNodes.insert(l, file);
} }
} }
@@ -549,7 +571,7 @@ void ProjectNode::removeFileNodes(const QList<FileNode*> &files, FolderNode *fol
const bool emitSignals = (folder->projectNode() == this); const bool emitSignals = (folder->projectNode() == this);
QList<FileNode*> toRemove = files; QList<FileNode*> toRemove = files;
qSort(toRemove.begin(), toRemove.end(), sortNodesByPath); qSort(toRemove.begin(), toRemove.end());
if (emitSignals) if (emitSignals)
foreach (NodesWatcher *watcher, m_watchers) foreach (NodesWatcher *watcher, m_watchers)
@@ -558,7 +580,7 @@ void ProjectNode::removeFileNodes(const QList<FileNode*> &files, FolderNode *fol
QList<FileNode*>::const_iterator toRemoveIter = toRemove.constBegin(); QList<FileNode*>::const_iterator toRemoveIter = toRemove.constBegin();
QList<FileNode*>::iterator filesIter = folder->m_fileNodes.begin(); QList<FileNode*>::iterator filesIter = folder->m_fileNodes.begin();
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) { for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
while ((*filesIter)->path() != (*toRemoveIter)->path()) { while (*filesIter != *toRemoveIter) {
++filesIter; ++filesIter;
QTC_ASSERT(filesIter != folder->m_fileNodes.end(), QTC_ASSERT(filesIter != folder->m_fileNodes.end(),
qDebug("File to remove is not part of specified folder!")); qDebug("File to remove is not part of specified folder!"));
@@ -579,12 +601,6 @@ void ProjectNode::watcherDestroyed(QObject *watcher)
unregisterWatcher(static_cast<NodesWatcher*>(watcher)); unregisterWatcher(static_cast<NodesWatcher*>(watcher));
} }
/*!
\brief Sort pointers to FileNodes
*/
bool ProjectNode::sortNodesByPath(Node *n1, Node *n2) {
return n1->path() < n2->path();
}
/*! /*!
\class ProjectExplorer::SessionNode \class ProjectExplorer::SessionNode
@@ -663,6 +679,9 @@ void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes)
m_projectNodes.append(project); m_projectNodes.append(project);
} }
qSort(m_subFolderNodes);
qSort(m_projectNodes);
foreach (NodesWatcher *watcher, m_watchers) foreach (NodesWatcher *watcher, m_watchers)
emit watcher->foldersAdded(); emit watcher->foldersAdded();
} }
@@ -675,6 +694,8 @@ void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes)
foreach (ProjectNode *projectNode, projectNodes) foreach (ProjectNode *projectNode, projectNodes)
toRemove << projectNode; toRemove << projectNode;
qSort(toRemove);
foreach (NodesWatcher *watcher, m_watchers) foreach (NodesWatcher *watcher, m_watchers)
emit watcher->foldersAboutToBeRemoved(this, toRemove); emit watcher->foldersAboutToBeRemoved(this, toRemove);
@@ -682,12 +703,12 @@ void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes)
QList<FolderNode*>::iterator folderIter = m_subFolderNodes.begin(); QList<FolderNode*>::iterator folderIter = m_subFolderNodes.begin();
QList<ProjectNode*>::iterator projectIter = m_projectNodes.begin(); QList<ProjectNode*>::iterator projectIter = m_projectNodes.begin();
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) { for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
while ((*projectIter)->path() != (*toRemoveIter)->path()) { while (*projectIter != *toRemoveIter) {
++projectIter; ++projectIter;
QTC_ASSERT(projectIter != m_projectNodes.end(), QTC_ASSERT(projectIter != m_projectNodes.end(),
qDebug("Project to remove is not part of specified folder!")); qDebug("Project to remove is not part of specified folder!"));
} }
while ((*folderIter)->path() != (*toRemoveIter)->path()) { while (*folderIter != *toRemoveIter) {
++folderIter; ++folderIter;
QTC_ASSERT(folderIter != m_subFolderNodes.end(), QTC_ASSERT(folderIter != m_subFolderNodes.end(),
qDebug("Project to remove is not part of specified folder!")); qDebug("Project to remove is not part of specified folder!"));

View File

@@ -54,6 +54,7 @@ class RunConfiguration;
enum NodeType { enum NodeType {
FileNodeType = 1, FileNodeType = 1,
FolderNodeType, FolderNodeType,
VirtualFolderNodeType,
ProjectNodeType, ProjectNodeType,
SessionNodeType SessionNodeType
}; };
@@ -87,6 +88,8 @@ public:
ProjectNode *projectNode() const; // managing project ProjectNode *projectNode() const; // managing project
FolderNode *parentFolderNode() const; // parent folder or project FolderNode *parentFolderNode() const; // parent folder or project
QString path() const; // file system path QString path() const; // file system path
virtual QString displayName() const;
virtual QString tooltip() const;
protected: protected:
Node(NodeType nodeType, const QString &path); Node(NodeType nodeType, const QString &path);
@@ -122,7 +125,7 @@ private:
class PROJECTEXPLORER_EXPORT FolderNode : public Node { class PROJECTEXPLORER_EXPORT FolderNode : public Node {
Q_OBJECT Q_OBJECT
public: public:
explicit FolderNode(const QString &folderPath); explicit FolderNode(const QString &folderPath, NodeType nodeType = FolderNodeType);
virtual ~FolderNode(); virtual ~FolderNode();
QString displayName() const; QString displayName() const;
@@ -147,6 +150,18 @@ private:
mutable QIcon m_icon; mutable QIcon m_icon;
}; };
class PROJECTEXPLORER_EXPORT VirtualFolderNode : public FolderNode
{
Q_OBJECT
public:
explicit VirtualFolderNode(const QString &folderPath, int priority);
virtual ~VirtualFolderNode();
int priority() const;
private:
int m_priority;
};
// Documentation inside. // Documentation inside.
class PROJECTEXPLORER_EXPORT ProjectNode : public FolderNode class PROJECTEXPLORER_EXPORT ProjectNode : public FolderNode
{ {
@@ -213,8 +228,6 @@ public:
void accept(NodesVisitor *visitor); void accept(NodesVisitor *visitor);
static bool sortNodesByPath(Node *n1, Node *n2);
protected: protected:
// this is just the in-memory representation, a subclass // this is just the in-memory representation, a subclass
// will add the persistent stuff // will add the persistent stuff

View File

@@ -107,6 +107,11 @@ static const FileTypeDataStorage fileTypeDataStorage[] = {
":/qt4projectmanager/images/unknown.png" } ":/qt4projectmanager/images/unknown.png" }
}; };
bool sortNodesByPath(ProjectExplorer::Node *a, ProjectExplorer::Node *b)
{
return a->path() < b->path();
}
class Qt4NodeStaticData { class Qt4NodeStaticData {
public: public:
class FileTypeData { class FileTypeData {
@@ -278,20 +283,25 @@ void Qt4PriFileNode::scheduleUpdate()
namespace Internal { namespace Internal {
struct InternalNode struct InternalNode
{ {
QMap<QString, InternalNode*> subnodes; QList<InternalNode *> virtualfolders;
QMap<QString, InternalNode *> subnodes;
QStringList files; QStringList files;
ProjectExplorer::FileType type; ProjectExplorer::FileType type;
QString displayName; QString displayName;
QString typeName;
int priority;
QString fullPath; QString fullPath;
QIcon icon; QIcon icon;
InternalNode() InternalNode()
{ {
type = ProjectExplorer::UnknownFileType; type = ProjectExplorer::UnknownFileType;
priority = 0;
} }
~InternalNode() ~InternalNode()
{ {
qDeleteAll(virtualfolders);
qDeleteAll(subnodes); qDeleteAll(subnodes);
} }
@@ -381,61 +391,101 @@ struct InternalNode
subnodes = newSubnodes; subnodes = newSubnodes;
} }
FolderNode *createFolderNode(InternalNode *node)
{
FolderNode *newNode = 0;
if (node->typeName.isEmpty())
newNode = new FolderNode(node->fullPath);
else
newNode = new ProVirtualFolderNode(node->fullPath, node->priority, node->typeName);
newNode->setDisplayName(node->displayName);
if (!node->icon.isNull())
newNode->setIcon(node->icon);
return newNode;
}
// Makes the projectNode's subtree below the given folder match this internal node's subtree // Makes the projectNode's subtree below the given folder match this internal node's subtree
void updateSubFolders(Qt4ProjectManager::Qt4PriFileNode *projectNode, ProjectExplorer::FolderNode *folder) void updateSubFolders(Qt4ProjectManager::Qt4PriFileNode *projectNode, ProjectExplorer::FolderNode *folder)
{ {
updateFiles(projectNode, folder, type); updateFiles(projectNode, folder, type);
// update folders // updateFolders
QList<FolderNode *> existingFolderNodes; QMultiMap<QString, FolderNode *> existingFolderNodes;
foreach (FolderNode *node, folder->subFolderNodes()) { foreach (FolderNode *node, folder->subFolderNodes())
if (node->nodeType() != ProjectNodeType) if (node->nodeType() != ProjectNodeType)
existingFolderNodes << node; existingFolderNodes.insert(node->path(), node);
}
qSort(existingFolderNodes.begin(), existingFolderNodes.end(), ProjectNode::sortNodesByPath);
QList<FolderNode *> foldersToRemove; QList<FolderNode *> foldersToRemove;
QList<FolderNode *> foldersToAdd; QList<FolderNode *> foldersToAdd;
typedef QPair<InternalNode *, FolderNode *> NodePair; typedef QPair<InternalNode *, FolderNode *> NodePair;
QList<NodePair> nodesToUpdate; QList<NodePair> nodesToUpdate;
// Both lists should be already sorted... // Check virtual
QList<FolderNode*>::const_iterator existingNodeIter = existingFolderNodes.constBegin(); {
QMap<QString, InternalNode*>::const_iterator newNodeIter = subnodes.constBegin();; QList<InternalNode *>::const_iterator it = virtualfolders.constBegin();
while (existingNodeIter != existingFolderNodes.constEnd() QList<InternalNode *>::const_iterator end = virtualfolders.constEnd();
&& newNodeIter != subnodes.constEnd()) { for ( ; it != end; ++it) {
if ((*existingNodeIter)->path() < newNodeIter.value()->fullPath) { bool found = false;
foldersToRemove << *existingNodeIter; QString path = (*it)->fullPath;
++existingNodeIter; QMultiMap<QString, FolderNode *>::const_iterator oldit
} else if ((*existingNodeIter)->path() > newNodeIter.value()->fullPath) { = existingFolderNodes.constFind(path);
FolderNode *newNode = new FolderNode(newNodeIter.value()->fullPath); while (oldit != existingFolderNodes.end() && oldit.key() == path) {
newNode->setDisplayName(newNodeIter.value()->displayName); if (oldit.value()->nodeType() == ProjectExplorer::VirtualFolderNodeType) {
if (!newNodeIter.value()->icon.isNull()) ProjectExplorer::VirtualFolderNode *vfn
newNode->setIcon(newNodeIter.value()->icon); = qobject_cast<ProjectExplorer::VirtualFolderNode *>(oldit.value());
foldersToAdd << newNode; if (vfn->priority() == (*it)->priority) {
nodesToUpdate << NodePair(newNodeIter.value(), newNode); found = true;
++newNodeIter; break;
} else { // *existingNodeIter->path() == *newPathIter }
nodesToUpdate << NodePair(newNodeIter.value(), *existingNodeIter); }
++existingNodeIter; ++oldit;
++newNodeIter; }
if (found) {
nodesToUpdate << NodePair(*it, *oldit);
} else {
FolderNode *newNode = createFolderNode(*it);
foldersToAdd << newNode;
nodesToUpdate << NodePair(*it, newNode);
}
}
}
// Check subnodes
{
QMap<QString, InternalNode *>::const_iterator it = subnodes.constBegin();
QMap<QString, InternalNode *>::const_iterator end = subnodes.constEnd();
for ( ; it != end; ++it) {
bool found = false;
QString path = it.value()->fullPath;
QMultiMap<QString, FolderNode *>::const_iterator oldit
= existingFolderNodes.constFind(path);
while (oldit != existingFolderNodes.end() && oldit.key() == path) {
if (oldit.value()->nodeType() == ProjectExplorer::FolderNodeType) {
found = true;
break;
}
++oldit;
}
if (found) {
nodesToUpdate << NodePair(it.value(), *oldit);
} else {
FolderNode *newNode = createFolderNode(it.value());
foldersToAdd << newNode;
nodesToUpdate << NodePair(it.value(), newNode);
}
} }
} }
while (existingNodeIter != existingFolderNodes.constEnd()) { QSet<FolderNode *> toKeep;
foldersToRemove << *existingNodeIter; foreach (const NodePair &np, nodesToUpdate)
++existingNodeIter; toKeep << np.second;
}
while (newNodeIter != subnodes.constEnd()) { QMultiMap<QString, FolderNode *>::const_iterator jit = existingFolderNodes.constBegin();
FolderNode *newNode = new FolderNode(newNodeIter.value()->fullPath); QMultiMap<QString, FolderNode *>::const_iterator jend = existingFolderNodes.constEnd();
newNode->setDisplayName(newNodeIter.value()->displayName); for ( ; jit != jend; ++jit)
if (!newNodeIter.value()->icon.isNull()) if (!toKeep.contains(jit.value()))
newNode->setIcon(newNodeIter.value()->icon); foldersToRemove << jit.value();
foldersToAdd << newNode;
nodesToUpdate << NodePair(newNodeIter.value(), newNode);
++newNodeIter;
}
if (!foldersToRemove.isEmpty()) if (!foldersToRemove.isEmpty())
projectNode->removeFolderNodes(foldersToRemove, folder); projectNode->removeFolderNodes(foldersToRemove, folder);
@@ -459,7 +509,7 @@ struct InternalNode
QList<FileNode*> filesToAdd; QList<FileNode*> filesToAdd;
qSort(files); qSort(files);
qSort(existingFileNodes.begin(), existingFileNodes.end(), ProjectNode::sortNodesByPath); qSort(existingFileNodes.begin(), existingFileNodes.end(), sortNodesByPath);
QList<FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin(); QList<FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin();
QList<QString>::const_iterator newPathIter = files.constBegin(); QList<QString>::const_iterator newPathIter = files.constBegin();
@@ -647,10 +697,11 @@ void Qt4PriFileNode::update(ProFile *includeFileExact, QtSupport::ProFileReader
InternalNode *subfolder = new InternalNode; InternalNode *subfolder = new InternalNode;
subfolder->type = type; subfolder->type = type;
subfolder->icon = fileTypes.at(i).icon; subfolder->icon = fileTypes.at(i).icon;
subfolder->fullPath = m_projectDir + QLatin1String("/#") subfolder->fullPath = m_projectDir;
+ QString::number(i) + fileTypes.at(i).typeName; subfolder->typeName = fileTypes.at(i).typeName;
subfolder->priority = -i;
subfolder->displayName = fileTypes.at(i).typeName; subfolder->displayName = fileTypes.at(i).typeName;
contents.subnodes.insert(subfolder->fullPath, subfolder); contents.virtualfolders.append(subfolder);
// create the hierarchy with subdirectories // create the hierarchy with subdirectories
subfolder->create(m_projectDir, newFilePaths, type); subfolder->create(m_projectDir, newFilePaths, type);
} }
@@ -731,10 +782,11 @@ void Qt4PriFileNode::folderChanged(const QString &folder)
InternalNode *subfolder = new InternalNode; InternalNode *subfolder = new InternalNode;
subfolder->type = type; subfolder->type = type;
subfolder->icon = fileTypes.at(i).icon; subfolder->icon = fileTypes.at(i).icon;
subfolder->fullPath = m_projectDir + QLatin1String("/#") subfolder->fullPath = m_projectDir;
+ QString::number(i) + fileTypes.at(i).typeName; subfolder->typeName = fileTypes.at(i).typeName;
subfolder->priority = -i;
subfolder->displayName = fileTypes.at(i).typeName; subfolder->displayName = fileTypes.at(i).typeName;
contents.subnodes.insert(subfolder->fullPath, subfolder); contents.virtualfolders.append(subfolder);
// create the hierarchy with subdirectories // create the hierarchy with subdirectories
subfolder->create(m_projectDir, m_files[type], type); subfolder->create(m_projectDir, m_files[type], type);
} }
@@ -833,7 +885,7 @@ QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions(Node *node) c
} }
bool addExistingFiles = true; bool addExistingFiles = true;
if (node->path().contains(QLatin1Char('#'))) { if (node->nodeType() == ProjectExplorer::VirtualFolderNodeType) {
// A virtual folder, we do what the projectexplorer does // A virtual folder, we do what the projectexplorer does
FolderNode *folder = qobject_cast<FolderNode *>(node); FolderNode *folder = qobject_cast<FolderNode *>(node);
if (folder) { if (folder) {
@@ -1648,6 +1700,11 @@ void Qt4ProFileNode::applyAsyncEvaluate()
m_project->decrementPendingEvaluateFutures(); m_project->decrementPendingEvaluateFutures();
} }
bool sortByNodes(Node *a, Node *b)
{
return a->path() < b->path();
}
void Qt4ProFileNode::applyEvaluate(EvalResult evalResult, bool async) void Qt4ProFileNode::applyEvaluate(EvalResult evalResult, bool async)
{ {
if (!m_readerExact) if (!m_readerExact)
@@ -1996,7 +2053,7 @@ QStringList Qt4ProFileNode::updateUiFiles()
QStringList toUpdate; QStringList toUpdate;
qSort(newFilePaths); qSort(newFilePaths);
qSort(existingFileNodes.begin(), existingFileNodes.end(), ProjectNode::sortNodesByPath); qSort(existingFileNodes.begin(), existingFileNodes.end(), sortNodesByPath);
QList<ProjectExplorer::FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin(); QList<ProjectExplorer::FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin();
QList<QString>::const_iterator newPathIter = newFilePaths.constBegin(); QList<QString>::const_iterator newPathIter = newFilePaths.constBegin();

View File

@@ -264,6 +264,29 @@ private:
friend class Qt4PriFileNode; friend class Qt4PriFileNode;
}; };
class ProVirtualFolderNode : public ProjectExplorer::VirtualFolderNode
{
public:
explicit ProVirtualFolderNode(const QString &folderPath, int priority, const QString &typeName)
: VirtualFolderNode(folderPath, priority), m_typeName(typeName)
{
}
QString displayName() const
{
return m_typeName;
}
QString tooltip() const
{
return QString();
}
private:
QString m_typeName;
};
} // namespace Internal } // namespace Internal
struct QT4PROJECTMANAGER_EXPORT TargetInformation struct QT4PROJECTMANAGER_EXPORT TargetInformation