diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index 2c9f24cf48f7469b701de70cee8eeb945e1a8ed7..7cc4087a8e40d7ad5daa3782ac915d6755a389c2 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -426,6 +426,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
     cmd = am->registerAction(m_showInFinder, ProjectExplorer::Constants::SHOWINFINDER,
                        globalcontext);
     mfilec->addAction(cmd, Constants::G_FILE_OPEN);
+    mfolder->addAction(cmd, Constants::G_FOLDER_FILES);
 #endif
 
     // Open With menu
@@ -592,6 +593,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
                        globalcontext);
     mproject->addAction(cmd, Constants::G_PROJECT_FILES);
     msubProject->addAction(cmd, Constants::G_PROJECT_FILES);
+    mfolder->addAction(cmd, Constants::G_FOLDER_FILES);
 
     // add existing file action
     m_addExistingFilesAction = new QAction(tr("Add Existing Files..."), this);
@@ -599,6 +601,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
                        globalcontext);
     mproject->addAction(cmd, Constants::G_PROJECT_FILES);
     msubProject->addAction(cmd, Constants::G_PROJECT_FILES);
+    mfolder->addAction(cmd, Constants::G_FOLDER_FILES);
 
     // remove file action
     m_removeFileAction = new QAction(tr("Remove File..."), this);
