forked from qt-creator/qt-creator
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:
@@ -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();
|
||||||
|
@@ -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;
|
||||||
|
@@ -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: {
|
||||||
|
@@ -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!"));
|
||||||
|
@@ -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
|
||||||
|
@@ -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();
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user