From 7ebea974d69e0ca750ca77ea437e901936a7e8f5 Mon Sep 17 00:00:00 2001
From: con <qtc-committer@nokia.com>
Date: Mon, 17 Aug 2009 17:59:57 +0200
Subject: [PATCH] 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).
---
 src/plugins/projectexplorer/projectmodels.cpp |  10 +-
 src/plugins/projectexplorer/projectnodes.cpp  |  15 +-
 src/plugins/projectexplorer/projectnodes.h    |   3 +-
 .../qt4projectmanager/images/forms.png        | Bin 0 -> 311 bytes
 .../qt4projectmanager/images/headers.png      | Bin 0 -> 223 bytes
 .../qt4projectmanager/images/qt_qrc.png       | Bin 0 -> 676 bytes
 .../qt4projectmanager/images/sources.png      | Bin 0 -> 208 bytes
 .../qt4projectmanager/images/unknown.png      | Bin 0 -> 267 bytes
 src/plugins/qt4projectmanager/qt4nodes.cpp    | 290 +++++++++++++++---
 src/plugins/qt4projectmanager/qt4nodes.h      |   3 +
 .../qt4projectmanager/qt4projectmanager.qrc   |   7 +-
 .../qt4projectmanager/projecttree/foo.txt     |   0
 .../projecttree/headers/bar.h                 |   0
 .../projecttree/headers/foo.h                 |   0
 .../qt4projectmanager/projecttree/main.cpp    |   0
 .../qt4projectmanager/projecttree/main.h      |   0
 .../projecttree/prifile/headers/prifileinc.h  |   0
 .../projecttree/prifile/prifile.pri           |   2 +
 .../prifile/sources/prifileinc.cpp            |   0
 .../projecttree/projecttree.pro               |  48 +++
 .../projecttree/resource.qrc                  |   0
 .../projecttree/sources/bar.cpp               |   0
 .../projecttree/sources/foo.cpp               |   0
 .../projecttree/sub2/a/bar.cpp                |   0
 .../projecttree/sub2/a/bar.h                  |   0
 .../projecttree/sub2/a/sub/bar2.cpp           |   0
 .../projecttree/sub2/a/sub/bar2.h             |   0
 .../projecttree/subpath/a/foo.cpp             |   0
 .../projecttree/subpath/a/foo.h               |   0
 .../projecttree/subpath/b/foo.cpp             |   0
 .../projecttree/subpath/b/foo.h               |   0
 .../projecttree/uniquesub/path/bar.cpp        |   0
 .../projecttree/uniquesub/path/bar.h          |   0
 .../qt4projectmanager/projecttree/widget.cpp  |   0
 .../qt4projectmanager/projecttree/widget.h    |   0
 .../qt4projectmanager/projecttree/widget.ui   |   0
 .../projecttree_data1/a/foo.cpp               |   0
 .../projecttree_data1/a/foo.h                 |   0
 .../projecttree_data1/b/foo.cpp               |   0
 .../projecttree_data1/b/foo.h                 |   0
 .../projecttree_data2/a/bar.cpp               |   0
 .../projecttree_data2/a/bar.h                 |   0
 .../projecttree_data2/a/sub/bar2.cpp          |   0
 .../projecttree_data2/a/sub/bar2.h            |   0
 .../projecttree_data3/path/bar.cpp            |   0
 .../projecttree_data3/path/bar.h              |   0
 46 files changed, 329 insertions(+), 49 deletions(-)
 create mode 100644 src/plugins/qt4projectmanager/images/forms.png
 create mode 100644 src/plugins/qt4projectmanager/images/headers.png
 create mode 100644 src/plugins/qt4projectmanager/images/qt_qrc.png
 create mode 100644 src/plugins/qt4projectmanager/images/sources.png
 create mode 100644 src/plugins/qt4projectmanager/images/unknown.png
 create mode 100644 tests/manual/qt4projectmanager/projecttree/foo.txt
 create mode 100644 tests/manual/qt4projectmanager/projecttree/headers/bar.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree/headers/foo.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree/main.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree/main.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree/prifile/headers/prifileinc.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree/prifile/prifile.pri
 create mode 100644 tests/manual/qt4projectmanager/projecttree/prifile/sources/prifileinc.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree/projecttree.pro
 create mode 100644 tests/manual/qt4projectmanager/projecttree/resource.qrc
 create mode 100644 tests/manual/qt4projectmanager/projecttree/sources/bar.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree/sources/foo.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree/sub2/a/bar.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree/sub2/a/bar.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree/sub2/a/sub/bar2.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree/sub2/a/sub/bar2.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree/subpath/a/foo.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree/subpath/a/foo.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree/subpath/b/foo.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree/subpath/b/foo.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree/uniquesub/path/bar.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree/uniquesub/path/bar.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree/widget.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree/widget.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree/widget.ui
 create mode 100644 tests/manual/qt4projectmanager/projecttree_data1/a/foo.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree_data1/a/foo.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree_data1/b/foo.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree_data1/b/foo.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree_data2/a/bar.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree_data2/a/bar.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree_data2/a/sub/bar2.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree_data2/a/sub/bar2.h
 create mode 100644 tests/manual/qt4projectmanager/projecttree_data3/path/bar.cpp
 create mode 100644 tests/manual/qt4projectmanager/projecttree_data3/path/bar.h

diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp
index dcde9968e59..da793af74a8 100644
--- a/src/plugins/projectexplorer/projectmodels.cpp
+++ b/src/plugins/projectexplorer/projectmodels.cpp
@@ -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();
     }
diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp
index 6bd2205908b..7b7b54cf388 100644
--- a/src/plugins/projectexplorer/projectnodes.cpp
+++ b/src/plugins/projectexplorer/projectnodes.cpp
@@ -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();
 }
 
 /*!
diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h
index 958d524b048..cfd0d7ca49f 100644
--- a/src/plugins/projectexplorer/projectnodes.h
+++ b/src/plugins/projectexplorer/projectnodes.h
@@ -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
diff --git a/src/plugins/qt4projectmanager/images/forms.png b/src/plugins/qt4projectmanager/images/forms.png
new file mode 100644
index 0000000000000000000000000000000000000000..04059d99f0eb4db720066140f8b361ea24238d6c
GIT binary patch
literal 311
zcmV-70m%M|P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0002~Nkl<ZI1yuD
z7zKkk1pfd3&kS@PBR(er)rb*Nzz78Y(F|b(YP4ryuovGvg`<rLO%jERMKeeqXyBrN
zQ)^UKT)uYo8D0ZWOoMWOwp%~keIVfI!7YD3y!)~cn;M*A|Noy2JGUzQb8R%||D2?N
z+d!wV;#7<*0ko9~h=XoyPk1>im+QB`qtYWFKNMLFPBu^>D9}9jOfmhju!Q67oAnYo
z|Nk?v!8G6v1E59@phBH<hgTO%2=V{?_D_0(aKQ8FjEoGwU<Tl%fts~Wo;<m%sHo^s
zXlUpMAU_F+Ing!XbHV$aJ9irY{{5TF&(H4)P~&D`w0=i7003o{b!ZIJ#cBWm002ov
JPDHLkV1l=Gh4TOa

literal 0
HcmV?d00001

diff --git a/src/plugins/qt4projectmanager/images/headers.png b/src/plugins/qt4projectmanager/images/headers.png
new file mode 100644
index 0000000000000000000000000000000000000000..ff7797fa91aac20425d04c122debd96beb3ba4b2
GIT binary patch
literal 223
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`%RF5iLo5W76C_v{D>|fb$QWJO
z#d$=0gJ$|cwGO>+^BW&Z?~>>_&yoCKF~4Ny{e&O?|MM#|Ki>SG=l@zs2?>8=qrdvw
zZL8m^2;21<Sh}_S-`}|I$KUt=_j8s#Utef!@JIab|Ne!%D*jW%|NTv8xOMKs$#;jo
z<_0*cHs~={cWW>=ocnX;z=;py&y)mszwpU-sGVx~&(jlgz~BLUW&_iNx0ej~Tum6#
XL-g1G49GJFx|qS!)z4*}Q$iB}t7KXe

literal 0
HcmV?d00001

diff --git a/src/plugins/qt4projectmanager/images/qt_qrc.png b/src/plugins/qt4projectmanager/images/qt_qrc.png
new file mode 100644
index 0000000000000000000000000000000000000000..3643f37e1a3ede6454fe3d14224e6fc72f73a5db
GIT binary patch
literal 676
zcmV;V0$crwP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iXA|
z2`LYlwWpi_00JaQL_t(I%Y~CYOjA)5$A2Zj3@)HV;#Xo!@M~f~7d0^qkC+rfNgUC*
zIbh=8pbU<tiHYDsurN59+Cf(%I;kO{gCS{%#$sFPqwlpq-@EtR>p~yYDxTylH|PA$
z|D1nr%yAt47nw|^<;_|PKs!J>oyJ<*lB1)e3=a?g6A}T8F)hu;7yuH9#DPkh0Q*5o
zDFC{=yAOo41Bgh|WD#L|dmDg}k&y%M)7Aip2wH2j)@*HU5r!cX6BCS&kKb_DGR1g2
zZr!!aY74<}96Zlsb8{2db;;-R<Z?MSHZ~}gN(>EP3x&e<p#k16EG)bn8lc#4!CFhq
zaU4>q6vh~oQdFx|y1Kgf`0n+^x9Jz>SC*IN|Dt>vc(Sx&tL*?<Ym71YzK>E05#ddG
ze)d-4=-{abQvjr9XSjL$4r-^wmrtJ`K7RJ~GH|u60jSk#)a!M^FhoSiE`Jz2aqI|M
z8-mbKsaYz;EajhB`g%G6u0$?qt?_+7QX(P%)B`~bggY)}-%u{CqqIdS(`=*f`vgIN
zh(v(?-VUbj&onKboZB;@zqex#;CWutbP?fuK{0*z3}L8I%J6jY8<X)q^sa)rS3mXu
zK@ddE`&V$?9h9;tZTMBOR6K>&2Cc0Cl?aebCYz*=jg4{i__@XGYW`Z!q0YlvTgtwr
zT2*MV6wBfIu9d_Z-}2A6bT)PxxCcxEEazfeI2qMG2Ocf0*y3-LLyrbHi|Zl)0000<
KMNUMnLSTYYY$z50

literal 0
HcmV?d00001

diff --git a/src/plugins/qt4projectmanager/images/sources.png b/src/plugins/qt4projectmanager/images/sources.png
new file mode 100644
index 0000000000000000000000000000000000000000..60dc177b86430077a9413f4419cba0c2f9a1c979
GIT binary patch
literal 208
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`(>+}rLo5W76C_v{D>}3aB&b~L
zX<8vG9&h*e981W0<||vWZyt0gpAa{J!Eu80wzq}>o8vs^M=e;ycKq{y9-dzlzrFt6
zWU@)%3UA1VXHU;dJ9r(t5%HUE!ZfFA&QrJ>{KA~CwVY8q#lV>OZMlJO>CM~z%ya+S
zU#dG?G(qBG;|$SFslRuJ*Sktc{-4S4RW_o|;DTV9hN}s~Emh4pru3z6flg%bboFyt
I=akR{09qSS>Hq)$

literal 0
HcmV?d00001

diff --git a/src/plugins/qt4projectmanager/images/unknown.png b/src/plugins/qt4projectmanager/images/unknown.png
new file mode 100644
index 0000000000000000000000000000000000000000..0f2ad1818e23e7a6297b24ee61ffee458dc7fcb8
GIT binary patch
literal 267
zcmV+m0rdWfP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0002eNkl<ZI1$ZK
zI}U^(5PiFXa0+i=ZEK=79@Hy%4HG*pOib);Eo7EqBaPXWty~Ji0Pn**fE!12qxN4(
zKSJHKZA<IAp0112&X<iW%Rof_#xM-Hbim5<JbO@*BuLZL)qUUN=}$f^*mhM_D9aK`
zDHKHk21e2Q8(b1Fuh!audEGP(rfEVP$6O+)2TCiDA=Gt^ec#b_9i)`u1X4)XJY$Tv
z{*wb?)yRT50Vd(Wjoh{^><Ll`2WEmJ#&H~7f|oJoc}~l+IMrifWgD%-z5uinQ;s99
R82$hN002ovPDHLkV1mJIYp(zR

literal 0
HcmV?d00001

diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp
index 1b7f1ea2227..a47f43001ef 100644
--- a/src/plugins/qt4projectmanager/qt4nodes.cpp
+++ b/src/plugins/qt4projectmanager/qt4nodes.cpp
@@ -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());
diff --git a/src/plugins/qt4projectmanager/qt4nodes.h b/src/plugins/qt4projectmanager/qt4nodes.h
index 6a491dc6e4a..f1240e7cdda 100644
--- a/src/plugins/qt4projectmanager/qt4nodes.h
+++ b/src/plugins/qt4projectmanager/qt4nodes.h
@@ -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
diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.qrc b/src/plugins/qt4projectmanager/qt4projectmanager.qrc
index f733770e2f4..6b17ee4244e 100644
--- a/src/plugins/qt4projectmanager/qt4projectmanager.qrc
+++ b/src/plugins/qt4projectmanager/qt4projectmanager.qrc
@@ -1,9 +1,14 @@
 <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>
diff --git a/tests/manual/qt4projectmanager/projecttree/foo.txt b/tests/manual/qt4projectmanager/projecttree/foo.txt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/headers/bar.h b/tests/manual/qt4projectmanager/projecttree/headers/bar.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/headers/foo.h b/tests/manual/qt4projectmanager/projecttree/headers/foo.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/main.cpp b/tests/manual/qt4projectmanager/projecttree/main.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/main.h b/tests/manual/qt4projectmanager/projecttree/main.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/prifile/headers/prifileinc.h b/tests/manual/qt4projectmanager/projecttree/prifile/headers/prifileinc.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/prifile/prifile.pri b/tests/manual/qt4projectmanager/projecttree/prifile/prifile.pri
new file mode 100644
index 00000000000..5b1c723c8d2
--- /dev/null
+++ b/tests/manual/qt4projectmanager/projecttree/prifile/prifile.pri
@@ -0,0 +1,2 @@
+SOURCES += $$PWD/sources/prifileinc.cpp
+HEADERS += $$PWD/headers/prifileinc.h
diff --git a/tests/manual/qt4projectmanager/projecttree/prifile/sources/prifileinc.cpp b/tests/manual/qt4projectmanager/projecttree/prifile/sources/prifileinc.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/projecttree.pro b/tests/manual/qt4projectmanager/projecttree/projecttree.pro
new file mode 100644
index 00000000000..ec8fdc57013
--- /dev/null
+++ b/tests/manual/qt4projectmanager/projecttree/projecttree.pro
@@ -0,0 +1,48 @@
+#-------------------------------------------------
+#
+# 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
diff --git a/tests/manual/qt4projectmanager/projecttree/resource.qrc b/tests/manual/qt4projectmanager/projecttree/resource.qrc
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/sources/bar.cpp b/tests/manual/qt4projectmanager/projecttree/sources/bar.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/sources/foo.cpp b/tests/manual/qt4projectmanager/projecttree/sources/foo.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/sub2/a/bar.cpp b/tests/manual/qt4projectmanager/projecttree/sub2/a/bar.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/sub2/a/bar.h b/tests/manual/qt4projectmanager/projecttree/sub2/a/bar.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/sub2/a/sub/bar2.cpp b/tests/manual/qt4projectmanager/projecttree/sub2/a/sub/bar2.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/sub2/a/sub/bar2.h b/tests/manual/qt4projectmanager/projecttree/sub2/a/sub/bar2.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/subpath/a/foo.cpp b/tests/manual/qt4projectmanager/projecttree/subpath/a/foo.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/subpath/a/foo.h b/tests/manual/qt4projectmanager/projecttree/subpath/a/foo.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/subpath/b/foo.cpp b/tests/manual/qt4projectmanager/projecttree/subpath/b/foo.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/subpath/b/foo.h b/tests/manual/qt4projectmanager/projecttree/subpath/b/foo.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/uniquesub/path/bar.cpp b/tests/manual/qt4projectmanager/projecttree/uniquesub/path/bar.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/uniquesub/path/bar.h b/tests/manual/qt4projectmanager/projecttree/uniquesub/path/bar.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/widget.cpp b/tests/manual/qt4projectmanager/projecttree/widget.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/widget.h b/tests/manual/qt4projectmanager/projecttree/widget.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree/widget.ui b/tests/manual/qt4projectmanager/projecttree/widget.ui
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree_data1/a/foo.cpp b/tests/manual/qt4projectmanager/projecttree_data1/a/foo.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree_data1/a/foo.h b/tests/manual/qt4projectmanager/projecttree_data1/a/foo.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree_data1/b/foo.cpp b/tests/manual/qt4projectmanager/projecttree_data1/b/foo.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree_data1/b/foo.h b/tests/manual/qt4projectmanager/projecttree_data1/b/foo.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree_data2/a/bar.cpp b/tests/manual/qt4projectmanager/projecttree_data2/a/bar.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree_data2/a/bar.h b/tests/manual/qt4projectmanager/projecttree_data2/a/bar.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree_data2/a/sub/bar2.cpp b/tests/manual/qt4projectmanager/projecttree_data2/a/sub/bar2.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree_data2/a/sub/bar2.h b/tests/manual/qt4projectmanager/projecttree_data2/a/sub/bar2.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree_data3/path/bar.cpp b/tests/manual/qt4projectmanager/projecttree_data3/path/bar.cpp
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/manual/qt4projectmanager/projecttree_data3/path/bar.h b/tests/manual/qt4projectmanager/projecttree_data3/path/bar.h
new file mode 100644
index 00000000000..e69de29bb2d
-- 
GitLab