@@ -1676,9 +1679,9 @@ void ProjectExplorerPlugin::updateContextMenuActions()
 
 void ProjectExplorerPlugin::addNewFile()
 {
-    if (!m_currentNode && m_currentNode->nodeType() == ProjectNodeType)
-        return;
-    const QString location = QFileInfo(m_currentNode->path()).dir().absolutePath();
+    QTC_ASSERT(m_currentNode, return)
+    QFileInfo fi(m_currentNode->path());
+    const QString location = (fi.isDir() ? fi.absoluteFilePath() : fi.absolutePath());
     Core::ICore::instance()->showNewItemDialog(tr("New File", "Title of dialog"),
                               Core::IWizard::wizardsOfKind(Core::IWizard::FileWizard)
                               + Core::IWizard::wizardsOfKind(Core::IWizard::ClassWizard),
@@ -1687,11 +1690,12 @@ void ProjectExplorerPlugin::addNewFile()
 
 void ProjectExplorerPlugin::addExistingFiles()
 {
-    if (!m_currentNode && m_currentNode->nodeType() == ProjectNodeType)
-        return;
-    ProjectNode *projectNode = qobject_cast<ProjectNode*>(m_currentNode);
+    QTC_ASSERT(m_currentNode, return)
+
+    ProjectNode *projectNode = qobject_cast<ProjectNode*>(m_currentNode->projectNode());
     Core::ICore *core = Core::ICore::instance();
-    const QString dir = QFileInfo(m_currentNode->path()).dir().absolutePath();
+    QFileInfo fi(m_currentNode->path());
+    const QString dir = (fi.isDir() ? fi.absoluteFilePath() : fi.absolutePath());
     QStringList fileNames = QFileDialog::getOpenFileNames(core->mainWindow(), tr("Add Existing Files"), dir);
     if (fileNames.isEmpty())
         return;
@@ -1741,8 +1745,7 @@ void ProjectExplorerPlugin::addExistingFiles()
 
 void ProjectExplorerPlugin::openFile()
 {
-    if (!m_currentNode)
-        return;
+    QTC_ASSERT(m_currentNode, return)
     Core::EditorManager *em = Core::EditorManager::instance();
     em->openEditor(m_currentNode->path());
     em->ensureEditorManagerVisible();
@@ -1751,8 +1754,7 @@ void ProjectExplorerPlugin::openFile()
 #ifdef Q_OS_MAC
 void ProjectExplorerPlugin::showInFinder()
 {
-    if (!m_currentNode)
-        return;
+    QTC_ASSERT(m_currentNode, return)
     QProcess::execute("/usr/bin/osascript", QStringList()
                       << "-e"
                       << QString("tell application \"Finder\" to reveal POSIX file \"%1\"")
@@ -1765,8 +1767,7 @@ void ProjectExplorerPlugin::showInFinder()
 
 void ProjectExplorerPlugin::removeFile()
 {
-    if (!m_currentNode && m_currentNode->nodeType() == FileNodeType)
-        return;
+    QTC_ASSERT(m_currentNode && m_currentNode->nodeType() == FileNodeType, return)
 
     FileNode *fileNode = qobject_cast<FileNode*>(m_currentNode);
     Core::ICore *core = Core::ICore::instance();
@@ -1937,7 +1938,7 @@ void ProjectExplorerPlugin::populateOpenWithMenu()
             }
         } // matches
     }
-    m_openWithMenu->setEnabled(anyMatches);   
+    m_openWithMenu->setEnabled(anyMatches);
 }
 
 void ProjectExplorerPlugin::openWithMenuTriggered(QAction *action)
diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp
index dcde9968e59e52bda4c658319f2435c4a7de6698..da793af74a83eb705fab463faa22042141703085 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 6bd2205908b27a73662cacfac1a39bc2e1b532d6..7b7b54cf388e50d5daff8358e1b9a81546215810 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 958d524b048d0d2aa798c6e94acfac4a49b1ee1f..cfd0d7ca49f0be3f8121949285e2eaa1c5d98a78 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
Binary files /dev/null and b/src/plugins/qt4projectmanager/images/forms.png differ
diff --git a/src/plugins/qt4projectmanager/images/headers.png b/src/plugins/qt4projectmanager/images/headers.png
new file mode 100644
index 0000000000000000000000000000000000000000..ff7797fa91aac20425d04c122debd96beb3ba4b2
Binary files /dev/null and b/src/plugins/qt4projectmanager/images/headers.png differ
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
Binary files /dev/null and b/src/plugins/qt4projectmanager/images/qt_qrc.png differ
diff --git a/src/plugins/qt4projectmanager/images/sources.png b/src/plugins/qt4projectmanager/images/sources.png
new file mode 100644
index 0000000000000000000000000000000000000000..60dc177b86430077a9413f4419cba0c2f9a1c979
Binary files /dev/null and b/src/plugins/qt4projectmanager/images/sources.png differ
diff --git a/src/plugins/qt4projectmanager/images/unknown.png b/src/plugins/qt4projectmanager/images/unknown.png
new file mode 100644
index 0000000000000000000000000000000000000000..0f2ad1818e23e7a6297b24ee61ffee458dc7fcb8
Binary files /dev/null and b/src/plugins/qt4projectmanager/images/unknown.png differ
diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp
index 1b7f1ea22270db833158819bbb77e9bf5bb92a18..a47f43001efbd7bed506cedb77c1d7a61ed46ade 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 6a491dc6e4a3ebe9bb723922666d9139d5600384..f1240e7cdda174167a0f2f5aa7f2a45e15135c9a 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 f733770e2f4ec0cfdd07971989e6bfbe07f2a600..6b17ee4244e1e1633e8712c5db59c78e13396c4d 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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/headers/bar.h b/tests/manual/qt4projectmanager/projecttree/headers/bar.h
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/headers/foo.h b/tests/manual/qt4projectmanager/projecttree/headers/foo.h
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/main.cpp b/tests/manual/qt4projectmanager/projecttree/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/main.h b/tests/manual/qt4projectmanager/projecttree/main.h
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/prifile/prifile.pri b/tests/manual/qt4projectmanager/projecttree/prifile/prifile.pri
new file mode 100644
index 0000000000000000000000000000000000000000..5b1c723c8d29cbeb5b7becb753dc9b9da5da91c4
--- /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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/projecttree.pro b/tests/manual/qt4projectmanager/projecttree/projecttree.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ec8fdc57013e9081300563bef03d5aef74800915
--- /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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/sources/bar.cpp b/tests/manual/qt4projectmanager/projecttree/sources/bar.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/sources/foo.cpp b/tests/manual/qt4projectmanager/projecttree/sources/foo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/widget.cpp b/tests/manual/qt4projectmanager/projecttree/widget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/widget.h b/tests/manual/qt4projectmanager/projecttree/widget.h
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/qt4projectmanager/projecttree/widget.ui b/tests/manual/qt4projectmanager/projecttree/widget.ui
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/manual/trk/adapter.cpp b/tests/manual/trk/adapter.cpp
index 18d06b5bd131b3d1e7e47805605b1a4d7952d22a..dda0bb43fd66a5bd061128425b4cd86b0852c197 100644
--- a/tests/manual/trk/adapter.cpp
+++ b/tests/manual/trk/adapter.cpp
@@ -28,6 +28,7 @@
 **************************************************************************/
 
 #include "trkutils.h"
+#include "trkdevice.h"
 
 #include <QtCore/QPointer>
 #include <QtCore/QCoreApplication>
@@ -40,50 +41,6 @@
 #include <QtNetwork/QLocalServer>
 #include <QtNetwork/QLocalSocket>
 
-#ifdef Q_OS_WIN
-#include <windows.h>
-
-// Non-blocking replacement for win-api ReadFile function
-BOOL WINAPI TryReadFile(HANDLE          hFile,
-                        LPVOID          lpBuffer,
-                        DWORD           nNumberOfBytesToRead,
-                        LPDWORD         lpNumberOfBytesRead,
-                        LPOVERLAPPED    lpOverlapped)
-{
-    COMSTAT comStat;
-    if(!ClearCommError(hFile, NULL, &comStat)){
-        qDebug() << "ClearCommError() failed";
-        return FALSE;
-    }
-    if (!comStat.cbInQue)
-        return FALSE;
-    return ReadFile(hFile,
-                    lpBuffer,
-                    qMin(comStat.cbInQue, nNumberOfBytesToRead),
-                    lpNumberOfBytesRead,
-                    lpOverlapped);
-}
-
-// Format windows error from GetLastError() value.
-QString winErrorMessage(unsigned long error)
-{
-    QString rc = QString::fromLatin1("#%1: ").arg(error);
-    ushort *lpMsgBuf;
-
-    const int len = FormatMessage(
-            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-            NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
-    if (len) {
-        rc = QString::fromUtf16(lpMsgBuf, len);
-        LocalFree(lpMsgBuf);
-    } else {
-        rc += QString::fromLatin1("<unknown error>");
-    }
-    return rc;
-}
-
-#endif
-
 #ifdef Q_OS_UNIX
 
 #include <signal.h>
@@ -97,9 +54,6 @@ void signalHandler(int)
 
 using namespace trk;
 
-enum { TRK_SYNC = 0x7f };
-
-
 enum { KnownRegisters = RegisterPSGdb + 1};
 
 static const char *registerNames[KnownRegisters] =
@@ -137,13 +91,13 @@ struct AdapterOptions {
     QString trkServer;
 };
 
-#define CB(s) &Adapter::s
-
 class Adapter : public QObject
 {
     Q_OBJECT
 
 public:
+    typedef TrkFunctor1<const TrkResult &> Callback;
+
     Adapter();
     ~Adapter();
     void setGdbServerName(const QString &name);
@@ -154,38 +108,22 @@ public:
     void setUseSocket(bool s) { m_useSocket = s; }
     bool startServer();
 
+private slots:
+    void handleResult(const trk::TrkResult &data);
+
 private:
     //
     // TRK
     //
-    Q_SLOT void readFromTrk();
-
-    typedef void (Adapter::*TrkCallBack)(const TrkResult &);
-
-    struct TrkMessage
-    {
-        TrkMessage() : code(0), token(0), callBack(0), invokeOnFailure(0) {}
-        byte code;
-        byte token;
-        QByteArray data;
-        QVariant cookie;
-        TrkCallBack callBack;
-        bool invokeOnFailure;
-    };
 
     bool openTrkPort(const QString &port, QString *errorMessage); // or server name for local server
     void sendTrkMessage(byte code,
-        TrkCallBack calBack = 0,
+        Callback callBack = Callback(),
         const QByteArray &data = QByteArray(),
         const QVariant &cookie = QVariant(),
         bool invokeOnFailure = false);
-    // adds message to 'send' queue
-    void queueTrkMessage(const TrkMessage &msg);
-    void tryTrkWrite();
-    void tryTrkRead();
-    // actually writes a message to the device
-    void trkWrite(const TrkMessage &msg);
-    // convienience messages
+
+    // convenience messages
     void sendTrkInitialPing();
     void sendTrkContinue();
     void waitForTrkFinished();
@@ -194,10 +132,7 @@ private:
     // kill process and breakpoints
     void cleanUp();
 
-    void timerEvent(QTimerEvent *ev);
-    byte nextTrkWriteToken();
-
-    void handleCpuType(const TrkResult &result);
+   void handleCpuType(const TrkResult &result);
     void handleCreateProcess(const TrkResult &result);
     void handleClearBreakpoint(const TrkResult &result);
     void handleSignalContinue(const TrkResult &result);
@@ -216,25 +151,17 @@ private:
     void reportToGdb(const TrkResult &result);
 
     void clearTrkBreakpoint(const Breakpoint &bp);
-    void handleResult(const TrkResult &data);
     void readMemory(uint addr, uint len);
     void startInferiorIfNeeded();
     void interruptInferior();
 
-#ifdef Q_OS_WIN
-    HANDLE m_winComDevice;
-#endif
-     QLocalSocket *m_socketDevice;
+    QSharedPointer<TrkWriteQueueDevice> m_trkDevice;
+    QSharedPointer<QIODevice> m_socket;
+    QSharedPointer<TrkWriteQueueIODevice> m_socketDevice;
 
     QString m_trkServerName;
     QByteArray m_trkReadBuffer;
 
-    unsigned char m_trkWriteToken;
-    QQueue<TrkMessage> m_trkWriteQueue;
-    QHash<byte, TrkMessage> m_writtenTrkMessages;
-    QByteArray m_trkReadQueue;
-    bool m_trkWriteBusy;
-
     QList<Breakpoint> m_breakpoints;
 
     //
@@ -268,12 +195,6 @@ private:
 };
 
 Adapter::Adapter() :
-#ifdef Q_OS_WIN
-    m_winComDevice(NULL),
-#endif
-    m_socketDevice(0),
-    m_trkWriteToken(0),
-    m_trkWriteBusy(false),
     m_gdbConnection(0),
     m_gdbServerPort(0),
     m_gdbAckMode(true),
@@ -283,20 +204,14 @@ Adapter::Adapter() :
     m_serialFrame(true),
     m_startInferiorTriggered(false)
 {
-    startTimer(100);
 }
 
 Adapter::~Adapter()
 {
     // Trk
-#ifdef Q_OS_WIN
-    if (m_winComDevice)
-        CloseHandle(m_winComDevice);
-#endif
-    if (m_socketDevice) {
-        m_socketDevice->abort();
-        delete m_socketDevice;
-    }
+    if (!m_socket.isNull())
+        if (QLocalSocket *sock = qobject_cast<QLocalSocket *>(m_socket.data()))
+            sock->abort();
 
     // Gdb
     m_gdbServer.close();
@@ -325,9 +240,9 @@ bool Adapter::startServer()
 
     sendTrkInitialPing();
     sendTrkMessage(0x01); // Connect
-    sendTrkMessage(0x05, CB(handleSupportMask));
-    sendTrkMessage(0x06, CB(handleCpuType));
-    sendTrkMessage(0x04, CB(handleTrkVersions)); // Versions
+    sendTrkMessage(0x05, Callback(this, &Adapter::handleSupportMask));
+    sendTrkMessage(0x06, Callback(this, &Adapter::handleCpuType));
+    sendTrkMessage(0x04, Callback(this, &Adapter::handleTrkVersions)); // Versions
     //sendTrkMessage(0x09); // Unrecognized command
     //sendTrkMessage(0x4a, 0,
     //    "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File
@@ -491,7 +406,7 @@ void Adapter::sendGdbMessage(const QByteArray &msg, const QByteArray &logNote)
 void Adapter::sendGdbMessageAfterSync(const QByteArray &msg, const QByteArray &logNote)
 {
     QByteArray ba = msg + char(1) + logNote;
-    sendTrkMessage(TRK_SYNC, CB(reportToGdb), "", ba); // Answer gdb
+    sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, Callback(this, &Adapter::reportToGdb), "", ba); // Answer gdb
 }
 
 void Adapter::reportToGdb(const TrkResult &result)
@@ -545,7 +460,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         appendInt(&ba, 0); // end address
         appendInt(&ba, m_session.pid);
         appendInt(&ba, m_session.tid);
-        sendTrkMessage(0x18, 0, ba);
+        sendTrkMessage(0x18, Callback(), ba);
         // FIXME: should be triggered by real stop
         //sendGdbMessageAfterSync("S11", "target stopped");
     }
@@ -561,7 +476,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         QByteArray ba;
         appendInt(&ba, m_session.pid);
         appendInt(&ba, m_session.tid);
-        sendTrkMessage(0x18, CB(handleSignalContinue), ba, signalNumber); // Continue
+        sendTrkMessage(0x18, Callback(this, &Adapter::handleSignalContinue), ba, signalNumber); // Continue
     }
 
     else if (response.startsWith("D")) {
@@ -582,7 +497,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         appendShort(&ba, RegisterCount - 1); // last register
         appendInt(&ba, m_session.pid);
         appendInt(&ba, m_session.tid);
-        sendTrkMessage(0x12, CB(handleAndReportReadRegisters), ba, QVariant(), true);
+        sendTrkMessage(0x12, Callback(this, &Adapter::handleAndReportReadRegisters), ba, QVariant(), true);
     }
 
     else if (response.startsWith("Hc")) {
@@ -615,7 +530,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         QByteArray ba;
         appendByte(&ba, 0); // Sub-command: Delete Process
         appendInt(&ba, m_session.pid);
-        sendTrkMessage(0x41, 0, ba, "Delete process"); // Delete Item
+        sendTrkMessage(0x41, Callback(), ba, "Delete process"); // Delete Item
         sendGdbMessageAfterSync("", "process killed");
     }
 
@@ -793,7 +708,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address
         appendInt(&ba, m_session.pid);
         appendInt(&ba, m_session.tid);
-        sendTrkMessage(0x19, 0, ba, "Step range");
+        sendTrkMessage(0x19, Callback(), ba, "Step range");
         // FIXME: should be triggered by "real" stop"
         //sendGdbMessageAfterSync("S05", "target halted");
     }
@@ -815,7 +730,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         QByteArray ba;
         appendByte(&ba, 0); // Sub-command: Delete Process
         appendInt(&ba, m_session.pid);
-        sendTrkMessage(0x41, 0, ba, "Delete process"); // Delete Item
+        sendTrkMessage(0x41, Callback(), ba, "Delete process"); // Delete Item
         sendGdbMessageAfterSync("", "process killed");
     }
 
@@ -850,7 +765,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         appendInt(&ba, m_session.pid);
         appendInt(&ba, 0xFFFFFFFF);
 
-        sendTrkMessage(0x1B, CB(handleAndReportSetBreakpoint), ba);
+        sendTrkMessage(0x1B, Callback(this, &Adapter::handleAndReportSetBreakpoint), ba);
         //m_session.toekn
 
         //---TRK------------------------------------------------------
@@ -864,95 +779,47 @@ void Adapter::handleGdbResponse(const QByteArray &response)
     }
 }
 
-void Adapter::readFromTrk()
-{
-    //QByteArray ba = m_gdbConnection->readAll();
-    //logMessage("Read from gdb: " + ba);
-}
-
 bool Adapter::openTrkPort(const QString &port, QString *errorMessage)
 {
     if (m_useSocket) {
-        m_socketDevice = new QLocalSocket(this);
-        m_socketDevice->connectToServer(port);
-        const bool rc = m_socketDevice->waitForConnected();
-        if (!rc)
-            *errorMessage = "Unable to connect to TRK server " + m_trkServerName + ' ' + m_socketDevice->errorString();
-        return rc;
-    }
-#ifdef Q_OS_WIN
-    m_winComDevice = CreateFile(port.toStdWString().c_str(),
-                           GENERIC_READ | GENERIC_WRITE,
-                           0,
-                           NULL,
-                           OPEN_EXISTING,
-                           FILE_ATTRIBUTE_NORMAL,
-                           NULL);
-
-    if (INVALID_HANDLE_VALUE == m_winComDevice){
-        *errorMessage = "Could not open device " + port + ' ' + winErrorMessage(GetLastError());
-        return false;
-     }
-    return true;
-#else
-    logMessage("Not implemented", true);
-    return false;
-#endif
-
-#if 0
-    m_socketDevice = new Win_QextSerialPort(port);
-    m_socketDevice->setBaudRate(BAUD115200);
-    m_socketDevice->setDataBits(DATA_8);
-    m_socketDevice->setParity(PAR_NONE);
-    //m_socketDevice->setStopBits(STO);
-    m_socketDevice->setFlowControl(FLOW_OFF);
-    m_socketDevice->setTimeout(0, 500);
-
-    if (!m_socketDevice->open(QIODevice::ReadWrite)) {
-        QByteArray ba = m_socketDevice->errorString().toLatin1();
-        logMessage("Could not open device " << ba);
-        return false;
+        QLocalSocket *socket = new QLocalSocket;
+        socket->connectToServer(port);
+        if (!socket->waitForConnected()) {
+            *errorMessage = "Unable to connect to TRK server " + m_trkServerName + ' ' + m_socket->errorString();
+            delete socket;
+            return false;
+        }
+        m_socket = QSharedPointer<QIODevice>(socket);
+        m_socketDevice = QSharedPointer<TrkWriteQueueIODevice>(new TrkWriteQueueIODevice(m_socket));
+        connect(m_socketDevice.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult)));
+        if (m_verbose > 1)
+            m_socketDevice->setVerbose(true);
+        m_socketDevice->setSerialFrame(m_serialFrame);
+        return true;
     }
-    return true
-#endif
+    m_trkDevice = QSharedPointer<TrkWriteQueueDevice>(new TrkWriteQueueDevice);
+    connect(m_trkDevice.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult)));
+    if (m_verbose > 1)
+        m_trkDevice->setVerbose(true);
+    m_trkDevice->setSerialFrame(m_serialFrame);
+    return m_trkDevice->open(port, errorMessage);
 }
 
-void Adapter::timerEvent(QTimerEvent *)
-{
-    //qDebug(".");
-    tryTrkWrite();
-    tryTrkRead();
-}
-
-byte Adapter::nextTrkWriteToken()
-{
-    ++m_trkWriteToken;
-    if (m_trkWriteToken == 0)
-        ++m_trkWriteToken;
-    return m_trkWriteToken;
-}
-
-void Adapter::sendTrkMessage(byte code, TrkCallBack callBack,
+void Adapter::sendTrkMessage(byte code, Callback callBack,
     const QByteArray &data, const QVariant &cookie, bool invokeOnFailure)
 {
-    TrkMessage msg;
-    msg.code = code;
-    // Tokens must be strictly sequential
-    if (msg.code != TRK_SYNC)
-        msg.token = nextTrkWriteToken();
-    msg.callBack = callBack;
-    msg.data = data;
-    msg.cookie = cookie;
-    msg.invokeOnFailure = invokeOnFailure;
-    queueTrkMessage(msg);
+    if (m_useSocket)
+        m_socketDevice->sendTrkMessage(code, callBack, data, cookie, invokeOnFailure);
+    else
+        m_trkDevice->sendTrkMessage(code, callBack, data, cookie, invokeOnFailure);
 }
 
 void Adapter::sendTrkInitialPing()
 {
-    TrkMessage msg;
-    msg.code = 0x00; // Ping
-    msg.token = 0; // reset sequence count
-    queueTrkMessage(msg);
+    if (m_useSocket)
+        m_socketDevice->sendTrkInitialPing();
+    else
+        m_trkDevice->sendTrkInitialPing();
 }
 
 void Adapter::sendTrkContinue()
@@ -960,165 +827,39 @@ void Adapter::sendTrkContinue()
     QByteArray ba;
     appendInt(&ba, m_session.pid);
     appendInt(&ba, m_session.tid);
-    sendTrkMessage(0x18, 0, ba, "CONTINUE");
+    sendTrkMessage(0x18, Callback(), ba, "CONTINUE");
 }
 
 void Adapter::waitForTrkFinished()
 {
-    TrkMessage msg;
     // initiate one last roundtrip to ensure all is flushed
-    msg.code = 0x00; // Ping
-    msg.token = nextTrkWriteToken();
-    msg.callBack = CB(handleWaitForFinished);
-    queueTrkMessage(msg);
+    sendTrkMessage(0x0, Callback(this, &Adapter::handleWaitForFinished));
 }
 
 void Adapter::sendTrkAck(byte token)
 {
     logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token)));
-    TrkMessage msg;
-    msg.code = 0x80;
-    msg.token = token;
-    msg.data.append('\0');
-    // The acknowledgement must not be queued!
-    //queueMessage(msg);
-    trkWrite(msg);
-    // 01 90 00 07 7e 80 01 00 7d 5e 7e
+    if (m_useSocket)
+        m_socketDevice->sendTrkAck(token);
+    else
+        m_trkDevice->sendTrkAck(token);
 }
 
-void Adapter::queueTrkMessage(const TrkMessage &msg)
-{
-    m_trkWriteQueue.append(msg);
-}
-
-void Adapter::tryTrkWrite()
-{
-    if (m_trkWriteBusy)
-        return;
-    if (m_trkWriteQueue.isEmpty())
-        return;
-
-    TrkMessage msg = m_trkWriteQueue.dequeue();
-    if (msg.code == TRK_SYNC) {
-        logMessage(QString::fromLatin1("TRK SYNC [token=%1]").arg(msg.token));
-        TrkResult result;
-        result.code = msg.code;
-        result.token = msg.token;
-        result.data = msg.data;
-        result.cookie = msg.cookie;
-        TrkCallBack cb = msg.callBack;
-        if (cb)
-            (this->*cb)(result);
-    } else {
-        trkWrite(msg);
-    }
-}
-
-void Adapter::trkWrite(const TrkMessage &msg)
-{
-    QByteArray ba = frameMessage(msg.code, msg.token, msg.data, m_serialFrame);
-
-    m_writtenTrkMessages.insert(msg.token, msg);
-    m_trkWriteBusy = true;
-
-    if (m_verbose > 1) {
-        const QString logMsg = QString::fromLatin1("WRITE: 0x%1 [token=%2]: %3").arg(msg.code, 0, 16).arg(msg.token).arg(stringFromArray(ba));
-        logMessage(logMsg);
-    }
-
-    if (m_useSocket) {
-        if (!m_socketDevice->write(ba))
-            logMessage("WRITE ERROR: " + m_socketDevice->errorString());
-        m_socketDevice->flush();
-    } else {
-#ifdef Q_OS_WIN
-        DWORD charsWritten;
-        if (!WriteFile(m_winComDevice, ba.data(), ba.size(), &charsWritten, NULL))
-            logMessage("WRITE ERROR: " + winErrorMessage(GetLastError()));
-        FlushFileBuffers(m_winComDevice);
-#endif
-    }
-}
-
-void Adapter::tryTrkRead()
+void Adapter::handleResult(const TrkResult &result)
 {
-    //logMessage("TRY READ: " << m_socketDevice->bytesAvailable()
-    //        << stringFromArray(m_trkReadQueue);
-    if (m_useSocket) {
-        if (m_socketDevice->bytesAvailable() == 0 && m_trkReadQueue.isEmpty())
-            return;
-
-        QByteArray res = m_socketDevice->readAll();
-        m_trkReadQueue.append(res);
-    } else {
-#ifdef Q_OS_WIN
-        const DWORD BUFFERSIZE = 1024;
-        char buffer[BUFFERSIZE];
-        DWORD charsRead;
-        DWORD totalCharsRead = 0;
-        while (TryReadFile(m_winComDevice, buffer, BUFFERSIZE, &charsRead, NULL)) {
-            m_trkReadQueue.append(buffer, charsRead);
-            totalCharsRead += charsRead;
-            if (isValidTrkResult(m_trkReadQueue, m_serialFrame))
-                break;
-        }
-        if (!totalCharsRead)
-            return;
-#endif // USE_NATIVE
-    }
-
-    if (m_trkReadQueue.size() < 9) {
-        logMessage("ERROR READBUFFER INVALID (1): "
-            + stringFromArray(m_trkReadQueue));
-        m_trkReadQueue.clear();
+    if (result.isDebugOutput) {
+        logMessage(QLatin1String("APPLICATION OUTPUT: ") + QString::fromAscii(result.data));
         return;
     }
-
-    TrkResult r;
-    while (extractResult(&m_trkReadQueue, m_serialFrame, &r))
-        handleResult(r);
-
-    m_trkWriteBusy = false;
-}
-
-
-void Adapter::handleResult(const TrkResult &result)
-{
     QByteArray prefix = "READ BUF:                                       ";
     QByteArray str = result.toString().toUtf8();
     switch (result.code) {
-        case 0x80: { // ACK
-            //logMessage(prefix + "ACK: " + str);
-            if (const int ec = result.errorCode())
-                logMessage(QString::fromLatin1("READ BUF ACK/ERR %1 for token=%2").arg(ec).arg(result.token), true);
-            if (!m_writtenTrkMessages.contains(result.token)) {
-                logMessage("NO ENTRY FOUND!");
-            }
-            TrkMessage msg = m_writtenTrkMessages.take(result.token);
-            TrkResult result1 = result;
-            result1.cookie = msg.cookie;
-            TrkCallBack cb = msg.callBack;
-            if (cb) {
-                (this->*cb)(result1);
-            } else {
-                QString msg = result.cookie.toString();
-                if (!msg.isEmpty())
-                    logMessage("HANDLE: " + msg + stringFromArray(result.data));
-            }
+        case 0x80: // ACK
             break;
-        }
         case 0xff: { // NAK. This mostly means transmission error, not command failed.
-            const TrkMessage writtenMsg = m_writtenTrkMessages.take(result.token);
             QString logMsg;
-            QTextStream(&logMsg) << prefix << "NAK: for 0x" << QString::number(int(writtenMsg.code), 16)
-                    << " token=" << result.token << " ERROR: " << errorMessage(result.data.at(0)) << ' ' << str;
+            QTextStream(&logMsg) << prefix << "NAK: for token=" << result.token << " ERROR: " << errorMessage(result.data.at(0)) << ' ' << str;
             logMessage(logMsg, true);
-            // Invoke failure if desired
-            if (writtenMsg.callBack && writtenMsg.invokeOnFailure) {
-                TrkResult result1 = result;
-                result1.cookie = writtenMsg.cookie;
-                (this->*writtenMsg.callBack)(result1);
-            }
             break;
         }
         case 0x90: { // Notified Stopped
@@ -1258,10 +999,10 @@ void Adapter::handleCreateProcess(const TrkResult &result)
     //  Command: 0x42 Read Info
     //          [42 0C 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F
     //  72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00]
-    sendTrkMessage(0x42, CB(handleReadInfo),
+    sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo),
         "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F "
         "72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00");
-    //sendTrkMessage(0x42, CB(handleReadInfo),
+    //sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo),
     //        "00 01 00 00 00 00");
     //---TRK------------------------------------------------------
     //  Command: 0x80 Acknowledge
@@ -1273,7 +1014,7 @@ void Adapter::handleCreateProcess(const TrkResult &result)
     //  Command: 0x42 Read Info
     // [42 0D 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F
     //  72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00]
-    sendTrkMessage(0x42, CB(handleReadInfo),
+    sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo),
         "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F "
         "72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00");
     //---TRK------------------------------------------------------
@@ -1282,7 +1023,7 @@ void Adapter::handleCreateProcess(const TrkResult &result)
     // [80 0D 20]
 #endif
 
-    //sendTrkMessage(0x18, CB(handleStop),
+    //sendTrkMessage(0x18, Callback(this, &Adapter::handleStop),
     //    "01 " + formatInt(m_session.pid) + formatInt(m_session.tid));
 
     //---IDE------------------------------------------------------
@@ -1293,8 +1034,8 @@ void Adapter::handleCreateProcess(const TrkResult &result)
     QByteArray ba;
     appendInt(&ba, m_session.pid);
     appendInt(&ba, m_session.tid);
-    sendTrkMessage(0x18, CB(handleContinue), ba);
-    //sendTrkMessage(0x18, CB(handleContinue),
+    sendTrkMessage(0x18, Callback(this, &Adapter::handleContinue), ba);
+    //sendTrkMessage(0x18, Callback(this, &Adapter::handleContinue),
     //    formatInt(m_session.pid) + "ff ff ff ff");
     //---TRK------------------------------------------------------
     //  Command: 0x80 Acknowledge
@@ -1423,7 +1164,7 @@ void Adapter::clearTrkBreakpoint(const Breakpoint &bp)
     appendByte(&ba, 0x00);
     appendShort(&ba, bp.number);
     appendInt(&ba, m_session.codeseg + bp.offset);
-    sendTrkMessage(0x1C, CB(handleClearBreakpoint), ba);
+    sendTrkMessage(0x1C, Callback(this, &Adapter::handleClearBreakpoint), ba);
 }
 
 void Adapter::handleClearBreakpoint(const TrkResult &result)
@@ -1497,7 +1238,7 @@ void Adapter::cleanUp()
     appendByte(&ba, 0x00);
     appendByte(&ba, 0x00);
     appendInt(&ba, m_session.pid);
-    sendTrkMessage(0x41, 0, ba, "Delete process");
+    sendTrkMessage(0x41, Callback(), ba, "Delete process");
 
     //---TRK------------------------------------------------------
     //  Command: 0x80 Acknowledge
@@ -1507,7 +1248,7 @@ void Adapter::cleanUp()
     foreach (const Breakpoint &bp, m_breakpoints)
         clearTrkBreakpoint(bp);
 
-    sendTrkMessage(0x02, CB(handleDisconnect));
+    sendTrkMessage(0x02, Callback(this, &Adapter::handleDisconnect));
     m_startInferiorTriggered = false;
     //---IDE------------------------------------------------------
     //  Command: 0x1C Clear Break
@@ -1538,7 +1279,7 @@ void Adapter::cleanUp()
     //---IDE------------------------------------------------------
     //  Command: 0x02 Disconnect
     // [02 27]
-//    sendTrkMessage(0x02, CB(handleDisconnect));
+//    sendTrkMessage(0x02, Callback(this, &Adapter::handleDisconnect));
     //---TRK------------------------------------------------------
     //  Command: 0x80 Acknowledge
     // Error: 0x00
@@ -1565,11 +1306,11 @@ void Adapter::readMemory(uint addr, uint len)
             appendInt(&ba, m_session.pid);
             appendInt(&ba, m_session.tid);
             // Read Memory
-            sendTrkMessage(0x10, CB(handleReadMemory), ba, QVariant(blockaddr), true);
+            sendTrkMessage(0x10, Callback(this, &Adapter::handleReadMemory), ba, QVariant(blockaddr), true);
         }
     }
     qulonglong cookie = (qulonglong(addr) << 32) + len;
-    sendTrkMessage(TRK_SYNC, CB(reportReadMemory), QByteArray(), cookie);
+    sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, Callback(this, &Adapter::reportReadMemory), QByteArray(), cookie);
 }
 
 void Adapter::startInferiorIfNeeded()
@@ -1589,7 +1330,7 @@ void Adapter::startInferiorIfNeeded()
 
     QByteArray file("C:\\sys\\bin\\filebrowseapp.exe");
     appendString(&ba, file, TargetByteOrder);
-    sendTrkMessage(0x40, CB(handleCreateProcess), ba); // Create Item
+    sendTrkMessage(0x40, Callback(this, &Adapter::handleCreateProcess), ba); // Create Item
 }
 
 void Adapter::interruptInferior()
@@ -1599,7 +1340,7 @@ void Adapter::interruptInferior()
     appendByte(&ba, 1);
     appendInt(&ba, m_session.pid);
     appendInt(&ba, m_session.tid); // threadID: 4 bytes Variable number of bytes.
-    sendTrkMessage(0x1A, 0, ba, "Interrupting...");
+    sendTrkMessage(0x1A, Callback(), ba, "Interrupting...");
 }
 
 static bool readAdapterArgs(const QStringList &args, AdapterOptions *o)
diff --git a/tests/manual/trk/adapter.pro b/tests/manual/trk/adapter.pro
index 48ebd9bec67aefddfd82f670d3769b3b59733b00..22f4aa3cddb1785127a452b4ee5ee116deebe501 100644
--- a/tests/manual/trk/adapter.pro
+++ b/tests/manual/trk/adapter.pro
@@ -4,8 +4,11 @@ TEMPLATE = app
 QT = core network
 win32:CONFIG+=console
 
-HEADERS += trkutils.h
+HEADERS += trkutils.h \
+trkfunctor.h \
+trkdevice.h \
 
 SOURCES += \
     adapter.cpp \
-    trkutils.cpp
+    trkutils.cpp \
+    trkdevice.cpp
diff --git a/tests/manual/trk/launcher.cpp b/tests/manual/trk/launcher.cpp
index a3d3d06e0359427d3e888c2034b5fa25fcf559b3..474b965a236f478526896e759a6e2e64e6570b8d 100644
--- a/tests/manual/trk/launcher.cpp
+++ b/tests/manual/trk/launcher.cpp
@@ -67,7 +67,7 @@ LauncherPrivate::LauncherPrivate() :
 Launcher::Launcher() :
     d(new LauncherPrivate)
 {
-    connect(&d->m_device, SIGNAL(messageReceived(TrkResult)), this, SLOT(handleResult(TrkResult)));
+    connect(&d->m_device, SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult)));
 }
 
 Launcher::~Launcher()
@@ -147,7 +147,7 @@ void Launcher::installAndRun()
 void Launcher::logMessage(const QString &msg)
 {
     if (d->m_verbose)
-        qDebug() << "ADAPTER: " << qPrintable(msg);
+        qDebug() << "LAUNCHER: " << qPrintable(msg);
 }
 
 void Launcher::waitForTrkFinished(const TrkResult &result)
@@ -239,7 +239,7 @@ void Launcher::handleResult(const TrkResult &result)
         case TrkNotifyDeleted: { // NotifyDeleted
             const ushort itemType = (unsigned char)result.data.at(1);
             const ushort len = result.data.size() > 12 ? extractShort(result.data.data() + 10) : ushort(0);
-            const QString name = len ? QString::fromAscii(result.data.mid(13, len)) : QString();
+            const QString name = len ? QString::fromAscii(result.data.mid(12, len)) : QString();
             logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3").
                        arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")).
                        arg(name));
