diff --git a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d80f3de97ec0dad8a85676a05fe5951e12a767ed
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp
@@ -0,0 +1,121 @@
+#include "filefilteritems.h"
+#include <qdebug.h>
+
+namespace QmlProjectManager {
+
+FileFilterBaseItem::FileFilterBaseItem(QObject *parent) :
+        QmlProjectContentItem(parent),
+        m_recursive(false)
+{
+}
+
+QString FileFilterBaseItem::directory() const
+{
+    return m_rootDir;
+}
+
+void FileFilterBaseItem::setDirectory(const QString &dirPath)
+{
+    if (m_rootDir == dirPath)
+        return;
+    m_rootDir = dirPath;
+    emit directoryChanged();
+
+    updateFileList();
+}
+
+void FileFilterBaseItem::setDefaultDirectory(const QString &dirPath)
+{
+    if (m_defaultDir == dirPath)
+        return;
+    m_defaultDir = dirPath;
+
+    updateFileList();
+}
+
+QString FileFilterBaseItem::filter() const
+{
+    return m_filter;
+}
+
+void FileFilterBaseItem::setFilter(const QString &filter)
+{
+    if (filter == m_filter)
+        return;
+    m_filter = filter;
+    m_regex.setPattern(m_filter);
+    m_regex.setPatternSyntax(QRegExp::Wildcard);
+
+    emit filterChanged();
+    updateFileList();
+}
+
+bool FileFilterBaseItem::recursive() const
+{
+    return m_recursive;
+}
+
+void FileFilterBaseItem::setRecursive(bool recursive)
+{
+    if (recursive == m_recursive)
+        return;
+    m_recursive = recursive;
+    updateFileList();
+}
+
+QStringList FileFilterBaseItem::files() const
+{
+    return m_files.toList();
+}
+
+QString FileFilterBaseItem::absoluteDir() const
+{
+    QString absoluteDir;
+    if (QFileInfo(m_rootDir).isAbsolute()) {
+        absoluteDir = m_rootDir;
+    } else if (!m_defaultDir.isEmpty()) {
+        absoluteDir = m_defaultDir + QLatin1Char('/') + m_rootDir;
+    }
+
+    return absoluteDir;
+}
+
+void FileFilterBaseItem::updateFileList()
+{
+    const QString dir = absoluteDir();
+    if (dir.isEmpty())
+        return;
+
+    const QSet<QString> newFiles = filesInSubTree(QDir(m_defaultDir), QDir(dir));
+    if (newFiles != m_files) {
+        m_files = newFiles;
+        emit filesChanged();
+    }
+}
+
+QSet<QString> FileFilterBaseItem::filesInSubTree(const QDir &rootDir, const QDir &dir)
+{
+    QSet<QString> fileSet;
+
+    foreach (const QFileInfo &file, dir.entryInfoList(QDir::Files)) {
+        if (m_regex.exactMatch(file.fileName()))
+            fileSet.insert(rootDir.relativeFilePath(file.absoluteFilePath()));
+    }
+
+    if (m_recursive) {
+        foreach (const QFileInfo &subDir, dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) {
+            fileSet += filesInSubTree(rootDir, QDir(subDir.absoluteFilePath()));
+        }
+    }
+    return fileSet;
+}
+
+QmlFileFilterItem::QmlFileFilterItem(QObject *parent)
+    : FileFilterBaseItem(parent)
+{
+    setFilter(QLatin1String("*.qml"));
+}
+
+} // namespace QmlProjectManager
+
+QML_DEFINE_TYPE(QmlProject,1,0,QmlFiles,QmlProjectManager::QmlFileFilterItem)
diff --git a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h
new file mode 100644
index 0000000000000000000000000000000000000000..5857495be145d3d2ec013d75ce56f7efea99e776
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h
@@ -0,0 +1,72 @@
+#ifndef FILEFILTERITEMS_H
+#define FILEFILTERITEMS_H
+
+#include <QDir>
+#include <QObject>
+#include <QSet>
+#include <qml.h>
+
+#include "qmlprojectitem.h"
+
+namespace QmlProjectManager {
+
+class FileFilterBaseItem : public QmlProjectContentItem {
+    Q_OBJECT
+
+    Q_PROPERTY(QString directory READ directory WRITE setDirectory NOTIFY directoryChanged)
+    Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
+
+    Q_PROPERTY(QList<QString> files READ files NOTIFY filesChanged)
+
+public:
+    FileFilterBaseItem(QObject *parent = 0);
+
+    QString directory() const;
+    void setDirectory(const QString &directoryPath);
+
+    void setDefaultDirectory(const QString &directoryPath);
+
+    QString filter() const;
+    void setFilter(const QString &filter);
+
+    bool recursive() const;
+    void setRecursive(bool recursive);
+
+    virtual QStringList files() const;
+
+signals:
+    void directoryChanged();
+    void recursiveChanged();
+    void filterChanged();
+    void filesChanged();
+
+private:
+    QString absoluteDir() const;
+
+    void updateFileList();
+    QSet<QString> filesInSubTree(const QDir &rootDir, const QDir &dir);
+
+    QString m_rootDir;
+    QString m_defaultDir;
+
+    QString m_filter;
+    QRegExp m_regex;
+    bool m_recursive;
+
+    QSet<QString> m_files;
+
+    friend class ProjectItem;
+};
+
+class QmlFileFilterItem : public FileFilterBaseItem {
+    Q_OBJECT
+
+public:
+    QmlFileFilterItem(QObject *parent = 0);
+};
+
+} // namespace QmlProjectManager
+
+QML_DECLARE_TYPE(QmlProjectManager::QmlFileFilterItem)
+
+#endif // FILEFILTERITEMS_HPROJECTITEM_H
diff --git a/src/plugins/qmlprojectmanager/fileformat/fileformat.pri b/src/plugins/qmlprojectmanager/fileformat/fileformat.pri
new file mode 100644
index 0000000000000000000000000000000000000000..278e85e6c57593a65316d11f34cefd3dd910a133
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/fileformat/fileformat.pri
@@ -0,0 +1,4 @@
+HEADERS += $$PWD/qmlprojectitem.h \
+           $$PWD/filefilteritems.h
+SOURCES += $$PWD/qmlprojectitem.cpp \
+           $$PWD/filefilteritems.cpp
diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4bc66ecbd497a61d022da35e1639fea39f10133d
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp
@@ -0,0 +1,101 @@
+#include "qmlprojectitem.h"
+#include "filefilteritems.h"
+#include <qdebug.h>
+
+namespace QmlProjectManager {
+
+class QmlProjectItemPrivate : public QObject {
+    Q_OBJECT
+
+public:
+    QString sourceDirectory;
+
+    QList<QmlFileFilterItem*> qmlFileFilters() const;
+
+    // content property
+    QmlConcreteList<QmlProjectContentItem*> content;
+};
+
+QList<QmlFileFilterItem*> QmlProjectItemPrivate::qmlFileFilters() const
+{
+    QList<QmlFileFilterItem*> qmlFilters;
+    for (int i = 0; i < content.size(); ++i) {
+        QmlProjectContentItem *contentElement = content.at(i);
+        QmlFileFilterItem *qmlFileFilter = qobject_cast<QmlFileFilterItem*>(contentElement);
+        if (qmlFileFilter) {
+            qmlFilters << qmlFileFilter;
+        }
+    }
+    return qmlFilters;
+}
+
+QmlProjectItem::QmlProjectItem(QObject *parent) :
+        QObject(parent),
+        d_ptr(new QmlProjectItemPrivate)
+{
+//    Q_D(QmlProjectItem);
+//
+//    QmlFileFilter *defaultQmlFilter = new QmlFileFilter(this);
+//    d->content.append(defaultQmlFilter);
+}
+
+QmlProjectItem::~QmlProjectItem()
+{
+    delete d_ptr;
+}
+
+QmlList<QmlProjectContentItem*> *QmlProjectItem::content()
+{
+    Q_D(QmlProjectItem);
+    return &d->content;
+}
+
+QString QmlProjectItem::sourceDirectory() const
+{
+    const Q_D(QmlProjectItem);
+    return d->sourceDirectory;
+}
+
+void QmlProjectItem::setSourceDirectory(const QString &directoryPath)
+{
+    Q_D(QmlProjectItem);
+
+    if (d->sourceDirectory == directoryPath)
+        return;
+
+    d->sourceDirectory = directoryPath;
+
+    for (int i = 0; i < d->content.size(); ++i) {
+        QmlProjectContentItem *contentElement = d->content.at(i);
+        FileFilterBaseItem *fileFilter = qobject_cast<FileFilterBaseItem*>(contentElement);
+        if (fileFilter)
+            fileFilter->setDefaultDirectory(directoryPath);
+    }
+
+    emit sourceDirectoryChanged();
+}
+
+QStringList QmlProjectItem::qmlFiles() const
+{
+    const Q_D(QmlProjectItem);
+    QStringList qmlFiles;
+
+    for (int i = 0; i < d->content.size(); ++i) {
+        QmlProjectContentItem *contentElement = d->content.at(i);
+        QmlFileFilterItem *qmlFileFilter = qobject_cast<QmlFileFilterItem*>(contentElement);
+        if (qmlFileFilter) {
+            foreach (const QString &file, qmlFileFilter->files()) {
+                if (!qmlFiles.contains(file))
+                    qmlFiles << file;
+            }
+        }
+    }
+    return qmlFiles;
+}
+
+} // namespace QmlProjectManager
+
+QML_DEFINE_NOCREATE_TYPE(QmlProjectManager::QmlProjectContentItem)
+QML_DEFINE_TYPE(QmlProject,1,0,Project,QmlProjectManager::QmlProjectItem)
+
+#include "qmlprojectitem.moc"
diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h
new file mode 100644
index 0000000000000000000000000000000000000000..ce7a6b54670fee653c506416a7006e32a55220d4
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h
@@ -0,0 +1,55 @@
+#ifndef PROJECTITEM_H
+#define PROJECTITEM_H
+
+#include <QObject>
+#include <qml.h>
+
+namespace QmlProjectManager {
+
+class QmlProjectContentItem : public QObject {
+    // base class for all elements that should be direct children of Project element
+    Q_OBJECT
+
+public:
+    QmlProjectContentItem(QObject *parent = 0) : QObject(parent) {}
+};
+
+class QmlProjectItemPrivate;
+
+class QmlProjectItem : public QObject {
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(QmlProjectItem)
+    Q_DISABLE_COPY(QmlProjectItem)
+
+    Q_PROPERTY(QmlList<QmlProjectManager::QmlProjectContentItem*> *content READ content DESIGNABLE false)
+    Q_PROPERTY(QString sourceDirectory READ sourceDirectory NOTIFY sourceDirectoryChanged)
+
+    Q_CLASSINFO("DefaultProperty", "content");
+
+public:
+    QmlProjectItem(QObject *parent = 0);
+    ~QmlProjectItem();
+
+    QmlList<QmlProjectContentItem*> *content();
+
+    QString sourceDirectory() const;
+    void setSourceDirectory(const QString &directoryPath);
+
+    QStringList qmlFiles() const;
+
+signals:
+    void sourceDirectoryChanged();
+
+protected:
+    QmlProjectItemPrivate *d_ptr;
+
+};
+
+} // namespace QmlProjectManager
+
+QML_DECLARE_TYPE(QmlProjectManager::QmlProjectItem);
+QML_DECLARE_TYPE(QmlProjectManager::QmlProjectContentItem);
+Q_DECLARE_METATYPE(QList<QmlProjectManager::QmlProjectContentItem *>);
+
+
+#endif // PROJECTITEM_H
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index a902fa669cf5ab556da9cc740663b5ca8104e3f3..5a8a473eaf81e36e9a1fdd0fcc4bd81974632287 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -1,3 +1,3 @@
 TEMPLATE = subdirs
 
