From 47155f8518f154b7cea32936675e09322d293a8e Mon Sep 17 00:00:00 2001 From: Kai Koehne <kai.koehne@nokia.com> Date: Tue, 19 Jan 2010 09:33:06 +0100 Subject: [PATCH] New qml based .qmproject file format --- .../fileformat/filefilteritems.cpp | 121 +++++++++++++++ .../fileformat/filefilteritems.h | 72 +++++++++ .../fileformat/fileformat.pri | 4 + .../fileformat/qmlprojectitem.cpp | 101 +++++++++++++ .../fileformat/qmlprojectitem.h | 55 +++++++ tests/auto/qml/qml.pro | 2 +- .../fileformat/data/file1.qml | 0 .../fileformat/data/file1.qrc | 0 .../fileformat/data/file2.qml | 0 .../fileformat/data/subdir/file3.qml | 0 .../fileformat/fileformat.pro | 21 +++ .../fileformat/tst_fileformat.cpp | 141 ++++++++++++++++++ .../qmlprojectmanager/qmlprojectmanager.pro | 3 + 13 files changed, 519 insertions(+), 1 deletion(-) create mode 100644 src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp create mode 100644 src/plugins/qmlprojectmanager/fileformat/filefilteritems.h create mode 100644 src/plugins/qmlprojectmanager/fileformat/fileformat.pri create mode 100644 src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp create mode 100644 src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h create mode 100644 tests/auto/qml/qmlprojectmanager/fileformat/data/file1.qml create mode 100644 tests/auto/qml/qmlprojectmanager/fileformat/data/file1.qrc create mode 100644 tests/auto/qml/qmlprojectmanager/fileformat/data/file2.qml create mode 100644 tests/auto/qml/qmlprojectmanager/fileformat/data/subdir/file3.qml create mode 100644 tests/auto/qml/qmlprojectmanager/fileformat/fileformat.pro create mode 100644 tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp create mode 100644 tests/auto/qml/qmlprojectmanager/qmlprojectmanager.pro diff --git a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp new file mode 100644 index 00000000000..d80f3de97ec --- /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 00000000000..5857495be14 --- /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 00000000000..278e85e6c57 --- /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 00000000000..4bc66ecbd49 --- /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 00000000000..ce7a6b54670 --- /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 a902fa669cf..5a8a473eaf8 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 00000000000..e69de29bb2d 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 00000000000..e69de29bb2d 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 00000000000..e69de29bb2d 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 00000000000..e69de29bb2d diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.pro b/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.pro new file mode 100644 index 00000000000..b4b4577d86b --- /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 00000000000..18a90bf4741 --- /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 00000000000..e36121cd0de --- /dev/null +++ b/tests/auto/qml/qmlprojectmanager/qmlprojectmanager.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS += fileformat -- GitLab