diff --git a/tests/manual/trk/launcher.h b/tests/manual/trk/launcher.h
index c2527d57d5cee2f531be99aaece1d82c4db832ca..cb9881b5511b58d37683de9e8fac58cbf1bdecdd 100644
--- a/tests/manual/trk/launcher.h
+++ b/tests/manual/trk/launcher.h
@@ -67,7 +67,7 @@ public slots:
     void terminate();
 
 private slots:
-    void handleResult(const TrkResult &data);
+    void handleResult(const trk::TrkResult &data);
 
 private:
     void tryTrkRead();
diff --git a/tests/manual/trk/run.pl b/tests/manual/trk/run.pl
index 2644c30497059986c7fe767f1020f712a7f71575..9f4e31097c6d55aa38a884f23fb31e4a8511f069 100755
--- a/tests/manual/trk/run.pl
+++ b/tests/manual/trk/run.pl
@@ -21,10 +21,15 @@ Usage: run.pl -av -aq -tv -tq -l [COM]
 Options:
      -av     Adapter verbose
      -aq     Adapter quiet
+     -af     Adapter turn off serial frame
      -tv     TrkServer verbose
      -tq     TrkServer quiet
 
      trkserver simulator will be run unless COM is specified
+
+Bluetooth:
+     rfcomm listen /dev/rfcomm0 1 \$PWD/run.pl -av -af {}
+
 EOF
 
 # ------- Parse arguments
@@ -36,11 +41,16 @@ for (my $i = 0; $i < $argCount; $i++) {
 	    push(@ADAPTER_OPTIONS, '-v');
 	} elsif ($a eq '-aq') {
 	    push(@ADAPTER_OPTIONS, '-q');
+	} elsif ($a eq '-af') {
+	    push(@ADAPTER_OPTIONS, '-f');
 	} elsif ($a eq '-tv') {
 	    push(@TRKSERVEROPTIONS, '-v');
 	} elsif ($a eq '-tq') {
 	    push(@TRKSERVEROPTIONS, '-q');
 	}  elsif ($a eq '-h') {
+	    print $usage;
+	    exit(0);
+	}  else {
 	    print $usage;
 	    exit(1);
 	}
diff --git a/tests/manual/trk/trkdevice.cpp b/tests/manual/trk/trkdevice.cpp
index 13608cb2da8eb8312c5e0992b88139247d8e9280..6746e5b1f64e5d286af6a14a284381aa15c02890 100644
--- a/tests/manual/trk/trkdevice.cpp
+++ b/tests/manual/trk/trkdevice.cpp
@@ -35,6 +35,7 @@
 #include <QtCore/QQueue>
 #include <QtCore/QHash>
 #include <QtCore/QMap>
+#include <QtCore/QSharedPointer>
 
 #ifdef Q_OS_WIN
 #  include <windows.h>
@@ -312,10 +313,13 @@ void TrkDevice::tryTrkRead()
     }
 #endif // Q_OS_WIN
     TrkResult r;
-    while (extractResult(&d->trkReadBuffer, d->serialFrame, &r)) {
+    QByteArray rawData;
+    while (extractResult(&d->trkReadBuffer, d->serialFrame, &r, &rawData)) {
         if (d->verbose)
             qDebug() << "Read TrkResult " << r.data.toHex();
         emit messageReceived(r);
+        if (!rawData.isEmpty())
+            emit rawDataReceived(rawData);
     }
 }
 
@@ -359,28 +363,149 @@ TrkMessage::TrkMessage(unsigned char c,
 }
 
 // ------- TrkWriteQueueDevice
+typedef QSharedPointer<TrkMessage> SharedPointerTrkMessage;
 
-struct TrkWriteQueueDevicePrivate {
-    typedef QMap<unsigned char, TrkMessage> TokenMessageMap;
-    TrkWriteQueueDevicePrivate();
+/* Mixin class that manages a write queue of Trk messages. */
+
+class TrkWriteQueue {
+public:
+    typedef TrkWriteQueueDevice::Callback Callback;   
+
+    TrkWriteQueue();
+
+    // Enqueue messages.
+    void queueTrkMessage(unsigned char code, Callback callback,
+                        const QByteArray &data, const QVariant &cookie,
+                        bool invokeOnNAK);
+    void queueTrkInitialPing();
+
+    // Call this from the device read notification with the results.
+    void slotHandleResult(const TrkResult &result);
+
+    // This can be called periodically in a timer to retrieve
+    // the pending messages to be sent.
+    bool pendingMessage(SharedPointerTrkMessage *message = 0);
+    // Notify the queue about the success of the write operation
+    // after taking the pendingMessage off.
+    void notifyWriteResult(bool ok);
+
+    // Factory function for ack message
+    static SharedPointerTrkMessage trkAck(unsigned char token);
+
+private:
+    typedef QMap<unsigned char, SharedPointerTrkMessage> TokenMessageMap;
+
+    unsigned char nextTrkWriteToken();
 
     unsigned char trkWriteToken;
-    QQueue<TrkMessage> trkWriteQueue;
+    QQueue<SharedPointerTrkMessage> trkWriteQueue;
     TokenMessageMap writtenTrkMessages;
     bool trkWriteBusy;
 };
 
-TrkWriteQueueDevicePrivate::TrkWriteQueueDevicePrivate() :
+TrkWriteQueue::TrkWriteQueue() :
     trkWriteToken(0),
     trkWriteBusy(false)
 {
 }
 
+unsigned char TrkWriteQueue::nextTrkWriteToken()
+{
+    ++trkWriteToken;
+    if (trkWriteToken == 0)
+        ++trkWriteToken;
+    return trkWriteToken;
+}
+
+void TrkWriteQueue::queueTrkMessage(unsigned char code, Callback callback,
+                                         const QByteArray &data, const QVariant &cookie,
+                                         bool invokeOnNAK)
+{
+    const unsigned char token = code == TRK_WRITE_QUEUE_NOOP_CODE ?
+                                (unsigned char)(0) : nextTrkWriteToken();
+    SharedPointerTrkMessage msg(new TrkMessage(code, token, callback));
+    msg->data = data;
+    msg->cookie = cookie;
+    msg->invokeOnNAK = invokeOnNAK;
+    trkWriteQueue.append(msg);
+}
+
+bool TrkWriteQueue::pendingMessage(SharedPointerTrkMessage *message)
+{
+    // Invoked from timer, try to flush out message queue
+    if (trkWriteBusy || trkWriteQueue.isEmpty())
+        return false;
+    // Handle the noop message, just invoke CB
+    if (trkWriteQueue.front()->code == TRK_WRITE_QUEUE_NOOP_CODE) {
+        const SharedPointerTrkMessage noopMessage = trkWriteQueue.dequeue();
+        if (noopMessage->callback) {
+            TrkResult result;
+            result.code = noopMessage->code;
+            result.token = noopMessage->token;
+            result.data = noopMessage->data;
+            result.cookie = noopMessage->cookie;
+            noopMessage->callback(result);
+        }
+    }
+    // Check again for real messages
+    if (trkWriteQueue.isEmpty())
+        return false;
+    if (message)
+        *message = trkWriteQueue.front();
+    return true;
+}
+
+void TrkWriteQueue::notifyWriteResult(bool ok)
+{
+    // On success, dequeue message and await result
+    if (ok) {        
+        const SharedPointerTrkMessage firstMsg = trkWriteQueue.dequeue();
+        writtenTrkMessages.insert(firstMsg->token, firstMsg);
+        trkWriteBusy = true;
+    }
+}
+
+void TrkWriteQueue::slotHandleResult(const TrkResult &result)
+{
+    trkWriteBusy = false;
+    if (result.code != TrkNotifyAck && result.code != TrkNotifyNak)
+        return;
+    // Find which request the message belongs to and invoke callback
+    // if ACK or on NAK if desired.
+    const TokenMessageMap::iterator it = writtenTrkMessages.find(result.token);
+    if (it == writtenTrkMessages.end())
+        return;
+    const bool invokeCB = it.value()->callback
+                          && (result.code == TrkNotifyAck || it.value()->invokeOnNAK);
+
+    if (invokeCB) {
+        TrkResult result1 = result;
+        result1.cookie = it.value()->cookie;
+        it.value()->callback(result1);
+    }
+    writtenTrkMessages.erase(it);
+}
+
+SharedPointerTrkMessage TrkWriteQueue::trkAck(unsigned char token)
+{
+    SharedPointerTrkMessage msg(new TrkMessage(0x80, token));
+    msg->token = token;
+    msg->data.append('\0');
+    return msg;
+}
+
+void TrkWriteQueue::queueTrkInitialPing()
+{
+    const SharedPointerTrkMessage msg(new TrkMessage(0, 0)); // Ping, reset sequence count
+    trkWriteQueue.append(msg);
+}
+
+// -----------------------
 TrkWriteQueueDevice::TrkWriteQueueDevice(QObject *parent) :
     TrkDevice(parent),
-    qd(new TrkWriteQueueDevicePrivate)
+    qd(new TrkWriteQueue)
 {
-    connect(this, SIGNAL(messageReceived(TrkResult)), this, SLOT(slotHandleResult(TrkResult)));
+    connect(this, SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(slotHandleResult(trk::TrkResult)));
 }
 
 TrkWriteQueueDevice::~TrkWriteQueueDevice()
@@ -388,56 +513,34 @@ TrkWriteQueueDevice::~TrkWriteQueueDevice()
     delete qd;
 }
 
-unsigned char TrkWriteQueueDevice::nextTrkWriteToken()
-{
-    ++qd->trkWriteToken;
-    if (qd->trkWriteToken == 0)
-        ++qd->trkWriteToken;
-    return qd->trkWriteToken;
-}
-
 void TrkWriteQueueDevice::sendTrkMessage(unsigned char code, Callback callback,
                                          const QByteArray &data, const QVariant &cookie,
                                          bool invokeOnNAK)
 {
-    TrkMessage msg(code, nextTrkWriteToken(), callback);
-    msg.data = data;
-    msg.cookie = cookie;
-    msg.invokeOnNAK = invokeOnNAK;
-    queueTrkMessage(msg);
+    qd->queueTrkMessage(code, callback, data, cookie, invokeOnNAK);
 }
 
 void TrkWriteQueueDevice::sendTrkInitialPing()
 {
-    const TrkMessage msg(0, 0); // Ping, reset sequence count
-    queueTrkMessage(msg);
+    qd->queueTrkInitialPing();
 }
 
 bool TrkWriteQueueDevice::sendTrkAck(unsigned char token)
 {
-    TrkMessage msg(0x80, token);
-    msg.token = token;
-    msg.data.append('\0');
     // The acknowledgement must not be queued!
-    return trkWriteRawMessage(msg);
+    const SharedPointerTrkMessage ack = TrkWriteQueue::trkAck(token);
+    return trkWriteRawMessage(*ack);
     // 01 90 00 07 7e 80 01 00 7d 5e 7e
 }
 
-void TrkWriteQueueDevice::queueTrkMessage(const TrkMessage &msg)
-{
-    qd->trkWriteQueue.append(msg);
-}
-
 void TrkWriteQueueDevice::tryTrkWrite()
 {
-    // Invoked from timer, try to flush out message queue
-    if (qd->trkWriteBusy)
+    if (!qd->pendingMessage())
         return;
-    if (qd->trkWriteQueue.isEmpty())
-        return;
-
-    const TrkMessage msg = qd->trkWriteQueue.dequeue();
-    trkWrite(msg);
+    SharedPointerTrkMessage message;
+    qd->pendingMessage(&message);
+    const bool success = trkWriteRawMessage(*message);
+    qd->notifyWriteResult(success);
 }
 
 bool TrkWriteQueueDevice::trkWriteRawMessage(const TrkMessage &msg)
@@ -452,13 +555,6 @@ bool TrkWriteQueueDevice::trkWriteRawMessage(const TrkMessage &msg)
     return rc;
 }
 
