Commit 7ebea974 authored by con's avatar con
Browse files

Show pro file's subdirectory structure in project tree in non-simple mode.

Also adding category folders for the different file types
(source files, header files, resource files, form files, other files).
parent f888f5df
......@@ -961,11 +961,15 @@ FolderNode *FlatModel::visibleFolderNode(FolderNode *node) const
bool FlatModel::filter(Node *node) const
{
bool isHidden = false;
if (ProjectNode *projectNode = qobject_cast<ProjectNode*>(node)) {
if (node->nodeType() == SessionNodeType) {
isHidden = false;
} else if (ProjectNode *projectNode = qobject_cast<ProjectNode*>(node)) {
if (m_filterProjects && projectNode->parentFolderNode() != m_rootNode)
isHidden = !projectNode->hasTargets();
}
if (FileNode *fileNode = qobject_cast<FileNode*>(node)) {
} else if (node->nodeType() == FolderNodeType) {
if (m_filterProjects)
isHidden = true;
} else if (FileNode *fileNode = qobject_cast<FileNode*>(node)) {
if (m_filterGeneratedFiles)
isHidden = fileNode->isGenerated();
}
......
......@@ -153,7 +153,11 @@ FolderNode::FolderNode(const QString &folderPath)
: Node(FolderNodeType, folderPath),
m_folderName(folderPath)
{
m_icon = QApplication::style()->standardIcon(QStyle::SP_DirIcon);
static QIcon dirIcon;
if (dirIcon.isNull()) {
dirIcon = QApplication::style()->standardIcon(QStyle::SP_DirIcon);
}
m_icon = dirIcon;
}
FolderNode::~FolderNode()
......@@ -549,8 +553,13 @@ void ProjectNode::watcherDestroyed(QObject *watcher)
/*!
Sort pointers to FileNodes
*/
bool ProjectNode::sortNodesByPath(Node *f1, Node *f2) {
return f1->path() < f2->path();
bool ProjectNode::sortNodesByPath(Node *n1, Node *n2) {
return n1->path() < n2->path();
}
bool ProjectNode::sortFolderNodesByName(FolderNode *f1, FolderNode *f2)
{
return f1->name() < f2->name();
}
/*!
......
......@@ -136,10 +136,10 @@ public:
virtual void accept(NodesVisitor *visitor);
protected:
void setFolderName(const QString &name);
void setIcon(const QIcon &icon);
protected:
QList<FolderNode*> m_subFolderNodes;
QList<FileNode*> m_fileNodes;
......@@ -193,6 +193,7 @@ public:
void accept(NodesVisitor *visitor);
static bool sortNodesByPath(Node *n1, Node *n2);
static bool sortFolderNodesByName(FolderNode *f1, FolderNode *f2);
protected:
// this is just the in-memory representation, a subclass
......
......@@ -116,6 +116,217 @@ void Qt4PriFileNode::scheduleUpdate()
m_qt4ProFileNode->scheduleUpdate();
}
namespace Qt4ProjectManager {
namespace Internal {
struct InternalNode
{
QMap<QString, InternalNode*> subnodes;
QStringList files;
ProjectExplorer::FileType type;
QString fullName;
QIcon icon;
~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;
QList<InternalNode *> internalNodesToUpdate;
QList<FolderNode *> folderNodesToUpdate;
// 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;
internalNodesToUpdate << newNodeIter.value();
folderNodesToUpdate << newNode;
++newNodeIter;
} else { // *existingNodeIter->path() == *newPathIter
internalNodesToUpdate << newNodeIter.value();
folderNodesToUpdate << *existingNodeIter;
++existingNodeIter;
++newNodeIter;
}
}
while (existingNodeIter != existingFolderNodes.constEnd()) {
foldersToRemove << *existingNodeIter;
++existingNodeIter;
}
while (newNodeIter != subnodes.constEnd()) {
FolderNode *newNode = new FolderNode(newNodeIter.value()->fullName);
newNode->setFolderName(newNodeIter.key());
if (!newNodeIter.value()->icon.isNull())
newNode->setIcon(newNodeIter.value()->icon);
foldersToAdd << newNode;
internalNodesToUpdate << newNodeIter.value();
folderNodesToUpdate << newNode;
++newNodeIter;
}
if (!foldersToRemove.isEmpty())
projectNode->removeFolderNodes(foldersToRemove, folder);
if (!foldersToAdd.isEmpty())
projectNode->addFolderNodes(foldersToAdd, folder);
QList<FolderNode *>::const_iterator folderIt = folderNodesToUpdate.constBegin();
QList<InternalNode *>::const_iterator iNodeIt = internalNodesToUpdate.constBegin();
while (folderIt != folderNodesToUpdate.constEnd()
&& iNodeIt != internalNodesToUpdate.constEnd()) {
(*iNodeIt)->updateSubFolders(projectNode, *folderIt);
++folderIt;
++iNodeIt;
}
}
// Makes the folder's files match this internal node's file list
void updateFiles(Qt4PriFileNode *projectNode, FolderNode *folder, FileType type)
{
QList<FileNode*> existingFileNodes;
foreach (FileNode *fileNode, folder->fileNodes()) {
if (fileNode->fileType() == type && !fileNode->isGenerated())
existingFileNodes << fileNode;
}
QList<FileNode*> filesToRemove;
QList<FileNode*> filesToAdd;
qSort(files);
qSort(existingFileNodes.begin(), existingFileNodes.end(), ProjectNode::sortNodesByPath);
QList<FileNode*>::const_iterator existingNodeIter = existingFileNodes.constBegin();
QList<QString>::const_iterator newPathIter = files.constBegin();
while (existingNodeIter != existingFileNodes.constEnd()
&& newPathIter != files.constEnd()) {
if ((*existingNodeIter)->path() < *newPathIter) {
filesToRemove << *existingNodeIter;
++existingNodeIter;
} else if ((*existingNodeIter)->path() > *newPathIter) {
filesToAdd << new FileNode(*newPathIter, type, false);
++newPathIter;
} else { // *existingNodeIter->path() == *newPathIter
++existingNodeIter;
++newPathIter;
}
}
while (existingNodeIter != existingFileNodes.constEnd()) {
filesToRemove << *existingNodeIter;
++existingNodeIter;
}
while (newPathIter != files.constEnd()) {
filesToAdd << new FileNode(*newPathIter, type, false);
++newPathIter;
}
if (!filesToRemove.isEmpty())
projectNode->removeFileNodes(filesToRemove, folder);
if (!filesToAdd.isEmpty())
projectNode->addFileNodes(filesToAdd, folder);
}
};
} // Internal namespace
} // namespace
void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
{
Q_ASSERT(includeFile);
......@@ -131,6 +342,30 @@ void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
<< ProjectExplorer::FormType
<< ProjectExplorer::ResourceType
<< ProjectExplorer::UnknownFileType);
static QStringList fileTypeNames =
QStringList() << tr("Headers")
<< tr("Sources")
<< tr("Forms")
<< tr("Resources")
<< tr("Other files");
static QList<QIcon> fileTypeIcons;
if (fileTypeIcons.isEmpty()) {
QStringList iconPaths;
iconPaths << ":/qt4projectmanager/images/headers.png"
<< ":/qt4projectmanager/images/sources.png"
<< ":/qt4projectmanager/images/forms.png"
<< ":/qt4projectmanager/images/qt_qrc.png"
<< ":/qt4projectmanager/images/unknown.png";
foreach (const QString &iconPath, iconPaths) {
QIcon dirIcon;
Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
QPixmap dirIconPixmap = iconProvider->overlayIcon(QStyle::SP_DirIcon,
QIcon(iconPath),
QSize(16, 16));
dirIcon.addPixmap(dirIconPixmap);
fileTypeIcons.append(dirIcon);
}
}
const QString &projectDir = m_qt4ProFileNode->m_projectDir;
......@@ -140,8 +375,11 @@ void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
baseVPaths += reader->absolutePathValues("DEPENDPATH", projectDir);
baseVPaths.removeDuplicates();
InternalNode contents;
// update files
foreach (FileType type, fileTypes) {
for (int i = 0; i < fileTypes.size(); ++i) {
FileType type = fileTypes.at(i);
const QStringList qmakeVariables = varNames(type);
QStringList newFilePaths;
......@@ -157,47 +395,17 @@ void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
}
newFilePaths.removeDuplicates();
QList<FileNode*> existingFileNodes;
foreach (FileNode *fileNode, fileNodes()) {
if (fileNode->fileType() == type && !fileNode->isGenerated())
existingFileNodes << fileNode;
}
QList<FileNode*> toRemove;
QList<FileNode*> toAdd;
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, type, false);
++newPathIter;
} else { // *existingNodeIter->path() == *newPathIter
++existingNodeIter;
++newPathIter;
}
}
while (existingNodeIter != existingFileNodes.constEnd()) {
toRemove << *existingNodeIter;
++existingNodeIter;
}
while (newPathIter != newFilePaths.constEnd()) {
toAdd << new FileNode(*newPathIter, type, false);
++newPathIter;
if (!newFilePaths.isEmpty()) {
InternalNode *subfolder = new InternalNode;
subfolder->type = type;
subfolder->icon = fileTypeIcons.at(i);
subfolder->fullName = m_projectDir;
contents.subnodes.insert(fileTypeNames.at(i), subfolder);
// create the hierarchy with subdirectories
subfolder->create(m_projectDir, newFilePaths, type);
}
if (!toRemove.isEmpty())
removeFileNodes(toRemove, this);
if (!toAdd.isEmpty())
addFileNodes(toAdd, this);
}
contents.updateSubFolders(this, this);
}
QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions() const
......@@ -1084,7 +1292,7 @@ void Qt4ProFileNode::createUiCodeModelSupport()
foreach (FileNode *uiFile, uiFiles) {
QString uiHeaderFilePath
= QString("%1/ui_%2.h").arg(uiDir, QFileInfo(uiFile->path()).completeBaseName());
uiHeaderFilePath = QDir::cleanPath(uiHeaderFilePath);
uiHeaderFilePath = QDir::cleanPath(uiHeaderFilePath);
// qDebug()<<"code model support for "<<uiFile->path()<<" "<<uiHeaderFilePath;
QMap<QString, Qt4UiCodeModelSupport *>::iterator it = oldCodeModelSupport.find(uiFile->path());
......
......@@ -104,6 +104,7 @@ enum Qt4Variable {
class Qt4PriFileNode;
class Qt4ProFileNode;
struct InternalNode;
// Implements ProjectNode for qt4 pro files
class Qt4PriFileNode : public ProjectExplorer::ProjectNode
......@@ -175,6 +176,8 @@ private:
// managed by Qt4ProFileNode
friend class Qt4ProFileNode;
// internal temporary subtree representation
friend class InternalNode;
};
// Implements ProjectNode for qt4 pro files
......
<RCC>
<qresource prefix="/qt4projectmanager" >
<qresource prefix="/qt4projectmanager">
<file>images/window.png</file>
<file>images/run_qmake.png</file>
<file>images/run_qmake_small.png</file>
<file>images/qt_project.png</file>
<file>Qt4ProjectManager.mimetypes.xml</file>
<file>images/forms.png</file>
<file>images/headers.png</file>
<file>images/qt_qrc.png</file>
<file>images/sources.png</file>
<file>images/unknown.png</file>
</qresource>
</RCC>
SOURCES += $$PWD/sources/prifileinc.cpp
HEADERS += $$PWD/headers/prifileinc.h
#-------------------------------------------------
#
# Project created by QtCreator 2009-05-12T12:31:37
#
#-------------------------------------------------
TARGET = projecttree
TEMPLATE = app
include(prifile/prifile.pri)
SOURCES += main.cpp\
widget.cpp \
/etc/cups/cupsd.conf \
/etc/cups/printers.conf \
/etc/apache2/mime.types \
/etc/apache2/extra/httpd-info.conf \
../projecttree_data1/a/foo.cpp \
../projecttree_data1/b/foo.cpp \
../projecttree_data2/a/bar.cpp \
../projecttree_data2/a/sub/bar2.cpp \
../projecttree_data3/path/bar.cpp \
subpath/a/foo.cpp \
subpath/b/foo.cpp \
sub2/a/bar.cpp \
sub2/a/sub/bar2.cpp \
uniquesub/path/bar.cpp \
sources/foo.cpp \
sources/bar.cpp
HEADERS += main.h\
widget.h \
../projecttree_data1/a/foo.h \
../projecttree_data1/b/foo.h \
../projecttree_data2/a/bar.h \
../projecttree_data2/a/sub/bar2.h \
../projecttree_data3/path/bar.h \
subpath/a/foo.h \
subpath/b/foo.h \
sub2/a/bar.h \
sub2/a/sub/bar2.h \
uniquesub/path/bar.h \
headers/foo.h \
headers/bar.h
FORMS += widget.ui
RESOURCES += resource.qrc
OTHER_FILES += foo.txt
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment