From 42ab4b839af7d02258bc40389f11ec615cf42f0c Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Fri, 8 Jan 2010 10:17:02 +1000 Subject: doc Task-number: QTBUG-7125 --- doc/src/declarative/extending.qdoc | 8 +++-- doc/src/declarative/modules.qdoc | 69 +++++++++++++++++++++++++++++--------- 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc index 056b8ab..84d7089 100644 --- a/doc/src/declarative/extending.qdoc +++ b/doc/src/declarative/extending.qdoc @@ -54,6 +54,7 @@ QML for their own independent use. \tableofcontents \section1 Adding Types +\target adding-types \snippet examples/declarative/extending/adding/example.qml 0 @@ -71,11 +72,11 @@ Custom C++ types are made available to QML using these two macros: \quotation \code #define QML_DECLARE_TYPE(T) -#define QML_DEFINE_TYPE(URI,VMAJ,VFROM,VTO,QmlName,T) +#define QML_DEFINE_TYPE(URI,VMAJ,VMIN,QmlName,T) \endcode Register the C++ type \a T with the QML system, and make it available in QML -under the name \a QmlName in library URI version VMAJ.VFROM to VMAJ.VTO. +under the name \a QmlName in library URI version VMAJ.VMIN. \a T and \a QmlName may be the same. Generally the QML_DECLARE_TYPE() macro should be included immediately following @@ -87,6 +88,9 @@ Type \a T must be a concrete type that inherits QObject and has a default constructor. \endquotation +Types can be registered by libraries (such as Qt does), application code, +or by plugins (see QmlModulePlugin). + Once registered, all of the \l {Qt's Property System}{properties} of a supported type are available for use within QML. QML has intrinsic support for properties of these types: diff --git a/doc/src/declarative/modules.qdoc b/doc/src/declarative/modules.qdoc index 1491fea..ec36fe7 100644 --- a/doc/src/declarative/modules.qdoc +++ b/doc/src/declarative/modules.qdoc @@ -46,24 +46,51 @@ A \bold module is a collection of QML types. To use types from a module it must be imported using the \c import statement. Successive -import statements override earlier import statements. +import statements override earlier import statements, however, since imports have version +qualifiers, changes in modules do not alter the semantics of imports. -\section1 Importing Built-in Types +\section1 Importing Types Defined in C++ -To use built-in types, you must import the module defining them. -For example, to use types from Qt, import it: +Types \link adding-types defined in C++\endlink can be from types your application defines, standard QML types, +or types defined in plugins. To use any such types, you must import +the module defining them. For example, to use types from Qt, import it: \code import Qt 4.6 \endcode This makes available all types in Qt that were available in Qt 4.6, regardless of the -actual version of Qt executing the QML. +actual version of Qt executing the QML. So even if Qt 4.7 adds a type that would conflict +with a type you defined while using 4.6, that type is not imported, so there is no conflict. -Modules can be compiled-in (such as the Qt module), or they can be -defined in QML files. +Types defined by plugins are made using QmlModulePlugin. -\section1 Importing QML Files + +\section1 Importing Types Defined in QML + +When importing types \link components defined using QML\endlink, the syntax depends +on whether or not the types are installed on the system. + +\section2 Installed QML Files + +To import types defined in QML files that are installed on the system running the +QML, a URI import is used: + +\code +import com.nokia.Example 1.0 +\endcode + +Files imported in this way are found on the paths added by QmlEngine::addImportPath(), +which by default only inludes \c $QTDIR/qml, so the above would make available those types +defined in \c $QTDIR/qml/com/nokia/Example which are specified as being in version 1.0. + +The specification of types to versions is given by a special file, \c qmldir which must +exist in the module directory. The syntax is described below. + +The \c -L option to the \l {qmlviewer}{viewer} application also adds paths to the import path. + + +\section2 Local QML Files To import types defined in QML files in directories relative to the file importing them, a quoted import directory is used: @@ -75,18 +102,27 @@ import "path" This allows all components defined in the directory \c path to be used in the component where this statement appears. -To import types defined in QML files that are installed somewhere on the system, -an unquoted URI is used: +In this case, and only this case, it is not necessary for the module directory to include +a \c qmldir file, nor is it necessary to provide a version qualifier. The basis of this is +that the files in the subdirectory are assumed to be packaged with the importer, and therefore +they form a single versioned unit. + + +\section2 Remote QML Files + +To import types defined in QML file at arbitrary network locations, a quoted absolute URL is used: \code -import com.nokia.CoolStuff 1.0 +import "http://url/.../" 1.0 \endcode -This will access file in the directory \c com/nokia/CoolStuff/, found in some -location determined outside QML. See QmlEngine::addImportPath() and the \c -L option -to the \l {qmlviewer}{viewer} application. +This works the same as for relative directory imports, except that the target location \e must +include a \c qmldir file, and a version qualifier must be given. + -The directory of installed files must include a file \c qmldir which specifies the +\section2 The \c qmldir File + +Directories of installed files and remote content must include a file \c qmldir which specifies the mapping from all type names to versioned QML files. It is a list of lines of the form: \code @@ -105,7 +141,7 @@ since the \e first name-version match is used. Installed files do not need to import the module of which they are a part, as they can refer to the other QML files in the module as relative (local) files. -Installed files \e must be referred to by version information described above, +Installed and remote files \e must be referred to by version information described above, local files \e may have it. The versioning system ensures that a given QML file will work regardless of the version @@ -113,6 +149,7 @@ of installed software, since a versioned import \e only imports types for that v leaving other identifiers available, even if the actual installed version might otherwise use those identifiers. + \section1 Namespaces - Named Imports When importing content it by default imports types into the global namespace. -- cgit v0.12 From 9151c4838ac7428107246abb9c99f296ab395c3d Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Fri, 8 Jan 2010 14:32:41 +1000 Subject: Allow QML types defined in both C++ and QML files to be in the same module. --- doc/src/declarative/modules.qdoc | 5 +- examples/declarative/plugins/README | 8 ++- examples/declarative/plugins/files/Clock.qml | 50 +++++++++++++ examples/declarative/plugins/files/center.png | Bin 0 -> 765 bytes examples/declarative/plugins/files/clock.png | Bin 0 -> 20653 bytes examples/declarative/plugins/files/hour.png | Bin 0 -> 625 bytes examples/declarative/plugins/files/minute.png | Bin 0 -> 625 bytes examples/declarative/plugins/plugin.cpp | 82 ++++++++++++++++++--- examples/declarative/plugins/plugins.pro | 4 +- examples/declarative/plugins/plugins.qml | 22 ++---- src/declarative/qml/qmlengine.cpp | 99 ++++++++++++++------------ src/declarative/qml/qmlmetatype.cpp | 1 - 12 files changed, 193 insertions(+), 78 deletions(-) create mode 100644 examples/declarative/plugins/files/Clock.qml create mode 100644 examples/declarative/plugins/files/center.png create mode 100644 examples/declarative/plugins/files/clock.png create mode 100644 examples/declarative/plugins/files/hour.png create mode 100644 examples/declarative/plugins/files/minute.png diff --git a/doc/src/declarative/modules.qdoc b/doc/src/declarative/modules.qdoc index ec36fe7..368595f 100644 --- a/doc/src/declarative/modules.qdoc +++ b/doc/src/declarative/modules.qdoc @@ -63,7 +63,8 @@ This makes available all types in Qt that were available in Qt 4.6, regardless o actual version of Qt executing the QML. So even if Qt 4.7 adds a type that would conflict with a type you defined while using 4.6, that type is not imported, so there is no conflict. -Types defined by plugins are made using QmlModulePlugin. +Types defined by plugins are made using QmlModulePlugin. Installed plugins and QML files +can both contribute types to the same module. \section1 Importing Types Defined in QML @@ -71,6 +72,7 @@ Types defined by plugins are made using QmlModulePlugin. When importing types \link components defined using QML\endlink, the syntax depends on whether or not the types are installed on the system. + \section2 Installed QML Files To import types defined in QML files that are installed on the system running the @@ -83,6 +85,7 @@ import com.nokia.Example 1.0 Files imported in this way are found on the paths added by QmlEngine::addImportPath(), which by default only inludes \c $QTDIR/qml, so the above would make available those types defined in \c $QTDIR/qml/com/nokia/Example which are specified as being in version 1.0. +Installed plugins and QML files can both contribute types to the same module. The specification of types to versions is given by a special file, \c qmldir which must exist in the module directory. The syntax is described below. diff --git a/examples/declarative/plugins/README b/examples/declarative/plugins/README index e67b1de..621f570 100644 --- a/examples/declarative/plugins/README +++ b/examples/declarative/plugins/README @@ -1,6 +1,8 @@ -This example show a C++ plugin that provides additional modules of QML types -(in this case, a single module with a single extra type). -to run: +This example shows a module "com.nokia.TimeExample" that is implelement +by a C++ plugin (providing the "Time" type), and by QML files (providing the +"Clock" type). + +To run: make install qmlviewer plugins.qml diff --git a/examples/declarative/plugins/files/Clock.qml b/examples/declarative/plugins/files/Clock.qml new file mode 100644 index 0000000..01ec686 --- /dev/null +++ b/examples/declarative/plugins/files/Clock.qml @@ -0,0 +1,50 @@ +import Qt 4.6 + +Item { + id: clock + width: 200; height: 200 + + property alias city: cityLabel.text + property var hours + property var minutes + property var shift : 0 + + Image { id: background; source: "clock.png" } + + Image { + x: 92.5; y: 27 + source: "hour.png" + smooth: true + transform: Rotation { + id: hourRotation + origin.x: 7.5; origin.y: 73; angle: 0 + angle: SpringFollow { + spring: 2; damping: 0.2; modulus: 360 + source: (clock.hours * 30) + (clock.minutes * 0.5) + } + } + } + + Image { + x: 93.5; y: 17 + source: "minute.png" + smooth: true + transform: Rotation { + id: minuteRotation + origin.x: 6.5; origin.y: 83; angle: 0 + angle: SpringFollow { + spring: 2; damping: 0.2; modulus: 360 + source: clock.minutes * 6 + } + } + } + + Image { + anchors.centerIn: background; source: "center.png" + } + + Text { + id: cityLabel; font.bold: true; font.pixelSize: 14; y:200; color: "white" + anchors.horizontalCenter: parent.horizontalCenter + } +} diff --git a/examples/declarative/plugins/files/center.png b/examples/declarative/plugins/files/center.png new file mode 100644 index 0000000..7fbd802 Binary files /dev/null and b/examples/declarative/plugins/files/center.png differ diff --git a/examples/declarative/plugins/files/clock.png b/examples/declarative/plugins/files/clock.png new file mode 100644 index 0000000..462edac Binary files /dev/null and b/examples/declarative/plugins/files/clock.png differ diff --git a/examples/declarative/plugins/files/hour.png b/examples/declarative/plugins/files/hour.png new file mode 100644 index 0000000..f8061a1 Binary files /dev/null and b/examples/declarative/plugins/files/hour.png differ diff --git a/examples/declarative/plugins/files/minute.png b/examples/declarative/plugins/files/minute.png new file mode 100644 index 0000000..1297ec7 Binary files /dev/null and b/examples/declarative/plugins/files/minute.png differ diff --git a/examples/declarative/plugins/plugin.cpp b/examples/declarative/plugins/plugin.cpp index ac44e7e..9688caf 100644 --- a/examples/declarative/plugins/plugin.cpp +++ b/examples/declarative/plugins/plugin.cpp @@ -44,22 +44,35 @@ #include #include #include +#include -class Time : public QObject +// Implements a "Time" class with hour and minute properties +// that change on-the-minute yet efficiently sleep the rest +// of the time. + +class MinuteTimer : public QObject { Q_OBJECT - Q_PROPERTY(int hour READ hour NOTIFY timeChanged) - Q_PROPERTY(int minute READ minute NOTIFY timeChanged) - public: - Time(QObject *parent=0) : QObject(parent) + MinuteTimer(QObject *parent) : QObject(parent) + { + } + + void start() { - timerEvent(0); - timer.start(30000,this); + if (!timer.isActive()) { + time = QTime::currentTime(); + timer.start(60000-time.second()*1000, this); + } } - int minute() const { return t.minute(); } - int hour() const { return t.hour(); } + void stop() + { + timer.stop(); + } + + int hour() const { return time.hour(); } + int minute() const { return time.minute(); } signals: void timeChanged(); @@ -67,18 +80,67 @@ signals: protected: void timerEvent(QTimerEvent *) { - t = QTime::currentTime(); + QTime now = QTime::currentTime(); + if (now.second() == 59 && now.minute() == time.minute() && now.hour() == time.hour()) { + // just missed time tick over, force it, wait extra 0.5 seconds + time.addSecs(60); + timer.start(60500, this); + } else { + time = now; + timer.start(60000-time.second()*1000, this); + } emit timeChanged(); } private: + QTime time; QBasicTimer timer; +}; + +class Time : public QObject +{ + Q_OBJECT + Q_PROPERTY(int hour READ hour NOTIFY timeChanged) + Q_PROPERTY(int minute READ minute NOTIFY timeChanged) + +public: + Time(QObject *parent=0) : QObject(parent) + { + if (++instances == 1) { + if (!timer) + timer = new MinuteTimer(qApp); + connect(timer, SIGNAL(timeChanged()), this, SIGNAL(timeChanged())); + timer->start(); + } + } + + ~Time() + { + if (--instances == 0) { + timer->stop(); + } + } + + int minute() const { return timer->minute(); } + int hour() const { return timer->hour(); } + +signals: + void timeChanged(); + +private: QTime t; + static MinuteTimer *timer; + static int instances; }; +int Time::instances=0; +MinuteTimer *Time::timer=0; + + QML_DECLARE_TYPE(Time); QML_DEFINE_TYPE(com.nokia.TimeExample,1,0,Time,Time); + class QExampleQmlPlugin : public QmlModulePlugin { Q_OBJECT diff --git a/examples/declarative/plugins/plugins.pro b/examples/declarative/plugins/plugins.pro index a1a94f9..4109eba 100644 --- a/examples/declarative/plugins/plugins.pro +++ b/examples/declarative/plugins/plugins.pro @@ -5,7 +5,9 @@ CONFIG += qt plugin declarative SOURCES += plugin.cpp target.path += $$[QT_INSTALL_PLUGINS]/qmlmodules -INSTALLS += target +sources.files += files/Clock.qml files/qmldir files/background.png files/center.png files/clock-night.png files/clock.png files/hour.png files/minute.png +sources.path += $$[QT_INSTALL_DATA]/qml/com/nokia/TimeExample +INSTALLS += target sources VERSION=1.0.0 diff --git a/examples/declarative/plugins/plugins.qml b/examples/declarative/plugins/plugins.qml index df6b5d4..97c1b69 100644 --- a/examples/declarative/plugins/plugins.qml +++ b/examples/declarative/plugins/plugins.qml @@ -1,23 +1,11 @@ -import Qt 4.6 import com.nokia.TimeExample 1.0 -Item { +Clock { // this class is defined in QML (files/Clock.qml) - Time { id: time } - - width: 200 - height: 100 - - Rectangle { - anchors.fill: parent - color: "blue" + Time { // this class is defined in C++ (plugins.cpp) + id: time } - Text { - text: time.hour + ":" + (time.minute < 10 ? "0" : "") + time.minute - anchors.centerIn: parent - color: "white" - font.pixelSize: 42 - font.bold: true - } + hours: time.hour + minutes: time.minute } diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index c44f6b6..e7d0743 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -123,6 +124,7 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) inBeginCreate(false), networkAccessManager(0), typeManager(e), uniqueId(1) { globalClass = new QmlGlobalScriptClass(&scriptEngine); + fileImportPath.append(QLibraryInfo::location(QLibraryInfo::DataPath)+QDir::separator()+QLatin1String("qml")); } QUrl QmlScriptEngine::resolvedUrl(QScriptContext *context, const QUrl& url) @@ -1083,11 +1085,12 @@ static QString toLocalFileOrQrc(const QUrl& url) ///////////////////////////////////////////////////////////// struct QmlEnginePrivate::ImportedNamespace { + QStringList uris; QStringList urls; QList majversions; QList minversions; QList isLibrary; - QList isBuiltin; + QList isBuiltin; // Types provided by C++ code (including plugins) QList qmlDirContent; bool find(const QByteArray& type, int *vmajor, int *vminor, QmlType** type_return, QUrl* url_return) const @@ -1097,57 +1100,60 @@ struct QmlEnginePrivate::ImportedNamespace { int vmin = minversions.at(i); if (isBuiltin.at(i)) { - QByteArray qt = urls.at(i).toUtf8(); + QByteArray qt = uris.at(i).toUtf8(); qt += '/'; qt += type; + if (qmlImportTrace()) + qDebug() << "Look in" << qt; QmlType *t = QmlMetaType::qmlType(qt,vmaj,vmin); if (vmajor) *vmajor = vmaj; if (vminor) *vminor = vmin; if (t) { + if (qmlImportTrace()) + qDebug() << "Found" << qt; if (type_return) *type_return = t; return true; } - } else { - QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml")); - QString qmldircontent = qmlDirContent.at(i); - if (vmaj || vmin || !qmldircontent.isEmpty()) { - // Check version file - XXX cache these in QmlEngine! - if (qmldircontent.isEmpty()) { - QFile qmldir(toLocalFileOrQrc(QUrl(urls.at(i)+QLatin1String("/qmldir")))); - if (qmldir.open(QIODevice::ReadOnly)) { - qmldircontent = QString::fromUtf8(qmldir.readAll()); - } + } + QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml")); + QString qmldircontent = qmlDirContent.at(i); + if (vmaj || vmin || !qmldircontent.isEmpty()) { + // Check version file - XXX cache these in QmlEngine! + if (qmldircontent.isEmpty()) { + QFile qmldir(toLocalFileOrQrc(QUrl(urls.at(i)+QLatin1String("/qmldir")))); + if (qmldir.open(QIODevice::ReadOnly)) { + qmldircontent = QString::fromUtf8(qmldir.readAll()); } - QString typespace = QString::fromUtf8(type)+QLatin1Char(' '); - QStringList lines = qmldircontent.split(QLatin1Char('\n')); - foreach (QString line, lines) { - if (line.isEmpty() || line.at(0) == QLatin1Char('#')) - continue; - if (line.startsWith(typespace)) { - int space1 = line.indexOf(QLatin1Char(' ')); - int space2 = space1 >=0 ? line.indexOf(QLatin1Char(' '),space1+1) : -1; - QString mapversions = line.mid(space1+1,space2<0?line.length()-space1-1:space2-space1-1); - int dot = mapversions.indexOf(QLatin1Char('.')); - int mapvmaj = mapversions.left(dot).toInt(); - if (mapvmaj<=vmaj) { - if (mapvmaj= mapversions.mid(dot+1).toInt()) { - QStringRef mapfile = space2<0 ? QStringRef() : line.midRef(space2+1,line.length()-space2-1); - if (url_return) - *url_return = url.resolved(mapfile.toString()); - return true; - } + } + QString typespace = QString::fromUtf8(type)+QLatin1Char(' '); + QStringList lines = qmldircontent.split(QLatin1Char('\n')); + foreach (QString line, lines) { + if (line.isEmpty() || line.at(0) == QLatin1Char('#')) + continue; + if (line.startsWith(typespace)) { + int space1 = line.indexOf(QLatin1Char(' ')); + int space2 = space1 >=0 ? line.indexOf(QLatin1Char(' '),space1+1) : -1; + QString mapversions = line.mid(space1+1,space2<0?line.length()-space1-1:space2-space1-1); + int dot = mapversions.indexOf(QLatin1Char('.')); + int mapvmaj = mapversions.left(dot).toInt(); + if (mapvmaj<=vmaj) { + if (mapvmaj= mapversions.mid(dot+1).toInt()) { + QStringRef mapfile = space2<0 ? QStringRef() : line.midRef(space2+1,line.length()-space2-1); + if (url_return) + *url_return = url.resolved(mapfile.toString()); + return true; } } } - } else { - // XXX search non-files too! (eg. zip files, see QT-524) - QFileInfo f(toLocalFileOrQrc(url)); - if (f.exists()) { - if (url_return) - *url_return = url; - return true; - } + } + } else { + // XXX search non-files too! (eg. zip files, see QT-524) + QFileInfo f(toLocalFileOrQrc(url)); + if (f.exists()) { + if (url_return) + *url_return = url; + return true; } } } @@ -1195,19 +1201,19 @@ public: } } if (!found) { - if (uri != QLatin1String("Qt")) { // skip well-known, it's not in a plugin - QFactoryLoader *l = loader(); - QmlModuleFactoryInterface *factory = - qobject_cast(l->instance(uri)); - // return value not used currently - } - // XXX assume it is a built-in type qualifier isbuiltin = true; + } else { + QFactoryLoader *l = loader(); + QmlModuleFactoryInterface *factory = + qobject_cast(l->instance(uri)); + if (factory) + isbuiltin = true; } } else { url = base.resolved(QUrl(url)).toString(); } + s->uris.prepend(uri); s->urls.prepend(url); s->majversions.prepend(vmaj); s->minversions.prepend(vmin); @@ -1389,6 +1395,9 @@ QUrl QmlEnginePrivate::Imports::baseUrl() const in \c /opt/MyApp/lib/qml/com/mycompany/Feature/ for the components provided by that module (and in the case of versioned imports, for the \c qmldir file definiting the type version mapping. + + By default, only the "qml" subdirectory of QLibraryInfo::location(QLibraryInfo::DataPath) + is included on the import path. */ void QmlEngine::addImportPath(const QString& path) { diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp index fbb3952..0b79a21 100644 --- a/src/declarative/qml/qmlmetatype.cpp +++ b/src/declarative/qml/qmlmetatype.cpp @@ -462,7 +462,6 @@ int QmlMetaType::registerType(const QmlPrivate::MetaTypeIds &id, QmlPrivate::Fun if (uri) name += '/'; name += cname; - name.replace('.','/'); QmlType *type = new QmlType(id.typeId, id.listId, id.qmlListId, func, name, version_maj, version_min, mo, attach, attachMo, pStatus, -- cgit v0.12 From 838e3f7771cc0d8b8ca1802b8bc73d4f37cbb107 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Fri, 8 Jan 2010 15:02:46 +1000 Subject: Fix painting to pixmap. If we render the graphics view in a pixmap effectiveClip is empty. From Marco --- src/declarative/graphicsitems/qmlgraphicspainteditem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/graphicsitems/qmlgraphicspainteditem.cpp b/src/declarative/graphicsitems/qmlgraphicspainteditem.cpp index 146b1e4..e50e3e4 100644 --- a/src/declarative/graphicsitems/qmlgraphicspainteditem.cpp +++ b/src/declarative/graphicsitems/qmlgraphicspainteditem.cpp @@ -256,7 +256,7 @@ void QmlGraphicsPaintedItem::paint(QPainter *p, const QStyleOptionGraphicsItem * topaint = QRect(0,0,p->device()->width(),p->device()->height()); else topaint = effectiveClip; - } else { + } else if (!effectiveClip.isEmpty()) { topaint &= effectiveClip; } -- cgit v0.12