-bool TrkWriteQueueDevice::trkWrite(const TrkMessage &msg)
-{
-    qd->writtenTrkMessages.insert(msg.token, msg);
-    qd->trkWriteBusy = true;
-    return trkWriteRawMessage(msg);
-}
-
 void TrkWriteQueueDevice::timerEvent(QTimerEvent *ev)
 {
     tryTrkWrite();
@@ -467,23 +563,128 @@ void TrkWriteQueueDevice::timerEvent(QTimerEvent *ev)
 
 void TrkWriteQueueDevice::slotHandleResult(const TrkResult &result)
 {
-    qd->trkWriteBusy = false;
-    if (result.code != TrkNotifyAck && result.code != TrkNotifyNak)
-        return;
-    // Find which request the message belongs to and invoke callback
-    // if ACK or on NAK if desired.
-    const TrkWriteQueueDevicePrivate::TokenMessageMap::iterator it = qd->writtenTrkMessages.find(result.token);
-    if (it == qd->writtenTrkMessages.end())
+    qd->slotHandleResult(result);
+}
+
+// ----------- TrkWriteQueueDevice
+
+struct TrkWriteQueueIODevicePrivate {
+    TrkWriteQueueIODevicePrivate(const QSharedPointer<QIODevice> &d);
+
+    const QSharedPointer<QIODevice> device;
+    TrkWriteQueue queue;
+    QByteArray readBuffer;
+    bool serialFrame;
+    bool verbose;
+};
+
+TrkWriteQueueIODevicePrivate::TrkWriteQueueIODevicePrivate(const QSharedPointer<QIODevice> &d) :
+    device(d),
+    serialFrame(true),
+    verbose(false)
+{
+}
+
+TrkWriteQueueIODevice::TrkWriteQueueIODevice(const QSharedPointer<QIODevice> &device,
+                                             QObject *parent) :
+    QObject(parent),
+    d(new TrkWriteQueueIODevicePrivate(device))
+{
+    startTimer(TimerInterval);
+}
+
+TrkWriteQueueIODevice::~TrkWriteQueueIODevice()
+{
+    delete d;
+}
+
+bool TrkWriteQueueIODevice::serialFrame() const
+{
+    return d->serialFrame;
+}
+
+void TrkWriteQueueIODevice::setSerialFrame(bool f)
+{
+    d->serialFrame = f;
+}
+
+bool TrkWriteQueueIODevice::verbose() const
+{
+    return d->verbose;
+}
+
+void TrkWriteQueueIODevice::setVerbose(bool b)
+{
+    d->verbose = b;
+}
+
+void TrkWriteQueueIODevice::sendTrkMessage(unsigned char code, Callback callback,
+                                         const QByteArray &data, const QVariant &cookie,
+                                         bool invokeOnNAK)
+{
+    d->queue.queueTrkMessage(code, callback, data, cookie, invokeOnNAK);
+}
+
+void TrkWriteQueueIODevice::sendTrkInitialPing()
+{
+    d->queue.queueTrkInitialPing();
+}
+
+bool TrkWriteQueueIODevice::sendTrkAck(unsigned char token)
+{
+    // The acknowledgement must not be queued!
+    const SharedPointerTrkMessage ack = TrkWriteQueue::trkAck(token);
+    return trkWriteRawMessage(*ack);
+    // 01 90 00 07 7e 80 01 00 7d 5e 7e
+}
+
+
+void TrkWriteQueueIODevice::timerEvent(QTimerEvent *)
+{
+    tryTrkWrite();
+    tryTrkRead();
+}
+
+void TrkWriteQueueIODevice::tryTrkWrite()
+{
+    if (!d->queue.pendingMessage())
         return;
-    const bool invokeCB = it.value().callback
-                          && (result.code == TrkNotifyAck || it.value().invokeOnNAK);
+    SharedPointerTrkMessage message;
+    d->queue.pendingMessage(&message);
+    const bool success = trkWriteRawMessage(*message);
+    d->queue.notifyWriteResult(success);
+}
 
-    if (invokeCB) {
-        TrkResult result1 = result;
-        result1.cookie = it.value().cookie;
-        it.value().callback(result1);
+bool TrkWriteQueueIODevice::trkWriteRawMessage(const TrkMessage &msg)
+{
+    const QByteArray ba = frameMessage(msg.code, msg.token, msg.data, serialFrame());
+    if (verbose())
+         qDebug() << ("WRITE: " + stringFromArray(ba));
+    const bool ok = d->device->write(ba) != -1;
+    if (!ok) {
+        const QString msg = QString::fromLatin1("Unable to write %1 bytes: %2:").arg(ba.size()).arg(d->device->errorString());
+        qWarning("%s\n", qPrintable(msg));
+    }
+    return ok;
+}
+
+void TrkWriteQueueIODevice::tryTrkRead()
+{
+    const  quint64 bytesAvailable = d->device->bytesAvailable();
+    if (!bytesAvailable)
+        return;
+    const QByteArray newData = d->device->read(bytesAvailable);
+    if (d->verbose)
+        qDebug() << "READ " << newData.toHex();
+    d->readBuffer.append(newData);
+    TrkResult r;
+    QByteArray rawData;
+    while (extractResult(&(d->readBuffer), d->serialFrame, &r, &rawData)) {
+        d->queue.slotHandleResult(r);
+        emit messageReceived(r);
+        if (!rawData.isEmpty())
+            emit rawDataReceived(rawData);
     }
-    qd->writtenTrkMessages.erase(it);
 }
 
 } // namespace tr
diff --git a/tests/manual/trk/trkdevice.h b/tests/manual/trk/trkdevice.h
index 53047bfb8995f59359b5848d68c7fc4bda8781f6..61b382ad5766bdc0a89d2dbfe2fc7a8160169f5d 100644
--- a/tests/manual/trk/trkdevice.h
+++ b/tests/manual/trk/trkdevice.h
@@ -35,13 +35,19 @@
 #include <QtCore/QObject>
 #include <QtCore/QVariant>
 #include <QtCore/QByteArray>
+#include <QtCore/QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+QT_END_NAMESPACE
 
 namespace trk {
 
 struct TrkResult;
 struct TrkMessage;
 struct TrkDevicePrivate;
-struct TrkWriteQueueDevicePrivate;
+class TrkWriteQueue;
+struct TrkWriteQueueIODevicePrivate;
 
 /* TrkDevice: Implements a Windows COM or Linux device for
  * Trk communications. Provides synchronous write and asynchronous
@@ -74,7 +80,9 @@ public:
     bool write(const QByteArray &data, QString *errorMessage);
 
 signals:
-    void messageReceived(const TrkResult&);
+    void messageReceived(const trk::TrkResult&);
+    // Emitted with the contents of messages enclosed in 07e, not for log output
+    void rawDataReceived(const QByteArray &data);
     void error(const QString &s);
 
 protected:
@@ -89,7 +97,12 @@ private:
 
 /* TrkWriteQueueDevice: Extends TrkDevice by write message queue allowing
  * for queueing messages with a notification callback. If the message receives
- * an ACK, the callback is invoked. */
+ * an ACK, the callback is invoked.
+ * The special message TRK_WRITE_QUEUE_NOOP_CODE code can be used for synchronisation.
+ * The respective  message will not be sent, the callback is just invoked. */
+
+enum { TRK_WRITE_QUEUE_NOOP_CODE = 0x7f };
+
 class TrkWriteQueueDevice : public TrkDevice
 {
     Q_OBJECT
@@ -115,21 +128,64 @@ public:
     bool sendTrkAck(unsigned char token);
 
 private slots:
-    void slotHandleResult(const TrkResult &);
+    void slotHandleResult(const trk::TrkResult &);
 
 protected:
     virtual void timerEvent(QTimerEvent *ev);
 
 private:
-    unsigned char nextTrkWriteToken();
-    void queueTrkMessage(const TrkMessage &msg);
     void tryTrkWrite();
     bool trkWriteRawMessage(const TrkMessage &msg);
-    bool trkWrite(const TrkMessage &msg);
 
-    TrkWriteQueueDevicePrivate *qd;
+    TrkWriteQueue *qd;
 };
 
+/* A Trk queueing device wrapping around a QIODevice (otherwise
+ * mimicking TrkWriteQueueDevice).
+ * Can be used to forward Trk over a network or to simulate things. */
+
+class TrkWriteQueueIODevice : public QObject
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(TrkWriteQueueIODevice)
+    Q_PROPERTY(bool serialFrame READ serialFrame WRITE setSerialFrame)
+    Q_PROPERTY(bool verbose READ verbose WRITE setVerbose)
+public:
+    typedef TrkFunctor1<const TrkResult &> Callback;
+
+    explicit TrkWriteQueueIODevice(const QSharedPointer<QIODevice> &device,
+                                   QObject *parent = 0);
+    virtual ~TrkWriteQueueIODevice();
+
+    bool serialFrame() const;
+    void setSerialFrame(bool f);
+
+    bool verbose() const;
+    void setVerbose(bool b);
+
+    void sendTrkMessage(unsigned char code,
+                        Callback callback = Callback(),
+                        const QByteArray &data = QByteArray(),
+                        const QVariant &cookie = QVariant(),
+                        bool invokeOnNAK = false);
+    void sendTrkInitialPing();
+    bool sendTrkAck(unsigned char token);
+
+signals:
+    void messageReceived(const trk::TrkResult&);
+    // Emitted with the contents of messages enclosed in 07e, not for log output
+    void rawDataReceived(const QByteArray &data);
+
+protected:
+    virtual void timerEvent(QTimerEvent *ev);
+
+private:
+    void tryTrkRead();    
+    void tryTrkWrite();
+    bool trkWriteRawMessage(const TrkMessage &msg);
+
+    TrkWriteQueueIODevicePrivate *d;
+};
 
 } // namespace trk
 
diff --git a/tests/manual/trk/trkutils.cpp b/tests/manual/trk/trkutils.cpp
index 8b5622ed9faa77d2cc1ec7d34ea6b3b0989de4f2..81925c07d674e0efb19afb836f658c193eaf47a3 100644
--- a/tests/manual/trk/trkutils.cpp
+++ b/tests/manual/trk/trkutils.cpp
@@ -122,9 +122,11 @@ ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame)
     return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size();
 }
 
-bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result)
+bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByteArray *rawData)
 {
     result->clear();
+    if(rawData)
+        rawData->clear();
     const ushort len = isValidTrkResult(*buffer, serialFrame);
     if (!len)
         return false;
@@ -140,6 +142,8 @@ bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result)
     // FIXME: what happens if the length contains 0xfe?
     // Assume for now that it passes unencoded!
     const QByteArray data = decode7d(buffer->mid(delimiterPos + 1, len - 2));
+    if(rawData)
+        *rawData = data;
     *buffer->remove(0, delimiterPos + len);
 
     byte sum = 0;
diff --git a/tests/manual/trk/trkutils.h b/tests/manual/trk/trkutils.h
index 77e469b8068e6f2bd9cf207fe84396e2157d6b56..e54efc6f6e915c214f1b7ae2f4e575da754b6869 100644
--- a/tests/manual/trk/trkutils.h
+++ b/tests/manual/trk/trkutils.h
@@ -188,7 +188,7 @@ struct TrkResult
 // the serial frame [0x01 0x90 <len>] and 0x7e encoded7d(ba) 0x7e
 QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame);
 ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame);
-bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r);
+bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r, QByteArray *rawData = 0);
 QByteArray errorMessage(byte code);
 QByteArray hexNumber(uint n, int digits = 0);
 uint swapEndian(uint in);