Add Singleton support for QML
This introduces Singleton support for QML (Composite Singleton). For now, the Singleton support is only availabe for QML types in modules or (remote and local) directories with qmldir file. However, in the future this support may be expanded to arbitrary QML file imports without by leaving out the qmldir requirement. You define a QML type as a Singleton with the following two steps: 1. By adding a pragma Singleton to a type's QML file: pragma Singleton The pragma and import statements can be mixed and their order does not matter. Singleton is the only supported pragma for now. Others will generate errors. 2. By specifying a qmldir file for the directory of your imported type and prepending the type with "singleton" keyword as follows: singleton TestTypeSingleton TestTypeSingleton.qml Alternatively you may specify a qmldir file for a module and specify your type as a singleton as follows: singleton TestTypeSingleton 1.0 TestTypeSingleton.qml Composite Singletons may be included in a module and may be used with a local namespace qualifier when imported with: "import xxx as NameSpace" A singleton instance is created at first use and stored into the QmlEngine (one instance per engine) and eventually released by the engine's destructor. CompositeSingletonType has a dual nature and will return true to both isComposite() and isSingleton() calls. In most cases its enough to check for just isComposite() or isSingleton(). However, there is a isCompositeSingleton() available as well. I used "qlalr --no-debug --no-lines --qt qqmljs.g" to generate the qqmljsparser and qqmljsgrammar files from qqmljs.g. Unit tests are included. Change-Id: I91b303612c5e132143b325b9a8f982e9355bc90e Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com>
This commit is contained in:
parent
b365471f0a
commit
200a869441
|
@ -128,7 +128,7 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
|
|||
|
||||
sourceCode = code;
|
||||
|
||||
accept(program->imports);
|
||||
accept(program->headers);
|
||||
|
||||
if (program->members->next) {
|
||||
QQmlError error;
|
||||
|
@ -241,7 +241,7 @@ bool QQmlCodeGenerator::visit(AST::UiArrayBinding *node)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool QQmlCodeGenerator::visit(AST::UiImportList *list)
|
||||
bool QQmlCodeGenerator::visit(AST::UiHeaderItemList *list)
|
||||
{
|
||||
return AST::Visitor::visit(list);
|
||||
}
|
||||
|
@ -418,6 +418,11 @@ bool QQmlCodeGenerator::visit(AST::UiImport *node)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool QQmlCodeGenerator::visit(AST::UiPragma *ast)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
|
||||
{
|
||||
if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
|
||||
|
|
|
@ -188,7 +188,8 @@ public:
|
|||
|
||||
virtual bool visit(AST::UiArrayMemberList *ast);
|
||||
virtual bool visit(AST::UiImport *ast);
|
||||
virtual bool visit(AST::UiImportList *ast);
|
||||
virtual bool visit(AST::UiPragma *ast);
|
||||
virtual bool visit(AST::UiHeaderItemList *ast);
|
||||
virtual bool visit(AST::UiObjectInitializer *ast);
|
||||
virtual bool visit(AST::UiObjectMemberList *ast);
|
||||
virtual bool visit(AST::UiParameterList *ast);
|
||||
|
|
|
@ -937,7 +937,13 @@ bool Codegen::visit(UiImport *)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Codegen::visit(UiImportList *)
|
||||
bool Codegen::visit(UiHeaderItemList *)
|
||||
{
|
||||
assert(!"unreachable");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Codegen::visit(UiPragma *)
|
||||
{
|
||||
assert(!"unreachable");
|
||||
return false;
|
||||
|
@ -973,6 +979,12 @@ bool Codegen::visit(UiQualifiedId *)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Codegen::visit(UiQualifiedPragmaId *)
|
||||
{
|
||||
assert(!"unreachable");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Codegen::visit(VariableDeclaration *)
|
||||
{
|
||||
assert(!"unreachable");
|
||||
|
|
|
@ -326,12 +326,14 @@ protected:
|
|||
virtual bool visit(AST::StatementList *ast);
|
||||
virtual bool visit(AST::UiArrayMemberList *ast);
|
||||
virtual bool visit(AST::UiImport *ast);
|
||||
virtual bool visit(AST::UiImportList *ast);
|
||||
virtual bool visit(AST::UiHeaderItemList *ast);
|
||||
virtual bool visit(AST::UiPragma *ast);
|
||||
virtual bool visit(AST::UiObjectInitializer *ast);
|
||||
virtual bool visit(AST::UiObjectMemberList *ast);
|
||||
virtual bool visit(AST::UiParameterList *ast);
|
||||
virtual bool visit(AST::UiProgram *ast);
|
||||
virtual bool visit(AST::UiQualifiedId *ast);
|
||||
virtual bool visit(AST::UiQualifiedPragmaId *ast);
|
||||
virtual bool visit(AST::VariableDeclaration *ast);
|
||||
virtual bool visit(AST::VariableDeclarationList *ast);
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
--- context keywords.
|
||||
%token T_PUBLIC "public"
|
||||
%token T_IMPORT "import"
|
||||
%token T_PRAGMA "pragma"
|
||||
%token T_AS "as"
|
||||
%token T_ON "on"
|
||||
%token T_GET "get"
|
||||
|
@ -253,7 +254,8 @@ public:
|
|||
AST::VariableDeclarationList *VariableDeclarationList;
|
||||
|
||||
AST::UiProgram *UiProgram;
|
||||
AST::UiImportList *UiImportList;
|
||||
AST::UiHeaderItemList *UiHeaderItemList;
|
||||
AST::UiPragma *UiPragma;
|
||||
AST::UiImport *UiImport;
|
||||
AST::UiParameterList *UiParameterList;
|
||||
AST::UiPublicMember *UiPublicMember;
|
||||
|
@ -266,6 +268,7 @@ public:
|
|||
AST::UiObjectMemberList *UiObjectMemberList;
|
||||
AST::UiArrayMemberList *UiArrayMemberList;
|
||||
AST::UiQualifiedId *UiQualifiedId;
|
||||
AST::UiQualifiedPragmaId *UiQualifiedPragmaId;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -347,6 +350,7 @@ protected:
|
|||
{ return location_stack [tos + index - 1]; }
|
||||
|
||||
AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
|
||||
AST::UiQualifiedPragmaId *reparseAsQualifiedPragmaId(AST::ExpressionNode *expr);
|
||||
|
||||
protected:
|
||||
Engine *driver;
|
||||
|
@ -486,6 +490,19 @@ AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
AST::UiQualifiedPragmaId *Parser::reparseAsQualifiedPragmaId(AST::ExpressionNode *expr)
|
||||
{
|
||||
if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(expr)) {
|
||||
AST::UiQualifiedPragmaId *q = new (pool) AST::UiQualifiedPragmaId(idExpr->name);
|
||||
q->identifierToken = idExpr->identifierToken;
|
||||
|
||||
return q->finish();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Parser::parse(int startToken)
|
||||
{
|
||||
Lexer *lexer = driver->lexer();
|
||||
|
@ -594,38 +611,62 @@ case $rule_number: {
|
|||
} break;
|
||||
./
|
||||
|
||||
UiProgram: UiImportListOpt UiRootMember ;
|
||||
UiProgram: UiHeaderItemListOpt UiRootMember;
|
||||
/.
|
||||
case $rule_number: {
|
||||
sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiImportList,
|
||||
sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiHeaderItemList,
|
||||
sym(2).UiObjectMemberList->finish());
|
||||
} break;
|
||||
./
|
||||
|
||||
UiImportListOpt: Empty ;
|
||||
UiImportListOpt: UiImportList ;
|
||||
UiHeaderItemListOpt: Empty ;
|
||||
UiHeaderItemListOpt: UiHeaderItemList ;
|
||||
/.
|
||||
case $rule_number: {
|
||||
sym(1).Node = sym(1).UiImportList->finish();
|
||||
sym(1).Node = sym(1).UiHeaderItemList->finish();
|
||||
} break;
|
||||
./
|
||||
|
||||
UiImportList: UiImport ;
|
||||
UiHeaderItemList: UiPragma ;
|
||||
/.
|
||||
case $rule_number: {
|
||||
sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImport);
|
||||
sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiPragma);
|
||||
} break;
|
||||
./
|
||||
|
||||
UiImportList: UiImportList UiImport ;
|
||||
UiHeaderItemList: UiImport ;
|
||||
/.
|
||||
case $rule_number: {
|
||||
sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImportList, sym(2).UiImport);
|
||||
sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiImport);
|
||||
} break;
|
||||
./
|
||||
|
||||
UiHeaderItemList: UiHeaderItemList UiPragma ;
|
||||
/.
|
||||
case $rule_number: {
|
||||
sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiHeaderItemList, sym(2).UiPragma);
|
||||
} break;
|
||||
./
|
||||
|
||||
UiHeaderItemList: UiHeaderItemList UiImport ;
|
||||
/.
|
||||
case $rule_number: {
|
||||
sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiHeaderItemList, sym(2).UiImport);
|
||||
} break;
|
||||
./
|
||||
|
||||
PragmaId: MemberExpression ;
|
||||
|
||||
ImportId: MemberExpression ;
|
||||
|
||||
UiPragma: UiPragmaHead T_AUTOMATIC_SEMICOLON ;
|
||||
UiPragma: UiPragmaHead T_SEMICOLON ;
|
||||
/.
|
||||
case $rule_number: {
|
||||
sym(1).UiPragma->semicolonToken = loc(2);
|
||||
} break;
|
||||
./
|
||||
|
||||
UiImport: UiImportHead T_AUTOMATIC_SEMICOLON ;
|
||||
UiImport: UiImportHead T_SEMICOLON ;
|
||||
/.
|
||||
|
@ -666,6 +707,28 @@ case $rule_number: {
|
|||
} break;
|
||||
./
|
||||
|
||||
UiPragmaHead: T_PRAGMA PragmaId ;
|
||||
/.
|
||||
case $rule_number: {
|
||||
AST::UiPragma *node = 0;
|
||||
|
||||
if (AST::UiQualifiedPragmaId *qualifiedId = reparseAsQualifiedPragmaId(sym(2).Expression)) {
|
||||
node = new (pool) AST::UiPragma(qualifiedId);
|
||||
}
|
||||
|
||||
sym(1).Node = node;
|
||||
|
||||
if (node) {
|
||||
node->pragmaToken = loc(1);
|
||||
} else {
|
||||
diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
|
||||
QLatin1String("Expected a qualified name id")));
|
||||
|
||||
return false; // ### remove me
|
||||
}
|
||||
} break;
|
||||
./
|
||||
|
||||
|
||||
UiImportHead: T_IMPORT ImportId ;
|
||||
/.
|
||||
|
@ -1261,6 +1324,7 @@ case $rule_number: {
|
|||
} break;
|
||||
./
|
||||
|
||||
|
||||
UiQualifiedId: MemberExpression ;
|
||||
/.
|
||||
case $rule_number: {
|
||||
|
|
|
@ -821,7 +821,7 @@ void DebuggerStatement::accept0(Visitor *visitor)
|
|||
void UiProgram::accept0(Visitor *visitor)
|
||||
{
|
||||
if (visitor->visit(this)) {
|
||||
accept(imports, visitor);
|
||||
accept(headers, visitor);
|
||||
accept(members, visitor);
|
||||
}
|
||||
|
||||
|
@ -932,16 +932,34 @@ void UiImport::accept0(Visitor *visitor)
|
|||
visitor->endVisit(this);
|
||||
}
|
||||
|
||||
void UiImportList::accept0(Visitor *visitor)
|
||||
void UiQualifiedPragmaId::accept0(Visitor *visitor)
|
||||
{
|
||||
if (visitor->visit(this)) {
|
||||
accept(import, visitor);
|
||||
}
|
||||
|
||||
visitor->endVisit(this);
|
||||
}
|
||||
|
||||
void UiPragma::accept0(Visitor *visitor)
|
||||
{
|
||||
if (visitor->visit(this)) {
|
||||
accept(pragmaType, visitor);
|
||||
}
|
||||
|
||||
visitor->endVisit(this);
|
||||
}
|
||||
|
||||
void UiHeaderItemList::accept0(Visitor *visitor)
|
||||
{
|
||||
if (visitor->visit(this)) {
|
||||
accept(headerItem, visitor);
|
||||
accept(next, visitor);
|
||||
}
|
||||
|
||||
visitor->endVisit(this);
|
||||
}
|
||||
|
||||
|
||||
void UiSourceElement::accept0(Visitor *visitor)
|
||||
{
|
||||
if (visitor->visit(this)) {
|
||||
|
|
|
@ -207,18 +207,20 @@ public:
|
|||
|
||||
Kind_UiArrayBinding,
|
||||
Kind_UiImport,
|
||||
Kind_UiImportList,
|
||||
Kind_UiObjectBinding,
|
||||
Kind_UiObjectDefinition,
|
||||
Kind_UiObjectInitializer,
|
||||
Kind_UiObjectMemberList,
|
||||
Kind_UiArrayMemberList,
|
||||
Kind_UiPragma,
|
||||
Kind_UiProgram,
|
||||
Kind_UiParameterList,
|
||||
Kind_UiPublicMember,
|
||||
Kind_UiQualifiedId,
|
||||
Kind_UiQualifiedPragmaId,
|
||||
Kind_UiScriptBinding,
|
||||
Kind_UiSourceElement
|
||||
Kind_UiSourceElement,
|
||||
Kind_UiHeaderItemList
|
||||
};
|
||||
|
||||
inline Node()
|
||||
|
@ -2271,44 +2273,6 @@ public:
|
|||
SourceLocation semicolonToken;
|
||||
};
|
||||
|
||||
class QML_PARSER_EXPORT UiImportList: public Node
|
||||
{
|
||||
public:
|
||||
QQMLJS_DECLARE_AST_NODE(UiImportList)
|
||||
|
||||
UiImportList(UiImport *import)
|
||||
: import(import),
|
||||
next(this)
|
||||
{ kind = K; }
|
||||
|
||||
UiImportList(UiImportList *previous, UiImport *import)
|
||||
: import(import)
|
||||
{
|
||||
kind = K;
|
||||
next = previous->next;
|
||||
previous->next = this;
|
||||
}
|
||||
|
||||
UiImportList *finish()
|
||||
{
|
||||
UiImportList *head = next;
|
||||
next = 0;
|
||||
return head;
|
||||
}
|
||||
|
||||
virtual void accept0(Visitor *visitor);
|
||||
|
||||
virtual SourceLocation firstSourceLocation() const
|
||||
{ return import->firstSourceLocation(); }
|
||||
|
||||
virtual SourceLocation lastSourceLocation() const
|
||||
{ return next ? next->lastSourceLocation() : import->lastSourceLocation(); }
|
||||
|
||||
// attributes
|
||||
UiImport *import;
|
||||
UiImportList *next;
|
||||
};
|
||||
|
||||
class QML_PARSER_EXPORT UiObjectMember: public Node
|
||||
{
|
||||
public:
|
||||
|
@ -2355,21 +2319,131 @@ public:
|
|||
UiObjectMember *member;
|
||||
};
|
||||
|
||||
class QML_PARSER_EXPORT UiQualifiedPragmaId: public Node
|
||||
{
|
||||
public:
|
||||
QQMLJS_DECLARE_AST_NODE(UiQualifiedPragmaId)
|
||||
|
||||
UiQualifiedPragmaId(const QStringRef &name)
|
||||
: next(this), name(name)
|
||||
{ kind = K; }
|
||||
|
||||
UiQualifiedPragmaId(UiQualifiedPragmaId *previous, const QStringRef &name)
|
||||
: name(name)
|
||||
{
|
||||
kind = K;
|
||||
next = previous->next;
|
||||
previous->next = this;
|
||||
}
|
||||
|
||||
UiQualifiedPragmaId *finish()
|
||||
{
|
||||
UiQualifiedPragmaId *head = next;
|
||||
next = 0;
|
||||
return head;
|
||||
}
|
||||
|
||||
virtual void accept0(Visitor *visitor);
|
||||
|
||||
virtual SourceLocation firstSourceLocation() const
|
||||
{ return identifierToken; }
|
||||
|
||||
virtual SourceLocation lastSourceLocation() const
|
||||
{ return next ? next->lastSourceLocation() : identifierToken; }
|
||||
|
||||
// attributes
|
||||
UiQualifiedPragmaId *next;
|
||||
QStringRef name;
|
||||
SourceLocation identifierToken;
|
||||
};
|
||||
|
||||
class QML_PARSER_EXPORT UiPragma: public Node
|
||||
{
|
||||
public:
|
||||
QQMLJS_DECLARE_AST_NODE(UiPragma)
|
||||
|
||||
UiPragma(UiQualifiedPragmaId *type)
|
||||
: pragmaType(type)
|
||||
{ kind = K; }
|
||||
|
||||
virtual void accept0(Visitor *visitor);
|
||||
|
||||
virtual SourceLocation firstSourceLocation() const
|
||||
{ return pragmaToken; }
|
||||
|
||||
virtual SourceLocation lastSourceLocation() const
|
||||
{ return semicolonToken; }
|
||||
|
||||
// attributes
|
||||
UiQualifiedPragmaId *pragmaType;
|
||||
SourceLocation pragmaToken;
|
||||
SourceLocation semicolonToken;
|
||||
};
|
||||
|
||||
class QML_PARSER_EXPORT UiHeaderItemList: public Node
|
||||
{
|
||||
public:
|
||||
QQMLJS_DECLARE_AST_NODE(UiHeaderItemList)
|
||||
|
||||
UiHeaderItemList(UiImport *import)
|
||||
: headerItem(import), next(this)
|
||||
{ kind = K; }
|
||||
|
||||
UiHeaderItemList(UiPragma *pragma)
|
||||
: headerItem(pragma), next(this)
|
||||
{ kind = K; }
|
||||
|
||||
UiHeaderItemList(UiHeaderItemList *previous, UiImport *import)
|
||||
: headerItem(import)
|
||||
{
|
||||
kind = K;
|
||||
next = previous->next;
|
||||
previous->next = this;
|
||||
}
|
||||
|
||||
UiHeaderItemList(UiHeaderItemList *previous, UiPragma *pragma)
|
||||
: headerItem(pragma)
|
||||
{
|
||||
kind = K;
|
||||
next = previous->next;
|
||||
previous->next = this;
|
||||
}
|
||||
|
||||
UiHeaderItemList *finish()
|
||||
{
|
||||
UiHeaderItemList *head = next;
|
||||
next = 0;
|
||||
return head;
|
||||
}
|
||||
|
||||
virtual void accept0(Visitor *visitor);
|
||||
|
||||
virtual SourceLocation firstSourceLocation() const
|
||||
{ return headerItem->firstSourceLocation(); }
|
||||
|
||||
virtual SourceLocation lastSourceLocation() const
|
||||
{ return next ? next->lastSourceLocation() : headerItem->lastSourceLocation(); }
|
||||
|
||||
// attributes
|
||||
Node *headerItem;
|
||||
UiHeaderItemList *next;
|
||||
};
|
||||
|
||||
class QML_PARSER_EXPORT UiProgram: public Node
|
||||
{
|
||||
public:
|
||||
QQMLJS_DECLARE_AST_NODE(UiProgram)
|
||||
|
||||
UiProgram(UiImportList *imports, UiObjectMemberList *members)
|
||||
: imports(imports), members(members)
|
||||
UiProgram(UiHeaderItemList *headers, UiObjectMemberList *members)
|
||||
: headers(headers), members(members)
|
||||
{ kind = K; }
|
||||
|
||||
virtual void accept0(Visitor *visitor);
|
||||
|
||||
virtual SourceLocation firstSourceLocation() const
|
||||
{
|
||||
if (imports)
|
||||
return imports->firstSourceLocation();
|
||||
if (headers)
|
||||
return headers->firstSourceLocation();
|
||||
else if (members)
|
||||
return members->firstSourceLocation();
|
||||
return SourceLocation();
|
||||
|
@ -2379,13 +2453,13 @@ public:
|
|||
{
|
||||
if (members)
|
||||
return members->lastSourceLocation();
|
||||
else if (imports)
|
||||
return imports->lastSourceLocation();
|
||||
else if (headers)
|
||||
return headers->lastSourceLocation();
|
||||
return SourceLocation();
|
||||
}
|
||||
|
||||
// attributes
|
||||
UiImportList *imports;
|
||||
UiHeaderItemList *headers;
|
||||
UiObjectMemberList *members;
|
||||
};
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ class NestedExpression;
|
|||
|
||||
// ui elements
|
||||
class UiProgram;
|
||||
class UiImportList;
|
||||
class UiPragma;
|
||||
class UiImport;
|
||||
class UiPublicMember;
|
||||
class UiParameterList;
|
||||
|
@ -181,6 +181,8 @@ class UiObjectMember;
|
|||
class UiObjectMemberList;
|
||||
class UiArrayMemberList;
|
||||
class UiQualifiedId;
|
||||
class UiQualifiedPragmaId;
|
||||
class UiHeaderItemList;
|
||||
|
||||
} } // namespace AST
|
||||
|
||||
|
|
|
@ -71,7 +71,8 @@ public:
|
|||
|
||||
// Ui
|
||||
virtual bool visit(UiProgram *) { return true; }
|
||||
virtual bool visit(UiImportList *) { return true; }
|
||||
virtual bool visit(UiHeaderItemList *) { return true; }
|
||||
virtual bool visit(UiPragma *) { return true; }
|
||||
virtual bool visit(UiImport *) { return true; }
|
||||
virtual bool visit(UiPublicMember *) { return true; }
|
||||
virtual bool visit(UiSourceElement *) { return true; }
|
||||
|
@ -84,10 +85,12 @@ public:
|
|||
virtual bool visit(UiObjectMemberList *) { return true; }
|
||||
virtual bool visit(UiArrayMemberList *) { return true; }
|
||||
virtual bool visit(UiQualifiedId *) { return true; }
|
||||
virtual bool visit(UiQualifiedPragmaId *) { return true; }
|
||||
|
||||
virtual void endVisit(UiProgram *) {}
|
||||
virtual void endVisit(UiImportList *) {}
|
||||
virtual void endVisit(UiImport *) {}
|
||||
virtual void endVisit(UiHeaderItemList *) {}
|
||||
virtual void endVisit(UiPragma *) {}
|
||||
virtual void endVisit(UiPublicMember *) {}
|
||||
virtual void endVisit(UiSourceElement *) {}
|
||||
virtual void endVisit(UiObjectDefinition *) {}
|
||||
|
@ -99,6 +102,7 @@ public:
|
|||
virtual void endVisit(UiObjectMemberList *) {}
|
||||
virtual void endVisit(UiArrayMemberList *) {}
|
||||
virtual void endVisit(UiQualifiedId *) {}
|
||||
virtual void endVisit(UiQualifiedPragmaId *) {}
|
||||
|
||||
// QQmlJS
|
||||
virtual bool visit(ThisExpression *) { return true; }
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -63,12 +63,12 @@ class QQmlJSGrammar
|
|||
public:
|
||||
enum VariousConstants {
|
||||
EOF_SYMBOL = 0,
|
||||
REDUCE_HERE = 104,
|
||||
SHIFT_THERE = 103,
|
||||
REDUCE_HERE = 105,
|
||||
SHIFT_THERE = 104,
|
||||
T_AND = 1,
|
||||
T_AND_AND = 2,
|
||||
T_AND_EQ = 3,
|
||||
T_AS = 92,
|
||||
T_AS = 93,
|
||||
T_AUTOMATIC_SEMICOLON = 62,
|
||||
T_BREAK = 4,
|
||||
T_CASE = 5,
|
||||
|
@ -90,19 +90,19 @@ public:
|
|||
T_EQ = 17,
|
||||
T_EQ_EQ = 18,
|
||||
T_EQ_EQ_EQ = 19,
|
||||
T_ERROR = 96,
|
||||
T_ERROR = 97,
|
||||
T_FALSE = 83,
|
||||
T_FEED_JS_EXPRESSION = 100,
|
||||
T_FEED_JS_PROGRAM = 102,
|
||||
T_FEED_JS_SOURCE_ELEMENT = 101,
|
||||
T_FEED_JS_STATEMENT = 99,
|
||||
T_FEED_UI_OBJECT_MEMBER = 98,
|
||||
T_FEED_UI_PROGRAM = 97,
|
||||
T_FEED_JS_EXPRESSION = 101,
|
||||
T_FEED_JS_PROGRAM = 103,
|
||||
T_FEED_JS_SOURCE_ELEMENT = 102,
|
||||
T_FEED_JS_STATEMENT = 100,
|
||||
T_FEED_UI_OBJECT_MEMBER = 99,
|
||||
T_FEED_UI_PROGRAM = 98,
|
||||
T_FINALLY = 20,
|
||||
T_FOR = 21,
|
||||
T_FUNCTION = 22,
|
||||
T_GE = 23,
|
||||
T_GET = 94,
|
||||
T_GET = 95,
|
||||
T_GT = 24,
|
||||
T_GT_GT = 25,
|
||||
T_GT_GT_EQ = 26,
|
||||
|
@ -130,13 +130,14 @@ public:
|
|||
T_NOT_EQ_EQ = 46,
|
||||
T_NULL = 81,
|
||||
T_NUMERIC_LITERAL = 47,
|
||||
T_ON = 93,
|
||||
T_ON = 94,
|
||||
T_OR = 48,
|
||||
T_OR_EQ = 49,
|
||||
T_OR_OR = 50,
|
||||
T_PLUS = 51,
|
||||
T_PLUS_EQ = 52,
|
||||
T_PLUS_PLUS = 53,
|
||||
T_PRAGMA = 92,
|
||||
T_PROPERTY = 66,
|
||||
T_PUBLIC = 90,
|
||||
T_QUESTION = 54,
|
||||
|
@ -149,7 +150,7 @@ public:
|
|||
T_RETURN = 59,
|
||||
T_RPAREN = 60,
|
||||
T_SEMICOLON = 61,
|
||||
T_SET = 95,
|
||||
T_SET = 96,
|
||||
T_SIGNAL = 67,
|
||||
T_STAR = 63,
|
||||
T_STAR_EQ = 64,
|
||||
|
@ -168,15 +169,15 @@ public:
|
|||
T_XOR = 79,
|
||||
T_XOR_EQ = 80,
|
||||
|
||||
ACCEPT_STATE = 655,
|
||||
RULE_COUNT = 351,
|
||||
STATE_COUNT = 656,
|
||||
TERMINAL_COUNT = 105,
|
||||
NON_TERMINAL_COUNT = 108,
|
||||
ACCEPT_STATE = 663,
|
||||
RULE_COUNT = 357,
|
||||
STATE_COUNT = 664,
|
||||
TERMINAL_COUNT = 106,
|
||||
NON_TERMINAL_COUNT = 111,
|
||||
|
||||
GOTO_INDEX_OFFSET = 656,
|
||||
GOTO_INFO_OFFSET = 2970,
|
||||
GOTO_CHECK_OFFSET = 2970
|
||||
GOTO_INDEX_OFFSET = 664,
|
||||
GOTO_INFO_OFFSET = 3104,
|
||||
GOTO_CHECK_OFFSET = 3104
|
||||
};
|
||||
|
||||
static const char *const spell [];
|
||||
|
|
|
@ -436,6 +436,17 @@ static inline int classify6(const QChar *s, bool qmlMode) {
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (s[1].unicode() == 'r') {
|
||||
if (s[2].unicode() == 'a') {
|
||||
if (s[3].unicode() == 'g') {
|
||||
if (s[4].unicode() == 'm') {
|
||||
if (s[5].unicode() == 'a') {
|
||||
return qmlMode ? Lexer::T_PRAGMA : Lexer::T_IDENTIFIER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (s[0].unicode() == 'r') {
|
||||
if (s[1].unicode() == 'e') {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -112,7 +112,8 @@ public:
|
|||
AST::VariableDeclarationList *VariableDeclarationList;
|
||||
|
||||
AST::UiProgram *UiProgram;
|
||||
AST::UiImportList *UiImportList;
|
||||
AST::UiHeaderItemList *UiHeaderItemList;
|
||||
AST::UiPragma *UiPragma;
|
||||
AST::UiImport *UiImport;
|
||||
AST::UiParameterList *UiParameterList;
|
||||
AST::UiPublicMember *UiPublicMember;
|
||||
|
@ -125,6 +126,7 @@ public:
|
|||
AST::UiObjectMemberList *UiObjectMemberList;
|
||||
AST::UiArrayMemberList *UiArrayMemberList;
|
||||
AST::UiQualifiedId *UiQualifiedId;
|
||||
AST::UiQualifiedPragmaId *UiQualifiedPragmaId;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -206,6 +208,7 @@ protected:
|
|||
{ return location_stack [tos + index - 1]; }
|
||||
|
||||
AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
|
||||
AST::UiQualifiedPragmaId *reparseAsQualifiedPragmaId(AST::ExpressionNode *expr);
|
||||
|
||||
protected:
|
||||
Engine *driver;
|
||||
|
@ -245,9 +248,9 @@ protected:
|
|||
|
||||
|
||||
|
||||
#define J_SCRIPT_REGEXPLITERAL_RULE1 81
|
||||
#define J_SCRIPT_REGEXPLITERAL_RULE1 87
|
||||
|
||||
#define J_SCRIPT_REGEXPLITERAL_RULE2 82
|
||||
#define J_SCRIPT_REGEXPLITERAL_RULE2 88
|
||||
|
||||
QT_QML_END_NAMESPACE
|
||||
|
||||
|
|
|
@ -821,6 +821,10 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
|
|||
QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
|
||||
|
||||
if (tref.typeData) { //QML-based type
|
||||
if (tref.type->isCompositeSingleton()) {
|
||||
QString err = tr( "Composite Singleton Type %1 is not creatable.").arg(tref.type->qmlTypeName());
|
||||
COMPILE_EXCEPTION(parserRef->firstUse, err);
|
||||
}
|
||||
ref.component = tref.typeData->compiledData();
|
||||
ref.component->addref();
|
||||
} else if (tref.type) {//C++-based type
|
||||
|
@ -886,6 +890,12 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree)
|
|||
output->importCache->add(ns);
|
||||
}
|
||||
|
||||
// Add any Composite Singletons that were used to the import cache
|
||||
for (int i = 0; i < unit->compositeSingletons().count(); ++i) {
|
||||
output->importCache->add(unit->compositeSingletons().at(i).type->qmlTypeName(),
|
||||
unit->compositeSingletons().at(i).type->sourceUrl(), unit->compositeSingletons().at(i).prefix);
|
||||
}
|
||||
|
||||
int scriptIndex = 0;
|
||||
foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
|
||||
QString qualifier = script.qualifier;
|
||||
|
@ -2546,7 +2556,7 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
|
|||
|
||||
if (!type && typeName != QLatin1String("Qt"))
|
||||
return true;
|
||||
if (type && type->isComposite()) //No enums on composite types
|
||||
if (type && type->isComposite()) //No enums on composite (or composite singleton) types
|
||||
return true;
|
||||
|
||||
int value = 0;
|
||||
|
@ -2984,6 +2994,8 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
|
|||
if (!unit->imports().resolveType(s->parameterTypeNames.at(i).toString(), &qmltype, 0, 0, 0))
|
||||
COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(s->parameterTypeNames.at(i).toString()));
|
||||
|
||||
// We dont mind even if the composite type ends up being composite singleton, here
|
||||
// we just acquire the metaTypeId.
|
||||
if (qmltype->isComposite()) {
|
||||
QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
|
||||
Q_ASSERT(tdata);
|
||||
|
|
|
@ -116,7 +116,7 @@ bool QQmlDirParser::parse(const QString &source)
|
|||
if (ch->isNull())
|
||||
break;
|
||||
|
||||
QString sections[3];
|
||||
QString sections[4];
|
||||
int sectionCount = 0;
|
||||
|
||||
do {
|
||||
|
@ -126,7 +126,7 @@ bool QQmlDirParser::parse(const QString &source)
|
|||
}
|
||||
const QChar *start = ch;
|
||||
scanWord(ch);
|
||||
if (sectionCount < 3) {
|
||||
if (sectionCount < 4) {
|
||||
sections[sectionCount++] = source.mid(start-source.constData(), ch-start);
|
||||
} else {
|
||||
reportError(lineNumber, start-lineStart, QLatin1String("unexpected token"));
|
||||
|
@ -167,7 +167,7 @@ bool QQmlDirParser::parse(const QString &source)
|
|||
_typeNamespace = sections[1];
|
||||
|
||||
} else if (sections[0] == QLatin1String("plugin")) {
|
||||
if (sectionCount < 2) {
|
||||
if (sectionCount < 2 || sectionCount > 3) {
|
||||
reportError(lineNumber, 0,
|
||||
QString::fromUtf8("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1));
|
||||
|
||||
|
@ -187,6 +187,43 @@ bool QQmlDirParser::parse(const QString &source)
|
|||
Component entry(sections[1], sections[2], -1, -1);
|
||||
entry.internal = true;
|
||||
_components.insertMulti(entry.typeName, entry);
|
||||
} else if (sections[0] == QLatin1String("singleton")) {
|
||||
if (sectionCount < 3 || sectionCount > 4) {
|
||||
reportError(lineNumber, 0,
|
||||
QString::fromUtf8("singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1));
|
||||
continue;
|
||||
} else if (sectionCount == 3) {
|
||||
// handle qmldir directory listing case where singleton is defined in the following pattern:
|
||||
// singleton TestSingletonType TestSingletonType.qml
|
||||
Component entry(sections[1], sections[2], -1, -1);
|
||||
entry.singleton = true;
|
||||
_components.insertMulti(entry.typeName, entry);
|
||||
} else {
|
||||
// handle qmldir module listing case where singleton is defined in the following pattern:
|
||||
// singleton TestSingletonType 2.0 TestSingletonType20.qml
|
||||
const QString &version = sections[2];
|
||||
const int dotIndex = version.indexOf(QLatin1Char('.'));
|
||||
|
||||
if (dotIndex == -1) {
|
||||
reportError(lineNumber, 0, QLatin1String("expected '.'"));
|
||||
} else if (version.indexOf(QLatin1Char('.'), dotIndex + 1) != -1) {
|
||||
reportError(lineNumber, 0, QLatin1String("unexpected '.'"));
|
||||
} else {
|
||||
bool validVersionNumber = false;
|
||||
const int majorVersion = parseInt(QStringRef(&version, 0, dotIndex), &validVersionNumber);
|
||||
|
||||
if (validVersionNumber) {
|
||||
const int minorVersion = parseInt(QStringRef(&version, dotIndex+1, version.length()-dotIndex-1), &validVersionNumber);
|
||||
|
||||
if (validVersionNumber) {
|
||||
const QString &fileName = sections[3];
|
||||
Component entry(sections[1], fileName, majorVersion, minorVersion);
|
||||
entry.singleton = true;
|
||||
_components.insertMulti(entry.typeName, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (sections[0] == QLatin1String("typeinfo")) {
|
||||
if (sectionCount != 2) {
|
||||
reportError(lineNumber, 0,
|
||||
|
|
|
@ -93,17 +93,18 @@ public:
|
|||
struct Component
|
||||
{
|
||||
Component()
|
||||
: majorVersion(0), minorVersion(0), internal(false) {}
|
||||
: majorVersion(0), minorVersion(0), internal(false), singleton(false) {}
|
||||
|
||||
Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion)
|
||||
: typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion),
|
||||
internal(false) {}
|
||||
internal(false), singleton(false) {}
|
||||
|
||||
QString typeName;
|
||||
QString fileName;
|
||||
int majorVersion;
|
||||
int minorVersion;
|
||||
bool internal;
|
||||
bool singleton;
|
||||
};
|
||||
|
||||
struct Script
|
||||
|
|
|
@ -129,25 +129,36 @@ bool isPathAbsolute(const QString &path)
|
|||
}
|
||||
|
||||
// If the type does not already exist as a file import, add the type and return the new type
|
||||
QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, QList<QQmlError> *errors)
|
||||
QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, bool isCompositeSingleton, QList<QQmlError> *errors)
|
||||
{
|
||||
QUrl url(urlString);
|
||||
QQmlType *ret = QQmlMetaType::qmlType(url);
|
||||
if (!ret) { //QQmlType not yet existing for composite type
|
||||
if (!ret) { //QQmlType not yet existing for composite or composite singleton type
|
||||
int dot = typeName.indexOf(QLatin1Char('.'));
|
||||
QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1);
|
||||
|
||||
//XXX: The constData of the string ref is pointing somewhere unsafe in qmlregister, so we need to create a temporary copy
|
||||
QByteArray buf(unqualifiedtype.toString().toUtf8());
|
||||
|
||||
QQmlPrivate::RegisterCompositeType reg = {
|
||||
url,
|
||||
"", //Empty URI indicates loaded via file imports
|
||||
-1,
|
||||
-1,
|
||||
buf.constData()
|
||||
};
|
||||
ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, ®));
|
||||
if (isCompositeSingleton) {
|
||||
QQmlPrivate::RegisterCompositeSingletonType reg = {
|
||||
url,
|
||||
"", //Empty URI indicates loaded via file imports
|
||||
-1,
|
||||
-1,
|
||||
buf.constData()
|
||||
};
|
||||
ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, ®));
|
||||
} else {
|
||||
QQmlPrivate::RegisterCompositeType reg = {
|
||||
url,
|
||||
"", //Empty URI indicates loaded via file imports
|
||||
-1,
|
||||
-1,
|
||||
buf.constData()
|
||||
};
|
||||
ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, ®));
|
||||
}
|
||||
}
|
||||
if (!ret) {//Usually when a type name is "found" but invalid
|
||||
//qDebug() << ret << urlString << QQmlMetaType::qmlType(url);
|
||||
|
@ -158,10 +169,9 @@ QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeNa
|
|||
errors->prepend(error);
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
struct RegisteredPlugin {
|
||||
QString uri;
|
||||
|
@ -362,6 +372,61 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
|
|||
}
|
||||
}
|
||||
|
||||
// We need to exclude the entry for the current baseUrl. This can happen for example
|
||||
// when handling qmldir files on the remote dir case and the current type is marked as
|
||||
// singleton.
|
||||
bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QString baseUrl)
|
||||
{
|
||||
if (importUrl.isEmpty())
|
||||
return false;
|
||||
|
||||
if (baseUrl.startsWith(importUrl))
|
||||
{
|
||||
QString typeUrl(importUrl);
|
||||
typeUrl.append(fileName);
|
||||
if (typeUrl == baseUrl)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::CompositeSingletonReference> &resultList, QUrl baseUrl)
|
||||
{
|
||||
typedef QQmlDirComponents::const_iterator ConstIterator;
|
||||
|
||||
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
|
||||
const QQmlImportNamespace::Import *import = set.imports.at(ii);
|
||||
|
||||
const QQmlDirComponents &components = import->qmlDirComponents;
|
||||
|
||||
ConstIterator cend = components.constEnd();
|
||||
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
|
||||
if (cit->singleton && excludeBaseUrl(import->url, cit->fileName, baseUrl.toString())) {
|
||||
QQmlImports::CompositeSingletonReference ref;
|
||||
ref.typeName = cit->typeName;
|
||||
ref.prefix = set.prefix;
|
||||
resultList.append(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSingletons() const
|
||||
{
|
||||
QList<QQmlImports::CompositeSingletonReference> compositeSingletons;
|
||||
|
||||
const QQmlImportNamespace &set = d->unqualifiedset;
|
||||
findCompositeSingletons(set, compositeSingletons, baseUrl());
|
||||
|
||||
for (QQmlImportNamespace *ns = d->qualifiedSets.first(); ns; ns = d->qualifiedSets.next(ns)) {
|
||||
const QQmlImportNamespace &set = *ns;
|
||||
findCompositeSingletons(set, compositeSingletons, baseUrl());
|
||||
}
|
||||
|
||||
return compositeSingletons;
|
||||
}
|
||||
|
||||
QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
|
||||
{
|
||||
QList<QQmlImports::ScriptReference> scripts;
|
||||
|
@ -452,7 +517,9 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
|
|||
#define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \
|
||||
<< ')' << "::resolveType: " << type.toString() << " => "
|
||||
|
||||
if (type_return && *type_return && (*type_return)->isComposite())
|
||||
if (type_return && *type_return && (*type_return)->isCompositeSingleton())
|
||||
RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << (*type_return)->sourceUrl() << " TYPE/URL-SINGLETON";
|
||||
else if (type_return && *type_return && (*type_return)->isComposite())
|
||||
RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << (*type_return)->sourceUrl() << " TYPE/URL";
|
||||
else if (type_return && *type_return)
|
||||
RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << " TYPE";
|
||||
|
@ -544,6 +611,7 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
|
|||
QQmlDirComponents::ConstIterator it = qmlDirComponents.find(type), end = qmlDirComponents.end();
|
||||
if (it != end) {
|
||||
QString componentUrl;
|
||||
bool isCompositeSingleton = false;
|
||||
QQmlDirComponents::ConstIterator candidate = end;
|
||||
for ( ; it != end && it.key() == type; ++it) {
|
||||
const QQmlDirParser::Component &c = *it;
|
||||
|
@ -568,13 +636,14 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
|
|||
|
||||
// This is our best candidate so far
|
||||
candidate = it;
|
||||
isCompositeSingleton = c.singleton;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (candidate != end) {
|
||||
if (type_return)
|
||||
*type_return = getTypeForUrl(componentUrl, type, 0);
|
||||
*type_return = getTypeForUrl(componentUrl, type, isCompositeSingleton, 0);
|
||||
return (*type_return != 0);
|
||||
}
|
||||
} else if (!isLibrary) {
|
||||
|
@ -594,7 +663,7 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
|
|||
*typeRecursionDetected = true;
|
||||
} else {
|
||||
if (type_return)
|
||||
*type_return = getTypeForUrl(qmlUrl, type, 0);
|
||||
*type_return = getTypeForUrl(qmlUrl, type, false, 0);
|
||||
return (*type_return) != 0;
|
||||
}
|
||||
}
|
||||
|
@ -637,7 +706,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
|
|||
return true;
|
||||
if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
|
||||
// qualified, and only 1 url
|
||||
*type_return = getTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, errors);
|
||||
*type_return = getTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors);
|
||||
return (*type_return != 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,14 @@ public:
|
|||
|
||||
QList<ScriptReference> resolvedScripts() const;
|
||||
|
||||
struct CompositeSingletonReference
|
||||
{
|
||||
QString typeName;
|
||||
QString prefix;
|
||||
};
|
||||
|
||||
QList<CompositeSingletonReference> resolvedCompositeSingletons() const;
|
||||
|
||||
static QString completeQmldirPath(const QString &uri, const QString &base, int vmaj, int vmin,
|
||||
QQmlImports::ImportVersion version);
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#include <qvector.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include "qqmlcomponent.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -77,6 +78,10 @@ struct QQmlMetaTypeData
|
|||
Names nameToType;
|
||||
typedef QHash<QUrl, QQmlType *> Files; //For file imported composite types only
|
||||
Files urlToType;
|
||||
Files urlToNonFileImportType; // For non-file imported composite and composite
|
||||
// singleton types. This way we can locate any
|
||||
// of them by url, even if it was registered as
|
||||
// a module via qmlRegisterCompositeType.
|
||||
typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
|
||||
MetaObjects metaObjectToType;
|
||||
typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
|
||||
|
@ -225,6 +230,10 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
|
|||
setScriptApi(e, scriptCallback(e, e));
|
||||
} else if (qobjectCallback && !qobjectApi(e)) {
|
||||
setQObjectApi(e, qobjectCallback(e, e));
|
||||
} else if (!url.isEmpty() && !qobjectApi(e)) {
|
||||
QQmlComponent component(e, url, QQmlComponent::PreferSynchronous);
|
||||
QObject *o = component.create();
|
||||
setQObjectApi(e, o);
|
||||
}
|
||||
v4->popContext();
|
||||
}
|
||||
|
@ -279,6 +288,7 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
|
|||
extraData.cd->propertyValueInterceptorCast = -1;
|
||||
break;
|
||||
case QQmlType::SingletonType:
|
||||
case QQmlType::CompositeSingletonType:
|
||||
extraData.sd = new QQmlSingletonTypeData;
|
||||
extraData.sd->singletonInstanceInfo = 0;
|
||||
break;
|
||||
|
@ -300,6 +310,7 @@ QQmlTypePrivate::~QQmlTypePrivate()
|
|||
delete extraData.cd;
|
||||
break;
|
||||
case QQmlType::SingletonType:
|
||||
case QQmlType::CompositeSingletonType:
|
||||
delete extraData.sd->singletonInstanceInfo;
|
||||
delete extraData.sd;
|
||||
break;
|
||||
|
@ -351,6 +362,22 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg
|
|||
= (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0;
|
||||
}
|
||||
|
||||
QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterCompositeSingletonType &type)
|
||||
: d(new QQmlTypePrivate(CompositeSingletonType))
|
||||
{
|
||||
d->elementName = elementName;
|
||||
d->module = QString::fromUtf8(type.uri);
|
||||
|
||||
d->version_maj = type.versionMajor;
|
||||
d->version_min = type.versionMinor;
|
||||
|
||||
d->index = index;
|
||||
|
||||
d->extraData.sd->singletonInstanceInfo = new SingletonInstanceInfo;
|
||||
d->extraData.sd->singletonInstanceInfo->url = type.url;
|
||||
d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
|
||||
}
|
||||
|
||||
QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type)
|
||||
: d(new QQmlTypePrivate(CppType))
|
||||
{
|
||||
|
@ -650,7 +677,7 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
|
|||
|
||||
QByteArray QQmlType::typeName() const
|
||||
{
|
||||
if (d->regType == SingletonType)
|
||||
if (d->regType == SingletonType || d->regType == CompositeSingletonType)
|
||||
return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8();
|
||||
else if (d->baseMetaObject)
|
||||
return d->baseMetaObject->className();
|
||||
|
@ -710,7 +737,7 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con
|
|||
|
||||
QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
|
||||
{
|
||||
if (d->regType != SingletonType)
|
||||
if (d->regType != SingletonType && d->regType != CompositeSingletonType)
|
||||
return 0;
|
||||
return d->extraData.sd->singletonInstanceInfo;
|
||||
}
|
||||
|
@ -757,7 +784,7 @@ bool QQmlType::isExtendedType() const
|
|||
|
||||
bool QQmlType::isSingleton() const
|
||||
{
|
||||
return d->regType == SingletonType;
|
||||
return d->regType == SingletonType || d->regType == CompositeSingletonType;
|
||||
}
|
||||
|
||||
bool QQmlType::isInterface() const
|
||||
|
@ -767,7 +794,12 @@ bool QQmlType::isInterface() const
|
|||
|
||||
bool QQmlType::isComposite() const
|
||||
{
|
||||
return d->regType == CompositeType;
|
||||
return d->regType == CompositeType || d->regType == CompositeSingletonType;
|
||||
}
|
||||
|
||||
bool QQmlType::isCompositeSingleton() const
|
||||
{
|
||||
return d->regType == CompositeSingletonType;
|
||||
}
|
||||
|
||||
int QQmlType::typeId() const
|
||||
|
@ -869,9 +901,12 @@ int QQmlType::index() const
|
|||
|
||||
QUrl QQmlType::sourceUrl() const
|
||||
{
|
||||
if (d->regType != CompositeType)
|
||||
if (d->regType == CompositeType)
|
||||
return d->extraData.fd->url;
|
||||
else if (d->regType == CompositeSingletonType)
|
||||
return d->extraData.sd->singletonInstanceInfo->url;
|
||||
else
|
||||
return QUrl();
|
||||
return d->extraData.fd->url;
|
||||
}
|
||||
|
||||
int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
|
||||
|
@ -1006,7 +1041,6 @@ QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const
|
|||
return retn;
|
||||
}
|
||||
|
||||
|
||||
QQmlTypeModuleVersion::QQmlTypeModuleVersion()
|
||||
: m_module(0), m_minor(0)
|
||||
{
|
||||
|
@ -1070,6 +1104,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h
|
|||
data->idToType.clear();
|
||||
data->nameToType.clear();
|
||||
data->urlToType.clear();
|
||||
data->urlToNonFileImportType.clear();
|
||||
data->metaObjectToType.clear();
|
||||
data->uriToModule.clear();
|
||||
|
||||
|
@ -1123,6 +1158,8 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
|
|||
typeStr = QStringLiteral("element");
|
||||
else if (typeType == QQmlType::SingletonType)
|
||||
typeStr = QStringLiteral("singleton type");
|
||||
else if (typeType == QQmlType::CompositeSingletonType)
|
||||
typeStr = QStringLiteral("composite singleton type");
|
||||
else
|
||||
typeStr = QStringLiteral("type");
|
||||
return typeStr;
|
||||
|
@ -1254,6 +1291,31 @@ int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
|
|||
return index;
|
||||
}
|
||||
|
||||
int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type)
|
||||
{
|
||||
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
|
||||
QWriteLocker lock(metaTypeDataLock());
|
||||
QQmlMetaTypeData *data = metaTypeData();
|
||||
QString typeName = QString::fromUtf8(type.typeName);
|
||||
bool fileImport = false;
|
||||
if (*(type.uri) == '\0')
|
||||
fileImport = true;
|
||||
if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? 0 : type.uri, typeName))
|
||||
return -1;
|
||||
|
||||
int index = data->types.count();
|
||||
|
||||
QQmlType *dtype = new QQmlType(index, typeName, type);
|
||||
|
||||
data->types.append(dtype);
|
||||
addTypeToData(dtype, data);
|
||||
|
||||
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
|
||||
files->insertMulti(type.url, dtype);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
|
||||
{
|
||||
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
|
||||
|
@ -1272,8 +1334,8 @@ int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
|
|||
data->types.append(dtype);
|
||||
addTypeToData(dtype, data);
|
||||
|
||||
if (fileImport)
|
||||
data->urlToType.insertMulti(type.url, dtype);
|
||||
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
|
||||
files->insertMulti(type.url, dtype);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
@ -1295,6 +1357,8 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
|
|||
return registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
|
||||
} else if (type == CompositeRegistration) {
|
||||
return registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
|
||||
} else if (type == CompositeSingletonRegistration) {
|
||||
return registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -1708,12 +1772,15 @@ QQmlType *QQmlMetaType::qmlType(int userType)
|
|||
|
||||
Returns null if no such type is registered.
|
||||
*/
|
||||
QQmlType *QQmlMetaType::qmlType(const QUrl &url)
|
||||
QQmlType *QQmlMetaType::qmlType(const QUrl &url, bool includeNonFileImports /* = false */)
|
||||
{
|
||||
QReadLocker lock(metaTypeDataLock());
|
||||
QQmlMetaTypeData *data = metaTypeData();
|
||||
|
||||
QQmlType *type = data->urlToType.value(url);
|
||||
if (!type && includeNonFileImports)
|
||||
type = data->urlToNonFileImportType.value(url);
|
||||
|
||||
if (type && type->sourceUrl() == url)
|
||||
return type;
|
||||
else
|
||||
|
|
|
@ -86,7 +86,7 @@ public:
|
|||
static QQmlType *qmlType(const QMetaObject *);
|
||||
static QQmlType *qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor);
|
||||
static QQmlType *qmlType(int);
|
||||
static QQmlType *qmlType(const QUrl &url);
|
||||
static QQmlType *qmlType(const QUrl &url, bool includeNonFileImports = false);
|
||||
static QQmlType *qmlTypeFromIndex(int);
|
||||
|
||||
static QMetaProperty defaultProperty(const QMetaObject *);
|
||||
|
@ -169,6 +169,8 @@ public:
|
|||
bool isSingleton() const;
|
||||
bool isInterface() const;
|
||||
bool isComposite() const;
|
||||
bool isCompositeSingleton() const;
|
||||
|
||||
int typeId() const;
|
||||
int qListTypeId() const;
|
||||
|
||||
|
@ -198,6 +200,7 @@ public:
|
|||
QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *);
|
||||
const QMetaObject *instanceMetaObject;
|
||||
QString typeName;
|
||||
QUrl url; // used by composite singletons
|
||||
|
||||
void setQObjectApi(QQmlEngine *, QObject *);
|
||||
QObject *qobjectApi(QQmlEngine *) const;
|
||||
|
@ -211,6 +214,7 @@ public:
|
|||
QHash<QQmlEngine *, QObject *> qobjectApis;
|
||||
};
|
||||
SingletonInstanceInfo *singletonInstanceInfo() const;
|
||||
|
||||
QUrl sourceUrl() const;
|
||||
|
||||
int enumValue(const QHashedStringRef &, bool *ok) const;
|
||||
|
@ -225,7 +229,8 @@ private:
|
|||
CppType = 0,
|
||||
SingletonType = 1,
|
||||
InterfaceType = 2,
|
||||
CompositeType = 3
|
||||
CompositeType = 3,
|
||||
CompositeSingletonType = 4
|
||||
};
|
||||
friend QString registrationTypeString(RegistrationType);
|
||||
friend bool checkRegistration(RegistrationType, QQmlMetaTypeData *, const char *, const QString &, int);
|
||||
|
@ -233,11 +238,13 @@ private:
|
|||
friend int registerSingletonType(const QQmlPrivate::RegisterSingletonType &);
|
||||
friend int registerInterface(const QQmlPrivate::RegisterInterface &);
|
||||
friend int registerCompositeType(const QQmlPrivate::RegisterCompositeType &);
|
||||
friend int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &);
|
||||
friend Q_QML_EXPORT void qmlClearTypeRegistrations();
|
||||
QQmlType(int, const QQmlPrivate::RegisterInterface &);
|
||||
QQmlType(int, const QString &, const QQmlPrivate::RegisterSingletonType &);
|
||||
QQmlType(int, const QString &, const QQmlPrivate::RegisterType &);
|
||||
QQmlType(int, const QString &, const QQmlPrivate::RegisterCompositeType &);
|
||||
QQmlType(int, const QString &, const QQmlPrivate::RegisterCompositeSingletonType &);
|
||||
~QQmlType();
|
||||
|
||||
QQmlTypePrivate *d;
|
||||
|
|
|
@ -260,12 +260,21 @@ namespace QQmlPrivate
|
|||
const char *typeName;
|
||||
};
|
||||
|
||||
struct RegisterCompositeSingletonType {
|
||||
QUrl url;
|
||||
const char *uri;
|
||||
int versionMajor;
|
||||
int versionMinor;
|
||||
const char *typeName;
|
||||
};
|
||||
|
||||
enum RegistrationType {
|
||||
TypeRegistration = 0,
|
||||
InterfaceRegistration = 1,
|
||||
AutoParentRegistration = 2,
|
||||
SingletonRegistration = 3,
|
||||
CompositeRegistration = 4
|
||||
CompositeRegistration = 4,
|
||||
CompositeSingletonRegistration = 5
|
||||
};
|
||||
|
||||
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
|
||||
|
|
|
@ -517,6 +517,7 @@ protected:
|
|||
|
||||
virtual bool visit(AST::UiProgram *node);
|
||||
virtual bool visit(AST::UiImport *node);
|
||||
virtual bool visit(AST::UiPragma *node);
|
||||
virtual bool visit(AST::UiObjectDefinition *node);
|
||||
virtual bool visit(AST::UiPublicMember *node);
|
||||
virtual bool visit(AST::UiObjectBinding *node);
|
||||
|
@ -794,10 +795,10 @@ LocationSpan ProcessAST::location(AST::SourceLocation start, AST::SourceLocation
|
|||
return rv;
|
||||
}
|
||||
|
||||
// UiProgram: UiImportListOpt UiObjectMemberList ;
|
||||
// UiProgram: UiHeaderItemListOpt UiObjectMemberList ;
|
||||
bool ProcessAST::visit(AST::UiProgram *node)
|
||||
{
|
||||
accept(node->imports);
|
||||
accept(node->headers);
|
||||
accept(node->members->member);
|
||||
return false;
|
||||
}
|
||||
|
@ -889,6 +890,41 @@ bool ProcessAST::visit(AST::UiImport *node)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ProcessAST::visit(AST::UiPragma *node)
|
||||
{
|
||||
QQmlScript::Pragma pragma;
|
||||
|
||||
// For now the only valid pragma is Singleton, so lets validate the input
|
||||
if (!node->pragmaType->name.isNull())
|
||||
{
|
||||
if (QLatin1String("Singleton") == node->pragmaType->name.toString())
|
||||
{
|
||||
pragma.type = QQmlScript::Pragma::Singleton;
|
||||
} else {
|
||||
QQmlError error;
|
||||
error.setDescription(QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
|
||||
error.setLine(node->pragmaToken.startLine);
|
||||
error.setColumn(node->pragmaToken.startColumn);
|
||||
_parser->_errors << error;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
QQmlError error;
|
||||
error.setDescription(QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
|
||||
error.setLine(node->pragmaToken.startLine);
|
||||
error.setColumn(node->pragmaToken.startColumn);
|
||||
_parser->_errors << error;
|
||||
return false;
|
||||
}
|
||||
|
||||
AST::SourceLocation startLoc = node->pragmaToken;
|
||||
AST::SourceLocation endLoc = node->semicolonToken;
|
||||
pragma.location = location(startLoc, endLoc);
|
||||
_parser->_pragmas << pragma;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProcessAST::visit(AST::UiPublicMember *node)
|
||||
{
|
||||
static const struct TypeNameToType {
|
||||
|
@ -1364,6 +1400,11 @@ QList<QQmlScript::Import> QQmlScript::Parser::imports() const
|
|||
return _imports;
|
||||
}
|
||||
|
||||
QList<QQmlScript::Pragma> QQmlScript::Parser::pragmas() const
|
||||
{
|
||||
return _pragmas;
|
||||
}
|
||||
|
||||
QList<QQmlError> QQmlScript::Parser::errors() const
|
||||
{
|
||||
return _errors;
|
||||
|
@ -1416,7 +1457,7 @@ QQmlScript::Object::ScriptBlock::Pragmas QQmlScript::Parser::extractPragmas(QStr
|
|||
|
||||
token = l.lex();
|
||||
|
||||
if (token != QQmlJSGrammar::T_IDENTIFIER ||
|
||||
if (token != QQmlJSGrammar::T_PRAGMA ||
|
||||
l.tokenStartLine() != startLine ||
|
||||
script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
|
||||
return rv;
|
||||
|
@ -1506,7 +1547,6 @@ QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QStri
|
|||
|
||||
QQmlScript::Object::ScriptBlock::Pragmas &pragmas = rv.pragmas;
|
||||
|
||||
const QString pragma(QLatin1String("pragma"));
|
||||
const QString js(QLatin1String(".js"));
|
||||
const QString library(QLatin1String("library"));
|
||||
|
||||
|
@ -1681,10 +1721,7 @@ QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QStri
|
|||
|
||||
rv.imports << import;
|
||||
}
|
||||
|
||||
} else if (token == QQmlJSGrammar::T_IDENTIFIER &&
|
||||
script.mid(l.tokenOffset(), l.tokenLength()) == pragma) {
|
||||
|
||||
} else if (token == QQmlJSGrammar::T_PRAGMA) {
|
||||
token = l.lex();
|
||||
|
||||
CHECK_TOKEN(T_IDENTIFIER);
|
||||
|
@ -1713,6 +1750,7 @@ QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QStri
|
|||
|
||||
void QQmlScript::Parser::clear()
|
||||
{
|
||||
_pragmas.clear();
|
||||
_imports.clear();
|
||||
_refTypes.clear();
|
||||
_errors.clear();
|
||||
|
|
|
@ -120,6 +120,17 @@ public:
|
|||
QQmlScript::LocationSpan location;
|
||||
};
|
||||
|
||||
class Pragma
|
||||
{
|
||||
public:
|
||||
Pragma() : type(Singleton) {}
|
||||
|
||||
enum Type { Singleton };
|
||||
Type type;
|
||||
|
||||
QQmlScript::LocationSpan location;
|
||||
};
|
||||
|
||||
class Object;
|
||||
class TypeReference : public QQmlPool::Class
|
||||
{
|
||||
|
@ -474,6 +485,7 @@ public:
|
|||
|
||||
QQmlScript::Object *tree() const;
|
||||
QList<Import> imports() const;
|
||||
QList<Pragma> pragmas() const;
|
||||
|
||||
void clear();
|
||||
|
||||
|
@ -505,6 +517,7 @@ public:
|
|||
QQmlPool _pool;
|
||||
QQmlScript::Object *root;
|
||||
QList<Import> _imports;
|
||||
QList<Pragma> _pragmas;
|
||||
QList<TypeReference*> _refTypes;
|
||||
QString _scriptFile;
|
||||
ParserJsASTData *data;
|
||||
|
|
|
@ -1172,7 +1172,7 @@ void QQmlDataLoader::shutdownThread()
|
|||
}
|
||||
|
||||
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
|
||||
: QQmlDataBlob(url, type), m_typeLoader(loader), m_imports(loader)
|
||||
: QQmlDataBlob(url, type), m_typeLoader(loader), m_imports(loader), m_isSingleton(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1336,6 +1336,51 @@ bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQm
|
|||
return true;
|
||||
}
|
||||
|
||||
bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQmlError> *errors)
|
||||
{
|
||||
Q_ASSERT(errors);
|
||||
|
||||
if (pragma.type == QQmlScript::Pragma::Singleton) {
|
||||
QUrl myUrl = url();
|
||||
|
||||
QQmlType *ret = QQmlMetaType::qmlType(myUrl, true);
|
||||
if (!ret) {
|
||||
QQmlError error;
|
||||
error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
|
||||
error.setUrl(myUrl);
|
||||
error.setLine(pragma.location.start.line);
|
||||
error.setColumn(pragma.location.start.column);
|
||||
errors->prepend(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ret->isCompositeSingleton()) {
|
||||
QQmlError error;
|
||||
error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(ret->qmlTypeName()));
|
||||
error.setUrl(myUrl);
|
||||
error.setLine(pragma.location.start.line);
|
||||
error.setColumn(pragma.location.start.column);
|
||||
errors->prepend(error);
|
||||
return false;
|
||||
}
|
||||
// This flag is used for error checking when a qmldir file marks a type as
|
||||
// composite singleton, but there is no pragma Singleton defined in QML.
|
||||
m_isSingleton = true;
|
||||
} else {
|
||||
QQmlError error;
|
||||
error.setDescription(QLatin1String("Invalid pragma"));
|
||||
error.setUrl(url());
|
||||
error.setLine(pragma.location.start.line);
|
||||
error.setColumn(pragma.location.start.column);
|
||||
errors->prepend(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void QQmlTypeLoader::Blob::dependencyError(QQmlDataBlob *blob)
|
||||
{
|
||||
if (blob->type() == QQmlDataBlob::QmldirFile) {
|
||||
|
@ -1941,6 +1986,11 @@ const QSet<QString> &QQmlTypeData::namespaces() const
|
|||
return m_namespaces;
|
||||
}
|
||||
|
||||
const QList<QQmlTypeData::TypeReference> &QQmlTypeData::compositeSingletons() const
|
||||
{
|
||||
return m_compositeSingletons;
|
||||
}
|
||||
|
||||
QQmlCompiledData *QQmlTypeData::compiledData() const
|
||||
{
|
||||
return m_compiledData;
|
||||
|
@ -2015,6 +2065,36 @@ void QQmlTypeData::done()
|
|||
}
|
||||
// ---
|
||||
|
||||
// Check all composite singleton type dependencies for errors
|
||||
for (int ii = 0; !isError() && ii < m_compositeSingletons.count(); ++ii) {
|
||||
const TypeReference &type = m_compositeSingletons.at(ii);
|
||||
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
|
||||
if (type.typeData && type.typeData->isError()) {
|
||||
QString typeName = type.type->qmlTypeName();
|
||||
|
||||
QList<QQmlError> errors = type.typeData->errors();
|
||||
QQmlError error;
|
||||
error.setUrl(finalUrl());
|
||||
error.setLine(type.location.line);
|
||||
error.setColumn(type.location.column);
|
||||
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
|
||||
errors.prepend(error);
|
||||
setError(errors);
|
||||
}
|
||||
}
|
||||
|
||||
// If the type is CompositeSingleton but there was no pragma Singleton in the
|
||||
// QML file, lets report an error.
|
||||
QQmlType *type = QQmlMetaType::qmlType(url(), true);
|
||||
if (type && type->isCompositeSingleton() && !m_isSingleton) {
|
||||
QString typeName = type->qmlTypeName();
|
||||
|
||||
QQmlError error;
|
||||
error.setDescription(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
|
||||
error.setUrl(finalUrl());
|
||||
setError(error);
|
||||
}
|
||||
|
||||
// Compile component
|
||||
if (!isError())
|
||||
compile();
|
||||
|
@ -2140,6 +2220,14 @@ void QQmlTypeData::dataReceived(const Data &data)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const QQmlScript::Pragma &pragma, scriptParser.pragmas()) {
|
||||
if (!addPragma(pragma, &errors)) {
|
||||
Q_ASSERT(errors.size());
|
||||
setError(errors);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QQmlTypeData::allDependenciesDone()
|
||||
|
@ -2327,61 +2415,51 @@ void QQmlTypeData::resolveTypes()
|
|||
m_scripts << ref;
|
||||
}
|
||||
|
||||
// Lets handle resolved composite singleton types
|
||||
foreach (const QQmlImports::CompositeSingletonReference &csRef, m_imports.resolvedCompositeSingletons()) {
|
||||
TypeReference ref;
|
||||
QQmlScript::TypeReference parserRef;
|
||||
parserRef.name = csRef.typeName;
|
||||
// we are basing our type on the information from qmldir and therefore
|
||||
// do not have a proper location.
|
||||
parserRef.firstUse = NULL;
|
||||
|
||||
if (!csRef.prefix.isEmpty()) {
|
||||
parserRef.name.prepend(csRef.prefix + QLatin1Char('.'));
|
||||
// Add a reference to the enclosing namespace
|
||||
m_namespaces.insert(csRef.prefix);
|
||||
}
|
||||
|
||||
int majorVersion = -1;
|
||||
int minorVersion = -1;
|
||||
|
||||
if (!resolveType(&parserRef, majorVersion, minorVersion, ref))
|
||||
return;
|
||||
|
||||
if (ref.type->isCompositeSingleton()) {
|
||||
ref.typeData = typeLoader()->getType(ref.type->sourceUrl());
|
||||
addDependency(ref.typeData);
|
||||
ref.prefix = csRef.prefix;
|
||||
|
||||
m_compositeSingletons << ref;
|
||||
}
|
||||
}
|
||||
|
||||
// --- old compiler:
|
||||
foreach (QQmlScript::TypeReference *parserRef, scriptParser.referencedTypes()) {
|
||||
TypeReference ref;
|
||||
|
||||
int majorVersion = -1;
|
||||
int minorVersion = -1;
|
||||
QQmlImportNamespace *typeNamespace = 0;
|
||||
QList<QQmlError> errors;
|
||||
|
||||
bool typeFound = m_imports.resolveType(parserRef->name, &ref.type,
|
||||
&majorVersion, &minorVersion, &typeNamespace, &errors);
|
||||
if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
|
||||
// Lazy loading of implicit import
|
||||
if (loadImplicitImport()) {
|
||||
// Try again to find the type
|
||||
errors.clear();
|
||||
typeFound = m_imports.resolveType(parserRef->name, &ref.type,
|
||||
&majorVersion, &minorVersion, &typeNamespace, &errors);
|
||||
} else {
|
||||
return; //loadImplicitImport() hit an error, and called setError already
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeFound || typeNamespace) {
|
||||
// Known to not be a type:
|
||||
// - known to be a namespace (Namespace {})
|
||||
// - type with unknown namespace (UnknownNamespace.SomeType {})
|
||||
QQmlError error;
|
||||
if (typeNamespace) {
|
||||
error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(parserRef->name));
|
||||
} else {
|
||||
if (errors.size()) {
|
||||
error = errors.takeFirst();
|
||||
} else {
|
||||
// this should not be possible!
|
||||
// Description should come from error provided by addImport() function.
|
||||
error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
|
||||
}
|
||||
error.setUrl(m_imports.baseUrl());
|
||||
error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(parserRef->name).arg(error.description()));
|
||||
}
|
||||
|
||||
Q_ASSERT(parserRef->firstUse);
|
||||
error.setLine(parserRef->firstUse->location.start.line);
|
||||
error.setColumn(parserRef->firstUse->location.start.column);
|
||||
|
||||
errors.prepend(error);
|
||||
setError(errors);
|
||||
if (!resolveType(parserRef, majorVersion, minorVersion, ref))
|
||||
return;
|
||||
}
|
||||
|
||||
if (ref.type->isComposite()) {
|
||||
ref.typeData = typeLoader()->getType(ref.type->sourceUrl());
|
||||
addDependency(ref.typeData);
|
||||
}
|
||||
|
||||
ref.majorVersion = majorVersion;
|
||||
ref.minorVersion = minorVersion;
|
||||
|
||||
|
@ -2466,6 +2544,58 @@ void QQmlTypeData::resolveTypes()
|
|||
}
|
||||
}
|
||||
|
||||
bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int &majorVersion, int &minorVersion, TypeReference &ref)
|
||||
{
|
||||
QQmlImportNamespace *typeNamespace = 0;
|
||||
QList<QQmlError> errors;
|
||||
|
||||
bool typeFound = m_imports.resolveType(parserRef->name, &ref.type,
|
||||
&majorVersion, &minorVersion, &typeNamespace, &errors);
|
||||
if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
|
||||
// Lazy loading of implicit import
|
||||
if (loadImplicitImport()) {
|
||||
// Try again to find the type
|
||||
errors.clear();
|
||||
typeFound = m_imports.resolveType(parserRef->name, &ref.type,
|
||||
&majorVersion, &minorVersion, &typeNamespace, &errors);
|
||||
} else {
|
||||
return false; //loadImplicitImport() hit an error, and called setError already
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeFound || typeNamespace) {
|
||||
// Known to not be a type:
|
||||
// - known to be a namespace (Namespace {})
|
||||
// - type with unknown namespace (UnknownNamespace.SomeType {})
|
||||
QQmlError error;
|
||||
if (typeNamespace) {
|
||||
error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(parserRef->name));
|
||||
} else {
|
||||
if (errors.size()) {
|
||||
error = errors.takeFirst();
|
||||
} else {
|
||||
// this should not be possible!
|
||||
// Description should come from error provided by addImport() function.
|
||||
error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
|
||||
}
|
||||
error.setUrl(m_imports.baseUrl());
|
||||
error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(parserRef->name).arg(error.description()));
|
||||
}
|
||||
|
||||
if (parserRef->firstUse)
|
||||
{
|
||||
error.setLine(parserRef->firstUse->location.start.line);
|
||||
error.setColumn(parserRef->firstUse->location.start.column);
|
||||
}
|
||||
|
||||
errors.prepend(error);
|
||||
setError(errors);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
|
||||
{
|
||||
ScriptReference ref;
|
||||
|
|
|
@ -279,6 +279,7 @@ public:
|
|||
|
||||
protected:
|
||||
bool addImport(const QQmlScript::Import &import, QList<QQmlError> *errors);
|
||||
bool addPragma(const QQmlScript::Pragma &pragma, QList<QQmlError> *errors);
|
||||
|
||||
bool fetchQmldir(const QUrl &url, const QQmlScript::Import *import, int priority, QList<QQmlError> *errors);
|
||||
bool updateQmldir(QQmlQmldirData *data, const QQmlScript::Import *import, QList<QQmlError> *errors);
|
||||
|
@ -294,6 +295,7 @@ public:
|
|||
protected:
|
||||
QQmlTypeLoader *m_typeLoader;
|
||||
QQmlImports m_imports;
|
||||
bool m_isSingleton;
|
||||
QHash<const QQmlScript::Import *, int> m_unresolvedImports;
|
||||
QList<QQmlQmldirData *> m_qmldirs;
|
||||
};
|
||||
|
@ -401,6 +403,7 @@ public:
|
|||
int majorVersion;
|
||||
int minorVersion;
|
||||
QQmlTypeData *typeData;
|
||||
QString prefix; // used by CompositeSingleton types
|
||||
};
|
||||
|
||||
struct ScriptReference
|
||||
|
@ -425,6 +428,7 @@ public:
|
|||
const QList<TypeReference> &resolvedTypes() const;
|
||||
const QList<ScriptReference> &resolvedScripts() const;
|
||||
const QSet<QString> &namespaces() const;
|
||||
const QList<TypeReference> &compositeSingletons() const;
|
||||
|
||||
QQmlCompiledData *compiledData() const;
|
||||
|
||||
|
@ -447,6 +451,7 @@ protected:
|
|||
private:
|
||||
void resolveTypes();
|
||||
void compile();
|
||||
bool resolveType(const QQmlScript::TypeReference *parserRef, int &majorVersion, int &minorVersion, TypeReference &ref);
|
||||
|
||||
virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace);
|
||||
|
||||
|
@ -459,6 +464,7 @@ private:
|
|||
QList<ScriptReference> m_scripts;
|
||||
|
||||
QSet<QString> m_namespaces;
|
||||
QList<TypeReference> m_compositeSingletons;
|
||||
|
||||
// --- old compiler
|
||||
QList<TypeReference> m_types;
|
||||
|
|
|
@ -53,6 +53,21 @@ QQmlTypeNameCache::~QQmlTypeNameCache()
|
|||
{
|
||||
}
|
||||
|
||||
void QQmlTypeNameCache::add(const QHashedString &name, const QUrl &url, const QHashedString &nameSpace)
|
||||
{
|
||||
if (nameSpace.length() != 0) {
|
||||
Import *i = m_namedImports.value(nameSpace);
|
||||
Q_ASSERT(i != 0);
|
||||
i->compositeSingletons.insert(name, url);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_anonymousCompositeSingletons.contains(name))
|
||||
return;
|
||||
|
||||
m_anonymousCompositeSingletons.insert(name, url);
|
||||
}
|
||||
|
||||
void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex, const QHashedString &nameSpace)
|
||||
{
|
||||
Import import;
|
||||
|
@ -78,6 +93,9 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name)
|
|||
if (!result.isValid())
|
||||
result = typeSearch(m_anonymousImports, name);
|
||||
|
||||
if (!result.isValid())
|
||||
result = query(m_anonymousCompositeSingletons, name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -88,7 +106,12 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
|
|||
const Import *i = static_cast<const Import *>(importNamespace);
|
||||
Q_ASSERT(i->scriptIndex == -1);
|
||||
|
||||
return typeSearch(i->modules, name);
|
||||
Result result = result = typeSearch(i->modules, name);
|
||||
|
||||
if (!result.isValid())
|
||||
result = query(i->compositeSingletons, name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name)
|
||||
|
@ -98,6 +121,9 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name)
|
|||
if (!result.isValid())
|
||||
result = typeSearch(m_anonymousImports, name);
|
||||
|
||||
if (!result.isValid())
|
||||
result = query(m_anonymousCompositeSingletons, name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -114,7 +140,12 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons
|
|||
return r;
|
||||
}
|
||||
|
||||
return typeSearch(i->modules, name);
|
||||
Result r = typeSearch(i->modules, name);
|
||||
|
||||
if (!r.isValid())
|
||||
r = query(i->compositeSingletons, name);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
inline bool isEmpty() const;
|
||||
|
||||
void add(const QHashedString &name, int sciptIndex = -1, const QHashedString &nameSpace = QHashedString());
|
||||
void add(const QHashedString &name, const QUrl &url, const QHashedString &nameSpace = QHashedString());
|
||||
|
||||
struct Result {
|
||||
inline Result();
|
||||
|
@ -103,6 +104,9 @@ private:
|
|||
|
||||
// Or, imported script
|
||||
int scriptIndex;
|
||||
|
||||
// Or, imported compositeSingletons
|
||||
QStringHash<QUrl> compositeSingletons;
|
||||
};
|
||||
|
||||
template<typename Key>
|
||||
|
@ -120,6 +124,19 @@ private:
|
|||
return Result();
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
Result query(const QStringHash<QUrl> &urls, Key key)
|
||||
{
|
||||
QUrl *url = urls.value(key);
|
||||
if (url) {
|
||||
QQmlType *type = QQmlMetaType::qmlType(*url);
|
||||
if (type)
|
||||
return Result(type);
|
||||
}
|
||||
|
||||
return Result();
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
Result typeSearch(const QVector<QQmlTypeModuleVersion> &modules, Key key)
|
||||
{
|
||||
|
@ -135,8 +152,7 @@ private:
|
|||
QStringHash<Import> m_namedImports;
|
||||
QMap<const Import *, QStringHash<Import> > m_namespacedImports;
|
||||
QVector<QQmlTypeModuleVersion> m_anonymousImports;
|
||||
|
||||
QQmlEngine *engine;
|
||||
QStringHash<QUrl> m_anonymousCompositeSingletons;
|
||||
};
|
||||
|
||||
QQmlTypeNameCache::Result::Result()
|
||||
|
@ -176,7 +192,8 @@ QQmlTypeNameCache::Import::Import()
|
|||
|
||||
bool QQmlTypeNameCache::isEmpty() const
|
||||
{
|
||||
return m_namedImports.isEmpty() && m_anonymousImports.isEmpty();
|
||||
return m_namedImports.isEmpty() && m_anonymousImports.isEmpty()
|
||||
&& m_anonymousCompositeSingletons.isEmpty();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -157,8 +157,7 @@ void tst_qqmldirparser::parse_data()
|
|||
|
||||
QTest::newRow("four-sections")
|
||||
<< "four-sections/qmldir"
|
||||
<< (QStringList() << "qmldir:1:12: unexpected token"
|
||||
<< "qmldir:1: invalid qmldir directive contains too many tokens")
|
||||
<< (QStringList() << "qmldir:1: a component declaration requires two or three arguments, but 4 were provided")
|
||||
<< QStringList()
|
||||
<< QStringList()
|
||||
<< QStringList();
|
||||
|
@ -200,8 +199,7 @@ void tst_qqmldirparser::parse_data()
|
|||
|
||||
QTest::newRow("excessive-plugin")
|
||||
<< "excessive-plugin/qmldir"
|
||||
<< (QStringList() << "qmldir:1:15: unexpected token"
|
||||
<< "qmldir:1: invalid qmldir directive contains too many tokens")
|
||||
<< (QStringList() << "qmldir:1: plugin directive requires one or two arguments, but 3 were provided")
|
||||
<< QStringList()
|
||||
<< QStringList()
|
||||
<< QStringList();
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import QtQuick 2.0
|
||||
pragma Singleton
|
||||
|
||||
Item {
|
||||
id: singletonId
|
||||
|
||||
property int testProp1: 125
|
||||
property int testProp2: 25
|
||||
property int testProp3: -55
|
||||
|
||||
width: 25; height: 25
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
border.color: "white"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||
** of its contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
.pragma library
|
||||
|
||||
var value = 333
|
|
@ -0,0 +1,17 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: singletonId
|
||||
|
||||
property int testProp1: 125
|
||||
property int testProp2: 25
|
||||
property int testProp3: -55
|
||||
|
||||
width: 25; height: 25
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
border.color: "white"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: singletonId
|
||||
|
||||
property int testProp1: 225
|
||||
property int testProp2: 125
|
||||
property int testProp3: 55
|
||||
|
||||
width: 25; height: 25
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
border.color: "white"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import QtQuick 2.0
|
||||
pragma Singleton
|
||||
|
||||
Item {
|
||||
id: singletonId
|
||||
|
||||
property int testProp1: 125
|
||||
property int testProp2: 25
|
||||
property int testProp3: -55
|
||||
|
||||
width: 25; height: 25
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
border.color: "white"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
pragma Singleton
|
||||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: singletonId
|
||||
|
||||
property int testProp1: 225
|
||||
property int testProp2: 125
|
||||
property int testProp3: 55
|
||||
|
||||
width: 25; height: 25
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
border.color: "white"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module org.qtproject.SingletonTest
|
||||
singleton SingletonType 1.0 SingletonType.qml
|
||||
singleton SingletonType 2.2 SingletonType22.qml
|
||||
NonSingletonType 1.0 NonSingletonType.qml
|
||||
NonSingletonType 2.5 NonSingletonType25.qml
|
|
@ -0,0 +1,3 @@
|
|||
singleton SingletonType SingletonType.qml
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import QtQuick 2.0
|
||||
pragma Singleton
|
||||
|
||||
Item {
|
||||
id: singletonId
|
||||
|
||||
property int testProp1: 125
|
||||
property int testProp2: 25
|
||||
property int testProp3: -55
|
||||
|
||||
width: 25; height: 25
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
border.color: "white"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
singleton SType2
|
|
@ -0,0 +1,17 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: singletonId
|
||||
|
||||
property int testProp1: 125
|
||||
property int testProp2: 25
|
||||
property int testProp3: -55
|
||||
|
||||
width: 25; height: 25
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
border.color: "white"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import QtQuick 2.0
|
||||
pragma Singleton
|
||||
|
||||
Item {
|
||||
id: singletonId
|
||||
|
||||
property int testProp1: 325
|
||||
property int testProp2: 225
|
||||
property int testProp3: 155
|
||||
|
||||
width: 25; height: 25
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
border.color: "white"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import QtQuick 2.0
|
||||
pragma Singleton
|
||||
|
||||
Item {
|
||||
id: singletonId
|
||||
|
||||
property int testProp1: 525
|
||||
property int testProp2: 425
|
||||
property int testProp3: 355
|
||||
|
||||
width: 25; height: 25
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
border.color: "white"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
singleton RemoteSingletonType2 RemoteSingletonType2.qml
|
|
@ -0,0 +1,17 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: singletonId
|
||||
|
||||
property int testProp1: 125
|
||||
property int testProp2: 25
|
||||
property int testProp3: -55
|
||||
|
||||
width: 25; height: 25
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
border.color: "white"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
singleton ErrorSingletonType ErrorSingletonType.qml
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton"
|
||||
|
||||
Item {
|
||||
property int value1: SingletonType.testProp1;
|
||||
property string value2: "Test value: " + SingletonType.testProp3;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
4:1:Composite Singleton Type SingletonType is not creatable.
|
|
@ -0,0 +1,6 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton"
|
||||
|
||||
Item {
|
||||
property SingletonType test
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton"
|
||||
|
||||
Item {
|
||||
id: test
|
||||
|
||||
property int value1: SingletonType.testProp1;
|
||||
property string value2: "Test value: " + SingletonType.testProp3;
|
||||
|
||||
signal customSignal(SingletonType type)
|
||||
|
||||
onCustomSignal: {
|
||||
type.testProp1 = 99
|
||||
}
|
||||
|
||||
Component.onCompleted: test.customSignal(SingletonType)
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
5:5:Type RegisteredCompositeType unavailable
|
||||
2:1:pragma Singleton used with a non composite singleton type CompositeSingletonTest/RegisteredCompositeType
|
|
@ -0,0 +1,6 @@
|
|||
import QtQuick 2.0
|
||||
import CompositeSingletonTest 1.0
|
||||
|
||||
Item {
|
||||
RegisteredCompositeType { }
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
-1:-1:Type ErrorSingletonType unavailable
|
||||
-1:-1:qmldir defines type as singleton, but no pragma Singleton found in type ErrorSingletonType.
|
|
@ -0,0 +1,8 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton/subdir"
|
||||
|
||||
Item {
|
||||
property int value1: ErrorSingletonType.testProp1;
|
||||
property string value2: "Test value: " + ErrorSingletonType.testProp3;
|
||||
property variant singletonInstance: ErrorSingletonType;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
2:1:singleton types require 2 or 3 arguments, but 1 were provided
|
|
@ -0,0 +1,7 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton/qmldir-error"
|
||||
|
||||
Item {
|
||||
property int value1: SType2.testProp1;
|
||||
property string value2: "Test value: " + SType2.testProp3;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import QtQuick 2.0
|
||||
import "http://127.0.0.1:14447/singleton/remote"
|
||||
|
||||
Item {
|
||||
property int value1: RemoteSingletonType2.testProp1;
|
||||
property string value2: "Test value: " + RemoteSingletonType2.testProp3;
|
||||
property variant singletonInstance: RemoteSingletonType2;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton"
|
||||
import "singleton/js/jspragma.js" as JsPragmaTest
|
||||
|
||||
Item {
|
||||
id: test
|
||||
|
||||
property int value1: SingletonType.testProp1;
|
||||
property string value2: "Test value: " + JsPragmaTest.value;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton"
|
||||
|
||||
Item {
|
||||
property variant singleton1: SingletonType;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton"
|
||||
|
||||
Item {
|
||||
property QtObject singleton2: SingletonType;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
2:1:No matching type found, pragma Singleton files cannot be used by QQmlComponent.
|
|
@ -0,0 +1,6 @@
|
|||
import QtQuick 2.0
|
||||
pragma Singleton
|
||||
|
||||
Item {
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton" as TestNameSpace
|
||||
|
||||
Item {
|
||||
property int value1: TestNameSpace.SingletonType.testProp1;
|
||||
property string value2: "Test value: " + TestNameSpace.SingletonType.testProp3;
|
||||
property variant singletonInstance: TestNameSpace.SingletonType;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton"
|
||||
|
||||
Item {
|
||||
property variant singletonInstance: SingletonType;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import QtQuick 2.0
|
||||
import org.qtproject.SingletonTest 1.0
|
||||
|
||||
Item {
|
||||
property int value1: SingletonType.testProp1;
|
||||
property string value2: "Test value: " + SingletonType.testProp3;
|
||||
property variant singletonInstance: SingletonType;
|
||||
|
||||
NonSingletonType { id: nonSingleton }
|
||||
|
||||
property int value3: nonSingleton.testProp1;
|
||||
property string value4: "Test value: " + nonSingleton.testProp3;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import QtQuick 2.0
|
||||
import org.qtproject.SingletonTest 1.0
|
||||
|
||||
Item {
|
||||
property variant singletonInstance: SingletonType;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import QtQuick 2.0
|
||||
import org.qtproject.SingletonTest 2.5
|
||||
|
||||
Item {
|
||||
property int value1: SingletonType.testProp1;
|
||||
property string value2: "Test value: " + SingletonType.testProp3;
|
||||
property variant singletonInstance: SingletonType;
|
||||
|
||||
NonSingletonType { id: nonSingleton }
|
||||
|
||||
property int value3: nonSingleton.testProp1;
|
||||
property string value4: "Test value: " + nonSingleton.testProp3;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import QtQuick 2.0
|
||||
import org.qtproject.SingletonTest 2.5
|
||||
|
||||
Item {
|
||||
property variant singletonInstance: SingletonType;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import QtQuick 2.0
|
||||
import org.qtproject.SingletonTest 2.5 as TestNameSpace
|
||||
|
||||
Item {
|
||||
property int value1: TestNameSpace.SingletonType.testProp1;
|
||||
property string value2: "Test value: " + TestNameSpace.SingletonType.testProp3;
|
||||
property variant singletonInstance: TestNameSpace.SingletonType;
|
||||
|
||||
TestNameSpace.NonSingletonType { id: nonSingleton }
|
||||
|
||||
property int value3: nonSingleton.testProp1;
|
||||
property string value4: "Test value: " + nonSingleton.testProp3;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import QtQuick 2.0
|
||||
import org.qtproject.SingletonTest 2.5
|
||||
|
||||
Item {
|
||||
property variant singletonInstance: SingletonType;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
5:5:Composite Singleton Type SingletonType is not creatable.
|
|
@ -0,0 +1,6 @@
|
|||
import QtQuick 2.0
|
||||
import "singleton"
|
||||
|
||||
Item {
|
||||
SingletonType {}
|
||||
}
|
|
@ -193,6 +193,23 @@ private slots:
|
|||
|
||||
void deepProperty();
|
||||
|
||||
void compositeSingletonProperties();
|
||||
void compositeSingletonSameEngine();
|
||||
void compositeSingletonDifferentEngine();
|
||||
void compositeSingletonNonTypeError();
|
||||
void compositeSingletonQualifiedNamespace();
|
||||
void compositeSingletonModule();
|
||||
void compositeSingletonModuleVersioned();
|
||||
void compositeSingletonModuleQualified();
|
||||
void compositeSingletonInstantiateError();
|
||||
void compositeSingletonDynamicPropertyError();
|
||||
void compositeSingletonDynamicSignal();
|
||||
void compositeSingletonQmlRegisterTypeError();
|
||||
void compositeSingletonQmldirNoPragmaError();
|
||||
void compositeSingletonQmlDirError();
|
||||
void compositeSingletonRemote();
|
||||
void compositeSingletonJavaScriptPragma();
|
||||
|
||||
private:
|
||||
QQmlEngine engine;
|
||||
QStringList defaultImportPathList;
|
||||
|
@ -210,6 +227,9 @@ private:
|
|||
|| userType == (int) QVariant::UInt
|
||||
|| userType == (int) QVariant::Double;
|
||||
}
|
||||
|
||||
void getSingletonInstance(QQmlEngine& engine, const char* fileName, const char* propertyName, QObject** result /* out */);
|
||||
void getSingletonInstance(QObject* o, const char* propertyName, QObject** result /* out */);
|
||||
};
|
||||
|
||||
#define DETERMINE_ERRORS(errorfile,expected,actual)\
|
||||
|
@ -1893,6 +1913,7 @@ void tst_qqmllanguage::reservedWords_data()
|
|||
QTest::newRow("if") << QByteArray("if");
|
||||
QTest::newRow("implements") << QByteArray("implements");
|
||||
QTest::newRow("import") << QByteArray("import");
|
||||
QTest::newRow("pragma") << QByteArray("pragma");
|
||||
QTest::newRow("in") << QByteArray("in");
|
||||
QTest::newRow("instanceof") << QByteArray("instanceof");
|
||||
QTest::newRow("int") << QByteArray("int");
|
||||
|
@ -3194,6 +3215,291 @@ void tst_qqmllanguage::implicitImportsLast()
|
|||
engine.setImportPathList(defaultImportPathList);
|
||||
}
|
||||
|
||||
void tst_qqmllanguage::getSingletonInstance(QQmlEngine& engine, const char* fileName, const char* propertyName, QObject** result /* out */)
|
||||
{
|
||||
QVERIFY(fileName != 0);
|
||||
QVERIFY(propertyName != 0);
|
||||
|
||||
if (!fileName || !propertyName)
|
||||
return;
|
||||
|
||||
QQmlComponent component(&engine, testFile(fileName));
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *object = component.create();
|
||||
QVERIFY(object != 0);
|
||||
|
||||
getSingletonInstance(object, propertyName, result);
|
||||
}
|
||||
|
||||
void tst_qqmllanguage::getSingletonInstance(QObject* o, const char* propertyName, QObject** result /* out */)
|
||||
{
|
||||
QVERIFY(o != 0);
|
||||
QVERIFY(propertyName != 0);
|
||||
|
||||
if (!o || !propertyName)
|
||||
return;
|
||||
|
||||
QVariant variant = o->property(propertyName);
|
||||
QVERIFY(variant.userType() == qMetaTypeId<QObject *>());
|
||||
|
||||
QObject *singleton = NULL;
|
||||
if (variant.canConvert<QObject*>())
|
||||
singleton = variant.value<QObject*>();
|
||||
|
||||
QVERIFY(singleton != 0);
|
||||
*result = singleton;
|
||||
}
|
||||
|
||||
void verifyCompositeSingletonPropertyValues(QObject* o, const char* n1, int v1, const char* n2, int v2)
|
||||
{
|
||||
QCOMPARE(o->property(n1).userType(), (int)QMetaType::Int);
|
||||
QCOMPARE(o->property(n1), QVariant(v1));
|
||||
|
||||
QCOMPARE(o->property(n2).userType(), (int)QVariant::String);
|
||||
QString numStr;
|
||||
QCOMPARE(o->property(n2), QVariant(QString(QLatin1String("Test value: ")).append(numStr.setNum(v2))));
|
||||
}
|
||||
|
||||
// Reads values from a composite singleton type
|
||||
void tst_qqmllanguage::compositeSingletonProperties()
|
||||
{
|
||||
QQmlComponent component(&engine, testFile("singletonTest1.qml"));
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *o = component.create();
|
||||
QVERIFY(o != 0);
|
||||
|
||||
verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55);
|
||||
}
|
||||
|
||||
// Checks that the addresses of the composite singletons used in the same
|
||||
// engine are the same.
|
||||
void tst_qqmllanguage::compositeSingletonSameEngine()
|
||||
{
|
||||
QObject* s1 = NULL;
|
||||
getSingletonInstance(engine, "singletonTest2.qml", "singleton1", &s1);
|
||||
QVERIFY(s1 != 0);
|
||||
s1->setProperty("testProp2", QVariant(13));
|
||||
|
||||
QObject* s2 = NULL;
|
||||
getSingletonInstance(engine, "singletonTest3.qml", "singleton2", &s2);
|
||||
QVERIFY(s2 != 0);
|
||||
QCOMPARE(s2->property("testProp2"), QVariant(13));
|
||||
|
||||
QVERIFY(s1 == s2);
|
||||
}
|
||||
|
||||
// Checks that the addresses of the composite singletons used in different
|
||||
// engines are different.
|
||||
void tst_qqmllanguage::compositeSingletonDifferentEngine()
|
||||
{
|
||||
QQmlEngine e2;
|
||||
|
||||
QObject* s1 = NULL;
|
||||
getSingletonInstance(engine, "singletonTest2.qml", "singleton1", &s1);
|
||||
QVERIFY(s1 != 0);
|
||||
s1->setProperty("testProp2", QVariant(13));
|
||||
|
||||
QObject* s2 = NULL;
|
||||
getSingletonInstance(e2, "singletonTest3.qml", "singleton2", &s2);
|
||||
QVERIFY(s2 != 0);
|
||||
QCOMPARE(s2->property("testProp2"), QVariant(25));
|
||||
|
||||
QVERIFY(s1 != s2);
|
||||
}
|
||||
|
||||
// pragma Singleton in a non-type qml file fails
|
||||
void tst_qqmllanguage::compositeSingletonNonTypeError()
|
||||
{
|
||||
QQmlComponent component(&engine, testFile("singletonTest4.qml"));
|
||||
VERIFY_ERRORS("singletonTest4.error.txt");
|
||||
}
|
||||
|
||||
// Loads the singleton using a namespace qualifier
|
||||
void tst_qqmllanguage::compositeSingletonQualifiedNamespace()
|
||||
{
|
||||
QQmlComponent component(&engine, testFile("singletonTest5.qml"));
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *o = component.create();
|
||||
QVERIFY(o != 0);
|
||||
|
||||
verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55);
|
||||
|
||||
// lets verify that the singleton instance we are using is the same
|
||||
// when loaded through another file (without namespace!)
|
||||
QObject *s1 = NULL;
|
||||
getSingletonInstance(o, "singletonInstance", &s1);
|
||||
QVERIFY(s1 != 0);
|
||||
|
||||
QObject* s2 = NULL;
|
||||
getSingletonInstance(engine, "singletonTest5a.qml", "singletonInstance", &s2);
|
||||
QVERIFY(s2 != 0);
|
||||
|
||||
QVERIFY(s1 == s2);
|
||||
}
|
||||
|
||||
// Loads a singleton from a module
|
||||
void tst_qqmllanguage::compositeSingletonModule()
|
||||
{
|
||||
engine.addImportPath(testFile("singleton/module"));
|
||||
|
||||
QQmlComponent component(&engine, testFile("singletonTest6.qml"));
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *o = component.create();
|
||||
QVERIFY(o != 0);
|
||||
|
||||
verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55);
|
||||
verifyCompositeSingletonPropertyValues(o, "value3", 125, "value4", -55);
|
||||
|
||||
// lets verify that the singleton instance we are using is the same
|
||||
// when loaded through another file
|
||||
QObject *s1 = NULL;
|
||||
getSingletonInstance(o, "singletonInstance", &s1);
|
||||
QVERIFY(s1 != 0);
|
||||
|
||||
QObject* s2 = NULL;
|
||||
getSingletonInstance(engine, "singletonTest6a.qml", "singletonInstance", &s2);
|
||||
QVERIFY(s2 != 0);
|
||||
|
||||
QVERIFY(s1 == s2);
|
||||
}
|
||||
|
||||
// Loads a singleton from a module with a higher version
|
||||
void tst_qqmllanguage::compositeSingletonModuleVersioned()
|
||||
{
|
||||
engine.addImportPath(testFile("singleton/module"));
|
||||
|
||||
QQmlComponent component(&engine, testFile("singletonTest7.qml"));
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *o = component.create();
|
||||
QVERIFY(o != 0);
|
||||
|
||||
verifyCompositeSingletonPropertyValues(o, "value1", 225, "value2", 55);
|
||||
verifyCompositeSingletonPropertyValues(o, "value3", 225, "value4", 55);
|
||||
|
||||
// lets verify that the singleton instance we are using is the same
|
||||
// when loaded through another file
|
||||
QObject *s1 = NULL;
|
||||
getSingletonInstance(o, "singletonInstance", &s1);
|
||||
QVERIFY(s1 != 0);
|
||||
|
||||
QObject* s2 = NULL;
|
||||
getSingletonInstance(engine, "singletonTest7a.qml", "singletonInstance", &s2);
|
||||
QVERIFY(s2 != 0);
|
||||
|
||||
QVERIFY(s1 == s2);
|
||||
}
|
||||
|
||||
// Loads a singleton from a module with a qualified namespace
|
||||
void tst_qqmllanguage::compositeSingletonModuleQualified()
|
||||
{
|
||||
engine.addImportPath(testFile("singleton/module"));
|
||||
|
||||
QQmlComponent component(&engine, testFile("singletonTest8.qml"));
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *o = component.create();
|
||||
QVERIFY(o != 0);
|
||||
|
||||
verifyCompositeSingletonPropertyValues(o, "value1", 225, "value2", 55);
|
||||
verifyCompositeSingletonPropertyValues(o, "value3", 225, "value4", 55);
|
||||
|
||||
// lets verify that the singleton instance we are using is the same
|
||||
// when loaded through another file
|
||||
QObject *s1 = NULL;
|
||||
getSingletonInstance(o, "singletonInstance", &s1);
|
||||
QVERIFY(s1 != 0);
|
||||
|
||||
QObject* s2 = NULL;
|
||||
getSingletonInstance(engine, "singletonTest8a.qml", "singletonInstance", &s2);
|
||||
QVERIFY(s2 != 0);
|
||||
|
||||
QVERIFY(s1 == s2);
|
||||
}
|
||||
|
||||
// Tries to instantiate a type with a pragma Singleton and fails
|
||||
void tst_qqmllanguage::compositeSingletonInstantiateError()
|
||||
{
|
||||
QQmlComponent component(&engine, testFile("singletonTest9.qml"));
|
||||
VERIFY_ERRORS("singletonTest9.error.txt");
|
||||
}
|
||||
|
||||
// Having a composite singleton type as dynamic property type fails
|
||||
// (like C++ singleton)
|
||||
void tst_qqmllanguage::compositeSingletonDynamicPropertyError()
|
||||
{
|
||||
QQmlComponent component(&engine, testFile("singletonTest10.qml"));
|
||||
VERIFY_ERRORS("singletonTest10.error.txt");
|
||||
}
|
||||
|
||||
// Having a composite singleton type as dynamic signal parameter succeeds
|
||||
// (like C++ singleton)
|
||||
void tst_qqmllanguage::compositeSingletonDynamicSignal()
|
||||
{
|
||||
QQmlComponent component(&engine, testFile("singletonTest11.qml"));
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *o = component.create();
|
||||
QVERIFY(o != 0);
|
||||
|
||||
verifyCompositeSingletonPropertyValues(o, "value1", 99, "value2", -55);
|
||||
}
|
||||
|
||||
// Use qmlRegisterType to register a qml composite type with pragma Singleton defined in it.
|
||||
// This will fail as qmlRegisterType will only instantiate CompositeTypes.
|
||||
void tst_qqmllanguage::compositeSingletonQmlRegisterTypeError()
|
||||
{
|
||||
qmlRegisterType(testFileUrl("singleton/registeredComposite/CompositeType.qml"),
|
||||
"CompositeSingletonTest", 1, 0, "RegisteredCompositeType");
|
||||
QQmlComponent component(&engine, testFile("singletonTest12.qml"));
|
||||
VERIFY_ERRORS("singletonTest12.error.txt");
|
||||
}
|
||||
|
||||
// Qmldir defines a type as a singleton, but the qml file does not have a pragma Singleton.
|
||||
void tst_qqmllanguage::compositeSingletonQmldirNoPragmaError()
|
||||
{
|
||||
QQmlComponent component(&engine, testFile("singletonTest13.qml"));
|
||||
VERIFY_ERRORS("singletonTest13.error.txt");
|
||||
}
|
||||
|
||||
// Invalid singleton definition in the qmldir file results in an error
|
||||
void tst_qqmllanguage::compositeSingletonQmlDirError()
|
||||
{
|
||||
QQmlComponent component(&engine, testFile("singletonTest14.qml"));
|
||||
VERIFY_ERRORS("singletonTest14.error.txt");
|
||||
}
|
||||
|
||||
// Load a remote composite singleton type via qmldir that defines the type as a singleton
|
||||
void tst_qqmllanguage::compositeSingletonRemote()
|
||||
{
|
||||
TestHTTPServer server(14447);
|
||||
server.serveDirectory(dataDirectory());
|
||||
|
||||
QQmlComponent component(&engine, testFile("singletonTest15.qml"));
|
||||
|
||||
while (component.isLoading())
|
||||
QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents, 50);
|
||||
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *o = component.create();
|
||||
QVERIFY(o != 0);
|
||||
|
||||
verifyCompositeSingletonPropertyValues(o, "value1", 525, "value2", 355);
|
||||
}
|
||||
|
||||
// Load a composite singleton type and a javascript file that has .pragma library
|
||||
// in it. This will make sure that the javascript .pragma does not get mixed with
|
||||
// the pragma Singleton changes.
|
||||
void tst_qqmllanguage::compositeSingletonJavaScriptPragma()
|
||||
{
|
||||
QQmlComponent component(&engine, testFile("singletonTest16.qml"));
|
||||
VERIFY_ERRORS(0);
|
||||
QObject *o = component.create();
|
||||
QVERIFY(o != 0);
|
||||
|
||||
// The value1 that is read from the SingletonType was changed from 125 to 99
|
||||
// in compositeSingletonDynamicSignal() above. As the type is a singleton and
|
||||
// the engine has not been destroyed, we just retrieve the old instance and
|
||||
// the value is still 99.
|
||||
verifyCompositeSingletonPropertyValues(o, "value1", 99, "value2", 333);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmllanguage)
|
||||
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
1:12:unexpected token
|
||||
1:-1:invalid qmldir directive contains too many tokens
|
||||
2:17:unexpected token
|
||||
2:-1:invalid qmldir directive contains too many tokens
|
||||
1:-1:a component declaration requires two or three arguments, but 4 were provided
|
||||
2:-1:internal types require 2 arguments, but 3 were provided
|
||||
|
|
Loading…
Reference in New Issue