-SUBDIRS += qmleditor qmldesigner
+SUBDIRS += qmleditor qmldesigner qmlprojectmanager
diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/data/file1.qml b/tests/auto/qml/qmlprojectmanager/fileformat/data/file1.qml
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/data/file1.qrc b/tests/auto/qml/qmlprojectmanager/fileformat/data/file1.qrc
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/data/file2.qml b/tests/auto/qml/qmlprojectmanager/fileformat/data/file2.qml
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/data/subdir/file3.qml b/tests/auto/qml/qmlprojectmanager/fileformat/data/subdir/file3.qml
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.pro b/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b4b4577d86b1bc269d8a99fc6998ee0d429a3a17
--- /dev/null
+++ b/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.pro
@@ -0,0 +1,21 @@
+TEMPLATE = app
+
+CONFIG += qt warn_on console depend_includepath
+CONFIG -= app_bundle
+
+QT += testlib \
+    script \
+    declarative
+
+PLUGIN_DIR=../../../../../src/plugins/qmlprojectmanager
+
+include($$PLUGIN_DIR/fileformat/fileformat.pri)
+
+INCLUDEPATH += $$PLUGIN_DIR/fileformat
+
+TARGET=tst_$$TARGET
+
+DEFINES += SRCDIR=\\\"$$PWD\\\"
+
+TEMPLATE = app
+SOURCES += tst_fileformat.cpp
diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp b/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..18a90bf474116698a9e1de353300fd6bbd18462e
--- /dev/null
+++ b/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp
@@ -0,0 +1,141 @@
+#include "qmlprojectitem.h"
+#include "filefilteritems.h"
+#include <QmlComponent>
+#include <QmlContext>
+#include <QmlEngine>
+#include <QtTest>
+
+using namespace QmlProjectManager;
+
+class TestProject : public QObject
+{
+    Q_OBJECT
+public:
+    TestProject();
+
+private slots:
+    void testQmlFileFilter();
+};
+
+TestProject::TestProject()
+{
+
+}
+
+QString testDataDir = QLatin1String(SRCDIR "/data");
+
+void TestProject::testQmlFileFilter()
+{
+    //
+    // search for qml files in local directory
+    //
+    QString projectFile = QLatin1String(
+            "import QmlProject 1.0\n"
+            "Project {\n"
+            "  QmlFiles {"
+            "  }"
+            "}\n");
+
+    {
+        QmlEngine engine;
+        QmlComponent component(&engine);
+        component.setData(projectFile.toUtf8(), QUrl());
+        if (!component.isReady())
+            qDebug() << component.errorsString();
+        QVERIFY(component.isReady());
+
+        QmlProjectItem *project = qobject_cast<QmlProjectItem*>(component.create());
+        QVERIFY(project);
+
+        project->setSourceDirectory(testDataDir);
+
+        QStringList expectedFiles(QStringList() << "file1.qml" << "file2.qml");
+        QCOMPARE(project->qmlFiles().toSet(), expectedFiles.toSet());
+    }
+
+    //
+    // search for all qml files in all subdirectories
+    //
+    projectFile = QLatin1String(
+            "import QmlProject 1.0\n"
+            "Project {\n"
+            "  QmlFiles {\n"
+            "    recursive: true\n"
+            "  }\n"
+            "}\n");
+
+    {
+        QmlEngine engine;
+        QmlComponent component(&engine);
+        component.setData(projectFile.toUtf8(), QUrl());
+        QVERIFY(component.isReady());
+
+        QmlProjectItem *project = qobject_cast<QmlProjectItem*>(component.create());
+        QVERIFY(project);
+
+        project->setSourceDirectory(testDataDir);
+
+        QStringList expectedFiles(QStringList() << "file1.qml" << "file2.qml" << "subdir/file3.qml");
+        QCOMPARE(project->qmlFiles().toSet(), expectedFiles.toSet());
+    }
+
+    //
+    // search for all qml files in subdirectory
+    //
+    projectFile = QLatin1String(
+            "import QmlProject 1.0\n"
+            "Project {\n"
+            "  QmlFiles {\n"
+            "    directory: \"subdir\"\n"
+            "  }\n"
+            "}\n");
+
+    {
+        QmlEngine engine;
+        QmlComponent component(&engine);
+        component.setData(projectFile.toUtf8(), QUrl());
+        QVERIFY(component.isReady());
+
+        QmlProjectItem *project = qobject_cast<QmlProjectItem*>(component.create());
+        QVERIFY(project);
+
+        project->setSourceDirectory(testDataDir);
+
+        QStringList expectedFiles(QStringList() << "subdir/file3.qml");
+        QCOMPARE(project->qmlFiles().toSet(), expectedFiles.toSet());
+    }
+
+    //
+    // combination
+    //
+    projectFile = QLatin1String(
+            "import QmlProject 1.0\n"
+            "Project {\n"
+            "  QmlFiles {\n"
+            "  }"
+            "  QmlFiles {\n"
+            "    directory: \"subdir\"\n"
+            "  }\n"
+            "}\n");
+
+    {
+        QmlEngine engine;
+        QmlComponent component(&engine);
+        component.setData(projectFile.toUtf8(), QUrl());
+        qDebug() << component.errorsString();
+        QVERIFY(component.isReady());
+
+        QmlProjectItem *project = qobject_cast<QmlProjectItem*>(component.create());
+        QVERIFY(project);
+
+        project->setSourceDirectory(testDataDir);
+
+        QStringList expectedFiles(QStringList() << "file1.qml" << "file2.qml" << "subdir/file3.qml");
+        QCOMPARE(project->qmlFiles().size(), 3);
+        QCOMPARE(project->qmlFiles().toSet(), expectedFiles.toSet());
+    }
+}
+
+
+QTEST_MAIN(TestProject);
+#include "tst_fileformat.moc"
diff --git a/tests/auto/qml/qmlprojectmanager/qmlprojectmanager.pro b/tests/auto/qml/qmlprojectmanager/qmlprojectmanager.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e36121cd0dedc1e4ac104c696fd5c5eca024b5e0
--- /dev/null
+++ b/tests/auto/qml/qmlprojectmanager/qmlprojectmanager.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += fileformat