Details
-
User Story
-
Resolution: Fixed
-
P1: Critical
-
5.15.0 Alpha
-
None
Description
Our current conception of value types and containers in QML has a few deficiencies, as expressed in other bugs and tasks. In particular:
- We have a qv4sequenceobject.cpp that spells out a number of combinations of value types and containers and generates adapters for them. The result is both incomplete by design and a huge amount of code due to template explosion. (
QTBUG-71574) - We have a list<Foo> syntax for declaring QQmlListProperty properties in QML, but we don't have a corresponding map<Foo>. list<Foo> only works for object types, not for value types. (
QTBUG-79264) - Value types can only be created with specific built-in constructor functions and there is no way to declare additional value types, either in C++ or in QML. (
QTBUG-54983, QTBUG-56484, QTBUG-72223,QTBUG-81593, and more) - Assigning to list<Foo> actually appends instead of replacing the contents. This behavior specifically targets the "children" property of QQuickItem. (
QTBUG-77529) - We need a consistent way of specifying the data a view requires from its model and that it can pass on to its delegates. (
QTBUG-80797,QTBUG-76848)
Those problems are interrelated and can be fixed by adding a few new concepts to the language. In particular:
- Allow assignment to value types from any compatible JavaScript object or other value type:
property font f: { bold: true, family: "sans" } property font f: unrelatedThingThatLooksLikeFont
The assignment shall be done property-by-property, for properties named and typed (or convertible) like the target. Additional properties on the source object are ignored, properties on the target object that are not present on the source object are reset to default constructed values.
You can also assign by only specifying the target's default property as single value. That is a short hand for "p: { <nameOfDefaultProperty> : <newValue> }". Allowing generic assignment makes the special constructor functions unnecessary. You can always default-construct a value type and then assign to it. - Maybe introduce an operator "+:" that amends a property, rather than replacing it. This is not particularly elegant and needs some further research. The exact semantics would depend on the target object. For lists, it would mean "append", for structured value types, it would replace the properties mentioned in the argument, without resetting the others:
// T.qml QtObject { property list<QtObject> l // destroys "family" binding below if b is updated property font f: { bold: b } property bool b: true } // U.qml T { // Does _not_ destroy "bold" binding above if f is updated f+: { family: f } property string f: "Tahoma" l+: QtObject { objectName: "add me" } // Appends to the list }
The nice thing about this, if you only use +: for your composite value types, is that you can escape the grouped properties trap. Suddenly you can have "whole object" replacement and "grouped" property access on the same property without causing ambiguity (unless you change the same sub-property from both). We can also deprecate the strange assignment-is-append behavior of list<Foo> this way.
- Introduce sequential<foo> and associative<bar> as interfaces. "sequential" and "associative" are keywords, not specific container implementations. C++ classes can declare QML_SEQUENTIAL or QML_ASSOCIATIVE and implement the respective functions to fulfill those interfaces. In addition, an elementMetaObject property needs to be available from the class. That property could be used to check whether the container can be assigned to a specific sequential<> or
associative<>. A view would then declare its model as having the type sequential<data> for some value type "data". This would be fulfilled by any container that provides compatible objects. - Allow registration of lower case value types. Those can again be either simple Q_GADGET or container types. They can only exist as properties of object types and they have no signals. Much like current value types, they will signal on the enclosing type if changed. You can register custom simple containers like QVector<int> that way. This makes qv4sequenceobject.cpp unnecessary. You would generally register a specific combination of container and value that way, like "QVector<int>" would be registered as "vector<int>" using a special macro in the C++ type declaration. You can have additional properties, even default properties, on those containers. Corollary: A "range<int>" may be registered by QtQml.Models, with an "int count" as default property. That would do what we currently see when assigning a plain number to the "model" property of e.g. Repeater.
- list<foo> and map<foo> for value types is just a QVariantList or QVariantMap. For object types we stick to QQmlListProperty and introduce QQmlMapProperty as complement. The assignment-is-append behavior gets deprecated. You will be reminded to use "+:" for appending and (for now) clear() and append() for replacing.
- We may provide syntax for declaring value types in QML. The specifics are still to be defined.
Attachments
Issue Links
- depends on
-
QTBUG-81716 Improve Q*Iterable
- Closed
- relates to
-
QTBUG-99115 Make it easier to read and write model data outside of a delegate
- Reported
-
QTBUG-84738 unable to define custom basic numeric type(like real) for qml
- Open
-
QTBUG-77529 Overriding QQmlListProperty in QML appends instead of replacing
- Closed
-
QTBUG-80797 No consistent way to refer to model data within a delegate
- Closed
-
QTBUG-99766 QML value type write-back support is inconsistent
- Closed
-
QTBUG-100313 Support value type lists in qmltc
- Closed
-
QTBUG-102884 Create extension types for Q_GADGETs in a good way
- Reported
-
QTBUG-72223 Make it possible to declare Q_GADGET instances in QML
- Open
-
QTBUG-71574 Provide a better way to register sequential and associative types for usage in QML
- Closed
-
QTBUG-76848 Typed model data in QML
- Closed
-
QTBUG-56484 Definition of gadgets in QML
- Open
-
QTBUG-54983 Create Q_GADGET objects in QML
- Closed
-
QTBUG-81593 Add support for registering value type to QML engine
- Closed
-
QTBUG-81716 Improve Q*Iterable
- Closed
- resulted in
-
QTBUG-79264 Provide a "lightweight model" template to mimic a key/value map
- Closed
For Gerrit Dashboard: QTBUG-82443 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
313314,10 | V4: Rewrite qv4sequenceobject based on QMetaSequence | dev | qt/qtdeclarative | Status: MERGED | +2 | 0 |
314188,12 | Allow proper registration of value types | dev | qt/qtdeclarative | Status: MERGED | +2 | 0 |
320714,7 | QtQml: Integrate sequences with registration macros | dev | qt/qtdeclarative | Status: MERGED | +2 | 0 |
389016,25 | QML: Allow named lists of value types | dev | qt/qtdeclarative | Status: MERGED | +2 | 0 |
389027,26 | Allow custom named value types in QML | dev | qt/qtdeclarative | Status: MERGED | +2 | 0 |
389781,1 | QML: Test assignment of lists of derived type to lists of base type | dev | qt/qtdeclarative | Status: ABANDONED | 0 | 0 |
391452,5 | QML: Allow declaring and binding list<foo> properties in one step | dev | qt/qtdeclarative | Status: MERGED | +2 | 0 |
421422,15 | Fix array-like methods on V4 sequences | dev | qt/qtdeclarative | Status: MERGED | +2 | 0 |
422534,3 | Fix array-like methods on V4 sequences | 6.4 | qt/qtdeclarative | Status: MERGED | +2 | 0 |